Mercurial > repos > tabletprog
diff cbackend.js @ 126:a2d2d8e09291
Merge
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 05 Aug 2013 23:37:17 -0700 |
parents | 9820ecd4eed4 |
children | 34e0befbdd77 bf8f75b69048 |
line wrap: on
line diff
--- a/cbackend.js Mon Aug 05 23:36:18 2013 -0700 +++ b/cbackend.js Mon Aug 05 23:37:17 2013 -0700 @@ -7,43 +7,33 @@ { if (!(methodName in methodIds)) { methodIds[methodName] = nextmethodId++; - + } return methodIds[methodName]; } -function importSym(obj, src, key) -{ - if(!(key in src)) { - throw new Error(key +' not found in source object for import'); - } - if(key in obj) { - throw new Error(key +' already exists in target object for import') - } - obj[key] = src[key]; -} - -function doImport(obj, src, symlist) +function getOpMethodName(opname) { - if (symlist === undefined) { - each(src, function(key,val) { - if (key != 'parent') { - importSym(obj, src, key); - } - }); + var optoMeth = {'+': 'ADD_', '-': 'SUB_', '*': 'MUL_', '/': 'DIV_', '%': 'MOD_', '=': 'EQ_', '!=': 'NEQ_', '<': 'LT_', '>': 'GT_', '>=': 'GEQ_', '<=': 'LEQ_', '.': 'CAT_', '&&':'if', '||':'ifnot'}; + if (opname in optoMeth) { + return optoMeth[opname]; } else { - for (var i = 0; i < symlist.length; ++i) { - importSym(obj, src, symlist[i]); - } + return opname; } - return obj; } op.prototype.toC = function(isReceiver) { - var optoMeth = {'+': 'ADD_', '-': 'SUB_', '*': 'MUL_', '/': 'DIV_', '%': 'MOD_', '=': 'EQ_', '!=': 'NEQ_', '<': 'LT_', '>': 'GT_', '>=': 'GEQ_', '<=': 'LEQ_', '.': 'CAT_'}; - var method = optoMeth[this.op]; - return 'mcall(' + getMethodId(method) + '/* ' + method + ' */, 2, (object *)' + this.left.toC() + ', ' + this.right.toC() + ')\n'; + var method = getOpMethodName(this.op); + return 'mcall(' + getMethodId(method) + '/* operator ' + method + ' */, 2, (object *)' + this.left.toC() + ', ' + this.right.toC() + ')\n'; }; +op.prototype.toCLLExpr = function(vars) { + var opmap = {'=': '==', 'xor': '^'}; + return this.left.toCLLExpr(vars) + (this.op in opmap ? opmap[this.op] : this.op) + this.right.toCLLExpr(vars); +}; +op.prototype.toCLines = function(vars, needsreturn) { + return [ (needsreturn ? 'return (object *)' : '' ) + this.toCLLExpr(vars) + ';']; +}; + function escapeCName(name) { @@ -60,7 +50,7 @@ var pre = ''; switch(info.type) { case 'self': - + pre = (new symbol('self', symbols)).toC() + '->'; break; case 'parent': @@ -108,6 +98,40 @@ } return getSymbolPrefix(info, this.symbols) + escapeCName(name); } +symbol.prototype.toCTypeName = function() { + return this.cleanName(); +}; +symbol.prototype.toCLLExpr = function(vars) { + var name = this.cleanName(); + if (name in vars) { + return name; + } + if (name == 'self') { + return 'self'; + } + var info = this.symbols.find(name, false, true); + var symbols = this.symbols; + while (info && info.type == 'local') { + symbols = symbols.parent; + info = symbols.find(name, false, true); + } + if (!info) { + return name; + } + if (info.type == 'toplevel') { + return toplevel.moduleVar(name); + } else if (info.type == 'self') { + if (info.isll || !(info.def instanceof lambda)) { + return 'self->' + name; + } else { + return 'mcall(' + getMethodId(name) + '/* ' + name + ' */, 1, self)'; + } + } + throw new Error('Unsupported reference type ' + info.type + ' for variable ' + name); +}; +symbol.prototype.toCLines = function(vars, needsreturn) { + return [ (needsreturn ? 'return (object *)' : '' ) + this.toCLLExpr(vars) + ';' ]; +}; var declaredInts = {}; @@ -119,10 +143,22 @@ } return '((object *)&int32_' + str + ')'; } +intlit.prototype.toCLLExpr = function(vars) { + return this.val.toString(); +}; +intlit.prototype.toCLines = function(vars, needsreturn) { + return [ (needsreturn ? 'return (object *)' : '' ) + this.toCLLExpr(vars) + ';' ]; +}; floatlit.prototype.toC = function() { return 'make_float(' + this.val.toString() + ')'; } +floatlit.prototype.toCLLExpr = function(vars) { + return this.val.toString(); +}; +floatlit.prototype.toCLines = function(vars, needsreturn) { + return [ (needsreturn ? 'return (object *)' : '' ) + this.toCLLExpr(vars) + ';' ]; +}; var declaredStrings = {}; var nextStringId = 0; @@ -134,7 +170,13 @@ declaredStrings[this.val] = nextStringId++; } return '((object *)&str_' + declaredStrings[this.val] + ')'; -} +}; +strlit.prototype.toCLLExpr = function(vars) { + return '"' + this.val.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') + '"'; +}; +strlit.prototype.toCLines = function(vars, needsreturn) { + return [ (needsreturn ? 'return (object *)' : '' ) + this.toCLLExpr(vars) +';' ]; +}; listlit.prototype.toC = function() { var ret = 'make_list(' + this.val.length; @@ -162,6 +204,8 @@ } else { throw new Error("Unexpected AST type for foreign:"); } + } else if(name == 'llProperty:withType' || name == 'llProperty:withVars:andCode') { + return null; } var args = this.args.slice(0, this.args.length); if (this.receiver) { @@ -170,7 +214,7 @@ var method = false; var funinfo = this.symbols.find(name); var start = 0; - if (!funinfo || funinfo.def instanceof setter) { + if (!funinfo || funinfo.def instanceof setter || funinfo.type == 'toplevel') { method = true; } else { switch(funinfo.type) @@ -202,12 +246,122 @@ } 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(); } return callpart + ', ' + args.length + args.join('') + ')'; -} +}; +funcall.prototype.toCTypeName = function() { + switch(this.name) + { + case 'ptr:': + case 'ptr': + var receiver = this.receiver ? this.receiver : this.args[0]; + return receiver.toCTypeName() + ' *'; + break; + default: + throw new Error('invalid use of funcall expression where a C type name is expected'); + } +}; +funcall.prototype.toCLines = function(vars, needsreturn) { + var lines = []; + 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]); + } + switch(name) + { + case 'if': + lines.push('if (' + this.args[0].toCLLExpr(vars) + ') {'); + var blines = this.args[1].toCLines(vars, needsreturn); + for (var i in blines) { + lines.push('\t' + blines[i]); + } + if (needsreturn) { + lines.push('} else {'); + lines.push('\t return module_false;'); + lines.push('}'); + } else { + lines.push('}'); + } + break; + case 'if:else': + lines.push('if (' + this.args[0].toCLLExpr(vars) + ') {'); + var blines = this.args[1].toCLines(vars, needsreturn); + for (var i in blines) { + lines.push('\t' + blines[i]); + } + lines.push('} else {'); + blines = this.args[2].toCLines(vars, needsreturn); + for (var i in blines) { + lines.push('\t' + blines[i]); + } + lines.push('}'); + break; + case 'while:do': + if (needsreturn) { + throw new Error("while:do can't be last statement in llMessage code block"); + } + lines.push('while (' + this.args[0].toCLLExpr(vars) + ') {'); + var blines = this.args[1].toCLines(vars); + for (var i in blines) { + lines.push('\t' + blines[i]); + } + lines.push('}'); + break; + default: + lines.push( (needsreturn ? 'return (object *)' : '') + this.toCLLExpr(vars) + ';'); + } + return lines; +}; + +funcall.prototype.toCLLExpr = function(vars) { + 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) { + if(this.args.length == 0) { + return this.receiver.toCLLExpr(vars) + '->' + this.name; + } else if (this.args.length == 1 && name[name.length-1] == '!') { + return this.receiver.toCLLExpr(vars) + '->' + this.name.substr(0, name.length-1) + ' = ' + args[0].toCLLExpr(vars); + } else { + args.splice(0, 0, this.receiver); + } + } + switch(name) + { + case 'if': + return '((' + args[0].toCLLExpr(vars) + ') ? (' + args[1].toCLLExpr(vars) + ') : 0)'; + case 'if:else': + return '((' + args[0].toCLLExpr(vars) + ') ? (' + args[1].toCLLExpr(vars) + ') : (' + args[2].toCLLExpr(vars) + '))'; + case 'while:do': + throw new Error('while:do not allowed in expression context in llMessage block'); + case 'addr_of': + return '&(' + args[0].toCLLExpr(vars) + ')'; + case 'sizeof': + return 'sizeof(' + args[0].toCTypeName() + ')'; + case 'get': + return args[0].toCLLExpr(vars) + '[' + args[1].toCLLExpr(vars) + ']'; + case 'set': + return args[0].toCLLExpr(vars) + '[' + args[1].toCLLExpr(vars) + '] = ' + args[2].toCLLExpr(vars); + case 'not': + return '!(' + args[0].toCLLExpr(vars) + ')'; + case 'mcall': + if (args[0] instanceof symbol) { + args[0] = new intlit(getMethodId(args[0].name)); + } + default: + for (var i in args) { + args[i] = args[i].toCLLExpr(vars); + } + return name + '(' + args.join(', ') + ')'; + } +}; function cObject(name) { this.name = name; @@ -275,7 +429,7 @@ this.addMessage('_init', { vars: {}, lines: init - }); + }); this.initmsgadded = true; } } @@ -316,7 +470,7 @@ } if (this.slots[i].length == 1) { slotdefs += '\tif (method_id == ' + this.slots[i][0][0] + ') { /* ' + this.slots[i][0][2] + '*/\n' + - '\t\t' + this.slots[i][0][1] + '\n' + + '\t\t' + this.slots[i][0][1] + '\n' + '\t}\n' + '\treturn no_impl(method_id, num_params, (object *)self, args);\n}\n'; } else { @@ -327,7 +481,7 @@ } slotdefs += '\t\tdefault:\n' + '\t\t\treturn no_impl(method_id, num_params, (object *)self, args);\n\t}\n}\n'; - + } metadef += this.name + '_slot_' + i; } else { @@ -355,11 +509,15 @@ var nextobject = 0; -object.prototype.toC = function() { + +object.prototype.toCObject = function() { var messages = this.messages; var values = []; - var imports = [] - var me = new cObject('object_' + nextobject++); + var imports = []; + if (!this.name) { + this.name = 'object_' + nextobject++; + } + var me = new cObject(this.name); this.symbols.typename = me.name; if (this.symbols.needsenv) { me.addProperty('env', this.symbols.envVar(), 'struct ' + this.symbols.getEnvType() + ' * '); @@ -381,16 +539,34 @@ importsyms.push(new strlit(el.name)); }); imports.push({symbols: new listlit(importsyms), src: messages[i].args[1]}); + } else if(messages[i].name == 'llProperty:withType:' && messages[i].args.length == 2) { + me.addProperty(messages[i].args[0].name, null, messages[i].args[1].toCTypeName()) + } else if(messages[i].name == 'llMessage:withVars:andCode:' && messages[i].args.length == 3) { + var msgname = messages[i].args[0].name + var rawvars = messages[i].args[1].expressions; + var vars = {}; + for(var v in rawvars) { + vars[rawvars[v].symbol.name] = rawvars[v].expression.toCTypeName(); + } + me.addMessage(msgname, { + vars: vars, + lines: messages[i].args[2].toCLines(vars, true) + }); } else { - throw new Error('Only import and import:from calls allowed in object context'); + + throw new Error('Only import and import:from calls allowed in object context. ' + messages[i].name + 'with ' + messages[i].args.length + ' arguments found instead.'); } } else { messages[i].toCObject(me); } } - return me.toC(); -} + return me; +}; + +object.prototype.toC = function() { + return this.toCObject().toC(); +}; var toplevelcode; var forwarddec; @@ -444,10 +620,16 @@ 'str = (string *)make_object(&string_meta, NULL, 0);', 'str->data = GC_MALLOC(12);', 'sprintf(str->data, "%d", self->num);', - 'str->length = str->bytes = strlen(str->data);', + 'str->len = str->bytes = strlen(str->data);', 'return &(str->header);' ] }); + int32.addMessage('isInteger?', { + vars: {}, + lines: [ + 'return ' + toplevel.moduleVar('true') + ';' + ] + }); int32.addMessage('hash', { vars: {}, lines: [ @@ -459,169 +641,20 @@ function makeArray() { - var array = new cObject('array'); - array.addProperty('size', null, 'uint32_t'); - array.addProperty('storage', null, 'uint32_t'); - array.addProperty('data', null, 'object **'); - array.addMessage('get', { - vars: {index: 'obj_int32 *'}, - lines: [ - 'index = va_arg(args, obj_int32 *);', - 'if (index->num >= 0 && index->num < self->size) {', - ' return self->data[index->num];', - '}', - 'return ' + toplevel.moduleVar('false') + ';' - ] - }); - array.addMessage('set', { - vars: {index: 'obj_int32 *'}, - lines: [ - 'index = va_arg(args, obj_int32 *);', - 'if (index->num >= 0 && index->num < self->size) {', - ' self->data[index->num] = va_arg(args, object *);', - '}', - 'return &(self->header);' - ] - }); - array.addMessage('foreach', { - vars: {index: 'obj_int32 *', i: 'int32_t', clos: 'lambda *'}, - lines: [ - 'clos = va_arg(args, lambda *);', - 'for (i = 0; i < self->size; i++) {', - ' index = (obj_int32 *)make_object(&obj_int32_meta, NULL, 0);', - ' index->num = i;', - ' ccall(clos, 2, index, self->data[i]);', - '}', - 'return &(self->header);' - ] - }); - array.addMessage('append', { - vars: {tmp: 'object **'}, - lines: [ - 'if (self->storage == self->size) {', - ' self->storage *= 2;', - ' tmp = GC_REALLOC(self->data, self->storage * sizeof(object *));', - ' if (!tmp) {', - ' fputs("Failed to increase array size\\n", stderr);', - ' exit(1);', - ' }', - ' self->data = tmp;', - '}', - 'self->data[self->size++] = va_arg(args, object *);', - 'return &(self->header);' - ] - }); - array.addMessage('length', { - vars: {intret: 'obj_int32 *'}, - lines: [ - 'intret = (obj_int32 *)make_object(&obj_int32_meta, NULL, 0);', - 'intret->num = self->size;', - 'return &(intret->header);' - ] - }); - return array; + var arrayfile = toplevel.names['array']; + var ast = parseFile(arrayfile.path + '/' + arrayfile.file); + ast.name = 'array'; + ast.populateSymbols(toplevel); + return ast.toCObject(); } function makeString() { - var string = new cObject('string'); - string.addProperty('length', null, 'uint32_t'); - string.addProperty('bytes', null, 'uint32_t'); - string.addProperty('data', null, 'char *'); - string.addMessage('length', { - vars: {intret: 'obj_int32 *'}, - lines: [ - 'intret = (obj_int32 *)make_object(&obj_int32_meta, NULL, 0);', - 'intret->num = self->length;', - 'return &(intret->header);' - ] - }); - string.addMessage('byte_length', { - vars: {intret: 'obj_int32 *'}, - lines: [ - 'intret = (obj_int32 *)make_object(&obj_int32_meta, NULL, 0);', - 'intret->num = self->bytes;', - 'return &(intret->header);' - ] - }); - string.addMessage('EQ_', { - vars: {argb: 'string *'}, - lines: [ - 'argb = va_arg(args, string *);', - 'if (self->length == argb->length && self->bytes == argb->bytes && !memcmp(self->data, argb->data, self->bytes)) {', - ' return ' + toplevel.moduleVar('true') + ';', - '}', - 'return ' + toplevel.moduleVar('false') + ';', - ] - }); - string.addMessage('NEQ_', { - vars: {argb: 'string *'}, - lines: [ - 'argb = va_arg(args, string *);', - 'if (self->length != argb->length || self->bytes != argb->bytes || memcmp(self->data, argb->data, self->bytes)) {', - ' return ' + toplevel.moduleVar('true') + ';', - '}', - 'return ' + toplevel.moduleVar('false') + ';', - ] - }); - string.addMessage('print', { - vars: {}, - lines: [ - 'fwrite(self->data, 1, self->bytes, stdout);', - 'return &(self->header);' - ] - }); - string.addMessage('string', { - vars: {}, - lines: [ 'return &(self->header);' ] - }); - string.addMessage('CAT_', { - vars: {argbo: 'object *', argb: 'string *', out: 'string *'}, - lines: [ - 'argbo = va_arg(args, object *);', - 'argb = (string *)mcall(' + getMethodId('string') + ', 1, argbo);', - 'out = (string *)make_object(&string_meta, NULL, 0);', - 'out->bytes = self->bytes + argb->bytes;', - 'out->length = self->length + argb->length;', - 'out->data = GC_MALLOC_ATOMIC(out->bytes+1);', - 'memcpy(out->data, self->data, self->bytes);', - 'memcpy(out->data + self->bytes, argb->data, argb->bytes + 1);', - 'return &(out->header);' - ] - }); - string.addMessage('byte', { - vars: {index: 'obj_int32 *', intret: 'obj_int32 *'}, - lines: [ - 'index = va_arg(args, obj_int32 *);', - 'intret = (obj_int32 *)make_object(&obj_int32_meta, NULL, 0);', - 'intret->num = index->num < self->bytes ? self->data[index->num] : 0;', - 'return &(intret->header);' - ] - }); - string.addMessage('int32', { - vars: {intret: 'obj_int32 *'}, - lines: [ - 'intret = (obj_int32 *)make_object(&obj_int32_meta, NULL, 0);', - 'intret->num = atoi(self->data);', - 'return &(intret->header);' - ] - }); - string.addMessage('hash', { - vars: {intret: 'obj_int32 *', i: 'uint32_t'}, - lines: [ - 'intret = (obj_int32 *)make_object(&obj_int32_meta, NULL, 0);', - 'intret->num = 0;', - 'if (self->bytes) {', - ' intret->num = self->data[0] << 7;', - ' for (i = 0; i < self->bytes; i++) {', - ' intret->num = (1000003 * intret->num) ^ self->data[i];', - ' }', - ' intret->num = intret->num ^ self->bytes;', - '}', - 'return &(intret->header);' - ] - }); - return string; + var arrayfile = toplevel.names['string']; + var ast = parseFile(arrayfile.path + '/' + arrayfile.file); + ast.name = 'string'; + ast.populateSymbols(toplevel); + return ast.toCObject(); } function makelambda() @@ -753,31 +786,21 @@ 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(); }; function processUsedToplevel(toplevel) -{ +{ var alwaysused = ['true', 'false']; var ret = ''; var modulenum = 0; - var newused = Object.keys(toplevel.used); - var allused = newused; var visited = {}; for (var i in alwaysused) { - forwarddec += 'object * ' + toplevel.moduleVar(alwaysused[i]) + ';\n'; - toplevel.names[alwaysused[i]].populateSymbols(toplevel); - visited[alwaysused[i]] = true; + toplevel.used[alwaysused[i]] = true; } + var newused = Object.keys(toplevel.used); + var allused = newused; while (newused.length) { for (var i in newused) { debugprint('//---module', newused[i], '--- populate symbols'); @@ -794,13 +817,10 @@ } } } - for (var i in alwaysused) { - allused.push(alwaysused[i]); - } - + for (var i = allused.length-1; i >= 0; i--) { var symbol = allused[i]; - debugprint('//---module', symbol, '--- compile'); + debugprint('//---module', symbol, '(' + i +')--- compile'); ret += '\t' + toplevel.moduleVar(symbol) + ' = ' + toplevel.names[symbol].toC() + ';\n'; } return ret; @@ -808,8 +828,8 @@ function makeCProg(obj) { + forwarddec = toplevelcode = ''; var builtins = builtinTypes(); - forwarddec = toplevelcode = ''; for (var i in builtins) { forwarddec += builtins[i].toEarlyCDef(); toplevelcode += builtins[i].toCDef(); @@ -833,15 +853,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); @@ -854,7 +872,7 @@ } for (var i = 0; i < args.length; ++i) { var argname = args[i].toC(); - + args[i] = (argname.indexOf('->') < 0 ? '\tobject * ' : '\t') + argname + ' = va_arg(args, object *);\n'; } var compiled = [] @@ -868,9 +886,9 @@ if (exprs.length) { exprs[exprs.length-1] = 'return (object *)(' + exprs[exprs.length-1] + ');'; } - + 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'; } @@ -881,18 +899,19 @@ forwarddec += '\tobject * ' + escapeCName(varname) + ';\n'; } } - forwarddec += '} lambda_' + mynum + '_env;\n' - - var myenvinit = '\tlambda_' + mynum + '_env * myenv = GC_MALLOC(sizeof(lambda_' + mynum + '_env));\n'; + forwarddec += '};\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 = ''; } - - toplevelcode += 'object * lambda_' + mynum + ' (' + this.symbols.parentEnvType() + ' * env, uint32_t num_args, ...) {\n\tva_list args;\n' + myenvinit + '\tva_start(args, num_args);\n'; + forwarddec += 'object *' + this.name + ' (' + this.symbols.parentEnvType() + ' * env, uint32_t 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') { @@ -900,11 +919,10 @@ } else { toplevelcode += '\t' + selfvar + ' = va_arg(args, ' + this.selftype + ' *);\n'; } - + } toplevelcode += args.join('') + '\tva_end(args);\n' + exprs.join(';\n\t') + '\n}\n'; - this.name = 'lambda_' + mynum; - + if (this.selftype) { return this.name; } else { @@ -914,11 +932,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 + ')'; + } else { + toplevelcode += 'lambda ' + this.name + '_obj = {{&lambda_meta, NULL}, NULL, lambda_' + mynum + '};\n'; + return '((object *)&' + this.name + '_obj)'; } } }; @@ -932,6 +950,31 @@ }; lambda.prototype.toCModule = function() { return makeCProg(this); +}; +lambda.prototype.toCLines = function(vars, needsreturn) { + var lines = []; + for (var i in this.args) { + var name = this.args[i].name; + if (name[0] == ':') { + name = name.substr(1); + } + if(name != 'self') { + lines.push(name + ' = va_arg(args, ' + vars[name] + ');'); + } + } + for (var i in this.expressions) { + var exprlines = this.expressions[i].toCLines(vars, needsreturn && i == this.expressions.length - 1); + for (var j in exprlines) { + lines.push('\t' + exprlines[j]); + } + } + return lines; +} +lambda.prototype.toCLLExpr = function(vars) { + if (this.expressions.length != 1) { + throw new Error('lambda in expression context must have a single statement in llMessage block'); + } + return this.expressions[0].toCLLExpr(vars); } assignment.prototype.toC = function() { @@ -971,7 +1014,7 @@ paramget += escaped + ' = va_arg(args, object *); '; } } - cobj.addMessage(this.symbol.name, { + cobj.addMessage(getOpMethodName(this.symbol.name), { vars: messagevars, lines: [paramget + 'return ' + val + '(' + (cobj.hasenv ? 'self->env' : 'NULL') + ', ' + params.length + (params.length ? ', ' : '') + params.join(', ') + ');'] }); @@ -982,3 +1025,6 @@ } } }; +assignment.prototype.toCLines = function(vars, needsreturn) { + return [(needsreturn ? 'return ' : '') + this.symbol.toCLLExpr(vars) + ' = ' + this.expression.toCLLExpr(vars) + ';'] +};