Mercurial > repos > tabletprog
comparison cbackend.js @ 92:6abbf2454657
merge
author | William Morgan <bill@mrgn.org> |
---|---|
date | Mon, 23 Jul 2012 01:07:52 -0700 |
parents | 25bc8a5ab41e |
children | f23ecd4e22af |
comparison
equal
deleted
inserted
replaced
91:3bf57ace3e0b | 92:6abbf2454657 |
---|---|
42 op.prototype.toC = function(isReceiver) { | 42 op.prototype.toC = function(isReceiver) { |
43 var optoMeth = {'+': 'ADD_', '-': 'SUB_', '*': 'MUL_', '/': 'DIV_', '%': 'MOD_', '=': 'EQ_', '!=': 'NEQ_', '<': 'LT_', '>': 'GT_', '>=': 'GEQ_', '<=': 'LEQ_', '.': 'CAT_'}; | 43 var optoMeth = {'+': 'ADD_', '-': 'SUB_', '*': 'MUL_', '/': 'DIV_', '%': 'MOD_', '=': 'EQ_', '!=': 'NEQ_', '<': 'LT_', '>': 'GT_', '>=': 'GEQ_', '<=': 'LEQ_', '.': 'CAT_'}; |
44 var method = optoMeth[this.op]; | 44 var method = optoMeth[this.op]; |
45 return 'mcall(' + getMethodId(method) + '/* ' + method + ' */, 2, (object *)' + this.left.toC() + ', ' + this.right.toC() + ')\n'; | 45 return 'mcall(' + getMethodId(method) + '/* ' + method + ' */, 2, (object *)' + this.left.toC() + ', ' + this.right.toC() + ')\n'; |
46 }; | 46 }; |
47 op.prototype.toCLLExpr = function(vars) { | |
48 var opmap = {'=': '==', 'xor': '^'}; | |
49 return this.left.toCLLExpr(vars) + (this.op in opmap ? opmap[this.op] : this.op) + this.right.toCLLExpr(vars); | |
50 }; | |
51 op.prototype.toCLines = function(vars, needsreturn) { | |
52 return [ (needsreturn ? 'return (object *)' : '' ) + this.toCLLExpr(vars) + ';']; | |
53 }; | |
54 | |
47 | 55 |
48 function escapeCName(name) | 56 function escapeCName(name) |
49 { | 57 { |
50 if (name == 'self') { | 58 if (name == 'self') { |
51 return name; | 59 return name; |
106 } | 114 } |
107 return 'mcall(' + getMethodId(name) + '/* ' + name + ' */, 1, ' + obj + ')'; | 115 return 'mcall(' + getMethodId(name) + '/* ' + name + ' */, 1, ' + obj + ')'; |
108 } | 116 } |
109 return getSymbolPrefix(info, this.symbols) + escapeCName(name); | 117 return getSymbolPrefix(info, this.symbols) + escapeCName(name); |
110 } | 118 } |
119 symbol.prototype.toCTypeName = function() { | |
120 return this.cleanName(); | |
121 }; | |
122 symbol.prototype.toCLLExpr = function(vars) { | |
123 var name = this.cleanName(); | |
124 if (name in vars) { | |
125 return name; | |
126 } | |
127 if (name == 'self') { | |
128 return 'self'; | |
129 } | |
130 var info = this.symbols.find(name, false, true); | |
131 var symbols = this.symbols; | |
132 while (info && info.type == 'local') { | |
133 symbols = symbols.parent; | |
134 info = symbols.find(name, false, true); | |
135 } | |
136 if (!info) { | |
137 return name; | |
138 } | |
139 if (info.type == 'toplevel') { | |
140 return toplevel.moduleVar(name); | |
141 } else if (info.type == 'self') { | |
142 if (info.isll || !(info.def instanceof lambda)) { | |
143 return 'self->' + name; | |
144 } else { | |
145 return 'mcall(' + getMethodId(name) + '/* ' + name + ' */, 1, self)'; | |
146 } | |
147 } | |
148 throw new Error('Unsupported reference type ' + info.type + ' for variable ' + name); | |
149 }; | |
150 symbol.prototype.toCLines = function(vars, needsreturn) { | |
151 return [ (needsreturn ? 'return (object *)' : '' ) + this.toCLLExpr(vars) + ';' ]; | |
152 }; | |
111 | 153 |
112 var declaredInts = {}; | 154 var declaredInts = {}; |
113 | 155 |
114 intlit.prototype.toC = function() { | 156 intlit.prototype.toC = function() { |
115 var str = this.val < 0 ? 'neg_' + (0-this.val).toString() : this.val.toString(); | 157 var str = this.val < 0 ? 'neg_' + (0-this.val).toString() : this.val.toString(); |
117 toplevelcode += 'obj_int32 int32_' + str + ' = {{&obj_int32_meta, NULL}, ' + this.val.toString() + '};\n'; | 159 toplevelcode += 'obj_int32 int32_' + str + ' = {{&obj_int32_meta, NULL}, ' + this.val.toString() + '};\n'; |
118 declaredInts[this.val] = true; | 160 declaredInts[this.val] = true; |
119 } | 161 } |
120 return '((object *)&int32_' + str + ')'; | 162 return '((object *)&int32_' + str + ')'; |
121 } | 163 } |
164 intlit.prototype.toCLLExpr = function(vars) { | |
165 return this.val.toString(); | |
166 }; | |
167 intlit.prototype.toCLines = function(vars, needsreturn) { | |
168 return [ (needsreturn ? 'return (object *)' : '' ) + this.toCLLExpr(vars) + ';' ]; | |
169 }; | |
122 | 170 |
123 floatlit.prototype.toC = function() { | 171 floatlit.prototype.toC = function() { |
124 return 'make_float(' + this.val.toString() + ')'; | 172 return 'make_float(' + this.val.toString() + ')'; |
125 } | 173 } |
174 floatlit.prototype.toCLLExpr = function(vars) { | |
175 return this.val.toString(); | |
176 }; | |
177 floatlit.prototype.toCLines = function(vars, needsreturn) { | |
178 return [ (needsreturn ? 'return (object *)' : '' ) + this.toCLLExpr(vars) + ';' ]; | |
179 }; | |
126 | 180 |
127 var declaredStrings = {}; | 181 var declaredStrings = {}; |
128 var nextStringId = 0; | 182 var nextStringId = 0; |
129 | 183 |
130 strlit.prototype.toC = function() { | 184 strlit.prototype.toC = function() { |
132 //TODO: get the proper byte length | 186 //TODO: get the proper byte length |
133 toplevelcode += 'string str_' + nextStringId + ' = {{&string_meta, NULL}, ' + this.val.length + ', ' + this.val.length + ', "' + this.val.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') + '"};\n'; | 187 toplevelcode += 'string str_' + nextStringId + ' = {{&string_meta, NULL}, ' + this.val.length + ', ' + this.val.length + ', "' + this.val.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') + '"};\n'; |
134 declaredStrings[this.val] = nextStringId++; | 188 declaredStrings[this.val] = nextStringId++; |
135 } | 189 } |
136 return '((object *)&str_' + declaredStrings[this.val] + ')'; | 190 return '((object *)&str_' + declaredStrings[this.val] + ')'; |
137 } | 191 }; |
192 strlit.prototype.toCLLExpr = function(vars) { | |
193 return '"' + this.val.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') + '"'; | |
194 }; | |
195 strlit.prototype.toCLines = function(vars, needsreturn) { | |
196 return [ (needsreturn ? 'return (object *)' : '' ) + this.toCLLExpr(vars) +';' ]; | |
197 }; | |
138 | 198 |
139 listlit.prototype.toC = function() { | 199 listlit.prototype.toC = function() { |
140 var ret = 'make_list(' + this.val.length; | 200 var ret = 'make_list(' + this.val.length; |
141 for (var i = 0; i < this.val.length; i++) { | 201 for (var i = 0; i < this.val.length; i++) { |
142 ret += ', ' + this.val[i].toC(); | 202 ret += ', ' + this.val[i].toC(); |
160 } else if(this.args[0] instanceof symbol) { | 220 } else if(this.args[0] instanceof symbol) { |
161 return this.args[0].name; | 221 return this.args[0].name; |
162 } else { | 222 } else { |
163 throw new Error("Unexpected AST type for foreign:"); | 223 throw new Error("Unexpected AST type for foreign:"); |
164 } | 224 } |
225 } else if(name == 'llProperty:withType' || name == 'llProperty:withVars:andCode') { | |
226 return null; | |
165 } | 227 } |
166 var args = this.args.slice(0, this.args.length); | 228 var args = this.args.slice(0, this.args.length); |
167 if (this.receiver) { | 229 if (this.receiver) { |
168 args.splice(0, 0, this.receiver); | 230 args.splice(0, 0, this.receiver); |
169 } | 231 } |
170 var method = false; | 232 var method = false; |
171 var funinfo = this.symbols.find(name); | 233 var funinfo = this.symbols.find(name); |
172 var start = 0; | 234 var start = 0; |
173 if (!funinfo || funinfo.def instanceof setter) { | 235 if (!funinfo || funinfo.def instanceof setter || funinfo.type == 'toplevel') { |
174 method = true; | 236 method = true; |
175 } else { | 237 } else { |
176 switch(funinfo.type) | 238 switch(funinfo.type) |
177 { | 239 { |
178 case 'self': | 240 case 'self': |
205 callpart = 'mcall(' + getMethodId(name) + '/* ' + name + ' */'; | 267 callpart = 'mcall(' + getMethodId(name) + '/* ' + name + ' */'; |
206 } else { | 268 } else { |
207 callpart = 'ccall(' + (new symbol(name, this.symbols)).toC(); | 269 callpart = 'ccall(' + (new symbol(name, this.symbols)).toC(); |
208 } | 270 } |
209 return callpart + ', ' + args.length + args.join('') + ')'; | 271 return callpart + ', ' + args.length + args.join('') + ')'; |
210 } | 272 }; |
273 funcall.prototype.toCTypeName = function() { | |
274 switch(this.name) | |
275 { | |
276 case 'ptr:': | |
277 case 'ptr': | |
278 var receiver = this.receiver ? this.receiver : this.args[0]; | |
279 return receiver.toCTypeName() + ' *'; | |
280 break; | |
281 default: | |
282 throw new Error('invalid use of funcall expression where a C type name is expected'); | |
283 } | |
284 }; | |
285 funcall.prototype.toCLines = function(vars, needsreturn) { | |
286 var lines = []; | |
287 var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name; | |
288 var args = this.args.slice(0, this.args.length); | |
289 if (this.receiver) { | |
290 args.splice(0, 0, [this.receiver]); | |
291 } | |
292 switch(name) | |
293 { | |
294 case 'if': | |
295 lines.push('if (' + this.args[0].toCLLExpr(vars) + ') {'); | |
296 var blines = this.args[1].toCLines(vars, needsreturn); | |
297 for (var i in blines) { | |
298 lines.push('\t' + blines[i]); | |
299 } | |
300 if (needsreturn) { | |
301 lines.push('} else {'); | |
302 lines.push('\t return module_false;'); | |
303 lines.push('}'); | |
304 } else { | |
305 lines.push('}'); | |
306 } | |
307 break; | |
308 case 'if:else': | |
309 lines.push('if (' + this.args[0].toCLLExpr(vars) + ') {'); | |
310 var blines = this.args[1].toCLines(vars, needsreturn); | |
311 for (var i in blines) { | |
312 lines.push('\t' + blines[i]); | |
313 } | |
314 lines.push('} else {'); | |
315 blines = this.args[2].toCLines(vars, needsreturn); | |
316 for (var i in blines) { | |
317 lines.push('\t' + blines[i]); | |
318 } | |
319 lines.push('}'); | |
320 break; | |
321 case 'while:do': | |
322 if (needsreturn) { | |
323 throw new Error("while:do can't be last statement in llMessage code block"); | |
324 } | |
325 lines.push('while (' + this.args[0].toCLLExpr(vars) + ') {'); | |
326 var blines = this.args[1].toCLines(vars); | |
327 for (var i in blines) { | |
328 lines.push('\t' + blines[i]); | |
329 } | |
330 lines.push('}'); | |
331 break; | |
332 default: | |
333 lines.push( (needsreturn ? 'return (object *)' : '') + this.toCLLExpr(vars) + ';'); | |
334 } | |
335 return lines; | |
336 }; | |
337 | |
338 funcall.prototype.toCLLExpr = function(vars) { | |
339 var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name; | |
340 var args = this.args.slice(0, this.args.length); | |
341 if (this.receiver) { | |
342 if(this.args.length == 0) { | |
343 return this.receiver.toCLLExpr(vars) + '->' + this.name; | |
344 } else if (this.args.length == 1 && name[name.length-1] == '!') { | |
345 return this.receiver.toCLLExpr(vars) + '->' + this.name.substr(0, name.length-1) + ' = ' + args[0].toCLLExpr(vars); | |
346 } else { | |
347 args.splice(0, 0, this.receiver); | |
348 } | |
349 } | |
350 switch(name) | |
351 { | |
352 case 'if': | |
353 return '((' + args[0].toCLLExpr(vars) + ') ? (' + args[1].toCLLExpr(vars) + ') : 0)'; | |
354 case 'if:else': | |
355 return '((' + args[0].toCLLExpr(vars) + ') ? (' + args[1].toCLLExpr(vars) + ') : (' + args[2].toCLLExpr(vars) + '))'; | |
356 case 'while:do': | |
357 throw new Error('while:do not allowed in expression context in llMessage block'); | |
358 case 'addr_of': | |
359 return '&(' + args[0].toCLLExpr(vars) + ')'; | |
360 case 'sizeof': | |
361 return 'sizeof(' + args[0].toCTypeName() + ')'; | |
362 case 'get': | |
363 return args[0].toCLLExpr(vars) + '[' + args[1].toCLLExpr(vars) + ']'; | |
364 case 'set': | |
365 return args[0].toCLLExpr(vars) + '[' + args[1].toCLLExpr(vars) + '] = ' + args[2].toCLLExpr(vars); | |
366 case 'not': | |
367 return '!(' + args[0].toCLLExpr(vars) + ')'; | |
368 case 'mcall': | |
369 if (args[0] instanceof symbol) { | |
370 args[0] = new intlit(getMethodId(args[0].name)); | |
371 } | |
372 default: | |
373 for (var i in args) { | |
374 args[i] = args[i].toCLLExpr(vars); | |
375 } | |
376 return name + '(' + args.join(', ') + ')'; | |
377 } | |
378 }; | |
211 | 379 |
212 function cObject(name) { | 380 function cObject(name) { |
213 this.name = name; | 381 this.name = name; |
214 this.slots = {}; | 382 this.slots = {}; |
215 this.properties = []; | 383 this.properties = []; |
353 return this.toCInstance(); | 521 return this.toCInstance(); |
354 } | 522 } |
355 | 523 |
356 var nextobject = 0; | 524 var nextobject = 0; |
357 | 525 |
358 object.prototype.toC = function() { | 526 |
527 object.prototype.toCObject = function() { | |
359 var messages = this.messages; | 528 var messages = this.messages; |
360 var values = []; | 529 var values = []; |
361 var imports = [] | 530 var imports = []; |
362 var me = new cObject('object_' + nextobject++); | 531 if (!this.name) { |
532 this.name = 'object_' + nextobject++; | |
533 } | |
534 var me = new cObject(this.name); | |
363 this.symbols.typename = me.name; | 535 this.symbols.typename = me.name; |
364 if (this.symbols.needsenv) { | 536 if (this.symbols.needsenv) { |
365 me.addProperty('env', this.symbols.envVar(), 'struct ' + this.symbols.getEnvType() + ' * '); | 537 me.addProperty('env', this.symbols.envVar(), 'struct ' + this.symbols.getEnvType() + ' * '); |
366 me.hasenv = true; | 538 me.hasenv = true; |
367 } | 539 } |
379 throw new Error('Names in import:from statement must be symbols'); | 551 throw new Error('Names in import:from statement must be symbols'); |
380 } | 552 } |
381 importsyms.push(new strlit(el.name)); | 553 importsyms.push(new strlit(el.name)); |
382 }); | 554 }); |
383 imports.push({symbols: new listlit(importsyms), src: messages[i].args[1]}); | 555 imports.push({symbols: new listlit(importsyms), src: messages[i].args[1]}); |
556 } else if(messages[i].name == 'llProperty:withType:' && messages[i].args.length == 2) { | |
557 me.addProperty(messages[i].args[0].name, null, messages[i].args[1].toCTypeName()) | |
558 } else if(messages[i].name == 'llMessage:withVars:andCode:' && messages[i].args.length == 3) { | |
559 var msgname = messages[i].args[0].name | |
560 var rawvars = messages[i].args[1].expressions; | |
561 var vars = {}; | |
562 for(var v in rawvars) { | |
563 vars[rawvars[v].symbol.name] = rawvars[v].expression.toCTypeName(); | |
564 } | |
565 me.addMessage(msgname, { | |
566 vars: vars, | |
567 lines: messages[i].args[2].toCLines(vars, true) | |
568 }); | |
384 } else { | 569 } else { |
385 throw new Error('Only import and import:from calls allowed in object context'); | 570 |
571 throw new Error('Only import and import:from calls allowed in object context. ' + messages[i].name + 'with ' + messages[i].args.length + ' arguments found instead.'); | |
386 } | 572 } |
387 } else { | 573 } else { |
388 messages[i].toCObject(me); | 574 messages[i].toCObject(me); |
389 } | 575 } |
390 } | 576 } |
391 | 577 |
392 return me.toC(); | 578 return me; |
393 } | 579 }; |
580 | |
581 object.prototype.toC = function() { | |
582 return this.toCObject().toC(); | |
583 }; | |
394 | 584 |
395 var toplevelcode; | 585 var toplevelcode; |
396 var forwarddec; | 586 var forwarddec; |
397 | 587 |
398 function addBinaryOp(cobject, opname, cop, objtype) | 588 function addBinaryOp(cobject, opname, cop, objtype) |
442 vars: {str: 'string *'}, | 632 vars: {str: 'string *'}, |
443 lines: [ | 633 lines: [ |
444 'str = (string *)make_object(&string_meta, NULL, 0);', | 634 'str = (string *)make_object(&string_meta, NULL, 0);', |
445 'str->data = GC_MALLOC(12);', | 635 'str->data = GC_MALLOC(12);', |
446 'sprintf(str->data, "%d", self->num);', | 636 'sprintf(str->data, "%d", self->num);', |
447 'str->length = str->bytes = strlen(str->data);', | 637 'str->len = str->bytes = strlen(str->data);', |
448 'return &(str->header);' | 638 'return &(str->header);' |
449 ] | 639 ] |
450 }); | 640 }); |
451 int32.addMessage('hash', { | 641 int32.addMessage('hash', { |
452 vars: {}, | 642 vars: {}, |
457 return int32; | 647 return int32; |
458 } | 648 } |
459 | 649 |
460 function makeArray() | 650 function makeArray() |
461 { | 651 { |
462 var array = new cObject('array'); | 652 var arrayfile = toplevel.names['array']; |
463 array.addProperty('size', null, 'uint32_t'); | 653 var ast = parseFile(arrayfile.path + '/' + arrayfile.file); |
464 array.addProperty('storage', null, 'uint32_t'); | 654 ast.name = 'array'; |
465 array.addProperty('data', null, 'object **'); | 655 ast.populateSymbols(toplevel); |
466 array.addMessage('get', { | 656 return ast.toCObject(); |
467 vars: {index: 'obj_int32 *'}, | |
468 lines: [ | |
469 'index = va_arg(args, obj_int32 *);', | |
470 'if (index->num >= 0 && index->num < self->size) {', | |
471 ' return self->data[index->num];', | |
472 '}', | |
473 'return ' + toplevel.moduleVar('false') + ';' | |
474 ] | |
475 }); | |
476 array.addMessage('set', { | |
477 vars: {index: 'obj_int32 *'}, | |
478 lines: [ | |
479 'index = va_arg(args, obj_int32 *);', | |
480 'if (index->num >= 0 && index->num < self->size) {', | |
481 ' self->data[index->num] = va_arg(args, object *);', | |
482 '}', | |
483 'return &(self->header);' | |
484 ] | |
485 }); | |
486 array.addMessage('foreach', { | |
487 vars: {index: 'obj_int32 *', i: 'int32_t', clos: 'lambda *'}, | |
488 lines: [ | |
489 'clos = va_arg(args, lambda *);', | |
490 'for (i = 0; i < self->size; i++) {', | |
491 ' index = (obj_int32 *)make_object(&obj_int32_meta, NULL, 0);', | |
492 ' index->num = i;', | |
493 ' ccall(clos, 2, index, self->data[i]);', | |
494 '}', | |
495 'return &(self->header);' | |
496 ] | |
497 }); | |
498 array.addMessage('append', { | |
499 vars: {tmp: 'object **'}, | |
500 lines: [ | |
501 'if (self->storage == self->size) {', | |
502 ' self->storage *= 2;', | |
503 ' tmp = GC_REALLOC(self->data, self->storage * sizeof(object *));', | |
504 ' if (!tmp) {', | |
505 ' fputs("Failed to increase array size\\n", stderr);', | |
506 ' exit(1);', | |
507 ' }', | |
508 ' self->data = tmp;', | |
509 '}', | |
510 'self->data[self->size++] = va_arg(args, object *);', | |
511 'return &(self->header);' | |
512 ] | |
513 }); | |
514 array.addMessage('length', { | |
515 vars: {intret: 'obj_int32 *'}, | |
516 lines: [ | |
517 'intret = (obj_int32 *)make_object(&obj_int32_meta, NULL, 0);', | |
518 'intret->num = self->size;', | |
519 'return &(intret->header);' | |
520 ] | |
521 }); | |
522 return array; | |
523 } | 657 } |
524 | 658 |
525 function makeString() | 659 function makeString() |
526 { | 660 { |
527 var string = new cObject('string'); | 661 var arrayfile = toplevel.names['string']; |
528 string.addProperty('length', null, 'uint32_t'); | 662 var ast = parseFile(arrayfile.path + '/' + arrayfile.file); |
529 string.addProperty('bytes', null, 'uint32_t'); | 663 ast.name = 'string'; |
530 string.addProperty('data', null, 'char *'); | 664 ast.populateSymbols(toplevel); |
531 string.addMessage('length', { | 665 return ast.toCObject(); |
532 vars: {intret: 'obj_int32 *'}, | |
533 lines: [ | |
534 'intret = (obj_int32 *)make_object(&obj_int32_meta, NULL, 0);', | |
535 'intret->num = self->length;', | |
536 'return &(intret->header);' | |
537 ] | |
538 }); | |
539 string.addMessage('byte_length', { | |
540 vars: {intret: 'obj_int32 *'}, | |
541 lines: [ | |
542 'intret = (obj_int32 *)make_object(&obj_int32_meta, NULL, 0);', | |
543 'intret->num = self->bytes;', | |
544 'return &(intret->header);' | |
545 ] | |
546 }); | |
547 string.addMessage('EQ_', { | |
548 vars: {argb: 'string *'}, | |
549 lines: [ | |
550 'argb = va_arg(args, string *);', | |
551 'if (self->length == argb->length && self->bytes == argb->bytes && !memcmp(self->data, argb->data, self->bytes)) {', | |
552 ' return ' + toplevel.moduleVar('true') + ';', | |
553 '}', | |
554 'return ' + toplevel.moduleVar('false') + ';', | |
555 ] | |
556 }); | |
557 string.addMessage('NEQ_', { | |
558 vars: {argb: 'string *'}, | |
559 lines: [ | |
560 'argb = va_arg(args, string *);', | |
561 'if (self->length != argb->length || self->bytes != argb->bytes || memcmp(self->data, argb->data, self->bytes)) {', | |
562 ' return ' + toplevel.moduleVar('true') + ';', | |
563 '}', | |
564 'return ' + toplevel.moduleVar('false') + ';', | |
565 ] | |
566 }); | |
567 string.addMessage('print', { | |
568 vars: {}, | |
569 lines: [ | |
570 'fwrite(self->data, 1, self->bytes, stdout);', | |
571 'return &(self->header);' | |
572 ] | |
573 }); | |
574 string.addMessage('string', { | |
575 vars: {}, | |
576 lines: [ 'return &(self->header);' ] | |
577 }); | |
578 string.addMessage('CAT_', { | |
579 vars: {argbo: 'object *', argb: 'string *', out: 'string *'}, | |
580 lines: [ | |
581 'argbo = va_arg(args, object *);', | |
582 'argb = (string *)mcall(' + getMethodId('string') + ', 1, argbo);', | |
583 'out = (string *)make_object(&string_meta, NULL, 0);', | |
584 'out->bytes = self->bytes + argb->bytes;', | |
585 'out->length = self->length + argb->length;', | |
586 'out->data = GC_MALLOC_ATOMIC(out->bytes+1);', | |
587 'memcpy(out->data, self->data, self->bytes);', | |
588 'memcpy(out->data + self->bytes, argb->data, argb->bytes + 1);', | |
589 'return &(out->header);' | |
590 ] | |
591 }); | |
592 string.addMessage('byte', { | |
593 vars: {index: 'obj_int32 *', intret: 'obj_int32 *'}, | |
594 lines: [ | |
595 'index = va_arg(args, obj_int32 *);', | |
596 'intret = (obj_int32 *)make_object(&obj_int32_meta, NULL, 0);', | |
597 'intret->num = index->num < self->bytes ? self->data[index->num] : 0;', | |
598 'return &(intret->header);' | |
599 ] | |
600 }); | |
601 string.addMessage('int32', { | |
602 vars: {intret: 'obj_int32 *'}, | |
603 lines: [ | |
604 'intret = (obj_int32 *)make_object(&obj_int32_meta, NULL, 0);', | |
605 'intret->num = atoi(self->data);', | |
606 'return &(intret->header);' | |
607 ] | |
608 }); | |
609 string.addMessage('hash', { | |
610 vars: {intret: 'obj_int32 *', i: 'uint32_t'}, | |
611 lines: [ | |
612 'intret = (obj_int32 *)make_object(&obj_int32_meta, NULL, 0);', | |
613 'intret->num = 0;', | |
614 'if (self->bytes) {', | |
615 ' intret->num = self->data[0] << 7;', | |
616 ' for (i = 0; i < self->bytes; i++) {', | |
617 ' intret->num = (1000003 * intret->num) ^ self->data[i];', | |
618 ' }', | |
619 ' intret->num = intret->num ^ self->bytes;', | |
620 '}', | |
621 'return &(intret->header);' | |
622 ] | |
623 }); | |
624 return string; | |
625 } | 666 } |
626 | 667 |
627 function makelambda() | 668 function makelambda() |
628 { | 669 { |
629 var clos = new cObject('lambda'); | 670 var clos = new cObject('lambda'); |
768 function processUsedToplevel(toplevel) | 809 function processUsedToplevel(toplevel) |
769 { | 810 { |
770 var alwaysused = ['true', 'false']; | 811 var alwaysused = ['true', 'false']; |
771 var ret = ''; | 812 var ret = ''; |
772 var modulenum = 0; | 813 var modulenum = 0; |
814 var visited = {}; | |
815 for (var i in alwaysused) { | |
816 toplevel.used[alwaysused[i]] = true; | |
817 } | |
773 var newused = Object.keys(toplevel.used); | 818 var newused = Object.keys(toplevel.used); |
774 var allused = newused; | 819 var allused = newused; |
775 var visited = {}; | |
776 for (var i in alwaysused) { | |
777 forwarddec += 'object * ' + toplevel.moduleVar(alwaysused[i]) + ';\n'; | |
778 toplevel.names[alwaysused[i]].populateSymbols(toplevel); | |
779 visited[alwaysused[i]] = true; | |
780 } | |
781 while (newused.length) { | 820 while (newused.length) { |
782 for (var i in newused) { | 821 for (var i in newused) { |
783 debugprint('//---module', newused[i], '--- populate symbols'); | 822 debugprint('//---module', newused[i], '--- populate symbols'); |
784 forwarddec += 'object * ' + toplevel.moduleVar(newused[i]) + ';\n'; | 823 forwarddec += 'object * ' + toplevel.moduleVar(newused[i]) + ';\n'; |
785 toplevel.names[newused[i]].populateSymbols(toplevel); | 824 toplevel.names[newused[i]].populateSymbols(toplevel); |
792 newused.push(symbol); | 831 newused.push(symbol); |
793 allused.push(symbol); | 832 allused.push(symbol); |
794 } | 833 } |
795 } | 834 } |
796 } | 835 } |
797 for (var i in alwaysused) { | |
798 allused.push(alwaysused[i]); | |
799 } | |
800 | 836 |
801 for (var i = allused.length-1; i >= 0; i--) { | 837 for (var i = allused.length-1; i >= 0; i--) { |
802 var symbol = allused[i]; | 838 var symbol = allused[i]; |
803 debugprint('//---module', symbol, '--- compile'); | 839 debugprint('//---module', symbol, '(' + i +')--- compile'); |
804 ret += '\t' + toplevel.moduleVar(symbol) + ' = ' + toplevel.names[symbol].toC() + ';\n'; | 840 ret += '\t' + toplevel.moduleVar(symbol) + ' = ' + toplevel.names[symbol].toC() + ';\n'; |
805 } | 841 } |
806 return ret; | 842 return ret; |
807 } | 843 } |
808 | 844 |
809 function makeCProg(obj) | 845 function makeCProg(obj) |
810 { | 846 { |
847 forwarddec = toplevelcode = ''; | |
811 var builtins = builtinTypes(); | 848 var builtins = builtinTypes(); |
812 forwarddec = toplevelcode = ''; | |
813 for (var i in builtins) { | 849 for (var i in builtins) { |
814 forwarddec += builtins[i].toEarlyCDef(); | 850 forwarddec += builtins[i].toEarlyCDef(); |
815 toplevelcode += builtins[i].toCDef(); | 851 toplevelcode += builtins[i].toCDef(); |
816 } | 852 } |
817 addBuiltinModules(toplevel); | 853 addBuiltinModules(toplevel); |
930 this.selftype = typename; | 966 this.selftype = typename; |
931 return this.toC(); | 967 return this.toC(); |
932 }; | 968 }; |
933 lambda.prototype.toCModule = function() { | 969 lambda.prototype.toCModule = function() { |
934 return makeCProg(this); | 970 return makeCProg(this); |
971 }; | |
972 lambda.prototype.toCLines = function(vars, needsreturn) { | |
973 var lines = []; | |
974 for (var i in this.args) { | |
975 var name = this.args[i].name; | |
976 if (name[0] == ':') { | |
977 name = name.substr(1); | |
978 } | |
979 if(name != 'self') { | |
980 lines.push(name + ' = va_arg(args, ' + vars[name] + ');'); | |
981 } | |
982 } | |
983 for (var i in this.expressions) { | |
984 var exprlines = this.expressions[i].toCLines(vars, needsreturn && i == this.expressions.length - 1); | |
985 for (var j in exprlines) { | |
986 lines.push('\t' + exprlines[j]); | |
987 } | |
988 } | |
989 return lines; | |
990 } | |
991 lambda.prototype.toCLLExpr = function(vars) { | |
992 if (this.expressions.length != 1) { | |
993 throw new Error('lambda in expression context must have a single statement in llMessage block'); | |
994 } | |
995 return this.expressions[0].toCLLExpr(vars); | |
935 } | 996 } |
936 | 997 |
937 assignment.prototype.toC = function() { | 998 assignment.prototype.toC = function() { |
938 debugprint('//assignment', this.symbol.name); | 999 debugprint('//assignment', this.symbol.name); |
939 var existing = this.symbols.find(this.symbol.name); | 1000 var existing = this.symbols.find(this.symbol.name); |
980 if (this.expression instanceof object && this.expression.symbols.needsparent) { | 1041 if (this.expression instanceof object && this.expression.symbols.needsparent) { |
981 cobj.addInit('self->' + escapeCName(this.symbol.name) + '->parent = (object *)self;'); | 1042 cobj.addInit('self->' + escapeCName(this.symbol.name) + '->parent = (object *)self;'); |
982 } | 1043 } |
983 } | 1044 } |
984 }; | 1045 }; |
1046 assignment.prototype.toCLines = function(vars, needsreturn) { | |
1047 return [(needsreturn ? 'return ' : '') + this.symbol.toCLLExpr(vars) + ' = ' + this.expression.toCLLExpr(vars) + ';'] | |
1048 }; |