prebirth: Initial function map
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.master
parent
61f6ba1470
commit
ef4f70bf96
|
@ -300,6 +300,21 @@ class Parser
|
|||
*/
|
||||
class Compiler
|
||||
{
|
||||
/**
|
||||
* Initialize with function map
|
||||
*
|
||||
* The function map will be used to map certain functions into other
|
||||
* names or forms. For example, `js:console' may map to `console.log'
|
||||
* and `if' to an `if' statement+expression.
|
||||
*
|
||||
* @param {Object} fnmap function map
|
||||
*/
|
||||
constructor( fnmap )
|
||||
{
|
||||
this._fnmap = fnmap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compile AST into ECMAScript
|
||||
*
|
||||
|
@ -484,10 +499,22 @@ class Compiler
|
|||
// simple function application (fn ...args)
|
||||
const [ { value: fn }, ...args ] = t;
|
||||
|
||||
const mapentry = this._fnmap[ fn ];
|
||||
|
||||
// if the fnmap contains a function entry, then it will handle the
|
||||
// remaining processing
|
||||
if ( mapentry && ( typeof mapentry === 'function' ) ) {
|
||||
return mapentry(
|
||||
args,
|
||||
this._sexpToEs.bind( this ),
|
||||
this._bodyToEs.bind( this )
|
||||
);
|
||||
}
|
||||
|
||||
// convert all remaining symbols (after the symbol representing the
|
||||
// function application) into arguments by parsing their sexps or
|
||||
// scalar values
|
||||
const idfn = this._idFromName( fn, true );
|
||||
const idfn = mapentry || this._idFromName( fn, true );
|
||||
const argstr = args.map( arg => this._sexpToEs( arg ) ).join( ", " );
|
||||
|
||||
// final function application
|
||||
|
@ -496,6 +523,54 @@ class Compiler
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function aliases and special forms
|
||||
*
|
||||
* This map allows for a steady transition---items can be removed as they
|
||||
* are written in Prebirth Lisp. This should give us a sane (but still
|
||||
* simple) environment with which we can start to self-host.
|
||||
*
|
||||
* String values are simple function aliases. Function values take over the
|
||||
* compilation of that function and allow for defining special forms. The
|
||||
* first argument to the function is the list of raw arguments (not yet
|
||||
* compiled); the second argument is `Compiler#_sexpToEs'; and the third is
|
||||
* `Compiler#bodyToEs'.
|
||||
*
|
||||
* These are by no means meant to be solid implementations.
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
const fnmap = {
|
||||
'js:console': 'console.log',
|
||||
|
||||
// simple if statement with optional else
|
||||
'if': ( [ pred, t, f ], stoes ) =>
|
||||
`if (${stoes(pred)}) {${stoes(t)};} ` +
|
||||
( ( f === undefined ) ? '' : `else {${stoes(f)};}` ),
|
||||
|
||||
// (let ((binding val) ...) ...body), compiled as a self-executing
|
||||
// function which allows us to easily represent the return value of the
|
||||
// entire expression while maintaining local scope
|
||||
'let*': ( [ bindings, ...body ], stoes, btoes ) =>
|
||||
"(function(){\n" +
|
||||
bindings
|
||||
.map( ([ x, val ]) => ` const ${stoes(x)} = ${stoes(val)};\n` )
|
||||
.join( '' ) +
|
||||
btoes( body ) + "\n" +
|
||||
" })()",
|
||||
|
||||
// similar to the above, but variables cannot reference one-another
|
||||
'let': ( [ bindings, ...body ], stoes, btoes ) =>
|
||||
"(function(" +
|
||||
bindings.map( ([ x ]) => stoes( x ) ).join( ", " ) +
|
||||
"){\n" +
|
||||
btoes( body ) + "\n" +
|
||||
"})(" +
|
||||
bindings.map( ([ , val ]) => stoes( val ) ).join( ", " ) +
|
||||
")",
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Prebirth was originally intended to be run via the command line using
|
||||
|
@ -510,7 +585,7 @@ class Compiler
|
|||
}
|
||||
|
||||
const p = new Parser();
|
||||
const c = new Compiler();
|
||||
const c = new Compiler( fnmap );
|
||||
|
||||
const fs = require( 'fs' );
|
||||
const src = fs.readFileSync( '/dev/stdin' ).toString();
|
||||
|
|
Loading…
Reference in New Issue