Mercurial > repos > tabletprog
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 }; |