fix lambdas and add a test to prevent rotting

Lambdas rotted because there wasn't any test for them, and after
return type moved to the end, lambdas stayed assumning it in the
front. We fix this and add test program
This commit is contained in:
2026-09-27 16:11:05 +03:00
parent 62316e1e3d
commit 26e8e6c374
5 changed files with 54 additions and 10 deletions

View File

@@ -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

View File

@@ -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)))))

View File

@@ -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)))))

View File

@@ -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))))

View File

@@ -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))