Mercurial > repos > tabletprog
view cbackend.js @ 56:a9bf3ffb6379
Fix escape for backslash
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 13 Jul 2012 21:28:37 -0700 |
parents | 93ddb4ad6fcb |
children | 08ae75d90dc2 |
line wrap: on
line source
var mainModule; var modules = {}; var nextmethodId = 0; var methodIds = {}; function getMethodId(methodName) { 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) { if (symlist === undefined) { each(src, function(key,val) { if (key != 'parent') { importSym(obj, src, key); } }); } else { for (var i = 0; i < symlist.length; ++i) { importSym(obj, src, symlist[i]); } } return obj; } op.prototype.toC = function(isReceiver) { var optoMeth = {'+': 'ADD_', '-': 'SUB_', '*': 'MUL_', '/': 'DIV_', '=': 'EQ_', '!=': 'NEQ_', '<': 'LT_', '>': 'GT_', '>=': 'GEQ_', '<=': 'LEQ_', '.': 'CAT_'}; var method = optoMeth[this.op]; return 'mcall(' + getMethodId(method) + ', 2, (object *)' + this.left.toC() + ', ' + this.right.toC() + ')\n'; }; 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; } function getSymbolPrefix(info, symbols) { var pre = ''; switch(info.type) { case 'self': pre = (new symbol('self', symbols)).toC() + '->'; break; case 'parent': pre = 'self->'; for (var i = 0; i < info.depth; ++i) { pre += 'parent->'; } break; case 'upvar': pre = 'env->'; for (var i = 1; i < info.depth; ++i) { pre += 'parent->'; } break; case 'recupvar': if (info.subtype == 'object') { pre = 'self->env->'; } else { //TODO: fill this case in if necessary } pre += getSymbolPrefix(info.parent); case 'closedover': pre = 'myenv->'; } return pre; } symbol.prototype.toC = function() { var name = this.cleanName(); var info = this.symbols.find(name); if (!info) { throw new Error('symbol ' + name + ' not found'); } if (info.type == 'toplevel') { return info.def.modulevar; } return getSymbolPrefix(info, this.symbols) + escapeCName(name); } var declaredInts = {}; intlit.prototype.toC = function() { var str = this.val.toString(); if (!(this.val in declaredInts)) { toplevelcode += 'obj_int32 int32_' + str + ' = {{&obj_int32_meta, NULL}, ' + str + '};\n'; declaredInts[this.val] = true; } return '((object *)&int32_' + str + ')'; } floatlit.prototype.toC = function() { return 'make_float(' + this.val.toString() + ')'; } var declaredStrings = {}; var nextStringId = 0; strlit.prototype.toC = function() { if (!(this.val in declaredStrings)) { //TODO: get the proper byte length toplevelcode += 'string str_' + nextStringId + ' = {{&string_meta, NULL}, ' + this.val.length + ', ' + this.val.length + ', "' + this.val.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') + '"};\n'; declaredStrings[this.val] = nextStringId++; } return '((object *)&str_' + declaredStrings[this.val] + ')'; } listlit.prototype.toC = function() { var ret = 'make_list(' + this.val.length; for (var i = 0; i < this.val.length; i++) { ret += ', ' + this.val[i].toC(); } return ret + ')'; } arraylit.prototype.toC = function() { var ret = 'make_array(' + this.val.length; for (var i = 0; i < this.val.length; i++) { ret += ', ' + this.val[i].toC(); } return ret + ')'; } funcall.prototype.toC = function() { var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name; if (name == 'foreign') { if ((this.args[0] instanceof lambda) || (this.args[0] instanceof object)) { return null; } else if(this.args[0] instanceof symbol) { return this.args[0].name; } else { throw new Error("Unexpected AST type for foreign:"); } } var args = this.args.slice(0, this.args.length); if (this.receiver) { args.splice(0, 0, this.receiver); } var method = false; var funinfo = this.symbols.find(name); if (!funinfo || funinfo.def instanceof setter) { method = true; } else { switch(funinfo.type) { case 'self': if (args.length < funinfo.def.args.length || !funinfo.def.args.length || funinfo.def.args[0].name != 'self') { args.splice(0, 0, new symbol('self', this.symbols)); } else { args.splice(0, 1); } method = true; break; case 'parent': ret = 'self'; for (var i = 0; i < funinfo.depth; ++i) { ret += '->parent'; } break; } } for (var i in args) { args[i] = ', ' + args[i].toC(); } var callpart; if (method) { callpart = 'mcall(' + getMethodId(name); } else { callpart = 'ccall(' + (new symbol(name, this.symbols)).toC(); } return callpart + ', ' + args.length + args.join('') + ')'; } function cObject(name) { this.name = name; this.slots = {}; this.properties = []; this.values = []; this.slotvars = {}; this.includes = {}; } cObject.prototype.addInclude = function(includefile) { this.includes[includefile] = true; } cObject.prototype.addMessage = function(msgname, implementation) { var methodid = getMethodId(msgname); var trunc = methodid & 0xF; if (!(trunc in this.slots)) { this.slots[trunc] = []; } this.slots[trunc].push([methodid, '\t\t' + implementation.lines.join('\n\t\t') + '\n', msgname]); if (!(trunc in this.slotvars)) { this.slotvars[trunc] = {}; } for (var varname in implementation.vars) { this.slotvars[trunc][varname] = implementation.vars[varname]; } } cObject.prototype.addProperty = function(propname, value, type) { if (type != undefined) { this.properties.push([propname, type]); if (value !== null) { this.values.push(value); } } else { var escaped = escapeCName(propname); this.addMessage(propname, { vars: {}, lines: [ 'va_end(args);', 'return self->' + escaped + ';' ]}); this.addMessage(propname + '!', { vars: {setval: 'object *'}, lines: [ 'setval = va_arg(args, object *);', 'va_end(args);', 'self->' + escaped + ' = setval;', 'return (object *)self;' ]}); this.properties.push(escaped); this.values.push(value); } } cObject.prototype.toEarlyCDef = function() { var includes = ''; for (var file in this.includes) { includes += '#include ' + file + '\n'; } var objdef = 'typedef struct ' + this.name + ' {\n\tobject header;\n'; for (var i in this.properties) { if (this.properties[i] instanceof Array) { objdef += '\t' + this.properties[i][1] + ' ' + this.properties[i][0] + ';\n'; } else { objdef += '\tobject * ' + this.properties[i] + ';\n' } } objdef += '} ' + this.name + ';\nobj_meta ' + this.name + '_meta;\n'; return includes + objdef; } cObject.prototype.toCDef = function() { var slotdefs = ''; var metadef = 'obj_meta ' + this.name + '_meta = {sizeof(' + this.name +'), {'; for (var i = 0; i < 16; i++) { if (i) { metadef += ', '; } if (i in this.slots) { slotdefs += 'object * ' + this.name + '_slot_' + i + '(uint32_t method_id, uint32_t num_params, object * oself, va_list args) {\n\t' + this.name + ' *self = (' + this.name + ' *)oself;\n'; for (var varname in this.slotvars[i]) { slotdefs += '\t' + this.slotvars[i][varname] + ' ' + varname + ';\n'; } 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}\n' + '\treturn no_impl(method_id, num_params, (object *)self, args);\n}\n'; } else { slotdefs += '\tswitch(method_id) {\n'; for (j in this.slots[i]) { slotdefs += '\t\tcase ' + this.slots[i][j][0] + ': /* ' + this.slots[i][j][2] + '*/\n' + '\t\t\t' + this.slots[i][j][1] + '\n'; } slotdefs += '\t\tdefault:\n' + '\treturn no_impl(method_id, num_params, params, args);\n}\n'; } metadef += this.name + '_slot_' + i; } else { metadef += 'no_impl'; } } metadef += '}};\n'; return slotdefs + metadef; } cObject.prototype.toCInstance = function() { return 'make_object(&' + this.name + '_meta, NULL, ' + this.values.length + (this.values.length ? ', ' : '') + this.values.join(', ') + ')'; } cObject.prototype.toC = function() { forwarddec += this.toEarlyCDef(); toplevelcode += this.toCDef(); return this.toCInstance(); } var nextobject = 0; object.prototype.toC = function() { var messages = this.messages; var values = []; var imports = [] var me = new cObject('object_' + nextobject++); if (this.symbols.needsenv) { me.addProperty('env', this.symbols.envVar(), 'struct ' + this.symbols.getEnvType() + ' * '); me.hasenv = true; } for (var i in messages) { if (messages[i] instanceof funcall) { if (messages[i].name == 'import:' && messages[i].args.length == 1) { imports.push({symbols: false, src: messages[i].args[0]}); } else if(messages[i].name == 'import:from:' && messages[i].args.length == 2) { var importsyms = []; each(messages[i].args[0].val, function(i, el) { if (!(el instanceof symbol)) { throw new Error('Names in import:from statement must be symbols'); } importsyms.push(new strlit(el.name)); }); imports.push({symbols: new listlit(importsyms), src: messages[i].args[1]}); } else { throw new Error('Only import and import:from calls allowed in object context'); } } else { messages[i].toCObject(me); } } return me.toC(); } var toplevelcode; var forwarddec; function addBinaryOp(cobject, opname, cop, objtype) { cobject.addMessage(opname, { vars: {ret: objtype + ' *', argb: objtype +' *'}, lines: [ 'argb = va_arg(args, ' + objtype + ' *);', 'ret = (' + objtype + ' *)make_object(&' + objtype + '_meta, NULL, 0);', 'ret->num = self->num ' + cop + ' argb->num;', 'return &(ret->header);' ] }); } function addCompOp(cobject, opname, cop, objtype) { cobject.addMessage(opname, { vars: {argb: objtype + ' *'}, lines: [ 'argb = va_arg(args, ' + objtype + ' *);', 'if (self->num ' + cop + ' argb->num) {', ' return mcall(METHOD_ID_TRUE, 1, main_module);', '}', 'return mcall(METHOD_ID_FALSE, 1, main_module);' ] }); } function makeInt32() { var int32 = new cObject('obj_int32'); int32.addProperty('num', null, 'int32_t'); addBinaryOp(int32, 'ADD_', '+', 'obj_int32'); addBinaryOp(int32, 'SUB_', '-', 'obj_int32'); addBinaryOp(int32, 'MUL_', '*', 'obj_int32'); addBinaryOp(int32, 'DIV_', '/', 'obj_int32'); addCompOp(int32, 'LT_', '<', 'obj_int32'); addCompOp(int32, 'GT_', '>', 'obj_int32'); addCompOp(int32, 'EQ_', '==', 'obj_int32'); addCompOp(int32, 'NEQ_', '!=', 'obj_int32'); addCompOp(int32, 'GEQ_', '>=', 'obj_int32'); addCompOp(int32, 'LEQ_', '<=', 'obj_int32'); int32.addInclude('<string.h>'); int32.addMessage('string', { vars: {str: 'string *'}, lines: [ 'str = (string *)make_object(&string_meta, NULL, 0);', 'str->data = malloc(12);', 'sprintf(str->data, "%d", self->num);', 'str->length = str->bytes = strlen(str->data);', 'return &(str->header);' ] }); return int32; } 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 mcall(METHOD_ID_FALSE, 1, main_module);' ] }); 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 = realloc(self->data, self->storage);', ' 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);' ] }); return array; } 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 mcall(METHOD_ID_TRUE, 1, main_module);', '}', 'return mcall(METHOD_ID_FALSE, 1, main_module);' ] }); 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 = malloc(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);' ] }); return string; } function makelambda() { var clos = new cObject('lambda'); clos.addProperty('env', null, 'void *'); clos.addProperty('func', null, 'closure_func'); clos.addMessage('while:do', { vars: {action: 'lambda *', valtrue: 'object *', ret: 'object *'}, lines: [ 'action = va_arg(args, lambda *);', 'valtrue = mcall(METHOD_ID_TRUE, 1, main_module);', 'ret = valtrue;', 'while(valtrue == ccall(self, 0)) {', ' ccall(action, 0);', '}', 'return ret;' ] }); return clos; } function builtinTypes() { return [makeInt32(), makeArray(), makeString(), makelambda()]; } function addBuiltinModules(toplevel) { var os = new cObject('mod_obj_os'); os.addInclude('<sys/stat.h>'); os.addInclude('<fcntl.h>'); os.addMessage('write', { vars: {str: 'string *', intret: 'obj_int32 *', filedes: 'obj_int32 *'}, lines: [ 'filedes = va_arg(args, obj_int32 *);', 'str = va_arg(args, string *);', 'intret = make_object(&obj_int32_meta, NULL, 0);', 'intret->num = write(filedes->num, str->data, str->bytes);', 'return intret;' ] }); os.addMessage('read', { vars: {str: 'string *', size: 'obj_int32 *', filedes: 'obj_int32 *'}, lines: [ 'filedes = va_arg(args, obj_int32 *);', 'size = va_arg(args, obj_int32 *);', 'str = make_object(&string_meta, NULL, 0);', 'str->data = malloc(size->num + 1);', 'str->length = str->bytes = read(filedes->num, str->data, size->num);', 'str->data[str->bytes+1] = 0;', 'return str;' ] }); os.addMessage('open', { vars: {str: 'string *', flags: 'obj_int32 *', filedes: 'obj_int32 *', perm: 'obj_int32 *'}, lines: [ 'str = va_arg(args, string *);', 'flags = va_arg(args, obj_int32 *);', 'filedes = make_object(&obj_int32_meta, NULL, 0);', 'if (num_params == 3) {', ' filedes->num = open(str->data, flags->num);', '} else if (num_params == 4) {', ' perm = va_arg(args, obj_int32 *);', ' filedes->num = open(str->data, flags->num, perm->num);', '} else {', ' filedes->num = -1;', '}', 'return filedes;' ] }); os.addMessage('close', { vars: {filedes: 'obj_int32 *', intret: 'obj_int32 *'}, lines: [ 'filedes = va_arg(args, obj_int32 *);', 'intret = make_object(&obj_int32_meta, NULL, 0);', 'intret->num = close(filedes->num);', 'return intret;' ] }); os.addMessage('O_RDONLY', { vars: {intret: 'obj_int32 *'}, lines: [ 'intret = make_object(&obj_int32_meta, NULL, 0);', 'intret->num = O_RDONLY;', 'return intret;' ] }); os.addMessage('O_WRONLY', { vars: {intret: 'obj_int32 *'}, lines: [ 'intret = make_object(&obj_int32_meta, NULL, 0);', 'intret->num = O_WRONLY;', 'return intret;' ] }); os.addMessage('O_RDWR', { vars: {intret: 'obj_int32 *'}, lines: [ 'intret = make_object(&obj_int32_meta, NULL, 0);', 'intret->num = O_RDWR;', 'return intret;' ] }); os.addMessage('O_CREAT', { vars: {intret: 'obj_int32 *'}, lines: [ 'intret = make_object(&obj_int32_meta, NULL, 0);', 'intret->num = O_CREAT;', 'return intret;' ] }); os.addMessage('O_APPEND', { vars: {intret: 'obj_int32 *'}, lines: [ 'intret = make_object(&obj_int32_meta, NULL, 0);', 'intret->num = O_APPEND;', 'return intret;' ] }); os.addMessage('O_TRUNC', { vars: {intret: 'obj_int32 *'}, lines: [ 'intret = make_object(&obj_int32_meta, NULL, 0);', 'intret->num = O_TRUNC;', 'return intret;' ] }); toplevel.names['os'] = os; } function processUsedToplevel(toplevel) { var ret = ''; var modulenum = 0; for (var symbol in toplevel.used) { ret += '\tmodule_' + (modulenum) + ' = ' + toplevel.names[symbol].toC() + ';\n'; toplevelcode += 'object * module_' + modulenum + ';\n'; toplevel.names[symbol].modulevar = 'module_' + (modulenum++); } return ret; } function makeCProg(obj) { var builtins = builtinTypes(); forwarddec = toplevelcode = ''; for (var i in builtins) { forwarddec += builtins[i].toEarlyCDef(); toplevelcode += builtins[i].toCDef(); } addBuiltinModules(toplevel); debugprint('//------POPULATING SYMBOLS-----'); obj.populateSymbols(toplevel); var moduleinit = processUsedToplevel(toplevel); debugprint('//------COMPILING AST-----'); var rest = 'object * mainModule() {\n' + moduleinit + '\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() { return makeCProg(this); } 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++; 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); } var offset = 1; } else { var offset = 0; } 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 = [] for (var i in exprs) { var js = exprs[i].toC(); if (js) { compiled.push(indent(js)); } } exprs = compiled; if (exprs.length) { exprs[exprs.length-1] = 'return ' + exprs[exprs.length-1] + ';'; } if (Object.keys(this.symbols.closedover).length) { forwarddec += 'typedef struct lambda_' + mynum + '_env {\n'; for (var varname in this.symbols.closedover) { if (varname == 'self' && this.selftype) { forwarddec += '\tstruct ' + this.selftype + ' * self;\n'; } else { 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, ...) {\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') { toplevelcode += '\t' + this.selftype + ' * self = va_arg(args, ' + this.selftype + ' *);\n'; } else { toplevelcode += '\t' + selfvar + ' = va_arg(args, ' + this.selftype + ' *);\n'; } } toplevelcode += args.join('') + '\tva_end(args);\n' + exprs.join(';\n\t') + '\n}\n'; if (this.selftype) { return 'lambda_' + mynum; } else { if (this.symbols.parentEnvType() != 'void') { if (this.symbols.parent.passthruenv) { var envvar = 'env'; } else { var envvar = 'myenv'; } debugprint('//lambda_' + mynum, 'has envvar:', envvar, 'num vars closed over:', Object.keys(this.symbols.closedover).length); return 'make_lambda(' + envvar + ', (closure_func)lambda_' + mynum + ')'; } else { toplevelcode += 'lambda lambda_obj_' + mynum + ' = {{&lambda_meta, NULL}, NULL, lambda_' + mynum + '};\n'; return '((object *)&lambda_obj_' + mynum + ')'; } } }; lambda.prototype.toCObject = function(typename) { this.selftype = typename; return this.toC(); }; lambda.prototype.toCModule = function() { return makeCProg(this); } assignment.prototype.toC = function() { debugprint('//assignment', this.symbol.name); var existing = this.symbols.find(this.symbol.name); var prefix = ''; var val = this.expression.toC(); if (val === null) { return null; } if (existing.type == 'local' && !existing.isdeclared) { prefix = 'object *'; this.symbols.declareVar(this.symbol.name); debugprint('//declared var', this.symbol.name); } return prefix + this.symbol.toC() + ' = ' + val; }; assignment.prototype.toCObject = function(cobj) { debugprint('//message definition', this.symbol.name); if (this.expression.toCObject) { var val = this.expression.toCObject(cobj.name); } else { var val = this.expression.toC(); } if (val === null) { return; } if (this.expression instanceof lambda) { var params = ['((object *)self)']; var paramget = ''; var messagevars = {}; for (var i in this.expression.args) { var escaped = escapeCName(this.expression.args[i].cleanName()); if (escaped != 'self') { messagevars[escaped] = 'object *'; params.push(escaped); paramget += escaped + ' = va_arg(args, object *); '; } } cobj.addMessage(this.symbol.name, { vars: messagevars, lines: [paramget + 'return ' + val + '(' + (cobj.hasenv ? 'self->env' : 'NULL') + ', ' + params.length + (params.length ? ', ' : '') + params.join(', ') + ');'] }); } else { cobj.addProperty(this.symbol.name, val); } };