Many of the procedures were encapsulated within `prebirth->ecmascript';
these have been moved out so that they can be accessed by other procedures,
allowing me to organize the code how I please.
Which also makes me realize that the procedure name is incorrect.
* build-aux/bootstrap/rebirth.scm: Move all procedures out of
`prebirth->ecmascript'.
This was pretty much a prerequisite for introducing macros (in commits to
follow)---the code would otherwise be far too verbose.
Note that this does _not_ introduce the shorthand forms ("'", "`", ",",
",@"), as implementing those in a reasonable manner would require
preprocesing the AST, which is not what I want to focus on right now. So
macros will still be a bit verbose, using the full
"(quasiquote ... (unquote-splicing ...))" and such instead of simply
"`(... ,@(...))"
* build-aux/bootstrap/rebirth.scm
(quote-sexp, quasiquote-sexp): Add procedures.
(fnmap)[quote]: Use `quote-sexp'.
[quasiquote]: Add special form.
This re-implements libprebirth in Rebirth Lisp, finally cutting the
cord. (Are these birth puns getting out of control?) We are finally purely
in Lisp land!
* build-aux/bootstrap/rebirth.scm: Define libprebith primitives when
`string->es' is available (using `cond-expand').
(prebirth->ecmascript): Do not include `libprebirth.js' in output.
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.
`define' can now be used to define values in addition to the procedure
short-hand.
* build-aux/bootstrap/rebirth.scm
(cdfn): New procedure. Renamed original `cdfn' to `cdfn-proc'.
(cdfn-var): New procedure.
(cdfn-proc): Renamed from `cdfn'.
This allows bootstrapping in either a development environment (Node.js) or
simply using the intended runtime environment: the user's browser.
* bootstrap.html: Add file (browser).
* bootstrap.js: Add file (command-line).
* bootstrap/Bootstrap.js: Add class. Formalize bootstrap process.
* bootstrap/libprebirth.js
(fsdata): Add variable to serve as filesystem stub.
(fs): Always throw error when `fs' module is unavailable.
($$js$file$_$$g$string): Consider `fsdata'.
* bootstrap/prebirth.js: Export as CommonJS module if in proper
environment. Abort automatic processing via stdin if root CommonJS
module.
This provides the complete compiler output, which is consistent with the
output of Birth. This will be useful for browser-based bootstrapping.
* build-aux/bootstrap/prebirth.js: Extract code into `Prebirth' class and
use the class.
(Prebirth): Add class.
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.
* build-aux/bootstrap/prebirth.js
(_cdfn): Remove second argument to `#_idFromName'.
(_idFromName): Remove second parameter `global'. Identify and echo
integers. Remove distinction between global and non-global
identifiers---process everything.
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.
This just reorganizes things slightly to allow for nested `define's. This
is a common means of encapsulation, and will Just Work™ because JS has
pretty much identical block scoping rules in this regard.
* build-aux/bootstrap/prebirth.js (compile): Invoke `#_sexpsToEs' directly
instead of `#_cdfn' on tree.
(_cdfn): Remove non-`define' check to proxy to `#_sexpsToEs'.
(_sexpsToEs): Treat `define' as a special case, invoking `#_cdfn'.
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!
Already implemented by `case', `or', `and'.
* build-aux/bootstrap/prebirth.js (fnmap)[if]: Use proper truth check, as
expected by RnRS Scheme. For JS, this means only `false' is non-true.
So much for simple. But it's not worth my suffering to not add them.
* build-aux/bootstrap/prebirth.js (fnmap): Add more information to docblock.
(and, or, case): Add special forms.
Empty string was not matching, which was causing its value to be '""', which
expanded (in JS) into the compiled string '""""'. Oops.
* build-aux/bootstrap/prebirth.js (Parser#_token): Distinguish empty values
from non-matches.
The Prebirth JS compiler is getting much more sophisticated than I had
hoped, but I need something to work with here. This starts to get us
in a good spot.
There are other conveniences I will want. More to come.
* build-aux/bootstrap/prebirth.js
(Compiler#constructor): Add method, accept fnmap.
(Compiler#_sexpToEs): Use fnmap as needed.
(fnmap): Add initial map.
Instantiate `Compiler' with fnmap.
This was implicit in the `define-block' implementation because of the
conversion from `<foo>' to `$foo$', but that's no longer the case.
This is just a simple, temporary implementation, so don't be alarmed.
* build-aux/bootstrap/libprebirth.js: Updated header documentation to
mention `$$' prefix.
($$js$console): Renamed from `js$console'.
* build-aux/bootstrap/prebirth.js
(_idFromName): Add `global' parameter to add `$$' prefix to generated
identifiers.
(_cdfn, _sexpToEs): Use it.
So we can invoke the main function for the program.
* build-aux/bootstrap/prebirth.js
(Compiler#_cdfn): Handle non-`define' applications.
(Compiler#assertApply): Remove function.
Turns out, I'll kill myself before writing a Prebirth compiler in a
block-define-based Prebirth Lisp. So, let's degrade even further into a
primitive Scheme. This is going down a dangerous path to simply
implementing Scheme...
Nonetheless, here I remove `define-block' in favor of a simple shorthand
function definition `define', as is custom in Scheme. We will worry
about block definitions later as metadata mapping to normal functions.
This is hopefully the beginning of a good thing that I'll actually
finish. I began planning this project formally just before the beginning of
Aug 2017.
* build-aux/bootstrap/prebirth.js: New file.