Macros and Scheme libraries
Macros are hygienic syntax-rules transformers, defined with
define-syntax at the top level or in a local body. Surface forms such as
let*, cond, case and the variadic list are macros in (snail-core base),
and they expand away before checking, so the checker sees only the core.
A library file may hold a generate-library recipe instead of a
define-library: the compiler builds and runs that program first, and
compiles the library syntax it returns, which the program writes as bytes
the compiler decodes rather than as text.
Scheme is a library too. (scheme base) gives R7RS names (cons, car,
vector, char=?, …) over the typed language, and (scheme compiler)
translates R7RS programs into Snail-Core libraries, run by a generate-library
recipe, with (scheme runtime) for the standard procedures. Its character
procedures are Unicode’s, from (snail-core text): char-upcase maps the full
repertoire, char-numeric? and digit-value hold for any script’s decimal
digits, and string-ci=? compares case-folded text, so "Straße" and
"STRASSE" are equal. The Scheme on Snail-Core tutorial runs
a Scheme program.
That compatibility rests on Snail-Core’s core being built so that erasing its typed forms leaves an R7RS program — which is also how Chibi Scheme runs the compiler’s own source. Bootstrap and self-hosting sets out the erasure property and the stages.
Full Scheme. (scheme compiler) is a Snail-Core library: a reader plus a
translator from R7RS source to the syntax of a Snail-Core library. Every Scheme
value is a Datum, the type of Scheme data in the dynamic libraries
(datum, number, read, write), so matching on one enum replaces
run-time type tests. Scheme code calls no typed Snail-Core code yet. Proposed:
wherever generated code meets typed Snail-Core code, the translator inserts
(type-convert e T), liberally and without proving it necessary:
- Upcast. Converting a typed value to
Anyis checked statically and injects the value with itsTypeId. - Downcast. Converting an
Anyto a specific type checks theTypeIdat run time and traps on a mismatch;(type-test e T)asks first, without trapping. - Redundancy. The compiler removes conversions it proves redundant, such as a downcast of a value just upcast from the same type.
On Chibi, type-convert erases to its expression. A generate-library recipe
runs the translator:
(generate-library (legacy program)
(import
(snail-core base)
(snail-core io)
(scheme compiler))
(scheme->snail-core-library (list "legacy" "program") (read-file "program.scm")))