From 2da5b5005b86e23a7bc1beb8b2dd8e15996dd61a Mon Sep 17 00:00:00 2001 From: alex-eg Date: Wed, 30 Sep 2026 13:22:07 +0300 Subject: [PATCH] give fmt-c a name for every parameter fmt-c takes a parameter's name with `cadr', so an unnamed one handed over bare lost its second word to it: `(* const char)' dropped its star, and `(int)' had no second word at all. --- Makefile | 2 +- fmt-c-writer.scm | 17 ++++----- tests/fmt-c-writer.scm | 10 +++--- tests/sex-programs/unnamed-params.sex | 51 +++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 14 deletions(-) create mode 100644 tests/sex-programs/unnamed-params.sex diff --git a/Makefile b/Makefile index 04094b6..3b4a8f4 100644 --- a/Makefile +++ b/Makefile @@ -98,7 +98,7 @@ sextest: SEX_TEST_PROGRAMS = hello-world lists comments unicode serialize features \ feature-flags lambdas compound-literals closures fixpoint \ - wildcards inference type-shapes + wildcards inference type-shapes unnamed-params # Multi-module linking is checked end to end; see tests/modules/Makefile. check-modules: sexc diff --git a/fmt-c-writer.scm b/fmt-c-writer.scm index da1f38f..53cbe05 100644 --- a/fmt-c-writer.scm +++ b/fmt-c-writer.scm @@ -378,20 +378,21 @@ forms, and what remains." (if (named-arg? arg) (walk-type (maybe-unwrap-type (cdr arg))) ;; A lone type may arrive wrapped in parens of its own, and those - ;; are not part of it: ((* const char)) - ;; Plain names e.g. (int) are left as is - (walk-type (if (and (pair? arg) (null? (cdr arg)) (pair? (car arg))) - (car arg) - arg)))) + ;; are not part of it: ((* const char)), (int) + (walk-type (maybe-unwrap-type arg)))) +;;; A parameter reaches fmt-c as `(type name)' and nothing else: it +;;; reads the name out with `cadr', so a nameless one is the type and +;;; an explicit #f. Handing it the bare type instead made it read the +;;; type's own second word as the name -- `(* const char)' lost its +;;; star -- and a one-word type had no second word to read at all. (define (walk-arglist form) ;; E.g.: ;; ((float) (int) (const char) (* const char) (¤ (* const struct res) 32)) ;; ((f1 float) (f2 float) (f3 float) (res (¤ float 4))) (map (lambda (arg) - (if (named-arg? arg) - (list (arg-type arg) (walk-type (car arg))) - (arg-type arg))) + (list (arg-type arg) + (and (named-arg? arg) (walk-type (car arg))))) (remove comment-form? form))) (define (walk-arg-types form) diff --git a/tests/fmt-c-writer.scm b/tests/fmt-c-writer.scm index 9cf76c9..152662a 100644 --- a/tests/fmt-c-writer.scm +++ b/tests/fmt-c-writer.scm @@ -40,15 +40,15 @@ (walk-type '(const * const char))) (test - '(%fun void ((int) (float) (%array (struct what * const)))) + '(%fun void (int float (%array (struct what * const)))) (walk-type '(fn ((int) (float) (¤ (const * struct what))) void))) (test - '(%fun void ((int) (%array float) (%array (struct what * const)))) + '(%fun void (int (%array float) (%array (struct what * const)))) (walk-type '(fn ((int) (¤ float) (¤ (const * struct what))) void))) (test - '(%array (%fun void ((int) (%array float) (%array (struct what * const))))) + '(%array (%fun void (int (%array float) (%array (struct what * const))))) (walk-type '(¤ (fn ((int) (¤ float) (¤ (const * struct what))) void)))) ;; Type convert to C @@ -136,7 +136,7 @@ ;;; Fn defs (test - '(%fun void puk ((int) (%array float 8))) + '(%fun void puk ((int #f) ((%array float 8) #f))) (walk-fn-def '(fn puk ((int) (¤ float 8)) void))) (test @@ -183,7 +183,7 @@ (test '(struct mega_kebab ((int a) ((struct ((int year) (int month) (int day))) dob) - ((%fun bool ((int) (%array int))) min))) + ((%fun bool (int (%array int))) min))) (walk-struct '(struct mega-kebab ((a int) (dob (struct ((year int) diff --git a/tests/sex-programs/unnamed-params.sex b/tests/sex-programs/unnamed-params.sex new file mode 100644 index 0000000..34e1940 --- /dev/null +++ b/tests/sex-programs/unnamed-params.sex @@ -0,0 +1,51 @@ +(input) +(output "one word: 7" + "pointer: 2" + "aggregate: 3" + "array: 2.5" + "variadic: 1 two") +(return 0) + +;;; A parameter that names nothing still has to reach the C writer as a +;;; type and a name, the name being absent. Handed the bare type +;;; instead, fmt-c read the type's own second word as the name -- so +;;; `(* const char)' came out `const char', which is a different +;;; function -- and a one-word type had no second word to read at all. + +(include stdio.h) +(include stdarg.h) + +(struct point ((x int) (y int))) + +;;; declared here rather than included, so the prototype we emit is the +;;; one the C compiler checks the call against +(extern fn abs ((int)) int) +(extern fn strlen ((* const char)) size-t) + +(fn origin-x ((p (* (struct point)))) int + (return (. (* p) x))) + +(fn second-of ((xs (¤ float 4))) float + (return (¤ xs 1))) + +(fn say ((fmt (* const char)) ...) void + (var ap va-list) + (va-start ap fmt) + (vprintf fmt ap) + (va-end ap)) + +(pub fn main () int + (printf "one word: %d\n" (abs -7)) + (printf "pointer: %d\n" (cast (strlen "hi") int)) + + ;; the same parameter lists written as types + (var p (struct point) #((struct point) : 3 4)) + (var f (fn ((* (struct point))) int) origin-x) + (printf "aggregate: %d\n" (f (& p))) + + (var xs (¤ float 4) #(1.5 2.5 3.5 4.5)) + (var g (fn ((¤ float 4)) float) second-of) + (printf "array: %g\n" (g xs)) + + (say "variadic: %d %s\n" 1 "two") + (return 0))