Welcome to the CHICKEN Scheme pasting service

c-struct concept pasted by rivo on Sun Sep 29 19:38:57 2013

#>
typedef struct { int x; int y; } point;
<#

(define-c-struct point "point" (x int) (y int))

(make-point x: 1 y: 1)
;=> #<point #{0000000100000001}>

(point-x-set! p 2)
;=> #<point #{0000000200000001}>

no title added by rivo on Sun Sep 29 19:43:22 2013

(module c-struct
 (define-c-struct)
 (import scheme chicken foreign)

(define-syntax define-c-struct
  (syntax-rules ()
    ((define-c-struct name type members ...)
     (gen-c-struct (name type) () members ...))))

(define-syntax gen-c-struct
  (syntax-rules (struct)
    ((_ hdr (lst ...))
     (gen-c-stubs hdr lst ...))
    ((_ hdr (lst ...) (name type) rest ...)
     (gen-c-struct hdr (lst ... name type) rest ...))
    ((_ hdr lst arg rest ...)
     (syntax-error "invalid c-struct member definition" arg))))

(define-syntax gen-c-stubs
  (er-macro-transformer
    (lambda (e r c)
      ;e (gen-c-stubs (struct-name struct-type) member-name member-type ...))
      (let* ((struct (cadr e))
             (struct-name (car struct))
             (struct-type (cadr struct)))
        (or (symbol? struct-name) (syntax-error "c-struct name expect symbol" struct-name))
        (or (string? struct-type) (syntax-error "c-struct type expect string" struct-type))
        (define (struct-type? type)
          (and (list? type) (eq? (car type) 'struct)))
        (define (gen-member-name name suffix)
          (string->symbol (sprintf "~A-~A~A" struct-name name suffix)))
        ; ffi cannot pass struct by value to make workaround
        (define (gen-type type)
          (if (struct-type? type) `(c-pointer ,type) type))
        (define (gen-value-ref name type)
          `(foreign-lambda* ,(gen-type type) ((scheme-pointer ptr))
             ,(if (struct-type? type)
                (sprintf "C_return( &((~A *)ptr) -> ~A);" struct-type name)
                (sprintf "C_return(  ((~A *)ptr) -> ~A);" struct-type name))))
        (define (gen-value-set! name type)
          `(foreign-lambda* void ((scheme-pointer ptr) (,(gen-type type) value))
             ,(if (struct-type? type)
                (sprintf " ((~A *)ptr) -> ~A = *value;" struct-type name)
                (sprintf " ((~A *)ptr) -> ~A =  value;" struct-type name))))
        (define (gen-member-init name)
          `(if ,name (,(gen-member-name name "-set!") cstruct ,name)))
        (define (gen-struct-init names)
          (flatten (list (string->symbol (sprintf "make-~A" struct-name)) '#!key names)))
        (define (gen-constructor names)
          `(define ,(gen-struct-init names)
             (let ((data (make-blob (foreign-value ,(sprintf "sizeof(~A)" struct-type) int))))
               (let ((cstruct (##sys#make-structure ',struct-name data)))
                 ,(cons 'begin (map gen-member-init names))
                 cstruct))))
        (define (gen-constructor-unsafe)
          ; unsafe constructor, make copy of structure from c-pointer
          `(define (,(string->symbol (sprintf "make-~A&" struct-name)) ptr)
             (let ((data (make-blob (foreign-value ,(sprintf "sizeof(~A)" struct-type) int))))
               (let ((cstruct (##sys#make-structure ',struct-name data)))
                 ((foreign-lambda* void ((scheme-pointer dst) (c-pointer src))
                    ,(sprintf "*(~A *)dst = *(~A *)src;" struct-type struct-type)) cstruct ptr)
                 cstruct))))
        ; direct access to struct blob
        (define (gen-struct-pointer)
          `(define (,(string->symbol (sprintf "~A&" struct-name)) c)
             (##sys#check-structure c ',struct-name)
             (##sys#slot c 1)))
        (let loop ((acc '())
                   (names '())
                   (lst (cddr e)))
          (if (eq? '() lst)
            `(begin ,(gen-constructor names)
                    ,(gen-constructor-unsafe)
                    ,(gen-struct-pointer)
                   ,(cons 'begin acc))
            (let ((name (car lst))
                  (type (cadr lst)))
              (or (symbol? name) (syntax-error "c-struct member name expect symbol" name))
              (loop (append
                      (list
                      `(define (,(gen-member-name name "-ref") c)
                         (##sys#check-structure c ',struct-name)
                         (,(gen-value-ref name type) (##sys#slot c 1)))
                      `(define (,(gen-member-name name "-set!") c value)
                         (##sys#check-structure c ',struct-name)
                         (,(gen-value-set! name type) (##sys#slot c 1) value)))
                      acc)
                    (cons name names)
                    (cddr lst)))))))))
)

Your annotation:

Enter a new annotation:

Your nick:
The title of your paste:
Your paste (mandatory) :
What's the procedure to access a character in a string by index in R5RS?
Visually impaired? Let me spell it for you (wav file) download WAV