comparison jsbackend.js @ 19:132c7756860e

Use populateSymbols to generate symbol tables during compilation rather than populating them as we go. This change allows us to refer to symbols defined later in the input stream and also gives the symbol table logic a single home that can be used both by the compiler and editor.
author Mike Pavone <pavone@retrodev.com>
date Sun, 25 Mar 2012 16:11:19 -0700
parents 6e4851a204a5
children bf03c9f0dd55
comparison
equal deleted inserted replaced
18:4dd99fde5f63 19:132c7756860e
25 function getP(o, p) 25 function getP(o, p)
26 { 26 {
27 return o[p]; 27 return o[p];
28 } 28 }
29 29
30 op.prototype.toJS = function(symbols, isReceiver) { 30 op.prototype.toJS = function(isReceiver) {
31 var ret = '(' + this.left.toJS(symbols) +' '+ (this.op == '=' ? '==' : this.op) +' '+ this.right.toJS(symbols) + ')'; 31 var ret = '(' + this.left.toJS() +' '+ (this.op == '=' ? '==' : this.op) +' '+ this.right.toJS() + ')';
32 if (isReceiver) { 32 if (isReceiver) {
33 ret = 'toobj' + ret; 33 ret = 'toobj' + ret;
34 } 34 }
35 return ret; 35 return ret;
36 }; 36 };
37 37
38 symbol.prototype.toJS = function(symbols) { 38 symbol.prototype.toJS = function() {
39 var name = this.cleanName(); 39 var name = this.cleanName();
40 if (name == 'self') { 40 if (name == 'self') {
41 return symbols.selfVar(); 41 return this.symbols.selfVar();
42 } 42 }
43 name = name.replace("_", "UN_").replace(":", "CN_").replace("!", "EX_").replace('?', 'QS_').replace('@', 'AT_'); 43 name = name.replace("_", "UN_").replace(":", "CN_").replace("!", "EX_").replace('?', 'QS_').replace('@', 'AT_');
44 var reserved = {'true': true, 'false': true, 'this': true, 'if': true, 'else': true, 'NaN': true}; 44 var reserved = {'true': true, 'false': true, 'this': true, 'if': true, 'else': true, 'NaN': true};
45 if (name in reserved) { 45 if (name in reserved) {
46 name = 's' + name; 46 name = 's' + name;
47 } 47 }
48 return name; 48 return name;
49 } 49 }
50 50
51 intlit.prototype.toJS = function(symbols) { 51 intlit.prototype.toJS = function() {
52 return this.val.toString(); 52 return this.val.toString();
53 } 53 }
54 54
55 floatlit.prototype.toJS = function(symbols) { 55 floatlit.prototype.toJS = function() {
56 return this.val.toString(); 56 return this.val.toString();
57 } 57 }
58 58
59 strlit.prototype.toJS = function(symbols) { 59 strlit.prototype.toJS = function() {
60 return '"' + this.val.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') + '"'; 60 return '"' + this.val.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') + '"';
61 } 61 }
62 62
63 funcall.prototype.toJS = function(symbols) { 63 funcall.prototype.toJS = function() {
64 var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name; 64 var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name;
65 if (name == 'foreign') { 65 if (name == 'foreign') {
66 if ((this.args[0] instanceof lambda) || (this.args[0] instanceof object)) { 66 if ((this.args[0] instanceof lambda) || (this.args[0] instanceof object)) {
67 return null; 67 return null;
68 } else if(this.args[0] instanceof symbol) { 68 } else if(this.args[0] instanceof symbol) {
73 } 73 }
74 var args = this.args.slice(0, this.args.length); 74 var args = this.args.slice(0, this.args.length);
75 if (this.receiver) { 75 if (this.receiver) {
76 args.splice(0, 0, this.receiver); 76 args.splice(0, 0, this.receiver);
77 } 77 }
78 var funinfo = symbols.find(name); 78 var funinfo = this.symbols.find(name);
79 if (!funinfo) { 79 if (!funinfo) {
80 var receiver = args[0]; 80 var receiver = args[0];
81 args.splice(0, 1); 81 args.splice(0, 1);
82 for (var i in args) { 82 for (var i in args) {
83 args[i] = args[i].toJS(symbols); 83 args[i] = args[i].toJS();
84 } 84 }
85 return receiver.toJS(symbols, true) + '.' + (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')'; 85 return receiver.toJS(true) + '.' + (new symbol(name, this.symbols)).toJS() + '(' + args.join(', ') + ')';
86 } 86 }
87 switch(funinfo.type) 87 switch(funinfo.type)
88 { 88 {
89 case 'self': 89 case 'self':
90 if (args.length < funinfo.def.args.length || funinfo.def.args[0].name != 'self') { 90 if (args.length < funinfo.def.args.length || funinfo.def.args[0].name != 'self') {
91 var receiver = new symbol('self'); 91 var receiver = new symbol('self', this.symbols);
92 } else { 92 } else {
93 var receiver = args[0]; 93 var receiver = args[0];
94 args.splice(0, 1); 94 args.splice(0, 1);
95 } 95 }
96 for (var i in args) { 96 for (var i in args) {
97 args[i] = args[i].toJS(symbols); 97 args[i] = args[i].toJS();
98 } 98 }
99 return receiver.toJS(symbols, true) + '.' + (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')'; 99 return receiver.toJS(true) + '.' + (new symbol(name, this.symbols)).toJS() + '(' + args.join(', ') + ')';
100 case 'parent': 100 case 'parent':
101 var ret = 'this'; 101 var ret = 'this';
102 for (var i = 0; i < funinfo.depth; ++i) { 102 for (var i = 0; i < funinfo.depth; ++i) {
103 ret += '.parent'; 103 ret += '.parent';
104 } 104 }
105 for (var i in args) { 105 for (var i in args) {
106 args[i] = args[i].toJS(symbols); 106 args[i] = args[i].toJS();
107 } 107 }
108 ret += (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')'; 108 ret += (new symbol(name, this.symbols)).toJS() + '(' + args.join(', ') + ')';
109 return ret; 109 return ret;
110 case 'local': 110 case 'local':
111 case 'upvar': 111 case 'upvar':
112 case 'foreign': 112 case 'foreign':
113 for (var i in args) { 113 for (var i in args) {
114 args[i] = args[i].toJS(symbols); 114 args[i] = args[i].toJS();
115 } 115 }
116 return (new symbol(name)).toJS(symbols) + '(' + args.join(', ') + ')'; 116 return (new symbol(name, this.symbols)).toJS() + '(' + args.join(', ') + ')';
117 } 117 }
118 } 118 }
119 119
120 object.prototype.toJS = function(symbols) { 120 object.prototype.toJS = function() {
121 var messages = this.messages; 121 var messages = this.messages;
122 symbols = new osymbols(symbols);
123 var compiled = [] 122 var compiled = []
124 for (var i in messages) { 123 for (var i in messages) {
125 var js = messages[i].toJSObject(symbols); 124 var js = messages[i].toJSObject();
126 if (js) { 125 if (js) {
127 compiled.push(indent(js)); 126 compiled.push(indent(js));
128 } 127 }
129 } 128 }
130 return '{\n\tparent: ' + symbols.parentObject() + ',\n\t' + compiled.join(',\n\t') + '\n}'; 129 return '{\n\tparent: ' + this.symbols.parentObject() + ',\n\t' + compiled.join(',\n\t') + '\n}';
131 } 130 }
132 131
133 object.prototype.toJSModule = function() { 132 object.prototype.toJSModule = function() {
134 return '(function () {\n\tvar module = ' + indent(this.toJS(null)) + ';\n\treturn module;\n})' 133 this.populateSymbols(null);
134 return '(function () {\n\tvar module = ' + indent(this.toJS()) + ';\n\treturn module;\n})'
135 } 135 }
136 136
137 lambda.prototype.toJS = function(symbols) { 137 lambda.prototype.toJS = function() {
138 var args = this.args ? this.args.slice(0, this.args.length) : []; 138 var args = this.args ? this.args.slice(0, this.args.length) : [];
139 if (args.length && args[0].cleanName() == 'self') { 139 if (args.length && args[0].cleanName() == 'self') {
140 args.splice(0, 1); 140 args.splice(0, 1);
141 } 141 }
142 var exprs = this.expressions; 142 var exprs = this.expressions;
143 symbols = new lsymbols(symbols);
144 for (var i in args) { 143 for (var i in args) {
145 symbols.defineVar(args[i].cleanName(), null); 144 args[i] = args[i].toJS();
146 args[i] = args[i].toJS(symbols);
147 } 145 }
148 var compiled = [] 146 var compiled = []
149 for (var i in exprs) { 147 for (var i in exprs) {
150 var js = exprs[i].toJS(symbols); 148 var js = exprs[i].toJS();
151 if (js) { 149 if (js) {
152 compiled.push(indent(js)); 150 compiled.push(indent(js));
153 } 151 }
154 } 152 }
155 exprs = compiled; 153 exprs = compiled;
156 if (exprs.length) { 154 if (exprs.length) {
157 exprs[exprs.length-1] = 'return ' + exprs[exprs.length-1] + ';'; 155 exprs[exprs.length-1] = 'return ' + exprs[exprs.length-1] + ';';
158 } 156 }
159 return 'function (' + args.join(', ') + ') {\n\t' + (symbols.needsSelfVar ? 'var self = this;\n\t' : '') + exprs.join(';\n\t') + '\n}' 157 return 'function (' + args.join(', ') + ') {\n\t' + (this.symbols.needsSelfVar ? 'var self = this;\n\t' : '') + exprs.join(';\n\t') + '\n}'
160 }; 158 };
161 lambda.prototype.toJSModule = lambda.prototype.toJS 159 lambda.prototype.toJSModule = function() {
160 this.populateSymbols(null);
161 return this.toJS();
162 }
162 163
163 assignment.prototype.toJS = function(symbols) { 164 assignment.prototype.toJS = function() {
164 var existing = symbols.find(this.symbol.name); 165 var existing = this.symbols.find(this.symbol.name);
165 var prefix = ''; 166 var prefix = '';
166 if (!existing) { 167 if (!existing) {
167 symbols.defineVar(this.symbol.name, this.expression);
168 prefix = 'var '; 168 prefix = 'var ';
169 } else { 169 } else {
170 switch (existing.type) 170 switch (existing.type)
171 { 171 {
172 case 'self': 172 case 'self':
178 prefix += 'parent.'; 178 prefix += 'parent.';
179 } 179 }
180 break; 180 break;
181 } 181 }
182 } 182 }
183 var val = this.expression.toJS(symbols); 183 var val = this.expression.toJS();
184 if (val === null) { 184 if (val === null) {
185 return null; 185 return null;
186 } 186 }
187 return prefix + this.symbol.toJS(symbols) + ' = ' + val; 187 return prefix + this.symbol.toJS() + ' = ' + val;
188 }; 188 };
189 assignment.prototype.toJSObject = function(symbols) { 189 assignment.prototype.toJSObject = function() {
190 symbols.defineMsg(this.symbol.name, this.expression); 190 var val = this.expression.toJS();
191 var val = this.expression.toJS(symbols);
192 if (val === null) { 191 if (val === null) {
193 return null; 192 return null;
194 } 193 }
195 return this.symbol.toJS(symbols) + ': ' + val; 194 return this.symbol.toJS() + ': ' + val;
196 }; 195 };