diff --git a/Makefile b/Makefile index 8b15de0..c60e88e 100644 --- a/Makefile +++ b/Makefile @@ -94,7 +94,7 @@ sextest: cp ./tools/sextest/sextest . SEX_TEST_PROGRAMS = hello-world lists comments unicode serialize features \ - feature-flags + feature-flags lambdas # Multi-module linking is checked end to end; see tests/modules/Makefile. check-modules: sexc diff --git a/example/lambdas.sex b/example/lambdas.sex index 4ffaec3..48eb54a 100644 --- a/example/lambdas.sex +++ b/example/lambdas.sex @@ -6,14 +6,14 @@ (pub fn main () int (var a int 10) (var b int 20) - (var (fn ((int) (int)) int) sum-fn sum) + (var sum-fn (fn ((int) (int)) int) sum) - (var (fn ((int) (int)) int) sum-lambda + (var sum-lambda (fn ((int) (int)) int) (lambda ((a int) (b int)) int () (return (+ a b)))) - (var (fn ((int)) int) sum-lambda-2 + (var sum-lambda-2 (fn ((int)) int) (lambda ((a int)) int () (return (+ a 20)))) @@ -28,9 +28,9 @@ (return (+ a b 100))) a b)) - (var (fn ((int)) int) l-1 + (var l-1 (fn ((int)) int) (lambda ((a int)) int () - (var (fn ((int)) int) l-2 + (var l-2 (fn ((int)) int) (lambda ((a int)) int () (return (+ 60 a)))) (return (+ 600 (l-2 a))))) diff --git a/fmt-c-writer.scm b/fmt-c-writer.scm index d64b749..63039ff 100644 --- a/fmt-c-writer.scm +++ b/fmt-c-writer.scm @@ -380,8 +380,8 @@ forms, and what remains." (map arg-type (remove comment-form? form))) (define (walk-function form) - ;; (fn ret-type name arglist body) -> normal function - ;; (fn ret-type name arglist) -> prototype + ;; (fn name arglist ret-type body) -> normal function + ;; (fn name arglist ret-type) -> prototype (if (>= (length form) 5) (walk-fn-def form) (cons '%prototype (cdr (walk-fn-def form))))) diff --git a/semen.scm b/semen.scm index c6e0da8..4262fa1 100644 --- a/semen.scm +++ b/semen.scm @@ -255,10 +255,10 @@ (define (make-aux-lambda-struct name form) (match form - (('lambda ret-type arglist captures . body) + (('lambda arglist ret-type captures . body) ;; Captures are ignored for now, but ;; we'll need them for TODO: closures support - (process-fn (copy-form-source! form `(fn ,ret-type ,name ,arglist ,@body)) + (process-fn (copy-form-source! form `(fn ,name ,arglist ,ret-type ,@body)) (list))) (else (sex-error form "malformed lambda" form)))) diff --git a/tests/sex-programs/lambdas.sex b/tests/sex-programs/lambdas.sex new file mode 100644 index 0000000..8de9a5d --- /dev/null +++ b/tests/sex-programs/lambdas.sex @@ -0,0 +1,44 @@ +(input) +(output "Named fn through a pointer: 30" + "Lambda through a pointer: 30" + "Lambda called in place: 130" + "Nested lambdas: 666") +(return 0) + +;;; Lambdas are lifted into toplevel functions by semen, so what this +;;; really checks is that the lifted `fn' comes out in the argument +;;; order the writer expects -- (fn name arglist ret-type . body). + +(include stdio.h) + +(fn sum ((a int) (b int)) int + (return (+ a b))) + +(pub fn main () int + (var a int 10) + (var b int 20) + + (var sum-fn (fn ((int) (int)) int) sum) + (printf "Named fn through a pointer: %d\n" (sum-fn a b)) + + (var sum-lambda (fn ((int) (int)) int) + (lambda ((a int) (b int)) int () + (return (+ a b)))) + (printf "Lambda through a pointer: %d\n" (sum-lambda a b)) + + (printf "Lambda called in place: %d\n" + ((lambda ((a int) (b int)) int () + (return (+ a b 100))) + a b)) + + ;; A lambda inside a lambda: the inner one is lifted out of a + ;; function that is itself being lifted + (var outer (fn ((int)) int) + (lambda ((x int)) int () + (var inner (fn ((int)) int) + (lambda ((y int)) int () + (return (+ 60 y)))) + (return (+ 600 (inner x))))) + (printf "Nested lambdas: %d\n" (outer 6)) + + (return 0))