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.
This commit is contained in:
2026-09-30 13:22:07 +03:00
parent 2b73fcf1c4
commit 2da5b5005b
4 changed files with 66 additions and 14 deletions

View File

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

View File

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

View File

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

View File

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