Last active
December 11, 2015 08:38
-
-
Save tj/4574520 to your computer and use it in GitHub Desktop.
quick hack of an example of how to add some type enforcement via pre-processing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def greet(first:string, last:string) { | |
ret "Hello " + first + " " + last | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function scan(str) { | |
return str.match(/(\bdef\b|\bret\b|[+:{}(),]|"(.*?)"|'(.*?)'|[_\w]+)/g); | |
} | |
function parse(str) { | |
var toks = scan(str); | |
return stmts(); | |
function stmts() { | |
var stmts = []; | |
while (toks.length) stmts.push(stmt()); | |
return { type: 'stmts', stmts: stmts }; | |
} | |
function stmt() { | |
var tok = toks.shift(); | |
switch (tok) { | |
case 'def': return def(); | |
case 'ret': return ret(); | |
default: | |
throw new Error('unexpected ' + tok); | |
} | |
} | |
function ret() { | |
return { | |
type: 'return', | |
expr: expr() | |
} | |
} | |
function expr() { | |
var node = { type: 'expr', val: toks.shift() }; | |
if ('+' == toks[0]) { | |
node = { | |
type: 'op', | |
op: toks.shift(), | |
left: node, | |
right: expr() | |
}; | |
} | |
return node; | |
} | |
function def() { | |
var id = toks.shift(); | |
toks.shift(); // ( | |
var p = params(); | |
toks.shift(); // ) | |
var b = block(); | |
return { | |
type: 'function', | |
id: id, | |
params: p, | |
body: b | |
} | |
} | |
function accept(tok) { | |
if (tok == toks[0]) { | |
return toks.shift(); | |
} | |
} | |
function params() { | |
var params = []; | |
if (')' == toks[0]) return params; | |
do { | |
var id = toks.shift(); | |
toks.shift(); // : | |
var type = toks.shift(); | |
params.push({ id: id, type: type }); | |
} while (accept(',')); | |
return params; | |
} | |
function block() { | |
var stmts = []; | |
toks.shift(); // { | |
while ('}' != toks[0]) stmts.push(stmt()); | |
toks.shift(); // } | |
return { type: 'stmts', stmts: stmts }; | |
} | |
} | |
function compile(ast) { | |
return visit(ast); | |
function visit(node) { | |
switch (node.type) { | |
case 'stmts': return stmts(node); | |
case 'function': return fn(node); | |
case 'return': return ret(node); | |
case 'expr': return expr(node); | |
case 'op': return op(node); | |
default: throw new Error('unhandled ' + node.type); | |
} | |
} | |
function ret(node) { | |
return ' return ' + visit(node.expr); | |
} | |
function expr(node) { | |
return node.val; | |
} | |
function op(node) { | |
return visit(node.left) + ' ' + node.op + ' ' + visit(node.right); | |
} | |
function fn(node) { | |
var asserts = []; | |
var params = node.params.map(function(p){ | |
asserts.push(' assertType(' + p.id + ', "' + p.id + '", "' + p.type + '")'); | |
return p.id; | |
}).join(', '); | |
return 'function ' | |
+ node.id + '(' + params + ') {\n' | |
+ asserts.join('\n') + '\n' | |
+ visit(node.body) | |
+ '\n}'; | |
} | |
function stmts(node) { | |
return node.stmts.map(visit).join('\n'); | |
} | |
} | |
var fs = require('fs'); | |
var vm = require('vm'); | |
var str = fs.readFileSync('example.js', 'utf8'); | |
var ast = parse(str); | |
// console.log(require('util').inspect(ast, false, 15, true)); | |
var js = compile(ast); | |
console.log(js); | |
// js += '\ngreet("tobi", "ferret")'; | |
js += '\ngreet("tobi", 5)'; | |
var ret = vm.runInNewContext(js, { | |
assertType: function(val, name, type){ | |
var actual = typeof val; | |
if (actual != type) { | |
throw new TypeError(name + ' must be of type '+ type + ', a ' + actual + '(' + val + ') was given'); | |
} | |
} | |
}); | |
console.log(ret); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function greet(first, last) { | |
assertType(first, "first", "string") | |
assertType(last, "last", "string") | |
return "Hello " + first + " " + last | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment