comparison cbackend.js @ 126:a2d2d8e09291

Merge
author Mike Pavone <pavone@retrodev.com>
date Mon, 05 Aug 2013 23:37:17 -0700
parents 9820ecd4eed4
children 34e0befbdd77 bf8f75b69048
comparison
equal deleted inserted replaced
125:6f8d868e8da0 126:a2d2d8e09291
5 var methodIds = {}; 5 var methodIds = {};
6 function getMethodId(methodName) 6 function getMethodId(methodName)
7 { 7 {
8 if (!(methodName in methodIds)) { 8 if (!(methodName in methodIds)) {
9 methodIds[methodName] = nextmethodId++; 9 methodIds[methodName] = nextmethodId++;
10 10
11 } 11 }
12 return methodIds[methodName]; 12 return methodIds[methodName];
13 } 13 }
14 14
15 function importSym(obj, src, key) 15 function getOpMethodName(opname)
16 { 16 {
17 if(!(key in src)) { 17 var optoMeth = {'+': 'ADD_', '-': 'SUB_', '*': 'MUL_', '/': 'DIV_', '%': 'MOD_', '=': 'EQ_', '!=': 'NEQ_', '<': 'LT_', '>': 'GT_', '>=': 'GEQ_', '<=': 'LEQ_', '.': 'CAT_', '&&':'if', '||':'ifnot'};
18 throw new Error(key +' not found in source object for import'); 18 if (opname in optoMeth) {
19 } 19 return optoMeth[opname];
20 if(key in obj) {
21 throw new Error(key +' already exists in target object for import')
22 }
23 obj[key] = src[key];
24 }
25
26 function doImport(obj, src, symlist)
27 {
28 if (symlist === undefined) {
29 each(src, function(key,val) {
30 if (key != 'parent') {
31 importSym(obj, src, key);
32 }
33 });
34 } else { 20 } else {
35 for (var i = 0; i < symlist.length; ++i) { 21 return opname;
36 importSym(obj, src, symlist[i]); 22 }
37 }
38 }
39 return obj;
40 } 23 }
41 24
42 op.prototype.toC = function(isReceiver) { 25 op.prototype.toC = function(isReceiver) {
43 var optoMeth = {'+': 'ADD_', '-': 'SUB_', '*': 'MUL_', '/': 'DIV_', '%': 'MOD_', '=': 'EQ_', '!=': 'NEQ_', '<': 'LT_', '>': 'GT_', '>=': 'GEQ_', '<=': 'LEQ_', '.': 'CAT_'}; 26 var method = getOpMethodName(this.op);
44 var method = optoMeth[this.op]; 27 return 'mcall(' + getMethodId(method) + '/* operator ' + 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'; 28 };
46 }; 29 op.prototype.toCLLExpr = function(vars) {
30 var opmap = {'=': '==', 'xor': '^'};
31 return this.left.toCLLExpr(vars) + (this.op in opmap ? opmap[this.op] : this.op) + this.right.toCLLExpr(vars);
32 };
33 op.prototype.toCLines = function(vars, needsreturn) {
34 return [ (needsreturn ? 'return (object *)' : '' ) + this.toCLLExpr(vars) + ';'];
35 };
36
47 37
48 function escapeCName(name) 38 function escapeCName(name)
49 { 39 {
50 if (name == 'self') { 40 if (name == 'self') {
51 return name; 41 return name;
58 function getSymbolPrefix(info, symbols) 48 function getSymbolPrefix(info, symbols)
59 { 49 {
60 var pre = ''; 50 var pre = '';
61 switch(info.type) { 51 switch(info.type) {
62 case 'self': 52 case 'self':
63 53
64 pre = (new symbol('self', symbols)).toC() + '->'; 54 pre = (new symbol('self', symbols)).toC() + '->';
65 break; 55 break;
66 case 'parent': 56 case 'parent':
67 pre = (new symbol('self', symbols)).toC() + '->header.'; 57 pre = (new symbol('self', symbols)).toC() + '->header.';
68 for (var i = 0; i < info.depth; ++i) { 58 for (var i = 0; i < info.depth; ++i) {
106 } 96 }
107 return 'mcall(' + getMethodId(name) + '/* ' + name + ' */, 1, ' + obj + ')'; 97 return 'mcall(' + getMethodId(name) + '/* ' + name + ' */, 1, ' + obj + ')';
108 } 98 }
109 return getSymbolPrefix(info, this.symbols) + escapeCName(name); 99 return getSymbolPrefix(info, this.symbols) + escapeCName(name);
110 } 100 }
101 symbol.prototype.toCTypeName = function() {
102 return this.cleanName();
103 };
104 symbol.prototype.toCLLExpr = function(vars) {
105 var name = this.cleanName();
106 if (name in vars) {
107 return name;
108 }
109 if (name == 'self') {
110 return 'self';
111 }
112 var info = this.symbols.find(name, false, true);
113 var symbols = this.symbols;
114 while (info && info.type == 'local') {
115 symbols = symbols.parent;
116 info = symbols.find(name, false, true);
117 }
118 if (!info) {
119 return name;
120 }
121 if (info.type == 'toplevel') {
122 return toplevel.moduleVar(name);
123 } else if (info.type == 'self') {
124 if (info.isll || !(info.def instanceof lambda)) {
125 return 'self->' + name;
126 } else {
127 return 'mcall(' + getMethodId(name) + '/* ' + name + ' */, 1, self)';
128 }
129 }
130 throw new Error('Unsupported reference type ' + info.type + ' for variable ' + name);
131 };
132 symbol.prototype.toCLines = function(vars, needsreturn) {
133 return [ (needsreturn ? 'return (object *)' : '' ) + this.toCLLExpr(vars) + ';' ];
134 };
111 135
112 var declaredInts = {}; 136 var declaredInts = {};
113 137
114 intlit.prototype.toC = function() { 138 intlit.prototype.toC = function() {
115 var str = this.val < 0 ? 'neg_' + (0-this.val).toString() : this.val.toString(); 139 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'; 141 toplevelcode += 'obj_int32 int32_' + str + ' = {{&obj_int32_meta, NULL}, ' + this.val.toString() + '};\n';
118 declaredInts[this.val] = true; 142 declaredInts[this.val] = true;
119 } 143 }
120 return '((object *)&int32_' + str + ')'; 144 return '((object *)&int32_' + str + ')';
121 } 145 }
146 intlit.prototype.toCLLExpr = function(vars) {
147 return this.val.toString();
148 };
149 intlit.prototype.toCLines = function(vars, needsreturn) {
150 return [ (needsreturn ? 'return (object *)' : '' ) + this.toCLLExpr(vars) + ';' ];
151 };
122 152
123 floatlit.prototype.toC = function() { 153 floatlit.prototype.toC = function() {
124 return 'make_float(' + this.val.toString() + ')'; 154 return 'make_float(' + this.val.toString() + ')';
125 } 155 }
156 floatlit.prototype.toCLLExpr = function(vars) {
157 return this.val.toString();
158 };
159 floatlit.prototype.toCLines = function(vars, needsreturn) {
160 return [ (needsreturn ? 'return (object *)' : '' ) + this.toCLLExpr(vars) + ';' ];
161 };
126 162
127 var declaredStrings = {}; 163 var declaredStrings = {};
128 var nextStringId = 0; 164 var nextStringId = 0;
129 165
130 strlit.prototype.toC = function() { 166 strlit.prototype.toC = function() {
132 //TODO: get the proper byte length 168 //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'; 169 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++; 170 declaredStrings[this.val] = nextStringId++;
135 } 171 }
136 return '((object *)&str_' + declaredStrings[this.val] + ')'; 172 return '((object *)&str_' + declaredStrings[this.val] + ')';
137 } 173 };
174 strlit.prototype.toCLLExpr = function(vars) {
175 return '"' + this.val.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') + '"';
176 };
177 strlit.prototype.toCLines = function(vars, needsreturn) {
178 return [ (needsreturn ? 'return (object *)' : '' ) + this.toCLLExpr(vars) +';' ];
179 };
138 180
139 listlit.prototype.toC = function() { 181 listlit.prototype.toC = function() {
140 var ret = 'make_list(' + this.val.length; 182 var ret = 'make_list(' + this.val.length;
141 for (var i = 0; i < this.val.length; i++) { 183 for (var i = 0; i < this.val.length; i++) {
142 ret += ', ' + this.val[i].toC(); 184 ret += ', ' + this.val[i].toC();
160 } else if(this.args[0] instanceof symbol) { 202 } else if(this.args[0] instanceof symbol) {
161 return this.args[0].name; 203 return this.args[0].name;
162 } else { 204 } else {
163 throw new Error("Unexpected AST type for foreign:"); 205 throw new Error("Unexpected AST type for foreign:");
164 } 206 }
207 } else if(name == 'llProperty:withType' || name == 'llProperty:withVars:andCode') {
208 return null;
165 } 209 }
166 var args = this.args.slice(0, this.args.length); 210 var args = this.args.slice(0, this.args.length);
167 if (this.receiver) { 211 if (this.receiver) {
168 args.splice(0, 0, this.receiver); 212 args.splice(0, 0, this.receiver);
169 } 213 }
170 var method = false; 214 var method = false;
171 var funinfo = this.symbols.find(name); 215 var funinfo = this.symbols.find(name);
172 var start = 0; 216 var start = 0;
173 if (!funinfo || funinfo.def instanceof setter) { 217 if (!funinfo || funinfo.def instanceof setter || funinfo.type == 'toplevel') {
174 method = true; 218 method = true;
175 } else { 219 } else {
176 switch(funinfo.type) 220 switch(funinfo.type)
177 { 221 {
178 case 'self': 222 case 'self':
200 for (var i = start; i < args.length; i++) { 244 for (var i = start; i < args.length; i++) {
201 args[i] = ', ' + (!i && method ? '(object *)(' : '') + args[i].toC() + (!i && method ? ')' : ''); 245 args[i] = ', ' + (!i && method ? '(object *)(' : '') + args[i].toC() + (!i && method ? ')' : '');
202 } 246 }
203 var callpart; 247 var callpart;
204 if (method) { 248 if (method) {
205 callpart = 'mcall(' + getMethodId(name) + '/* ' + name + ' */'; 249 if (funinfo && funinfo.type == 'self' && funinfo.def.name) {
250 callpart = funinfo.def.name + '(' + (funinfo.def.symbols.parent.needsenv ? (new symbol('self', this.symbols)).toC() + '->env' : 'NULL' );
251 } else {
252 callpart = 'mcall(' + getMethodId(name) + '/* ' + name + ' */';
253 }
206 } else { 254 } else {
207 callpart = 'ccall(' + (new symbol(name, this.symbols)).toC(); 255 callpart = 'ccall(' + (new symbol(name, this.symbols)).toC();
208 } 256 }
209 return callpart + ', ' + args.length + args.join('') + ')'; 257 return callpart + ', ' + args.length + args.join('') + ')';
210 } 258 };
259 funcall.prototype.toCTypeName = function() {
260 switch(this.name)
261 {
262 case 'ptr:':
263 case 'ptr':
264 var receiver = this.receiver ? this.receiver : this.args[0];
265 return receiver.toCTypeName() + ' *';
266 break;
267 default:
268 throw new Error('invalid use of funcall expression where a C type name is expected');
269 }
270 };
271 funcall.prototype.toCLines = function(vars, needsreturn) {
272 var lines = [];
273 var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name;
274 var args = this.args.slice(0, this.args.length);
275 if (this.receiver) {
276 args.splice(0, 0, [this.receiver]);
277 }
278 switch(name)
279 {
280 case 'if':
281 lines.push('if (' + this.args[0].toCLLExpr(vars) + ') {');
282 var blines = this.args[1].toCLines(vars, needsreturn);
283 for (var i in blines) {
284 lines.push('\t' + blines[i]);
285 }
286 if (needsreturn) {
287 lines.push('} else {');
288 lines.push('\t return module_false;');
289 lines.push('}');
290 } else {
291 lines.push('}');
292 }
293 break;
294 case 'if:else':
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 lines.push('} else {');
301 blines = this.args[2].toCLines(vars, needsreturn);
302 for (var i in blines) {
303 lines.push('\t' + blines[i]);
304 }
305 lines.push('}');
306 break;
307 case 'while:do':
308 if (needsreturn) {
309 throw new Error("while:do can't be last statement in llMessage code block");
310 }
311 lines.push('while (' + this.args[0].toCLLExpr(vars) + ') {');
312 var blines = this.args[1].toCLines(vars);
313 for (var i in blines) {
314 lines.push('\t' + blines[i]);
315 }
316 lines.push('}');
317 break;
318 default:
319 lines.push( (needsreturn ? 'return (object *)' : '') + this.toCLLExpr(vars) + ';');
320 }
321 return lines;
322 };
323
324 funcall.prototype.toCLLExpr = function(vars) {
325 var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name;
326 var args = this.args.slice(0, this.args.length);
327 if (this.receiver) {
328 if(this.args.length == 0) {
329 return this.receiver.toCLLExpr(vars) + '->' + this.name;
330 } else if (this.args.length == 1 && name[name.length-1] == '!') {
331 return this.receiver.toCLLExpr(vars) + '->' + this.name.substr(0, name.length-1) + ' = ' + args[0].toCLLExpr(vars);
332 } else {
333 args.splice(0, 0, this.receiver);
334 }
335 }
336 switch(name)
337 {
338 case 'if':
339 return '((' + args[0].toCLLExpr(vars) + ') ? (' + args[1].toCLLExpr(vars) + ') : 0)';
340 case 'if:else':
341 return '((' + args[0].toCLLExpr(vars) + ') ? (' + args[1].toCLLExpr(vars) + ') : (' + args[2].toCLLExpr(vars) + '))';
342 case 'while:do':
343 throw new Error('while:do not allowed in expression context in llMessage block');
344 case 'addr_of':
345 return '&(' + args[0].toCLLExpr(vars) + ')';
346 case 'sizeof':
347 return 'sizeof(' + args[0].toCTypeName() + ')';
348 case 'get':
349 return args[0].toCLLExpr(vars) + '[' + args[1].toCLLExpr(vars) + ']';
350 case 'set':
351 return args[0].toCLLExpr(vars) + '[' + args[1].toCLLExpr(vars) + '] = ' + args[2].toCLLExpr(vars);
352 case 'not':
353 return '!(' + args[0].toCLLExpr(vars) + ')';
354 case 'mcall':
355 if (args[0] instanceof symbol) {
356 args[0] = new intlit(getMethodId(args[0].name));
357 }
358 default:
359 for (var i in args) {
360 args[i] = args[i].toCLLExpr(vars);
361 }
362 return name + '(' + args.join(', ') + ')';
363 }
364 };
211 365
212 function cObject(name) { 366 function cObject(name) {
213 this.name = name; 367 this.name = name;
214 this.slots = {}; 368 this.slots = {};
215 this.properties = []; 369 this.properties = [];
273 var init = this.init.slice(0, this.init.length); 427 var init = this.init.slice(0, this.init.length);
274 init.push('return (object *)self;'); 428 init.push('return (object *)self;');
275 this.addMessage('_init', { 429 this.addMessage('_init', {
276 vars: {}, 430 vars: {},
277 lines: init 431 lines: init
278 }); 432 });
279 this.initmsgadded = true; 433 this.initmsgadded = true;
280 } 434 }
281 } 435 }
282 436
283 cObject.prototype.populateSymbols = function() {}; 437 cObject.prototype.populateSymbols = function() {};
314 for (var varname in this.slotvars[i]) { 468 for (var varname in this.slotvars[i]) {
315 slotdefs += '\t' + this.slotvars[i][varname] + ' ' + varname + ';\n'; 469 slotdefs += '\t' + this.slotvars[i][varname] + ' ' + varname + ';\n';
316 } 470 }
317 if (this.slots[i].length == 1) { 471 if (this.slots[i].length == 1) {
318 slotdefs += '\tif (method_id == ' + this.slots[i][0][0] + ') { /* ' + this.slots[i][0][2] + '*/\n' + 472 slotdefs += '\tif (method_id == ' + this.slots[i][0][0] + ') { /* ' + this.slots[i][0][2] + '*/\n' +
319 '\t\t' + this.slots[i][0][1] + '\n' + 473 '\t\t' + this.slots[i][0][1] + '\n' +
320 '\t}\n' + 474 '\t}\n' +
321 '\treturn no_impl(method_id, num_params, (object *)self, args);\n}\n'; 475 '\treturn no_impl(method_id, num_params, (object *)self, args);\n}\n';
322 } else { 476 } else {
323 slotdefs += '\tswitch(method_id) {\n'; 477 slotdefs += '\tswitch(method_id) {\n';
324 for (j in this.slots[i]) { 478 for (j in this.slots[i]) {
325 slotdefs += '\t\tcase ' + this.slots[i][j][0] + ': /* ' + this.slots[i][j][2] + '*/\n' + 479 slotdefs += '\t\tcase ' + this.slots[i][j][0] + ': /* ' + this.slots[i][j][2] + '*/\n' +
326 '\t\t\t' + this.slots[i][j][1] + '\n'; 480 '\t\t\t' + this.slots[i][j][1] + '\n';
327 } 481 }
328 slotdefs += '\t\tdefault:\n' + 482 slotdefs += '\t\tdefault:\n' +
329 '\t\t\treturn no_impl(method_id, num_params, (object *)self, args);\n\t}\n}\n'; 483 '\t\t\treturn no_impl(method_id, num_params, (object *)self, args);\n\t}\n}\n';
330 484
331 } 485 }
332 metadef += this.name + '_slot_' + i; 486 metadef += this.name + '_slot_' + i;
333 } else { 487 } else {
334 metadef += 'no_impl'; 488 metadef += 'no_impl';
335 } 489 }
353 return this.toCInstance(); 507 return this.toCInstance();
354 } 508 }
355 509
356 var nextobject = 0; 510 var nextobject = 0;
357 511
358 object.prototype.toC = function() { 512
513 object.prototype.toCObject = function() {
359 var messages = this.messages; 514 var messages = this.messages;
360 var values = []; 515 var values = [];
361 var imports = [] 516 var imports = [];
362 var me = new cObject('object_' + nextobject++); 517 if (!this.name) {
518 this.name = 'object_' + nextobject++;
519 }
520 var me = new cObject(this.name);
363 this.symbols.typename = me.name; 521 this.symbols.typename = me.name;
364 if (this.symbols.needsenv) { 522 if (this.symbols.needsenv) {
365 me.addProperty('env', this.symbols.envVar(), 'struct ' + this.symbols.getEnvType() + ' * '); 523 me.addProperty('env', this.symbols.envVar(), 'struct ' + this.symbols.getEnvType() + ' * ');
366 me.hasenv = true; 524 me.hasenv = true;
367 } 525 }
379 throw new Error('Names in import:from statement must be symbols'); 537 throw new Error('Names in import:from statement must be symbols');
380 } 538 }
381 importsyms.push(new strlit(el.name)); 539 importsyms.push(new strlit(el.name));
382 }); 540 });
383 imports.push({symbols: new listlit(importsyms), src: messages[i].args[1]}); 541 imports.push({symbols: new listlit(importsyms), src: messages[i].args[1]});
542 } else if(messages[i].name == 'llProperty:withType:' && messages[i].args.length == 2) {
543 me.addProperty(messages[i].args[0].name, null, messages[i].args[1].toCTypeName())
544 } else if(messages[i].name == 'llMessage:withVars:andCode:' && messages[i].args.length == 3) {
545 var msgname = messages[i].args[0].name
546 var rawvars = messages[i].args[1].expressions;
547 var vars = {};
548 for(var v in rawvars) {
549 vars[rawvars[v].symbol.name] = rawvars[v].expression.toCTypeName();
550 }
551 me.addMessage(msgname, {
552 vars: vars,
553 lines: messages[i].args[2].toCLines(vars, true)
554 });
384 } else { 555 } else {
385 throw new Error('Only import and import:from calls allowed in object context'); 556
557 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 } 558 }
387 } else { 559 } else {
388 messages[i].toCObject(me); 560 messages[i].toCObject(me);
389 } 561 }
390 } 562 }
391 563
392 return me.toC(); 564 return me;
393 } 565 };
566
567 object.prototype.toC = function() {
568 return this.toCObject().toC();
569 };
394 570
395 var toplevelcode; 571 var toplevelcode;
396 var forwarddec; 572 var forwarddec;
397 573
398 function addBinaryOp(cobject, opname, cop, objtype) 574 function addBinaryOp(cobject, opname, cop, objtype)
442 vars: {str: 'string *'}, 618 vars: {str: 'string *'},
443 lines: [ 619 lines: [
444 'str = (string *)make_object(&string_meta, NULL, 0);', 620 'str = (string *)make_object(&string_meta, NULL, 0);',
445 'str->data = GC_MALLOC(12);', 621 'str->data = GC_MALLOC(12);',
446 'sprintf(str->data, "%d", self->num);', 622 'sprintf(str->data, "%d", self->num);',
447 'str->length = str->bytes = strlen(str->data);', 623 'str->len = str->bytes = strlen(str->data);',
448 'return &(str->header);' 624 'return &(str->header);'
625 ]
626 });
627 int32.addMessage('isInteger?', {
628 vars: {},
629 lines: [
630 'return ' + toplevel.moduleVar('true') + ';'
449 ] 631 ]
450 }); 632 });
451 int32.addMessage('hash', { 633 int32.addMessage('hash', {
452 vars: {}, 634 vars: {},
453 lines: [ 635 lines: [
457 return int32; 639 return int32;
458 } 640 }
459 641
460 function makeArray() 642 function makeArray()
461 { 643 {
462 var array = new cObject('array'); 644 var arrayfile = toplevel.names['array'];
463 array.addProperty('size', null, 'uint32_t'); 645 var ast = parseFile(arrayfile.path + '/' + arrayfile.file);
464 array.addProperty('storage', null, 'uint32_t'); 646 ast.name = 'array';
465 array.addProperty('data', null, 'object **'); 647 ast.populateSymbols(toplevel);
466 array.addMessage('get', { 648 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 } 649 }
524 650
525 function makeString() 651 function makeString()
526 { 652 {
527 var string = new cObject('string'); 653 var arrayfile = toplevel.names['string'];
528 string.addProperty('length', null, 'uint32_t'); 654 var ast = parseFile(arrayfile.path + '/' + arrayfile.file);
529 string.addProperty('bytes', null, 'uint32_t'); 655 ast.name = 'string';
530 string.addProperty('data', null, 'char *'); 656 ast.populateSymbols(toplevel);
531 string.addMessage('length', { 657 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 } 658 }
626 659
627 function makelambda() 660 function makelambda()
628 { 661 {
629 var clos = new cObject('lambda'); 662 var clos = new cObject('lambda');
751 ] 784 ]
752 }); 785 });
753 toplevel.names['os'] = os; 786 toplevel.names['os'] = os;
754 } 787 }
755 788
756 modulefile.prototype.populateSymbols = function (toplevel) {
757 if (!this.ast) {
758 this.ast = parseFile(this.path + '/' + this.file);
759 this.ast.populateSymbols(toplevel);
760 }
761 };
762
763 modulefile.prototype.toC = function(){ 789 modulefile.prototype.toC = function(){
764 this.populateSymbols(toplevel);
765 return this.ast.toCModuleInstance(); 790 return this.ast.toCModuleInstance();
766 }; 791 };
767 792
768 function processUsedToplevel(toplevel) 793 function processUsedToplevel(toplevel)
769 { 794 {
770 var alwaysused = ['true', 'false']; 795 var alwaysused = ['true', 'false'];
771 var ret = ''; 796 var ret = '';
772 var modulenum = 0; 797 var modulenum = 0;
798 var visited = {};
799 for (var i in alwaysused) {
800 toplevel.used[alwaysused[i]] = true;
801 }
773 var newused = Object.keys(toplevel.used); 802 var newused = Object.keys(toplevel.used);
774 var allused = newused; 803 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) { 804 while (newused.length) {
782 for (var i in newused) { 805 for (var i in newused) {
783 debugprint('//---module', newused[i], '--- populate symbols'); 806 debugprint('//---module', newused[i], '--- populate symbols');
784 forwarddec += 'object * ' + toplevel.moduleVar(newused[i]) + ';\n'; 807 forwarddec += 'object * ' + toplevel.moduleVar(newused[i]) + ';\n';
785 toplevel.names[newused[i]].populateSymbols(toplevel); 808 toplevel.names[newused[i]].populateSymbols(toplevel);
792 newused.push(symbol); 815 newused.push(symbol);
793 allused.push(symbol); 816 allused.push(symbol);
794 } 817 }
795 } 818 }
796 } 819 }
797 for (var i in alwaysused) { 820
798 allused.push(alwaysused[i]);
799 }
800
801 for (var i = allused.length-1; i >= 0; i--) { 821 for (var i = allused.length-1; i >= 0; i--) {
802 var symbol = allused[i]; 822 var symbol = allused[i];
803 debugprint('//---module', symbol, '--- compile'); 823 debugprint('//---module', symbol, '(' + i +')--- compile');
804 ret += '\t' + toplevel.moduleVar(symbol) + ' = ' + toplevel.names[symbol].toC() + ';\n'; 824 ret += '\t' + toplevel.moduleVar(symbol) + ' = ' + toplevel.names[symbol].toC() + ';\n';
805 } 825 }
806 return ret; 826 return ret;
807 } 827 }
808 828
809 function makeCProg(obj) 829 function makeCProg(obj)
810 { 830 {
831 forwarddec = toplevelcode = '';
811 var builtins = builtinTypes(); 832 var builtins = builtinTypes();
812 forwarddec = toplevelcode = '';
813 for (var i in builtins) { 833 for (var i in builtins) {
814 forwarddec += builtins[i].toEarlyCDef(); 834 forwarddec += builtins[i].toEarlyCDef();
815 toplevelcode += builtins[i].toCDef(); 835 toplevelcode += builtins[i].toCDef();
816 } 836 }
817 addBuiltinModules(toplevel); 837 addBuiltinModules(toplevel);
831 851
832 object.prototype.toCModuleInstance = function() { 852 object.prototype.toCModuleInstance = function() {
833 return this.toC(); 853 return this.toC();
834 } 854 }
835 855
836 var lambdanum = 0;
837
838 lambda.prototype.toC = function() { 856 lambda.prototype.toC = function() {
839 var args = this.args ? this.args.slice(0, this.args.length) : []; 857 var args = this.args ? this.args.slice(0, this.args.length) : [];
840 var exprs = this.expressions; 858 var exprs = this.expressions;
841 var mynum = lambdanum++; 859 debugprint('//', this.name);
842 debugprint('//lambda', mynum);
843 if (Object.keys(this.symbols.closedover).length) { 860 if (Object.keys(this.symbols.closedover).length) {
844 this.symbols.envtype = 'lambda_' + mynum + '_env'; 861 this.symbols.envtype = this.name + '_env';
862 forwarddec += 'typedef struct ' + this.symbols.envtype + ' ' + this.symbols.envtype + ';\n'
845 } 863 }
846 if (this.selftype) { 864 if (this.selftype) {
847 this.symbols.defineVar('self', this.selftype); 865 this.symbols.defineVar('self', this.selftype);
848 if (args[0] && args[0].cleanName() == 'self') { 866 if (args[0] && args[0].cleanName() == 'self') {
849 args.splice(0, 1); 867 args.splice(0, 1);
852 } else { 870 } else {
853 var offset = 0; 871 var offset = 0;
854 } 872 }
855 for (var i = 0; i < args.length; ++i) { 873 for (var i = 0; i < args.length; ++i) {
856 var argname = args[i].toC(); 874 var argname = args[i].toC();
857 875
858 args[i] = (argname.indexOf('->') < 0 ? '\tobject * ' : '\t') + argname + ' = va_arg(args, object *);\n'; 876 args[i] = (argname.indexOf('->') < 0 ? '\tobject * ' : '\t') + argname + ' = va_arg(args, object *);\n';
859 } 877 }
860 var compiled = [] 878 var compiled = []
861 for (var i in exprs) { 879 for (var i in exprs) {
862 var js = exprs[i].toC(); 880 var js = exprs[i].toC();
866 } 884 }
867 exprs = compiled; 885 exprs = compiled;
868 if (exprs.length) { 886 if (exprs.length) {
869 exprs[exprs.length-1] = 'return (object *)(' + exprs[exprs.length-1] + ');'; 887 exprs[exprs.length-1] = 'return (object *)(' + exprs[exprs.length-1] + ');';
870 } 888 }
871 889
872 if (Object.keys(this.symbols.closedover).length) { 890 if (Object.keys(this.symbols.closedover).length) {
873 forwarddec += 'typedef struct lambda_' + mynum + '_env {\n'; 891 forwarddec += 'struct ' + this.name + '_env {\n';
874 if (this.symbols.needsParentEnv) { 892 if (this.symbols.needsParentEnv) {
875 forwarddec += '\tstruct ' + this.symbols.parentEnvType() + ' * parent;\n'; 893 forwarddec += '\tstruct ' + this.symbols.parentEnvType() + ' * parent;\n';
876 } 894 }
877 for (var varname in this.symbols.closedover) { 895 for (var varname in this.symbols.closedover) {
878 if (varname == 'self' && this.selftype) { 896 if (varname == 'self' && this.selftype) {
879 forwarddec += '\tstruct ' + this.selftype + ' * self;\n'; 897 forwarddec += '\tstruct ' + this.selftype + ' * self;\n';
880 } else { 898 } else {
881 forwarddec += '\tobject * ' + escapeCName(varname) + ';\n'; 899 forwarddec += '\tobject * ' + escapeCName(varname) + ';\n';
882 } 900 }
883 } 901 }
884 forwarddec += '} lambda_' + mynum + '_env;\n' 902 forwarddec += '};\n'
885 903
886 var myenvinit = '\tlambda_' + mynum + '_env * myenv = GC_MALLOC(sizeof(lambda_' + mynum + '_env));\n'; 904 var myenvinit = '\t' + this.name + '_env * myenv = GC_MALLOC(sizeof(' + this.name + '_env));\n';
887 if (this.symbols.needsParentEnv) { 905 if (this.symbols.needsParentEnv) {
888 myenvinit += '\tmyenv->parent = env;\n'; 906 myenvinit += '\tmyenv->parent = env;\n';
889 } 907 }
890 this.symbols.envtype = 'lambda_' + mynum + '_env'; 908 this.symbols.envtype = this.name + '_env';
891 } else { 909 } else {
892 var myenvinit = ''; 910 var myenvinit = '';
893 } 911 }
894 912 forwarddec += 'object *' + this.name + ' (' + this.symbols.parentEnvType() + ' * env, uint32_t num_args, ...);\n';
895 toplevelcode += 'object * lambda_' + mynum + ' (' + this.symbols.parentEnvType() + ' * env, uint32_t num_args, ...) {\n\tva_list args;\n' + myenvinit + '\tva_start(args, num_args);\n'; 913
914 toplevelcode += 'object * ' + this.name + ' ( ' + this.symbols.parentEnvType() + ' * env, uint32_t num_args, ...) {\n\tva_list args;\n' + myenvinit + '\tva_start(args, num_args);\n';
896 if (this.selftype) { 915 if (this.selftype) {
897 var selfvar = (new symbol('self', this.symbols)).toC(); 916 var selfvar = (new symbol('self', this.symbols)).toC();
898 if (selfvar == 'self') { 917 if (selfvar == 'self') {
899 toplevelcode += '\t' + this.selftype + ' * self = va_arg(args, ' + this.selftype + ' *);\n'; 918 toplevelcode += '\t' + this.selftype + ' * self = va_arg(args, ' + this.selftype + ' *);\n';
900 } else { 919 } else {
901 toplevelcode += '\t' + selfvar + ' = va_arg(args, ' + this.selftype + ' *);\n'; 920 toplevelcode += '\t' + selfvar + ' = va_arg(args, ' + this.selftype + ' *);\n';
902 } 921 }
903 922
904 } 923 }
905 toplevelcode += args.join('') + '\tva_end(args);\n' + exprs.join(';\n\t') + '\n}\n'; 924 toplevelcode += args.join('') + '\tva_end(args);\n' + exprs.join(';\n\t') + '\n}\n';
906 this.name = 'lambda_' + mynum; 925
907
908 if (this.selftype) { 926 if (this.selftype) {
909 return this.name; 927 return this.name;
910 } else { 928 } else {
911 if (this.symbols.parentEnvType() != 'void') { 929 if (this.symbols.parentEnvType() != 'void') {
912 if (this.symbols.parent.passthruenv) { 930 if (this.symbols.parent.passthruenv) {
913 var envvar = 'env'; 931 var envvar = 'env';
914 } else { 932 } else {
915 var envvar = 'myenv'; 933 var envvar = 'myenv';
916 } 934 }
917 debugprint('//lambda_' + mynum, 'has envvar:', envvar, 'num vars closed over:', Object.keys(this.symbols.closedover).length); 935 debugprint('//' + this.name, 'has envvar:', envvar, 'num vars closed over:', Object.keys(this.symbols.closedover).length);
918 return 'make_lambda(' + envvar + ', (closure_func)' + this.name + ')'; 936 return 'make_lambda(' + envvar + ', (closure_func)' + this.name + ')';
919 } else { 937 } else {
920 toplevelcode += 'lambda lambda_obj_' + mynum + ' = {{&lambda_meta, NULL}, NULL, lambda_' + mynum + '};\n'; 938 toplevelcode += 'lambda ' + this.name + '_obj = {{&lambda_meta, NULL}, NULL, lambda_' + mynum + '};\n';
921 return '((object *)&lambda_obj_' + mynum + ')'; 939 return '((object *)&' + this.name + '_obj)';
922 } 940 }
923 } 941 }
924 }; 942 };
925 lambda.prototype.toCModuleInstance = function() { 943 lambda.prototype.toCModuleInstance = function() {
926 this.toC(); 944 this.toC();
930 this.selftype = typename; 948 this.selftype = typename;
931 return this.toC(); 949 return this.toC();
932 }; 950 };
933 lambda.prototype.toCModule = function() { 951 lambda.prototype.toCModule = function() {
934 return makeCProg(this); 952 return makeCProg(this);
953 };
954 lambda.prototype.toCLines = function(vars, needsreturn) {
955 var lines = [];
956 for (var i in this.args) {
957 var name = this.args[i].name;
958 if (name[0] == ':') {
959 name = name.substr(1);
960 }
961 if(name != 'self') {
962 lines.push(name + ' = va_arg(args, ' + vars[name] + ');');
963 }
964 }
965 for (var i in this.expressions) {
966 var exprlines = this.expressions[i].toCLines(vars, needsreturn && i == this.expressions.length - 1);
967 for (var j in exprlines) {
968 lines.push('\t' + exprlines[j]);
969 }
970 }
971 return lines;
972 }
973 lambda.prototype.toCLLExpr = function(vars) {
974 if (this.expressions.length != 1) {
975 throw new Error('lambda in expression context must have a single statement in llMessage block');
976 }
977 return this.expressions[0].toCLLExpr(vars);
935 } 978 }
936 979
937 assignment.prototype.toC = function() { 980 assignment.prototype.toC = function() {
938 debugprint('//assignment', this.symbol.name); 981 debugprint('//assignment', this.symbol.name);
939 var existing = this.symbols.find(this.symbol.name); 982 var existing = this.symbols.find(this.symbol.name);
969 messagevars[escaped] = 'object *'; 1012 messagevars[escaped] = 'object *';
970 params.push(escaped); 1013 params.push(escaped);
971 paramget += escaped + ' = va_arg(args, object *); '; 1014 paramget += escaped + ' = va_arg(args, object *); ';
972 } 1015 }
973 } 1016 }
974 cobj.addMessage(this.symbol.name, { 1017 cobj.addMessage(getOpMethodName(this.symbol.name), {
975 vars: messagevars, 1018 vars: messagevars,
976 lines: [paramget + 'return ' + val + '(' + (cobj.hasenv ? 'self->env' : 'NULL') + ', ' + params.length + (params.length ? ', ' : '') + params.join(', ') + ');'] 1019 lines: [paramget + 'return ' + val + '(' + (cobj.hasenv ? 'self->env' : 'NULL') + ', ' + params.length + (params.length ? ', ' : '') + params.join(', ') + ');']
977 }); 1020 });
978 } else { 1021 } else {
979 cobj.addProperty(this.symbol.name, val); 1022 cobj.addProperty(this.symbol.name, val);
980 if (this.expression instanceof object && this.expression.symbols.needsparent) { 1023 if (this.expression instanceof object && this.expression.symbols.needsparent) {
981 cobj.addInit('self->' + escapeCName(this.symbol.name) + '->parent = (object *)self;'); 1024 cobj.addInit('self->' + escapeCName(this.symbol.name) + '->parent = (object *)self;');
982 } 1025 }
983 } 1026 }
984 }; 1027 };
1028 assignment.prototype.toCLines = function(vars, needsreturn) {
1029 return [(needsreturn ? 'return ' : '') + this.symbol.toCLLExpr(vars) + ' = ' + this.expression.toCLLExpr(vars) + ';']
1030 };