Gibble is still the ultimate goal, but since I seem to have gone down
precisely the path that I did _not_ want to go down (implementing a full
Scheme), this deserves to be its own project.
Oh, and Gibble is the "{General=>Graphical} Block-Based Learning
Environment".
This is a significant step toward abandoning the Rebirth compiler (which is
a slight, mostly unaltered version of the Birth compiler, at this point);
anything written for these macros from this point on can be re-used moving
forward, regardless of what compiler we have underneath it. I'll continue
writing more Scheme-like abstractions moving forward to begin to normalize
the syntax as I get closer to a point where it's worth starting to create
proper R⁷RS implementations.
Things are moving along slowly, but they're moving. I don't have a whole
lot of free time between kids and other obligations.
* build-aux/bootstrap/birth.scm (fnmap): Doc corrections.
* build-aux/bootstrap/rebirth.scm: Add more documentation.
Add numerous macros to replace built-in forms; I'm not listing them
here.
(%list-item): Whitespace fix.
(fnmap): Split into `fnmap-premacro'.
(fnmap-premacro): New procedure.
I've been torn on this for a bit, but we're using "es" (ECMAScript) in a lot
of important places. Thinks like "js:console" I was considering leaving
because "console" is not an ECMAScript thing---it is JavaScript. But now we
will take "es:" to mean "outputting in ECMAScript".
* build-aux/bootstrap/birth.scm, build-aux/bootstrap/rebirth.scm,
build-aux/bootstrap/prebirth.js:
s/js:/es:/g.
* build-aux/bootstrap/libprebirth.js: s/\$\$js\$/\$\$es\$/g.
Birth is pretty much at a feature freeze at this point, but `cond-expand'
really was difficult to work with in certain circumstances when it didn't
even support `else'.
* build-aux/bootstrap/birth.scm (fnmap)[cond-expand]: Always expand `else'
while dropping all others.
They were just out of date, having been copied from Prebirth.
* build-aux/bootstrap/birth.scm
(prebirth->ecmascript, birth>ecmascript): Former renamed to latter.
* build-aux/bootstrap/rebirth.scm
(prebirth->ecmascript, rebirth>ecmascript): Former renamed to latter.
This modifies each of the three lexers just to avoid confusion, even
though prebirth has no need for it. Birth does have a need, however, since
rebirth will contain newlines---despite the relevant rebirth code (next
commit) not being expanded, it still has to go through the lexer, which
otherwise errors out.
* build-aux/bootstrap/birth.scm (lex): Permit newlines in string regex.
* build-aux/bootstrap/prebirth.js (lex): Permit newlines in string regex.
* build-aux/bootstrap/rebirth.scm (lex): Permit newlines in string regex.
`cond-expand' allows moving forward with implementing features based on the
current bootstrapped state of the system---rebirth will be able to
recursively compile itself and introduce new features along the way.
`string->es' allows outputting raw ECMAScript, which gives us more control
over the code that is generated without having to hard-code it in the
compiler itself.
* build-aux/bootstrap/birth.scm
(fnmap)[cond-expand]: Always yield the empty string (do nothing).
* build-aux/bootstrap/rebirth.scm
(fnmap)[cond-expand]: Expand `string->es' only.
(fnmap)[string->es]: Add macro.
This needs to run in the browser too, where we have no control over stack
limits.
* build-aux/bootstrap/birth.scm
(lex): Non-recursive strategy (loop with mutable list).
(make-token): Update doc. Produce list of token, new string, and
position. Don't recurse.
(body->es): Add `ret' param. Only produce `return' statement if new param
is set.
(cdfn): Use it.
(fnmap)
[js:while, js:break]: Add forms.
[lambda, let, case]: Use new `body->es' `ret' param.
[let*]: Define JS variables in output using `let' instead of `const' to
permit mutating with new `set!' form. Use new `body->es' `ret' param.
[set!]: Add form.
(prebirth->ecmascript): Adjust libprebirth path to be relative to self.
* build-aux/bootstrap/libprebirth.js
($$append$b$): Add `append!' procedure.
($$js$regexp, $$js$match, $$js$replace): Move a few lines up.
(fs): Provide stub if `require' is not defined.
* build-aux/bootstrap/prebirth.js
(_lex): Non-recursive strategy (loop with array-appending).
(_token): No more mutual recursion with `#_lex'. Return new string
and position.
(_bodyToEs): Add `ret' param. Only produce `return' statement if new
param is set.
(fnmap) [js:while, js:break]: Add forms.
[let*]: Define JS variables in output using `let' instead of `const' to
permit mutating with new `set!' form. Use new `body->es' `ret' param.
[set!]: Add form.
This completes bootstrapping for Prebirth Lisp. The next step will be
Rebirth, which will replace libprebirth.js, removing hand-written JavaScript
entirely.
Just about ready for that sloppy code generation!
* build-aux/bootstrap/birth.scm: Update file header documentation.
Add some whitespace between existing procedures.
Invoke `parse-lisp' as the program in place of `lex', producing an AST as
output to the console.
(cadddr): Add procedure.
(token-{type,lexeme,value,pos}): Add procedures.
(parse-lisp): Add procedure (contains other procedures).
* build-aux/bootstrap/libprebirth.js
($$append): Add function (append).
($$$_$): Correct implementation (-).
($$zero$7$): Add predicate (zero?).
($$fold): Add function (fold).
* build-aux/bootstrap/prebirth.js (parseLisp): Lowercase some errors.
(Compiler): Update class docblock.
(fnmap)[labmda]: Add `lambda' form.
Exciting first step! Though it required a much more complicated Prebirth
Lisp than I was hoping to create. And I never intended to go into a full
Scheme implementation, but that's the route this is headed in. I just can't
stomach creating this full system in a block language.
With that said, the block language will still be able to work with all Lisp
code; you'll see.
* build-aux/bootstrap/birth.scm: Add beginning of Birth, capable of parsing
itself! Baby steps!