# HG changeset patch # User Mike Pavone # Date 1332387219 25200 # Node ID 04ae32e91598542f896e688becda5179380f7cca # Parent 8af72f11714e9c998094ea71e46916839a4c2826 Move compiler and test page related code out of parser.js diff -r 8af72f11714e -r 04ae32e91598 compiler.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/compiler.js Wed Mar 21 20:33:39 2012 -0700 @@ -0,0 +1,96 @@ +function indent(str) +{ + return str.split('\n').join('\n\t'); +} + +function osymbols(parent) +{ + this.parent = parent; + this.names = {}; + this.lastname = null; +} +osymbols.prototype.find = function(name) { + if (name in this.names) { + if (this.names[name] instanceof funcall && this.names[name].name == 'foreign:') { + return { + type: 'foreign', + def: this.names[name] + }; + } + return { + type: 'self', + def: this.names[name], + }; + } else if(this.parent) { + var ret = this.parent.find(name); + if (ret) { + if(ret.type == 'self') { + ret.type = 'parent'; + ret.depth = 1; + } else if(ret.type == 'parent') { + ret.depth++; + } + } + return ret; + } + return null; +}; +osymbols.prototype.defineMsg = function(name, def) { + this.lastname = name; + this.names[name] = def; +} +osymbols.prototype.parentObject = function() { + if (!this.parent) { + return 'null'; + } + return 'this'; +} + +function lsymbols(parent) +{ + this.parent = parent; + this.names = {}; + this.lastname = null; + this.needsSelfVar = false; +} +lsymbols.prototype.find = function(name) { + if (name in this.names) { + if (this.names[name] instanceof funcall && this.names[name].name == 'foreign:') { + return { + type: 'foreign', + def: this.names[name] + }; + } + return { + type: 'local', + def: this.names[name] + }; + } else if(this.parent) { + var ret = this.parent.find(name); + if (ret && ret.type == 'local') { + ret.type = 'upvar'; + } + return ret; + } + return null; +}; +lsymbols.prototype.defineVar = function(name, def) { + this.lastname = name; + this.names[name] = def; +}; +lsymbols.prototype.selfVar = function() { + if (this.parent && this.parent instanceof lsymbols) { + this.parent.needsSelf(); + return 'self'; + } else { + return 'this'; + } +}; +lsymbols.prototype.needsSelf = function() { + if (this.parent && this.parent instanceof lsymbols) { + this.parent.needsSelf(); + } else { + this.needsSelfVar = true; + } +}; + diff -r 8af72f11714e -r 04ae32e91598 jsbackend.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jsbackend.js Wed Mar 21 20:33:39 2012 -0700 @@ -0,0 +1,175 @@ +var mainModule; + +function toobj(val) +{ + switch(typeof val) + { + case 'boolean': + if(val) { + return mainModule.strue; + } else { + return mainModule.sfalse; + } + case 'number': + return mainModule.snumber(val); + } + throw new Error("can't make val into object"); +} + +op.prototype.toJS = function(symbols, isReceiver) { + var ret = '(' + this.left.toJS(symbols) +' '+ (this.op == '=' ? '==' : this.op) +' '+ this.right.toJS(symbols) + ')'; + if (isReceiver) { + ret = 'toobj' + ret; + } + return ret; +}; + +symbol.prototype.toJS = function(symbols) { + var name = this.cleanName(); + if (name == 'self') { + return symbols.selfVar(); + } + name = name.replace("_", "UN_").replace(":", "CN_").replace("!", "EX_").replace('?', 'QS_').replace('@', 'AT_'); + var reserved = {'true': true, 'false': true, 'this': true, 'if': true, 'else': true, 'NaN': true}; + if (name in reserved) { + name = 's' + name; + } + return name; +} + +intlit.prototype.toJS = function(symbols) { + return this.val.toString(); +} + +floatlit.prototype.toJS = function(symbols) { + return this.val.toString(); +} + +strlit.prototype.toJS = function(symbols) { + console.log('string:', this.val); + return '"' + this.val.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') + '"'; +} + +funcall.prototype.toJS = function(symbols) { + var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name; + var args = this.args.slice(0, this.args.length); + if (this.receiver) { + args.splice(0, 0, this.receiver); + } + var funinfo = symbols.find(name); + if (!funinfo) { + var receiver = args[0]; + args.splice(0, 1); + for (var i in args) { + args[i] = args[i].toJS(symbols); + } + return receiver.toJS(symbols, true) + '.' + (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')'; + } + switch(funinfo.type) + { + case 'self': + if (args.length < funinfo.def.args.length || funinfo.def.args[0].name != 'self') { + var receiver = new symbol('self'); + } else { + var receiver = args[0]; + args.splice(0, 1); + } + for (var i in args) { + args[i] = args[i].toJS(symbols); + } + return receiver.toJS(symbols, true) + '.' + (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')'; + case 'parent': + var ret = 'this'; + for (var i = 0; i < funinfo.depth; ++i) { + ret += '.parent'; + } + for (var i in args) { + args[i] = args[i].toJS(symbols); + } + ret += (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')'; + return ret; + case 'local': + case 'upvar': + case 'foreign': + for (var i in args) { + args[i] = args[i].toJS(symbols); + } + return (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')'; + } +} + +object.prototype.toJS = function(symbols) { + var messages = this.messages; + symbols = new osymbols(symbols); + var compiled = [] + for (var i in messages) { + var js = messages[i].toJSObject(symbols); + if (js) { + compiled.push(indent(js)); + } + } + return '{\n\tparent: ' + symbols.parentObject() + ',\n\t' + compiled.join(',\n\t') + '\n}'; +} + +object.prototype.toJSModule = function() { + return '(function () {\n\tvar module = ' + indent(this.toJS(null)) + ';\n\treturn module;\n})' +} + +lambda.prototype.toJS = function(symbols) { + var args = this.args ? this.args.slice(0, this.args.length) : []; + if (args.length && args[0].cleanName() == 'self') { + args.splice(0, 1); + } + var exprs = this.expressions; + symbols = new lsymbols(symbols); + for (var i in args) { + symbols.defineVar(args[i].cleanName(), null); + args[i] = args[i].toJS(symbols); + } + var compiled = [] + for (var i in exprs) { + var js = exprs[i].toJS(symbols); + if (js) { + compiled.push(indent(js)); + } + } + exprs = compiled; + if (exprs.length) { + exprs[exprs.length-1] = 'return ' + exprs[exprs.length-1] + ';'; + } + return 'function (' + args.join(', ') + ') {\n\t' + (symbols.needsSelfVar ? 'var self = this;\n\t' : '') + exprs.join(';\n\t') + '\n}' +}; +lambda.prototype.toJSModule = lambda.prototype.toJS + +assignment.prototype.toJS = function(symbols) { + var existing = symbols.find(this.symbol.name); + var prefix = ''; + if (!existing) { + symbols.defineVar(this.symbol.name, this.expression); + prefix = 'var '; + } else { + switch (existing.type) + { + case 'self': + prefix = 'this.'; + break; + case 'parent': + prefix = 'this.'; + for (var i = 0; i < existing.depth; ++i) { + prefix += 'parent.'; + } + break; + } + } + if (this.expression instanceof funcall && this.expression.name == 'foreign:') { + return null; + } + return prefix + this.symbol.toJS(symbols) + ' = ' + this.expression.toJS(symbols); +}; +assignment.prototype.toJSObject = function(symbols) { + symbols.defineMsg(this.symbol.name, this.expression); + if (this.expression instanceof funcall && this.expression.name == 'foreign:') { + return null; + } + return this.symbol.toJS(symbols) + ': ' + this.expression.toJS(symbols); +}; diff -r 8af72f11714e -r 04ae32e91598 parser.js --- a/parser.js Wed Mar 21 20:12:12 2012 -0700 +++ b/parser.js Wed Mar 21 20:33:39 2012 -0700 @@ -1,115 +1,3 @@ -var mainModule; -function toobj(val) -{ - switch(typeof val) - { - case 'boolean': - if(val) { - return mainModule.strue; - } else { - return mainModule.sfalse; - } - case 'number': - return mainModule.snumber(val); - } - throw new Error("can't make val into object"); -} - -function indent(str) -{ - return str.split('\n').join('\n\t'); -} - -function osymbols(parent) -{ - this.parent = parent; - this.names = {}; - this.lastname = null; -} -osymbols.prototype.find = function(name) { - if (name in this.names) { - if (this.names[name] instanceof funcall && this.names[name].name == 'foreign:') { - return { - type: 'foreign', - def: this.names[name] - }; - } - return { - type: 'self', - def: this.names[name], - }; - } else if(this.parent) { - var ret = this.parent.find(name); - if (ret) { - if(ret.type == 'self') { - ret.type = 'parent'; - ret.depth = 1; - } else if(ret.type == 'parent') { - ret.depth++; - } - } - return ret; - } - return null; -}; -osymbols.prototype.defineMsg = function(name, def) { - this.lastname = name; - this.names[name] = def; -} -osymbols.prototype.parentObject = function() { - if (!this.parent) { - return 'null'; - } - return 'this'; -} - -function lsymbols(parent) -{ - this.parent = parent; - this.names = {}; - this.lastname = null; - this.needsSelfVar = false; -} -lsymbols.prototype.find = function(name) { - if (name in this.names) { - if (this.names[name] instanceof funcall && this.names[name].name == 'foreign:') { - return { - type: 'foreign', - def: this.names[name] - }; - } - return { - type: 'local', - def: this.names[name] - }; - } else if(this.parent) { - var ret = this.parent.find(name); - if (ret && ret.type == 'local') { - ret.type = 'upvar'; - } - return ret; - } - return null; -}; -lsymbols.prototype.defineVar = function(name, def) { - this.lastname = name; - this.names[name] = def; -}; -lsymbols.prototype.selfVar = function() { - if (this.parent && this.parent instanceof lsymbols) { - this.parent.needsSelf(); - return 'self'; - } else { - return 'this'; - } -}; -lsymbols.prototype.needsSelf = function() { - if (this.parent && this.parent instanceof lsymbols) { - this.parent.needsSelf(); - } else { - this.needsSelfVar = true; - } -}; function op(left, op, right) { @@ -117,30 +5,11 @@ this.op = op; this.right = right; } -op.prototype.toJS = function(symbols, isReceiver) { - var ret = '(' + this.left.toJS(symbols) +' '+ (this.op == '=' ? '==' : this.op) +' '+ this.right.toJS(symbols) + ')'; - if (isReceiver) { - ret = 'toobj' + ret; - } - return ret; -}; function symbol(name) { this.name = name; } -symbol.prototype.toJS = function(symbols) { - var name = this.cleanName(); - if (name == 'self') { - return symbols.selfVar(); - } - name = name.replace("_", "UN_").replace(":", "CN_").replace("!", "EX_").replace('?', 'QS_').replace('@', 'AT_'); - var reserved = {'true': true, 'false': true, 'this': true, 'if': true, 'else': true, 'NaN': true}; - if (name in reserved) { - name = 's' + name; - } - return name; -} symbol.prototype.cleanName = function() { return this.name[0] == ':' ? this.name.substr(1) : this.name; } @@ -149,26 +18,16 @@ { this.val = val; } -intlit.prototype.toJS = function(symbols) { - return this.val.toString(); -} function floatlit(val) { this.val = val; } -floatlit.prototype.toJS = function(symbols) { - return this.val.toString(); -} function strlit(val) { this.val = val; } -strlit.prototype.toJS = function(symbols) { - console.log('string:', this.val); - return '"' + this.val.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') + '"'; -} function funcall(name, args) { @@ -176,143 +35,23 @@ this.args = args; this.receiver = null; } -funcall.prototype.toJS = function(symbols) { - var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name; - var args = this.args.slice(0, this.args.length); - if (this.receiver) { - args.splice(0, 0, this.receiver); - } - var funinfo = symbols.find(name); - if (!funinfo) { - var receiver = args[0]; - args.splice(0, 1); - for (var i in args) { - args[i] = args[i].toJS(symbols); - } - return receiver.toJS(symbols, true) + '.' + (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')'; - } - switch(funinfo.type) - { - case 'self': - if (args.length < funinfo.def.args.length || funinfo.def.args[0].name != 'self') { - var receiver = new symbol('self'); - } else { - var receiver = args[0]; - args.splice(0, 1); - } - for (var i in args) { - args[i] = args[i].toJS(symbols); - } - return receiver.toJS(symbols, true) + '.' + (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')'; - case 'parent': - var ret = 'this'; - for (var i = 0; i < funinfo.depth; ++i) { - ret += '.parent'; - } - for (var i in args) { - args[i] = args[i].toJS(symbols); - } - ret += (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')'; - return ret; - case 'local': - case 'upvar': - case 'foreign': - for (var i in args) { - args[i] = args[i].toJS(symbols); - } - return (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')'; - } -} function object(messages) { this.messages = messages; } -object.prototype.toJS = function(symbols) { - var messages = this.messages; - symbols = new osymbols(symbols); - var compiled = [] - for (var i in messages) { - var js = messages[i].toJSObject(symbols); - if (js) { - compiled.push(indent(js)); - } - } - return '{\n\tparent: ' + symbols.parentObject() + ',\n\t' + compiled.join(',\n\t') + '\n}'; -} - -object.prototype.toJSModule = function() { - return '(function () {\n\tvar module = ' + indent(this.toJS(null)) + ';\n\treturn module;\n})' -} function lambda(args, expressions) { this.args = args; this.expressions = expressions; } -lambda.prototype.toJS = function(symbols) { - var args = this.args ? this.args.slice(0, this.args.length) : []; - if (args.length && args[0].cleanName() == 'self') { - args.splice(0, 1); - } - var exprs = this.expressions; - symbols = new lsymbols(symbols); - for (var i in args) { - symbols.defineVar(args[i].cleanName(), null); - args[i] = args[i].toJS(symbols); - } - var compiled = [] - for (var i in exprs) { - var js = exprs[i].toJS(symbols); - if (js) { - compiled.push(indent(js)); - } - } - exprs = compiled; - if (exprs.length) { - exprs[exprs.length-1] = 'return ' + exprs[exprs.length-1] + ';'; - } - return 'function (' + args.join(', ') + ') {\n\t' + (symbols.needsSelfVar ? 'var self = this;\n\t' : '') + exprs.join(';\n\t') + '\n}' -}; -lambda.prototype.toJSModule = lambda.prototype.toJS function assignment(sym, expr) { this.symbol = sym; this.expression = expr; } -assignment.prototype.toJS = function(symbols) { - var existing = symbols.find(this.symbol.name); - var prefix = ''; - if (!existing) { - symbols.defineVar(this.symbol.name, this.expression); - prefix = 'var '; - } else { - switch (existing.type) - { - case 'self': - prefix = 'this.'; - break; - case 'parent': - prefix = 'this.'; - for (var i = 0; i < existing.depth; ++i) { - prefix += 'parent.'; - } - break; - } - } - if (this.expression instanceof funcall && this.expression.name == 'foreign:') { - return null; - } - return prefix + this.symbol.toJS(symbols) + ' = ' + this.expression.toJS(symbols); -}; -assignment.prototype.toJSObject = function(symbols) { - symbols.defineMsg(this.symbol.name, this.expression); - if (this.expression instanceof funcall && this.expression.name == 'foreign:') { - return null; - } - return this.symbol.toJS(symbols) + ': ' + this.expression.toJS(symbols); -}; var grammar = 'start = ws module:(object / lambda) ws { return module; };' + @@ -339,39 +78,4 @@ 'unarymeth = name:symbol { return new funcall(name.name, []); };'; var parser = PEG.buildParser(grammar); -//var parser = PEG.buildParser('start = expr; expr = int; int = digits:[0-9]+ { return parseInt(digits.join(""), 10); }'); -onReady(function() { - q('#parse').onclick = function() { - var text = q('textarea').value; - try { - var parsed = parser.parse(text); - q('pre').innerHTML = text + "\n\n" + JSON.stringify(parsed); - console.log(parsed); - } catch(e) { - q('pre').innerHTML = e.message + '\nLine: ' + e.line + '\nCol: ' + e.column; - } - } - q('#tojs').onclick = function() { - var text = q('textarea').value; - //try { - var parsed = parser.parse(text); - var js = parsed.toJSModule(); - q('pre').innerHTML = js; - console.log(parsed); - /*} catch(e) { - q('pre').innerHTML = e.message + '\nLine: ' + e.line + '\nCol: ' + e.column; - }*/ - } - q('#run').onclick = function() { - var text = q('textarea').value; - //try { - var parsed = parser.parse(text); - var js = parsed.toJSModule(); - mainModule = eval(js)(); - q('pre').innerHTML = mainModule.main(); - /*} catch(e) { - q('pre').innerHTML = e.message + '\nLine: ' + e.line + '\nCol: ' + e.column; - }*/ - } -}); diff -r 8af72f11714e -r 04ae32e91598 testparse.html --- a/testparse.html Wed Mar 21 20:12:12 2012 -0700 +++ b/testparse.html Wed Mar 21 20:33:39 2012 -0700 @@ -5,6 +5,9 @@ + + + diff -r 8af72f11714e -r 04ae32e91598 testparse.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testparse.js Wed Mar 21 20:33:39 2012 -0700 @@ -0,0 +1,35 @@ + +onReady(function() { + q('#parse').onclick = function() { + var text = q('textarea').value; + try { + var parsed = parser.parse(text); + q('pre').innerHTML = text + "\n\n" + JSON.stringify(parsed); + console.log(parsed); + } catch(e) { + q('pre').innerHTML = e.message + '\nLine: ' + e.line + '\nCol: ' + e.column; + } + } + q('#tojs').onclick = function() { + var text = q('textarea').value; + //try { + var parsed = parser.parse(text); + var js = parsed.toJSModule(); + q('pre').innerHTML = js; + console.log(parsed); + /*} catch(e) { + q('pre').innerHTML = e.message + '\nLine: ' + e.line + '\nCol: ' + e.column; + }*/ + } + q('#run').onclick = function() { + var text = q('textarea').value; + //try { + var parsed = parser.parse(text); + var js = parsed.toJSModule(); + mainModule = eval(js)(); + q('pre').innerHTML = mainModule.main(); + /*} catch(e) { + q('pre').innerHTML = e.message + '\nLine: ' + e.line + '\nCol: ' + e.column; + }*/ + } +});