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.
An arglist entry, an array's bound and its element type ask one
question, and disagreed: `(unsigned int)' was a name plus a type, a
trailing typedef a bound, a subscript the type's second word.
Two things out of one mechanism. `_' as a type means "work it out from
the initializer", so (var n _ (strlen s)) stops needing size-t spelled
out; `type-of' hands a macro the type of an expression, so a macro can
dispatch on what it was handed rather than on what was declared. Both
read the same answers from two sides.
Algorithm W's core, intra-procedural, with the extensions C forces:
- an unknown type, since (include stdio.h) brings in names we never
parsed. Unification is consistency rather than equality, so
anything touching an unparsed declaration stops constraining
instead of rejecting a program that compiled yesterday;
- the usual arithmetic conversions, since `+' is not a function of
one type;
- checking mode for initializers, since #(0 0) has no type of its own
and takes one from its context. #(T : ...) is the way out of that.
What it wanted on the way:
- what type a *name* has, which neither the typedef nor the tag
database recorded. One table serves functions and variables, since
a function type already has a surface spelling;
- a scope chain, so a (var c int 9) inside a do ends with the block;
- form-type, keyed by cons cell, so one form has one type;
- macros expanded during the walk rather than before it, so type-of
is answered in the scope the macro was written in.
Closures take the same machinery: a receiver whose type comes from a
call, captures written (name expr) and typed from the expression, and
conversion from a bare function wherever a closure is expected.
type-match grew `_' on the pattern side, since (closure ((int)) int)
and (closure ((float)) int) were separate clauses for one case.
A bare list was read as several forms, so a macro returning
`((make-adder 10) 5)' -- a call of what make-adder returns -- was
spliced into two. Add a new $ char to denote splicing, so ($ form ...)
splices.
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
sextest resolves #+ and #- itself -- it reads the program and prints
what survives to sexc -- so a flag spelling it does not recognise
decides which branch gets compiled
C has two namespaces and the database had one. A typedef of a tag's
name wiped it.
Tags, i.e. struct, enum and union, share one namespace; they move to a
table of their own. A name resolves the way C does: the ordinary
identifier first, the tag when that leads nowhere.
While resolving a typedef, the target was taken apart with cadr
whatever it was, so (typedef points (¤ point 4)) reported point's
fields as its own -- an array of four points claiming to be a point,
and a macro reaching through it with v->x. Only a name and
(struct|union|enum NAME) name a type now.
A dropped datum is replaced by whatever follows it, but what follows
may be the end of the file or the paren closing the list we are
in. Hand the token back to the caller instead: read-list closes its
list with it and the toplevel loop stops.
A `;' comment between a guard and the form it guards was also taken for
the guarded datum, so the form stayed unconditional and the guard did
nothing. Skip comments when reading the guard.
comment-form? was defined three times over; it moves to utils.
'#+' and '#-' introduce conditional compilation: the form that follows
is kept only when the feature expression is true, and otherwise is read
and thrown away. An expression is a feature name, or and / or / not
of them.
They are read time, not compile time.
Default features are the host's software-version, software-type and
machine-type as CHICKEN reports them, plus what --features flag adds.
compile-to-file returned process-wait's values and main dropped them,
so cc errors were printed, but then main compiler exited 0.
Also cleanup tmp C files when compilation failed.
Implement pub support for enums, and also anonymous enums declared
in-place.
Also give the cdr of a `pub' form the form's own location, so a
error about what follows `pub' can say where it was written
For source-level debug. Add --line-directives option, defaulted to
statement. Disabled when used with -C. Explicit non-none value
overrides disabling when -C is present
Also rename macros to sex-macros, module-system to sex-modules for
clarity, uniformity, and to avoid name clashes with Chicken's
units/modules named "macros" and "modules"
Types, fns and vars are now written in another, better, more intuitive
and readable way.
Types:
"pointer to const char" is "* const char"
"array of pointers to volatile int" is "[* volatile int]"
Read left to right
Vars (as well as fn args, struct fields):
(var name type)
(struct vec3 ((x float) (y float) (z float))
(fn vec3-add ((v1 vec3) (v2 vec3)) vec3 ...)
Also fns are now have return types after arg list.
* is now must not be attached to any type name (or variable for that
matter)