comparison cbackend.js @ 35:bf5e88f6419d

Use a function/method call strategy that actually works
author Mike Pavone <pavone@retrodev.com>
date Mon, 09 Jul 2012 21:32:28 -0700
parents a10f1b049193
children a6bf4869fcbe
comparison
equal deleted inserted replaced
34:a10f1b049193 35:bf5e88f6419d
40 } 40 }
41 41
42 op.prototype.toC = function(isReceiver) { 42 op.prototype.toC = function(isReceiver) {
43 var optoMeth = {'+': 'ADD_', '-': 'SUB_', '*': 'MUL_', '/': 'DIV_', '=': 'EQ_', '!=': 'NEQ_', '<': 'LT_', '>': 'GT_', '>=': 'GEQ_', '<=': 'LEQ_'}; 43 var optoMeth = {'+': 'ADD_', '-': 'SUB_', '*': 'MUL_', '/': 'DIV_', '=': 'EQ_', '!=': 'NEQ_', '<': 'LT_', '>': 'GT_', '>=': 'GEQ_', '<=': 'LEQ_'};
44 var method = optoMeth[this.op]; 44 var method = optoMeth[this.op];
45 var ret = '(params[0] = ' + this.left.toC() + ',\n'; 45 return 'mcall(' + getMethodId(method) + ', 2, ' + this.left.toC() + ', ' + this.right.toC() + ')\n';
46 ret += 'params[1] = ' + this.right.toC() + ',\n';
47 ret += 'mcall(' + getMethodId(method) + ', 2, params))\n';
48 return ret;
49 }; 46 };
50 47
51 function escapeCName(name) 48 function escapeCName(name)
52 { 49 {
53 if (name == 'self') { 50 if (name == 'self') {
63 var info = this.symbols.find(name); 60 var info = this.symbols.find(name);
64 if (!info) { 61 if (!info) {
65 throw new Error('symbol ' + name + ' not found'); 62 throw new Error('symbol ' + name + ' not found');
66 } 63 }
67 var pre = ''; 64 var pre = '';
68 console.log('symbol', info);
69 switch(info.type) { 65 switch(info.type) {
70 case 'self': 66 case 'self':
71 pre = 'self->'; 67 pre = 'self->';
72 break; 68 break;
73 case 'parent': 69 case 'parent':
156 } 152 }
157 break; 153 break;
158 } 154 }
159 } 155 }
160 for (var i in args) { 156 for (var i in args) {
161 args[i] = 'params[' + i + '] = ' + args[i].toC() + ',\n'; 157 args[i] = ', ' + args[i].toC();
162 } 158 }
163 var callpart; 159 var callpart;
164 if (method) { 160 if (method) {
165 callpart = 'mcall(' + getMethodId(name); 161 callpart = 'mcall(' + getMethodId(name);
166 } else { 162 } else {
167 callpart = 'ccall(' + escapeCName(name); 163 callpart = 'ccall(' + escapeCName(name);
168 } 164 }
169 return '(' + args.join('') + callpart + ', ' + args.length + ', ' + 'params))'; 165 return callpart + ', ' + args.length + args.join('') + ')';
170 } 166 }
171 167
172 function cObject(name) { 168 function cObject(name) {
173 this.name = name; 169 this.name = name;
174 this.slots = {}; 170 this.slots = {};
175 this.properties = []; 171 this.properties = [];
176 this.values = []; 172 this.values = [];
173 this.slotvars = {};
177 } 174 }
178 175
179 cObject.prototype.addMessage = function(msgname, implementation) { 176 cObject.prototype.addMessage = function(msgname, implementation) {
180 var methodid = getMethodId(msgname); 177 var methodid = getMethodId(msgname);
181 var trunc = methodid & 0xF; 178 var trunc = methodid & 0xF;
188 cObject.prototype.addProperty = function(propname, value, type) { 185 cObject.prototype.addProperty = function(propname, value, type) {
189 if (type != undefined) { 186 if (type != undefined) {
190 this.properties.push([propname, type]); 187 this.properties.push([propname, type]);
191 } else { 188 } else {
192 var escaped = escapeCName(propname); 189 var escaped = escapeCName(propname);
193 this.addMessage(propname, 'return self->' + escaped + ';'); 190 this.addMessage(propname, 'va_end(args); return self->' + escaped + ';');
194 this.addMessage(propname + '!', 'self->' + escaped + ' = params[1]; return params[0];'); 191 this.addMessageVar(propname + '!', 'setval', 'object *');
192 this.addMessage(propname + '!', 'setval = va_arg(args, object *); va_end(args); self->' + escaped + ' = setval; return (object *)self;');
195 this.properties.push(escaped); 193 this.properties.push(escaped);
196 this.values.push(value); 194 this.values.push(value);
197 } 195 }
196 }
197
198 cObject.prototype.addMessageVar = function(msgname, varname, type) {
199 var trunc = getMethodId(msgname) & 0xF;
200 if (!(trunc in this.slotvars)) {
201 this.slotvars[trunc] = {};
202 }
203 this.slotvars[trunc][varname] = type;
198 } 204 }
199 205
200 cObject.prototype.toEarlyCDef = function() { 206 cObject.prototype.toEarlyCDef = function() {
201 var objdef = 'typedef struct {\n\tobject header;\n'; 207 var objdef = 'typedef struct {\n\tobject header;\n';
202 for (var i in this.properties) { 208 for (var i in this.properties) {
216 for (var i = 0; i < 16; i++) { 222 for (var i = 0; i < 16; i++) {
217 if (i) { 223 if (i) {
218 metadef += ', '; 224 metadef += ', ';
219 } 225 }
220 if (i in this.slots) { 226 if (i in this.slots) {
221 slotdefs += 'object * ' + this.name + '_slot_' + i + '(uint32_t method_id, uint32_t num_params, object ** params) {\n\t' + 227 slotdefs += 'object * ' + this.name + '_slot_' + i + '(uint32_t method_id, uint32_t num_params, object * oself, va_list args) {\n\t' +
222 this.name + ' *self = (' + this.name + ' *)params[0];'; 228 this.name + ' *self = (' + this.name + ' *)oself;\n';
229 for (var varname in this.slotvars[i]) {
230 slotdefs += '\t' + this.slotvars[i][varname] + ' ' + varname + ';\n';
231 }
223 if (this.slots[i].length == 1) { 232 if (this.slots[i].length == 1) {
224 slotdefs += '\tif (method_id == ' + this.slots[i][0][0] + ') { /* ' + this.slots[i][0][2] + '*/\n' + 233 slotdefs += '\tif (method_id == ' + this.slots[i][0][0] + ') { /* ' + this.slots[i][0][2] + '*/\n' +
225 '\t\t' + this.slots[i][0][1] + '\n' + 234 '\t\t' + this.slots[i][0][1] + '\n' +
226 '\t}\n' + 235 '\t}\n' +
227 '\treturn no_impl(method_id, num_params, params);\n}\n'; 236 '\treturn no_impl(method_id, num_params, (object *)self, args);\n}\n';
228 } else { 237 } else {
229 slotdefs += '\tswitch(method_id) {\n'; 238 slotdefs += '\tswitch(method_id) {\n';
230 for (j in this.slots[i]) { 239 for (j in this.slots[i]) {
231 slotdefs += '\t\tcase ' + this.slots[i][j][0] + ': /* ' + this.slots[i][j][2] + '*/\n' + 240 slotdefs += '\t\tcase ' + this.slots[i][j][0] + ': /* ' + this.slots[i][j][2] + '*/\n' +
232 '\t\t\t' + this.slots[i][j][1] + '\n'; 241 '\t\t\t' + this.slots[i][j][1] + '\n';
233 } 242 }
234 slotdefs += '\t\tdefault:\n\treturn no_impl(method_id, num_params, params);\n}\n'; 243 slotdefs += '\t\tdefault:\n' +
244 '\treturn no_impl(method_id, num_params, params, args);\n}\n';
235 } 245 }
236 metadef += this.name + '_slot_' + i; 246 metadef += this.name + '_slot_' + i;
237 } else { 247 } else {
238 metadef += 'no_impl'; 248 metadef += 'no_impl';
239 } 249 }
283 293
284 function makeCProg(obj) 294 function makeCProg(obj)
285 { 295 {
286 var int32 = new cObject('obj_int32'); 296 var int32 = new cObject('obj_int32');
287 int32.addProperty('num', null, 'int32_t'); 297 int32.addProperty('num', null, 'int32_t');
288 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];'); 298 int32.addMessageVar('ADD_', 'ret', 'obj_int32 *');
289 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];'); 299 int32.addMessageVar('ADD_', 'argb', 'obj_int32 *');
290 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);'); 300 int32.addMessage('ADD_', 'argb = va_arg(args, obj_int32 *); ret = (obj_int32 *)make_object(&obj_int32_meta, NULL, 0); ret->num = self->num + argb->num; return ret;');
301 int32.addMessageVar('SUB_', 'ret', 'obj_int32 *');
302 int32.addMessageVar('SUB_', 'argb', 'obj_int32 *');
303 int32.addMessage('SUB_', 'argb = va_arg(args, obj_int32 *); ret = (obj_int32 *)make_object(&obj_int32_meta, NULL, 0); ret->num = self->num - argb->num; return ret;');
304 int32.addMessageVar('LT_', 'argb', 'obj_int32 *');
305 int32.addMessage('LT_', 'argb = va_arg(args, obj_int32 *); if (self->num < argb->num) { return mcall(METHOD_ID_TRUE, 1, main_module); } return mcall(METHOD_ID_FALSE, 1, main_module);');
291 forwarddec = toplevelcode = ''; 306 forwarddec = toplevelcode = '';
292 forwarddec += int32.toEarlyCDef(); 307 forwarddec += int32.toEarlyCDef();
293 toplevelcode += int32.toCDef(); 308 toplevelcode += int32.toCDef();
294 obj.populateSymbols(toplevel); 309 obj.populateSymbols(toplevel);
295 var rest = 'object * mainModule() {\n\tmain_module = ' + obj.toC() + ';\n\treturn main_module;\n}\n'; 310 var rest = 'object * mainModule() {\n\tmain_module = ' + obj.toC() + ';\n\treturn main_module;\n}\n';
323 var offset = 0; 338 var offset = 0;
324 } 339 }
325 for (var i = 0; i < args.length; ++i) { 340 for (var i = 0; i < args.length; ++i) {
326 var argname = args[i].toC(); 341 var argname = args[i].toC();
327 342
328 args[i] = (argname.indexOf('->') < 0 ? '\tobject * ' : '\t') + argname + ' = params[' + (offset + i) + '];\n'; 343 args[i] = (argname.indexOf('->') < 0 ? '\tobject * ' : '\t') + argname + ' = va_arg(args, object *);\n';
329 } 344 }
330 var compiled = [] 345 var compiled = []
331 for (var i in exprs) { 346 for (var i in exprs) {
332 var js = exprs[i].toC(); 347 var js = exprs[i].toC();
333 if (js) { 348 if (js) {
350 this.symbols.envtype = 'lambda_' + mynum + '_env'; 365 this.symbols.envtype = 'lambda_' + mynum + '_env';
351 } else { 366 } else {
352 var myenvinit = ''; 367 var myenvinit = '';
353 } 368 }
354 369
355 toplevelcode += 'object * lambda_' + mynum + ' (' + this.symbols.parentEnvType() + ' * env, uint32_t num_args, object ** params) {\n' + myenvinit; 370 toplevelcode += 'object * lambda_' + mynum + ' (' + this.symbols.parentEnvType() + ' * env, uint32_t num_args, ...) {\n\tva_list args;\n' + myenvinit + '\tva_start(args, num_args);\n';
356 if (this.selftype) { 371 if (this.selftype) {
357 var selfvar = (new symbol('self', this.symbols)).toC(); 372 var selfvar = (new symbol('self', this.symbols)).toC();
358 if (selfvar == 'self') { 373 if (selfvar == 'self') {
359 toplevelcode += '\t' + this.selftype + ' * self = (' + this.selftype + ' *)params[0];\n'; 374 toplevelcode += '\t' + this.selftype + ' * self = va_arg(args, ' + this.selftype + ' *);\n';
360 } else { 375 } else {
361 toplevelcode += '\t' + selfvar + ' = (' + this.selftype + ' *)params[0];\n'; 376 toplevelcode += '\t' + selfvar + ' = va_arg(args, ' + this.selftype + ' *);\n';
362 } 377 }
363 378
364 } 379 }
365 toplevelcode += args.join('') + exprs.join(';\n\t') + '\n}\n'; 380 toplevelcode += args.join('') + '\tva_end(args);\n' + exprs.join(';\n\t') + '\n}\n';
366 381
367 if (this.symbols.parentEnvType() != 'void') { 382 if (this.symbols.parentEnvType() != 'void') {
368 if (this.symbols.passthruenv) { 383 if (this.symbols.passthruenv) {
369 var envvar = 'env'; 384 var envvar = 'env';
370 } else { 385 } else {
404 } 419 }
405 if (val === null) { 420 if (val === null) {
406 return; 421 return;
407 } 422 }
408 if (this.expression instanceof lambda) { 423 if (this.expression instanceof lambda) {
409 cobj.addMessage(this.symbol.name, 'return ccall(' + val + ', num_params, params);'); 424 var params = ['((object *)self)'];
425 var paramget = '';
426 for (var i in this.expression.args) {
427 var escaped = escapeCName(this.expression.args[i].cleanName());
428 if (escaped != 'self') {
429 cobj.addMessageVar(this.symbol.name, escaped, 'object *');
430 params.push(escaped);
431 paramget += escaped + ' = va_arg(args, object *); ';
432 }
433 }
434 cobj.addMessage(this.symbol.name, paramget + 'return ccall(' + val + ', ' + params.length + (params.length ? ', ' : '') + params.join(', ') + ');');
410 } else { 435 } else {
411 cobj.addProperty(this.symbol.name, val); 436 cobj.addProperty(this.symbol.name, val);
412 } 437 }
413 }; 438 };