# HG changeset patch # User Mike Pavone # Date 1343371314 25200 # Node ID 094227f2f64e2c233c9be3f3abe687048e730de6 # Parent 59a94f3ad56f47157ef6c4ea5421a98830b2a5fb# Parent 6735db9b44ba62d420cc6b5a3110b11634d01e16 Merge diff -r 6735db9b44ba -r 094227f2f64e cbackend.js --- a/cbackend.js Tue Jul 24 01:01:00 2012 -0700 +++ b/cbackend.js Thu Jul 26 23:41:54 2012 -0700 @@ -13,7 +13,7 @@ } op.prototype.toC = function(isReceiver) { - var optoMeth = {'+': 'ADD_', '-': 'SUB_', '*': 'MUL_', '/': 'DIV_', '%': 'MOD_', '=': 'EQ_', '!=': 'NEQ_', '<': 'LT_', '>': 'GT_', '>=': 'GEQ_', '<=': 'LEQ_', '.': 'CAT_'}; + var optoMeth = {'+': 'ADD_', '-': 'SUB_', '*': 'MUL_', '/': 'DIV_', '%': 'MOD_', '=': 'EQ_', '!=': 'NEQ_', '<': 'LT_', '>': 'GT_', '>=': 'GEQ_', '<=': 'LEQ_', '.': 'CAT_', '&&':'if', '||':'ifnot'}; var method = optoMeth[this.op]; return 'mcall(' + getMethodId(method) + '/* ' + method + ' */, 2, (object *)' + this.left.toC() + ', ' + this.right.toC() + ')\n'; }; @@ -237,7 +237,11 @@ } var callpart; if (method) { - callpart = 'mcall(' + getMethodId(name) + '/* ' + name + ' */'; + if (funinfo && funinfo.type == 'self' && funinfo.def.name) { + callpart = funinfo.def.name + '(' + (funinfo.def.symbols.parent.needsenv ? (new symbol('self', this.symbols)).toC() + '->env' : 'NULL' ); + } else { + callpart = 'mcall(' + getMethodId(name) + '/* ' + name + ' */'; + } } else { callpart = 'ccall(' + (new symbol(name, this.symbols)).toC(); } @@ -767,15 +771,7 @@ toplevel.names['os'] = os; } -modulefile.prototype.populateSymbols = function (toplevel) { - if (!this.ast) { - this.ast = parseFile(this.path + '/' + this.file); - this.ast.populateSymbols(toplevel); - } -}; - modulefile.prototype.toC = function(){ - this.populateSymbols(toplevel); return this.ast.toCModuleInstance(); }; @@ -842,15 +838,13 @@ return this.toC(); } -var lambdanum = 0; - lambda.prototype.toC = function() { var args = this.args ? this.args.slice(0, this.args.length) : []; var exprs = this.expressions; - var mynum = lambdanum++; - debugprint('//lambda', mynum); + debugprint('//', this.name); if (Object.keys(this.symbols.closedover).length) { - this.symbols.envtype = 'lambda_' + mynum + '_env'; + this.symbols.envtype = this.name + '_env'; + forwarddec += 'typedef struct ' + this.symbols.envtype + ' ' + this.symbols.envtype + ';\n' } if (this.selftype) { this.symbols.defineVar('self', this.selftype); @@ -879,7 +873,7 @@ } if (Object.keys(this.symbols.closedover).length) { - forwarddec += 'typedef struct lambda_' + mynum + '_env {\n'; + forwarddec += 'struct ' + this.name + '_env {\n'; if (this.symbols.needsParentEnv) { forwarddec += '\tstruct ' + this.symbols.parentEnvType() + ' * parent;\n'; } @@ -890,18 +884,19 @@ forwarddec += '\tobject * ' + escapeCName(varname) + ';\n'; } } - forwarddec += '} lambda_' + mynum + '_env;\n' + forwarddec += '};\n' - var myenvinit = '\tlambda_' + mynum + '_env * myenv = GC_MALLOC(sizeof(lambda_' + mynum + '_env));\n'; + var myenvinit = '\t' + this.name + '_env * myenv = GC_MALLOC(sizeof(' + this.name + '_env));\n'; if (this.symbols.needsParentEnv) { myenvinit += '\tmyenv->parent = env;\n'; } - this.symbols.envtype = 'lambda_' + mynum + '_env'; + this.symbols.envtype = this.name + '_env'; } else { var myenvinit = ''; } + forwarddec += 'object *' + this.name + ' (' + this.symbols.parentEnvType() + ' * env, uint32_t num_args, ...);\n'; - toplevelcode += 'object * lambda_' + mynum + ' (' + this.symbols.parentEnvType() + ' * env, uint32_t num_args, ...) {\n\tva_list args;\n' + myenvinit + '\tva_start(args, num_args);\n'; + toplevelcode += 'object * ' + this.name + ' ( ' + this.symbols.parentEnvType() + ' * env, uint32_t num_args, ...) {\n\tva_list args;\n' + myenvinit + '\tva_start(args, num_args);\n'; if (this.selftype) { var selfvar = (new symbol('self', this.symbols)).toC(); if (selfvar == 'self') { @@ -912,7 +907,6 @@ } toplevelcode += args.join('') + '\tva_end(args);\n' + exprs.join(';\n\t') + '\n}\n'; - this.name = 'lambda_' + mynum; if (this.selftype) { return this.name; @@ -923,11 +917,11 @@ } else { var envvar = 'myenv'; } - debugprint('//lambda_' + mynum, 'has envvar:', envvar, 'num vars closed over:', Object.keys(this.symbols.closedover).length); + debugprint('//' + this.name, 'has envvar:', envvar, 'num vars closed over:', Object.keys(this.symbols.closedover).length); return 'make_lambda(' + envvar + ', (closure_func)' + this.name + ')'; } else { - toplevelcode += 'lambda lambda_obj_' + mynum + ' = {{&lambda_meta, NULL}, NULL, lambda_' + mynum + '};\n'; - return '((object *)&lambda_obj_' + mynum + ')'; + toplevelcode += 'lambda ' + this.name + '_obj = {{&lambda_meta, NULL}, NULL, lambda_' + mynum + '};\n'; + return '((object *)&' + this.name + '_obj)'; } } }; diff -r 6735db9b44ba -r 094227f2f64e compiler.js --- a/compiler.js Tue Jul 24 01:01:00 2012 -0700 +++ b/compiler.js Thu Jul 26 23:41:54 2012 -0700 @@ -11,6 +11,13 @@ this.file = file; } +modulefile.prototype.populateSymbols = function (toplevel) { + if (!this.ast) { + this.ast = parseFile(this.path + '/' + this.file); + this.ast.populateSymbols(toplevel); + } +}; + var toplevel = new topsymbols([]); function topsymbols(moduledirs) { @@ -289,6 +296,12 @@ op.prototype.populateSymbols = function(symbols, isReceiver) { this.left.populateSymbols(symbols); + if (this.op == '&&' || this.op == '||') { + //&& and || are syntactic sugar for if and ifnot with + //the second argument transformed into a lambda to + //achieve short-circuit evalutation + this.right = new lambda([], [this.right]); + } this.right.populateSymbols(symbols); }; @@ -322,6 +335,7 @@ } funcall.prototype.populateSymbols = function(symbols) { + var isll = false; if (this.name == 'foreign:') { if ((this.args[0] instanceof lambda) || (this.args[0] instanceof object) || (this.args[0] instanceof symbol)) { return; @@ -344,6 +358,7 @@ if (this.args[1] instanceof lambda) { if (this.args[2] instanceof lambda) { symbols.defineMsg(this.args[0].name, this.args[2]); + isll = true; } else { throw new Error("Third argument to llMessage:withVars:andCode: must be a lambda"); } @@ -361,10 +376,10 @@ symbols.find('self'); } for (var i in this.args) { - this.args[i].populateSymbols(symbols); + this.args[i].populateSymbols(symbols, undefined, isll); } if (this.receiver) { - this.receiver.populateSymbols(symbols); + this.receiver.populateSymbols(symbols, undefined, isll); } } @@ -379,8 +394,11 @@ } this.symbols = symbols; } - -lambda.prototype.populateSymbols = function(symbols, isobject) { +var lambdanum = 0; +lambda.prototype.populateSymbols = function(symbols, isobject, isll) { + if (!isll) { + this.name = 'lambda_' + lambdanum++; + } var args = this.args ? this.args.slice(0, this.args.length) : []; var exprs = this.expressions; var symbols = new lsymbols(symbols); diff -r 6735db9b44ba -r 094227f2f64e jsbackend.js --- a/jsbackend.js Tue Jul 24 01:01:00 2012 -0700 +++ b/jsbackend.js Thu Jul 26 23:41:54 2012 -0700 @@ -45,10 +45,8 @@ } op.prototype.toJS = function(isReceiver) { - var ret = '(' + this.left.toJS() +' '+ (this.op == '=' ? '==' : this.op) +' '+ this.right.toJS() + ')'; - if (isReceiver) { - ret = 'toobj' + ret; - } + var opmap = {'=': '==', '.': '+'}; + var ret = '(' + this.left.toJS() +' '+ (this.op in opmap ? opmap[this.op] : this.op) +' '+ this.right.toJS() + ')'; return ret; }; @@ -80,8 +78,7 @@ pre += '.parent'; } } else if (info.type == 'toplevel') { - pre = 'modules.'; - modules[name] = false; + return toplevel.moduleVar(name); } return pre + escapeJSName(name); } @@ -122,22 +119,21 @@ args.splice(0, 0, this.receiver); } var funinfo = this.symbols.find(name); - if (!funinfo || funinfo.def instanceof setter) { + if (!funinfo || funinfo.def instanceof setter || funinfo.type == 'toplevel') { var receiver = args[0]; args.splice(0, 1); for (var i in args) { args[i] = args[i].toJS(); } - var rJS = receiver.toJS(true); + var rJS = (funinfo ? '' : 'toobj(') + receiver.toJS(true) + (funinfo ? '' : ')') ; if ((name[name.length-1] == '!' && args.length == 1) || (funinfo && funinfo.def instanceof setter)) { return '(' + rJS + '.' + escapeJSName(name.substr(0, name.length-1)) + ' = ' + args[0] + ', ' + rJS + ')'; } else { var callee = rJS + '.' + escapeJSName(name); - var callCode = callee + '(' + args.join(', ') + ')'; if (args.length == 0) { - return '(' + callee + ' instanceof Function ? ' + callCode + ' : ' + callee + ')'; + return callee; } else { - return callCode; + return callee + '(' + args.join(', ') + ')'; } } } @@ -214,7 +210,7 @@ object.prototype.toJSModule = function() { this.populateSymbols(toplevel); - return '(function () {\n\tvar module = ' + indent(this.toJS()) + ';\n\treturn module;\n})' + return '(function () {\n\tvar module = ' + indent(this.toJS()) + ';\n\treturn module;\n})();' } lambda.prototype.toJS = function() { @@ -239,9 +235,69 @@ } return 'function (' + args.join(', ') + ') {\n\t' + (this.symbols.needsSelfVar ? 'var self = this;\n\t' : '') + exprs.join(';\n\t') + '\n}' }; +lambda.prototype.nonSelfArgs = function() { + var args = this.args ? this.args.slice(0, this.args.length) : []; + if (args.length && args[0].cleanName() == 'self') { + args.splice(0, 1); + } + return args; +}; lambda.prototype.toJSModule = function() { this.populateSymbols(toplevel); - return this.toJS(); + return this.toJS() + '();'; +} + +modulefile.prototype.toJSModule = function(){ + return this.ast.toJSModule(); +}; + +function processUsedToplevelJS(toplevel) +{ + var alwaysused = ['true', 'false']; + var ret = ''; + var modulenum = 0; + var visited = {}; + for (var i in alwaysused) { + toplevel.used[alwaysused[i]] = true; + } + var newused = Object.keys(toplevel.used); + var allused = newused; + while (newused.length) { + for (var i in newused) { + toplevel.names[newused[i]].populateSymbols(toplevel); + visited[newused[i]] = true; + } + newused = []; + for (var symbol in toplevel.used) { + if (!(symbol in visited)) { + newused.push(symbol); + allused.push(symbol); + } + } + } + + for (var i = allused.length-1; i >= 0; i--) { + var symbol = allused[i]; + ret += 'var ' + toplevel.moduleVar(symbol) + ' = ' + toplevel.names[symbol].toJSModule() + '\n'; + } + return ret; +} + +function makeJSProg(mainmodule) +{ + return processUsedToplevelJS(toplevel) + 'main_module = ' + mainmodule.toJSModule() + '\n' + + 'Number.prototype.__defineGetter__("string", function() { return "" + this; });\n' + + 'String.prototype.__defineGetter__("string", function() { return this; });\n' + + 'String.prototype.__defineGetter__("print", function() { write(this); });\n' + + 'Array.prototype.foreach = function(action) { var ret = module_false; for (var i = 0; i < this.length; i++) { ret = action(i, this[i]) }; return ret; };\n' + + 'Function.prototype.whileCN_do = function(action) { var ret = module_false; while(toobj(this()) == module_true) { ret = action(); } return ret; };\n' + + 'function toobj(val) {\n' + + ' return (typeof val == "boolean") ? (val ? module_true : module_false) : val;\n' + + '}\n' + + 'var m = main_module.main;\n' + + 'if (m instanceof Function) {\n' + + ' m(arguments);\n' + + '}\n'; } assignment.prototype.toJS = function() { @@ -269,10 +325,27 @@ } return prefix + this.symbol.toJS() + ' = ' + val; }; +function removeInitialFunction(str) +{ + var f = 'function'; + str = str.trim(); + if (str.substr(0, f.length) == f) { + return str.substr(f.length); + } + return str; +} assignment.prototype.toJSObject = function() { var val = this.expression.toJS(); if (val === null) { return null; } + if (this.expression instanceof lambda) { + var args = this.expression.nonSelfArgs(); + if (args.length == 0) { + return 'get ' + escapeJSName(this.symbol.name) + removeInitialFunction(val); + } else if(args.length == 1 && this.symbol.name[this.symbol.name.length-1] == '!') { + return 'set ' + escapeJSName(this.symbol.name.substr(0, this.symbol.name.length-1)) + removeInitialFunction(val); + } + } return escapeJSName(this.symbol.name) + ': ' + val; }; diff -r 6735db9b44ba -r 094227f2f64e modules/false.tp --- a/modules/false.tp Tue Jul 24 01:01:00 2012 -0700 +++ b/modules/false.tp Thu Jul 26 23:41:54 2012 -0700 @@ -2,6 +2,9 @@ if <- :self trueblock { self } + ifnot <- :self falseblock { + falseblock: + } if:else <- :self trueblock :elseblock { elseblock: } diff -r 6735db9b44ba -r 094227f2f64e modules/true.tp --- a/modules/true.tp Tue Jul 24 01:01:00 2012 -0700 +++ b/modules/true.tp Thu Jul 26 23:41:54 2012 -0700 @@ -2,6 +2,9 @@ if <- :self trueblock { trueblock: } + ifnot <- :self falseblock { + self + } if:else <- :self trueblock :elseblock { trueblock: } diff -r 6735db9b44ba -r 094227f2f64e samples/logical.tp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/samples/logical.tp Thu Jul 26 23:41:54 2012 -0700 @@ -0,0 +1,28 @@ +#{ + + foo <- { + print: "foo\n" + true + } + + bar <- { + print: "bar\n" + false + } + + baz <- { + print: "baz\n" + true + } + + qux <- { + print: "shouldn't be printed\n" + true + } + + + main <- { + foo && bar || (baz || qux) + } + +} diff -r 6735db9b44ba -r 094227f2f64e tpc.js --- a/tpc.js Tue Jul 24 01:01:00 2012 -0700 +++ b/tpc.js Thu Jul 26 23:41:54 2012 -0700 @@ -108,7 +108,7 @@ var c = parsed.toCModule(); break; case 'JS': - var c = parsed.toJSModule(); + var c = makeJSProg(parsed); break; default: print('Backend', backend, ' not recognized');