# HG changeset patch # User Mike Pavone # Date 1341849470 25200 # Node ID a10f1b049193db2ce70b45bfcfceabda533e94b0 # Parent 96e21f525b78ec92fce0a5a694fa3ad2a0f92e70 Working closures, but need to rethink method call strategy diff -r 96e21f525b78 -r a10f1b049193 cbackend.js --- a/cbackend.js Sun Jul 08 12:32:24 2012 -0700 +++ b/cbackend.js Mon Jul 09 08:57:50 2012 -0700 @@ -50,6 +50,9 @@ function escapeCName(name) { + if (name == 'self') { + return name; + } name = name.replace("_", "UN_").replace(":", "CN_").replace("!", "EX_").replace('?', 'QS_').replace('@', 'AT_'); name = 'tp_' + name; return name; @@ -57,36 +60,46 @@ symbol.prototype.toC = function() { var name = this.cleanName(); - if (name == 'self') { - return name; - } var info = this.symbols.find(name); if (!info) { throw new Error('symbol ' + name + ' not found'); } var pre = ''; - if (info.type == 'self') { - pre = this.symbols.selfVar() + '->'; - } else if(info.type == 'parent') { - pre = this.symbols.selfVar() + '->'; + console.log('symbol', info); + switch(info.type) { + case 'self': + pre = 'self->'; + break; + case 'parent': + pre = 'self->'; for (var i = 0; i < info.depth; ++i) { pre += 'parent->'; } - } else if(info.type == 'upvar') { + break; + case 'upvar': pre = 'env->'; for (var i = 1; i < info.depth; ++i) { pre += 'parent->'; } - } else if (info.type == 'toplevel') { + break; + case 'toplevel': pre = 'modules.'; modules[name] = false; + break; + case 'closedover': + pre = 'myenv->'; } return pre + escapeCName(name); } +var declaredInts = {}; + intlit.prototype.toC = function() { var str = this.val.toString(); - toplevelcode += 'obj_int32 int32_' + str + ' = {{&obj_int32_meta, NULL}, ' + str + '};\n'; + if (!(this.val in declaredInts)) { + toplevelcode += 'obj_int32 int32_' + str + ' = {{&obj_int32_meta, NULL}, ' + str + '};\n'; + declaredInts[this.val] = true; + } return '((object *)&int32_' + str + ')'; } @@ -274,12 +287,17 @@ int32.addProperty('num', null, 'int32_t'); int32.addMessage('ADD_', 'params[0] = make_object(&obj_int32_meta, NULL, 0); ((obj_int32 *)params[0])->num = self->num + ((obj_int32 *)params[1])->num; return params[0];'); int32.addMessage('SUB_', 'params[0] = make_object(&obj_int32_meta, NULL, 0); ((obj_int32 *)params[0])->num = self->num - ((obj_int32 *)params[1])->num; return params[0];'); + int32.addMessage('LT_', 'params[0] = main_module; if (self->num < ((obj_int32 *)params[1])->num) { return mcall(METHOD_ID_TRUE, 1, params); } return mcall(METHOD_ID_FALSE, 1, params);'); forwarddec = toplevelcode = ''; forwarddec += int32.toEarlyCDef(); toplevelcode += int32.toCDef(); obj.populateSymbols(toplevel); - var rest = 'object * mainModule() {\n\treturn ' + obj.toC() + ';\n}\n'; - return '#include "runtime/proghead.inc"\n#define METHOD_ID_MAIN ' + getMethodId('main') + '\n' + forwarddec + toplevelcode + rest + '#include "runtime/progfoot.inc"\n'; + var rest = 'object * mainModule() {\n\tmain_module = ' + obj.toC() + ';\n\treturn main_module;\n}\n'; + return '#include "runtime/proghead.inc"\n' + + '#define METHOD_ID_MAIN ' + getMethodId('main') + '\n' + + '#define METHOD_ID_TRUE ' + getMethodId('true') + '\n' + + '#define METHOD_ID_FALSE ' + getMethodId('false') + '\n' + + forwarddec + toplevelcode + rest + '#include "runtime/progfoot.inc"\n'; } object.prototype.toCModule = function() { @@ -291,7 +309,12 @@ lambda.prototype.toC = function() { var args = this.args ? this.args.slice(0, this.args.length) : []; var exprs = this.expressions; + var mynum = lambdanum++; + if (Object.keys(this.symbols.closedover).length) { + this.symbols.envtype = 'lambda_' + mynum + '_env'; + } if (this.selftype) { + this.symbols.defineVar('self', this.selftype); if (args[0] && args[0].cleanName() == 'self') { args.splice(0, 1); } @@ -300,7 +323,9 @@ var offset = 0; } for (var i = 0; i < args.length; ++i) { - args[i] = '\tobject * ' + args[i].toC() + ' = params[' + (offset + i) + '];\n'; + var argname = args[i].toC(); + + args[i] = (argname.indexOf('->') < 0 ? '\tobject * ' : '\t') + argname + ' = params[' + (offset + i) + '];\n'; } var compiled = [] for (var i in exprs) { @@ -313,15 +338,43 @@ if (exprs.length) { exprs[exprs.length-1] = 'return ' + exprs[exprs.length-1] + ';'; } - var mynum = lambdanum++; - toplevelcode += 'object * lambda_' + mynum + ' (void * env, uint32_t num_args, object ** params) {\n'; + + if (Object.keys(this.symbols.closedover).length) { + forwarddec += 'typedef struct {\n'; + for (var varname in this.symbols.closedover) { + forwarddec += '\tobject * ' + escapeCName(varname) + ';\n'; + } + forwarddec += '} lambda_' + mynum + '_env;\n' + + var myenvinit = '\tlambda_' + mynum + '_env * myenv = malloc(sizeof(lambda_' + mynum + '_env));\n'; + this.symbols.envtype = 'lambda_' + mynum + '_env'; + } else { + var myenvinit = ''; + } + + toplevelcode += 'object * lambda_' + mynum + ' (' + this.symbols.parentEnvType() + ' * env, uint32_t num_args, object ** params) {\n' + myenvinit; if (this.selftype) { - toplevelcode += '\t' + this.selftype + ' * self = (' + this.selftype + ' *)params[0];\n'; + var selfvar = (new symbol('self', this.symbols)).toC(); + if (selfvar == 'self') { + toplevelcode += '\t' + this.selftype + ' * self = (' + this.selftype + ' *)params[0];\n'; + } else { + toplevelcode += '\t' + selfvar + ' = (' + this.selftype + ' *)params[0];\n'; + } + } toplevelcode += args.join('') + exprs.join(';\n\t') + '\n}\n'; - - toplevelcode += 'closure lambda_obj_' + mynum + ' = {{&lambda_meta, NULL}, NULL, lambda_' + mynum + '};\n'; - return '((object *)&lambda_obj_' + mynum + ')'; + + if (this.symbols.parentEnvType() != 'void') { + if (this.symbols.passthruenv) { + var envvar = 'env'; + } else { + var envvar = 'myenv'; + } + return 'make_closure(' + envvar + ', lambda_' + mynum + ')'; + } else { + toplevelcode += 'closure lambda_obj_' + mynum + ' = {{&lambda_meta, NULL}, NULL, lambda_' + mynum + '};\n'; + return '((object *)&lambda_obj_' + mynum + ')'; + } }; lambda.prototype.toCObject = function(typename) { this.selftype = typename; @@ -336,19 +389,6 @@ var prefix = ''; if (!existing) { prefix = 'object * '; - } else { - switch (existing.type) - { - case 'self': - prefix = 'self->'; - break; - case 'parent': - prefix = 'self->header.'; - for (var i = 0; i < existing.depth; ++i) { - prefix += 'parent->'; - } - break; - } } var val = this.expression.toC(); if (val === null) { diff -r 96e21f525b78 -r a10f1b049193 compiler.js --- a/compiler.js Sun Jul 08 12:32:24 2012 -0700 +++ b/compiler.js Mon Jul 09 08:57:50 2012 -0700 @@ -37,6 +37,9 @@ } return null; } +topsymbols.prototype.getEnvType = function() { + return 'void'; +} function osymbols(parent) { @@ -95,14 +98,22 @@ } return curlist; } +osymbols.prototype.getEnvType = function() { + console.log('osymbol parent', this.parent); + return this.parent.getEnvType(); +} function lsymbols(parent) { this.parent = parent; this.names = {}; + this.closedover = {}; this.needsSelfVar = false; + this.passthruenv = false; + this.envtype = 'void'; } -lsymbols.prototype.find = function(name) { +lsymbols.prototype.find = function(name, nestedcall) { + console.log('find', name, nestedcall); if (name in this.names) { if (this.names[name] instanceof funcall && this.names[name].name == 'foreign:') { return { @@ -110,18 +121,32 @@ def: this.names[name] }; } + if (nestedcall) { + console.log('closedover', name); + this.closedover[name] = true; + } + if (name in this.closedover) { + return { + type: 'closedover', + def: this.names[name] + }; + } return { type: 'local', def: this.names[name] }; } else if(this.parent) { - var ret = this.parent.find(name); + var ret = this.parent.find(name, true); if (ret) { - if (ret.type == 'local') { + if (ret.type == 'closedover') { ret.type = 'upvar'; ret.depth = 1; } else if (ret.type == 'upvar') { - ret.depth++; + if (Object(this.closedover).keys.length) { + ret.depth++; + } else { + this.passthruenv = true; + } } } return ret; @@ -147,6 +172,20 @@ } }; lsymbols.prototype.allSymbols = osymbols.prototype.allSymbols; +lsymbols.prototype.parentEnvType = function() { + if (!this.parent) { + return 'void'; + } + return this.parent.getEnvType(); +}; +lsymbols.prototype.getEnvType = function() { + if (this.passthruenv) { + console.log('lsymbol parent', this.parent); + return this.parent.getEnvType(); + } else { + return this.envtype; + } +} var mainModule; @@ -173,6 +212,7 @@ symbol.prototype.populateSymbols = function(symbols) { this.symbols = symbols; + symbols.find(this.cleanName()); } intlit.prototype.populateSymbols = function(symbols) { diff -r 96e21f525b78 -r a10f1b049193 runtime/object.c --- a/runtime/object.c Sun Jul 08 12:32:24 2012 -0700 +++ b/runtime/object.c Mon Jul 09 08:57:50 2012 -0700 @@ -1,6 +1,7 @@ #include "object.h" #include #include +#include object * make_object(obj_meta * meta, void * parent, int num_props, ...) { @@ -14,8 +15,18 @@ for (; num_props > 0; num_props--) { *curprop = va_arg(args, object *); + curprop++; } va_end(args); return newobj; } +object * make_closure(void * env, closure_func func) +{ + closure * ret = malloc(sizeof(closure)); + ret->header.meta = &lambda_meta; + ret->header.parent = NULL; + ret->env = env; + ret->func = func; + return (object *) ret; +} diff -r 96e21f525b78 -r a10f1b049193 runtime/object.h --- a/runtime/object.h Sun Jul 08 12:32:24 2012 -0700 +++ b/runtime/object.h Mon Jul 09 08:57:50 2012 -0700 @@ -28,9 +28,12 @@ method meth_lookup[16]; }; +extern obj_meta lambda_meta; + #define mcall(method_id, num_args, args) (args[0])->meta->meth_lookup[method_id & 0xF](method_id, num_args, args) #define ccall(clos, num_args, args) (((closure *)clos)->func(((closure *)clos)->env, num_args, args)) object * make_object(obj_meta * meta, void * parent, int num_props, ...); +object * make_closure(void * env, closure_func func); #endif //OBJECT_H_ diff -r 96e21f525b78 -r a10f1b049193 runtime/proghead.inc --- a/runtime/proghead.inc Sun Jul 08 12:32:24 2012 -0700 +++ b/runtime/proghead.inc Mon Jul 09 08:57:50 2012 -0700 @@ -3,9 +3,12 @@ #include #include +object * main_module; + object * no_impl(uint32_t method_id, uint32_t num_args, object ** params) { - printf("method %d is not implemented on object\n", method_id); + printf("method %d is not implemented on object %p\n", method_id, params[0]); + printf("main_module %p\n", main_module); exit(0); return NULL; } @@ -15,4 +18,3 @@ {no_impl, no_impl, no_impl, no_impl, no_impl, no_impl, no_impl, no_impl, no_impl, no_impl, no_impl, no_impl, no_impl, no_impl, no_impl, no_impl} }; -