Mercurial > repos > tabletprog
comparison cbackend.js @ 273:0dc7322590da
Make import:from actually work. Fix some macro bugs. Add a cpointer primitive type for storing an opaque pointer to a C object.
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 20 Jul 2014 00:12:43 -0700 |
parents | bb2b4613fdc8 |
children | 361a449a7235 |
comparison
equal
deleted
inserted
replaced
272:bb2b4613fdc8 | 273:0dc7322590da |
---|---|
104 return getSymbolPrefix(info, this.symbols) + escapeCName(name); | 104 return getSymbolPrefix(info, this.symbols) + escapeCName(name); |
105 } | 105 } |
106 symbol.prototype.toCTypeName = function() { | 106 symbol.prototype.toCTypeName = function() { |
107 return this.cleanName(); | 107 return this.cleanName(); |
108 }; | 108 }; |
109 symbol.prototype.cSafeName = function() { | |
110 var name = this.cleanName(); | |
111 if (name[0] >= "0" && name[0] <= "9") { | |
112 name = '_tp_' + name; | |
113 } | |
114 return name; | |
115 }; | |
109 symbol.prototype.toCLLExpr = function(vars) { | 116 symbol.prototype.toCLLExpr = function(vars) { |
110 var name = this.cleanName(); | 117 var name = this.cleanName(); |
111 if (name in vars) { | 118 if (name in vars) { |
112 return name; | 119 return name; |
113 } | 120 } |
119 while (info && info.type == 'local') { | 126 while (info && info.type == 'local') { |
120 symbols = symbols.parent; | 127 symbols = symbols.parent; |
121 info = symbols.find(name, false, true); | 128 info = symbols.find(name, false, true); |
122 } | 129 } |
123 if (!info) { | 130 if (!info) { |
124 return name; | 131 return this.cSafeName(); |
125 } | 132 } |
126 if (info.type == 'toplevel') { | 133 if (info.type == 'toplevel') { |
127 return toplevel.moduleVar(name); | 134 return toplevel.moduleVar(name); |
128 } else if (info.type == 'self') { | 135 } else if (info.type == 'self') { |
129 if (info.isll || !(info.def instanceof lambda)) { | 136 if (info.isll || !(info.def instanceof lambda)) { |
130 return 'self->' + name; | 137 return 'self->' + this.cSafeName(); |
131 } else { | 138 } else { |
132 return 'mcall(' + getMethodId(name) + '/* ' + name + ' */, 1, self)'; | 139 return 'mcall(' + getMethodId(name) + '/* ' + name + ' */, 1, self)'; |
133 } | 140 } |
134 } | 141 } |
135 throw new Error('Unsupported reference type ' + info.type + ' for variable ' + name); | 142 throw new Error('Unsupported reference type ' + info.type + ' for variable ' + name); |
415 this.slotvars = {}; | 422 this.slotvars = {}; |
416 this.includes = {}; | 423 this.includes = {}; |
417 this.parent = 'NULL'; | 424 this.parent = 'NULL'; |
418 this.init = []; | 425 this.init = []; |
419 this.initmsgadded = false; | 426 this.initmsgadded = false; |
427 this.imported = []; | |
420 } | 428 } |
421 | 429 |
422 cObject.prototype.addInclude = function(includefile) { | 430 cObject.prototype.addInclude = function(includefile) { |
423 this.includes[includefile] = true; | 431 this.includes[includefile] = true; |
424 } | 432 } |
465 cObject.prototype.addInit = function(statement) { | 473 cObject.prototype.addInit = function(statement) { |
466 this.init.push(statement); | 474 this.init.push(statement); |
467 }; | 475 }; |
468 | 476 |
469 cObject.prototype.addImport = function(symbols, source) { | 477 cObject.prototype.addImport = function(symbols, source) { |
470 this.imported.push(source); | 478 var importNum = this.imported.indexOf(source); |
471 var importNum = imported.length - 1; | 479 if (importNum < 0) { |
480 var importNum = this.imported.length; | |
481 this.imported.push(source); | |
482 this.addInit('self->import_' + importNum + ' = ' + source.toC() + ';'); | |
483 } | |
472 if (symbols) { | 484 if (symbols) { |
485 var self = this; | |
473 each(symbols, function(i, sym) { | 486 each(symbols, function(i, sym) { |
474 this.addMessage(sym.name, { | 487 self.addMessage(sym.name, { |
475 vars: {}, | 488 vars: {}, |
476 lines: [ | 489 lines: [ |
477 'return self->import_' + importNum + '->meta->meth_lookup[method_id & 0xF](method_id, num_args, self->import_' + importNum + ', args);' | 490 'return self->import_' + importNum + '->meta->meth_lookup[method_id & 0xF](method_id, num_params, self->import_' + importNum + ', args);' |
478 ] | 491 ] |
479 }); | 492 }); |
480 }); | 493 }); |
481 } else { | 494 } else { |
482 //TODO: handle proxying for unimplemented methods | 495 //TODO: handle proxying for unimplemented methods |
512 objdef += '\t' + this.properties[i][1] + ' ' + this.properties[i][0] + ';\n'; | 525 objdef += '\t' + this.properties[i][1] + ' ' + this.properties[i][0] + ';\n'; |
513 } | 526 } |
514 } else { | 527 } else { |
515 objdef += '\tobject * ' + this.properties[i] + ';\n' | 528 objdef += '\tobject * ' + this.properties[i] + ';\n' |
516 } | 529 } |
530 } | |
531 for (var i in this.imported) { | |
532 objdef += '\tobject * import_' + i + ';\n'; | |
517 } | 533 } |
518 objdef += '} ' + this.name + ';\nobj_meta ' + this.name + '_meta;\n'; | 534 objdef += '} ' + this.name + ';\nobj_meta ' + this.name + '_meta;\n'; |
519 return includes + objdef; | 535 return includes + objdef; |
520 } | 536 } |
521 | 537 |
602 if (this.symbols.needsparent && !(this.symbols.parent instanceof osymbols)) { | 618 if (this.symbols.needsparent && !(this.symbols.parent instanceof osymbols)) { |
603 me.parent = '(object *)(' + (new symbol('self', this.symbols.parent)).toC() + ')'; | 619 me.parent = '(object *)(' + (new symbol('self', this.symbols.parent)).toC() + ')'; |
604 } | 620 } |
605 for (var i in messages) { | 621 for (var i in messages) { |
606 if (messages[i] instanceof funcall) { | 622 if (messages[i] instanceof funcall) { |
607 if (messages[i].name == 'import:' && messages[i].args.length == 1) { | 623 var msgname = messages[i].name; |
624 if (msgname[msgname.length-1] == ':') { | |
625 msgname = msgname.substr(0, msgname.length-1); | |
626 } | |
627 if (msgname == 'import' && messages[i].args.length == 1) { | |
608 me.addImport(false, messages[i].args[0]); | 628 me.addImport(false, messages[i].args[0]); |
609 } else if(messages[i].name == 'import:from:' && messages[i].args.length == 2) { | 629 } else if(msgname == 'import:from' && messages[i].args.length == 2) { |
610 var importsyms = []; | 630 var importsyms = []; |
611 each(messages[i].args[0].val, function(i, el) { | 631 each(messages[i].args[0].val, function(i, el) { |
612 if (!(el instanceof symbol)) { | 632 if (!(el instanceof symbol)) { |
613 throw new Error('Names in import:from statement must be symbols'); | 633 throw new Error('Names in import:from statement must be symbols'); |
614 } | 634 } |
615 importsyms.push(el); | 635 importsyms.push(el); |
616 }); | 636 }); |
617 me.addImport(importsyms, messages[i].args[1]); | 637 me.addImport(importsyms, messages[i].args[1]); |
618 } else if(messages[i].name == 'llProperty:withType:' && messages[i].args.length == 2) { | 638 } else if(msgname == 'llProperty:withType' && messages[i].args.length == 2) { |
619 me.addProperty(messages[i].args[0].name, null, messages[i].args[1].toCTypeName()); | 639 me.addProperty(messages[i].args[0].name, null, messages[i].args[1].toCTypeName()); |
620 } else if(messages[i].name == 'llMessage:withVars:andCode:' && messages[i].args.length == 3) { | 640 } else if(msgname == 'llMessage:withVars:andCode' && messages[i].args.length == 3) { |
621 if (messages[i].args[0] instanceof symbol) { | 641 if (messages[i].args[0] instanceof symbol) { |
622 var msgname = messages[i].args[0].name; | 642 var msgname = messages[i].args[0].name; |
623 } else if (messages[i].args[0] instanceof strlit) { | 643 } else if (messages[i].args[0] instanceof strlit) { |
624 var msgname = messages[i].args[0].val; | 644 var msgname = messages[i].args[0].val; |
625 } else { | 645 } else { |
626 throw new Error('First argument to llMessage:withVars:andCode must be a symbol or string'); | 646 throw new Error('First argument to llMessage:withVars:andCode must be a symbol or string'); |
627 } | 647 } |
628 var rawvars = messages[i].args[1].expressions; | 648 var rawvars = messages[i].args[1].expressions; |
629 var vars = {}; | 649 var vars = {}; |
630 for(var v in rawvars) { | 650 for(var v in rawvars) { |
631 vars[rawvars[v].symbol.name] = rawvars[v].expression.toCTypeName(); | 651 vars[rawvars[v].symbol.cSafeName()] = rawvars[v].expression.toCTypeName(); |
632 } | 652 } |
633 me.addMessage(msgname, { | 653 me.addMessage(msgname, { |
634 vars: vars, | 654 vars: vars, |
635 lines: messages[i].args[2].toCLines(vars, true) | 655 lines: messages[i].args[2].toCLines(vars, true) |
636 }); | 656 }); |
637 } else if(messages[i].name == 'includeSystemHeader:' && messages[i].args.length == 1) { | 657 } else if(msgname == 'includeSystemHeader' && messages[i].args.length == 1) { |
638 me.addInclude("<" + messages[i].args[0].val + ">"); | 658 me.addInclude("<" + messages[i].args[0].val + ">"); |
639 } else { | 659 } else { |
640 | 660 |
641 throw new Error('Only import and import:from calls allowed in object context. ' + messages[i].name + 'with ' + messages[i].args.length + ' arguments found instead.'); | 661 throw new Error('Only import and import:from calls allowed in object context. ' + messages[i].name + 'with ' + messages[i].args.length + ' arguments found instead.'); |
642 } | 662 } |
784 } | 804 } |
785 | 805 |
786 return intObj; | 806 return intObj; |
787 } | 807 } |
788 | 808 |
809 function makeCPointer() | |
810 { | |
811 var cptr = new cObject('cpointer'); | |
812 cptr.addProperty('val', null, 'void *'); | |
813 //cpointer: | |
814 //1234567890 | |
815 cptr.addMessage('string', { | |
816 vars: {ret: 'string *'}, | |
817 lines: [ | |
818 'ret = make_object(&string_meta, NULL, 0);', | |
819 //22 digits for worst case sensible representation | |
820 //10 chars for prefix | |
821 //4 for slop | |
822 //1 for null terminator | |
823 'ret->data = GC_MALLOC_ATOMIC(22+10+4+1);', | |
824 'snprintf(ret->data, 22+10+4, "cpointer: %p", self->val);', | |
825 'ret->data[22+10+4] = 0;', | |
826 'return (object *)ret;' | |
827 ] | |
828 }); | |
829 return cptr; | |
830 } | |
831 | |
789 function makeArray() | 832 function makeArray() |
790 { | 833 { |
791 var arrayfile = toplevel.names['array']; | 834 var arrayfile = toplevel.names['array']; |
792 var ast = parseFile(arrayfile.path + '/' + arrayfile.file); | 835 var ast = parseFile(arrayfile.path + '/' + arrayfile.file); |
793 ast.name = 'array'; | 836 ast.name = 'array'; |
825 | 868 |
826 function builtinTypes() | 869 function builtinTypes() |
827 { | 870 { |
828 return [makeInt(64, false), makeInt(32, false), makeInt(16, false), makeInt(8, false), | 871 return [makeInt(64, false), makeInt(32, false), makeInt(16, false), makeInt(8, false), |
829 makeInt(64, true) , makeInt(32, true), makeInt(16, true), makeInt(8, true), | 872 makeInt(64, true) , makeInt(32, true), makeInt(16, true), makeInt(8, true), |
830 makeArray(), makeString(), makelambda()]; | 873 makeArray(), makeString(), makelambda(), makeCPointer()]; |
831 } | 874 } |
832 | 875 |
833 function addBuiltinModules(toplevel) | 876 function addBuiltinModules(toplevel) |
834 { | 877 { |
835 var os = new cObject('mod_obj_os'); | 878 var os = new cObject('mod_obj_os'); |