diff --git a/tests/ffi/ffi-tests.scm b/tests/ffi/ffi-tests.scm index 6376ed72..e01509b5 100644 --- a/tests/ffi/ffi-tests.scm +++ b/tests/ffi/ffi-tests.scm @@ -219,6 +219,13 @@ typedef struct { Color color; } ColoredCircle; +struct Point make_point_struct(double x, double y) { + struct Point res; + res.x = x; + res.y = y; + return res; +} + void set_color(short r, short g, short b, Color* res) { res->r = r; res->g = g; @@ -255,6 +262,7 @@ double circle_area2(struct Circle circ) { constructor: (make-point x y) (double x point-x point-x-set!) (double y point-y point-y-set!)) + (define-c (struct Point) make-point-struct (double double)) (define-c-struct Rectangle predicate: rect? constructor: (make-rect top_left bottom_right) @@ -279,6 +287,8 @@ double circle_area2(struct Circle circ) { (test 1. (point-x (make-point 1. 2.))) (test 2. (point-y (make-point 1. 2.))) (test 3. (point-x (let ((pt (make-point 1. 2.))) (point-x-set! pt 3.) pt))) + (test 1. (point-x (make-point-struct 1. 2.))) + (test 2. (point-y (make-point-struct 1. 2.))) ;; need constructor argument checking ;;(test-error (rect? (make-rect 1 2))) ;; gc miss - we don't preserve the pointers diff --git a/tools/chibi-ffi b/tools/chibi-ffi index 350a2d93..1dd651a8 100755 --- a/tools/chibi-ffi +++ b/tools/chibi-ffi @@ -988,6 +988,9 @@ ((status-bool) (cat " bool err;\n")) ((non-null-string) (cat " char *err;\n")) ((non-null-pointer) (cat " void *err;\n"))) + (if (type-struct? ret-type) + (cat " struct " (type-base ret-type) " struct_res;\n" + " struct " (type-base ret-type) "* ptr_res;\n")) (cond ((pair? ints) (cat " int " (car ints)) @@ -1181,8 +1184,10 @@ (cat " loop:\n")) (cat (cond ((error-type? (type-base ret-type)) " err = ") ((type-array ret-type) " tmp = ") + ((type-struct? ret-type) " struct_res = ") (else " res = "))) - ((if (type-array ret-type) + ((if (or (type-array ret-type) + (type-struct? ret-type)) (lambda (t f x) (f)) c->scheme-converter) ret-type @@ -1227,7 +1232,15 @@ " if (sexp_filenop(" res "))\n" " fcntl(sexp_fileno_fd(" res "), F_SETFL, O_NONBLOCK " " | fcntl(sexp_fileno_fd(" res "), F_GETFL));\n" - "#endif\n"))))) + "#endif\n"))) + ;; non-pointer struct return types need to be copied to the heap + ((type-struct? result) + (cat + " ptr_res = (" (type-c-name result) ") malloc(sizeof(" + (type-c-name-derefed result) "));\n" + " memcpy(ptr_res, &struct_res, sizeof(" (type-c-name-derefed result) "));\n" + " res = sexp_make_cpointer(ctx, sexp_unbox_fixnum(sexp_opcode_return_type(self)), ptr_res, SEXP_FALSE, 0);\n")) + )) (define (write-result result . o) (let ((res (string-append "res" (type-index-string result)))