WASM: support variadic lambda parameters (rest args)
ober
6bf99f3544295f7427ceb2d9a28f5b26e33679b2
--- a/lib/jerboa/wasm/closure.sls +++ b/lib/jerboa/wasm/closure.sls @@ -28,6 +28,7 @@ (export lambda-lift ;; (list of forms) -> (list of forms) free-variables ;; (expr bound-set) -> (list of symbols) + lambda-params ;; formals -> (list of param names) ) (import (chezscheme)) --- a/lib/std/secure/wasm-target.sls +++ b/lib/std/secure/wasm-target.sls @@ -142,19 +142,26 @@ (symbol->string base) "_" (number->string init-counter)))) - ;; Lower parameters: strip type annotations, keep names + ;; Lower parameters: strip type annotations, keep names. + ;; Handles dotted lists for rest args: (x y . rest) → (x y . rest) (define (lower-params params) - (map (lambda (p) - (cond - [(symbol? p) p] - ;; (name type) -> name - [(and (pair? p) (symbol? (car p))) (car p)] - [else p])) - ;; Filter out -> return type annotation - (let loop ([ps params]) - (cond [(null? ps) '()] - [(eq? (car ps) '->) '()] - [else (cons (car ps) (loop (cdr ps)))])))) + (define (strip-param p) + (cond + [(symbol? p) p] + ;; (name type) -> name + [(and (pair? p) (symbol? (car p))) (car p)] + [else p])) + (let loop ([ps params]) + (cond + [(null? ps) '()] + ;; -> return type annotation — stop here + [(and (pair? ps) (eq? (car ps) '->)) '()] + ;; Dotted tail (rest arg): (x . rest) where rest is a symbol + [(symbol? ps) ps] + ;; Normal parameter + [(pair? ps) + (cons (strip-param (car ps)) (loop (cdr ps)))] + [else ps]))) ;; ================================================================ ;; Expression lowering: Slang -> compile-program subset --- a/tests/test-slang-wasm.ss +++ b/tests/test-slang-wasm.ss @@ -648,6 +648,34 @@ (check-pred bytevector? wasm) (check (> (bytevector-length wasm) 100) => #t)) +;; ================================================================ +;; Variadic Lambda Parameters +;; ================================================================ + +(section "Variadic Lambda Parameters") + +;; Lambda-params already handles rest args +(check (lambda-params '(x y)) => '(x y)) +(check (lambda-params '(x . rest)) => '(x rest)) +(check (lambda-params 'args) => '(args)) +(check (lambda-params '((x i32) . rest)) => '(x rest)) + +;; Free variable analysis handles rest args in lambda +(let ([fvs (free-variables '(lambda (x . rest) (+ x y rest)) '())]) + ;; x and rest are bound, y and + are free + (check-pred pair? (memq 'y fvs)) + (check (memq 'x fvs) => #f) + (check (memq 'rest fvs) => #f)) + +;; Lambda lifting of varargs lambda +(let ([result (lambda-lift + '((define (f x) + (let ([g (lambda (y . rest) (+ x y))]) + (g 1 2 3)))))]) + (check-pred pair? result) + ;; Should have lifted definitions + (check (> (length result) 1) => #t)) + ;; Full runtime with UTF-8 string-length compiles to valid WASM (let ([wasm (compile-program (append