comparison jsbackend.js @ 126:a2d2d8e09291

Merge
author Mike Pavone <pavone@retrodev.com>
date Mon, 05 Aug 2013 23:37:17 -0700
parents a83989115028
children
comparison
equal deleted inserted replaced
125:6f8d868e8da0 126:a2d2d8e09291
1 var mainModule; 1 var mainModule;
2 var modules = {}; 2 var modules = {};
3 3
4 function toobj(val) 4 function toobj(val)
5 { 5 {
6 switch(typeof val) 6 return (typeof val == "boolean") ? (val ? module_true : module_false) : val;
7 {
8 case 'boolean':
9 if(val) {
10 return mainModule.strue;
11 } else {
12 return mainModule.sfalse;
13 }
14 case 'number':
15 return mainModule.snumber(val);
16 }
17 throw new Error("can't make val into object");
18 } 7 }
19 8
20 function importSym(obj, src, key) 9 function importSym(obj, src, key)
21 { 10 {
22 if(!(key in src)) { 11 if(!(key in src)) {
43 } 32 }
44 return obj; 33 return obj;
45 } 34 }
46 35
47 op.prototype.toJS = function(isReceiver) { 36 op.prototype.toJS = function(isReceiver) {
48 var ret = '(' + this.left.toJS() +' '+ (this.op == '=' ? '==' : this.op) +' '+ this.right.toJS() + ')'; 37 if (this.op == '&&') {
49 if (isReceiver) { 38 var ret = 'toobj(' + this.left.toJS() + ').sif(' + this.right.toJS() + ')';
50 ret = 'toobj' + ret; 39 } else if(this.op == '||') {
40 var ret = 'toobj(' + this.left.toJS() + ').ifnot(' + this.right.toJS() + ')';
41 } else {
42 var opmap = {'=': '==', '.': '+'};
43 var ret = '(' + this.left.toJS() +' '+ (this.op in opmap ? opmap[this.op] : this.op) +' '+ this.right.toJS() + ')';
51 } 44 }
52 return ret; 45 return ret;
53 }; 46 };
54 47
55 function escapeJSName(name) 48 function escapeJSName(name)
78 pre = 'this'; 71 pre = 'this';
79 for (var i = 0; i < funinfo.depth; ++i) { 72 for (var i = 0; i < funinfo.depth; ++i) {
80 pre += '.parent'; 73 pre += '.parent';
81 } 74 }
82 } else if (info.type == 'toplevel') { 75 } else if (info.type == 'toplevel') {
83 pre = 'modules.'; 76 return toplevel.moduleVar(name);
84 modules[name] = false;
85 } 77 }
86 return pre + escapeJSName(name); 78 return pre + escapeJSName(name);
87 } 79 }
88 80
89 intlit.prototype.toJS = function() { 81 intlit.prototype.toJS = function() {
120 var args = this.args.slice(0, this.args.length); 112 var args = this.args.slice(0, this.args.length);
121 if (this.receiver) { 113 if (this.receiver) {
122 args.splice(0, 0, this.receiver); 114 args.splice(0, 0, this.receiver);
123 } 115 }
124 var funinfo = this.symbols.find(name); 116 var funinfo = this.symbols.find(name);
125 if (!funinfo || funinfo.def instanceof setter) { 117 if (!funinfo || funinfo.def instanceof setter || funinfo.type == 'toplevel') {
126 var receiver = args[0]; 118 var receiver = args[0];
127 args.splice(0, 1); 119 args.splice(0, 1);
128 for (var i in args) { 120 for (var i in args) {
129 args[i] = args[i].toJS(); 121 args[i] = args[i].toJS();
130 } 122 }
131 var rJS = receiver.toJS(true); 123 var rJS = (funinfo ? '' : 'toobj(') + receiver.toJS(true) + (funinfo ? '' : ')') ;
132 if ((name[name.length-1] == '!' && args.length == 1) || (funinfo && funinfo.def instanceof setter)) { 124 if ((name[name.length-1] == '!' && args.length == 1) || (funinfo && funinfo.def instanceof setter)) {
133 return '(' + rJS + '.' + escapeJSName(name.substr(0, name.length-1)) + ' = ' + args[0] + ', ' + rJS + ')'; 125 return '(' + rJS + '.' + escapeJSName(name.substr(0, name.length-1)) + ' = ' + args[0] + ', ' + rJS + ')';
134 } else { 126 } else {
135 var callee = rJS + '.' + escapeJSName(name); 127 var callee = rJS + '.' + escapeJSName(name);
136 var callCode = callee + '(' + args.join(', ') + ')';
137 if (args.length == 0) { 128 if (args.length == 0) {
138 return '(' + callee + ' instanceof Function ? ' + callCode + ' : ' + callee + ')'; 129 return callee;
139 } else { 130 } else {
140 return callCode; 131 return callee + '(' + args.join(', ') + ')';
141 } 132 }
142 } 133 }
143 } 134 }
144 var ret = ''; 135 var ret = '';
145 switch(funinfo.type) 136 switch(funinfo.type)
146 { 137 {
147 case 'self': 138 case 'self':
148 if (args.length < funinfo.def.args.length || funinfo.def.args[0].name != 'self') { 139 if (args.length < funinfo.def.args.length || funinfo.def.args.length == 0 || funinfo.def.args[0].name != 'self') {
149 var receiver = new symbol('self', this.symbols); 140 var receiver = new symbol('self', this.symbols);
150 } else { 141 } else {
151 var receiver = args[0]; 142 var receiver = args[0];
152 args.splice(0, 1); 143 args.splice(0, 1);
153 if (args.length == 0) { 144 if (args.length == 0) {
158 } 149 }
159 } 150 }
160 ret = receiver.toJS(true) + '.'; 151 ret = receiver.toJS(true) + '.';
161 break; 152 break;
162 case 'parent': 153 case 'parent':
163 ret = 'this'; 154 var receiver = new symbol('self', this.symbols);
155 ret = receiver.toJS(true);
164 for (var i = 0; i < funinfo.depth; ++i) { 156 for (var i = 0; i < funinfo.depth; ++i) {
165 ret += '.parent'; 157 ret += '.parent';
166 } 158 }
167 break; 159 break;
168 } 160 }
212 return pre+'{\n\tparent: ' + this.symbols.parentObject() + ',\n\t' + compiled.join(',\n\t') + '\n}'+post; 204 return pre+'{\n\tparent: ' + this.symbols.parentObject() + ',\n\t' + compiled.join(',\n\t') + '\n}'+post;
213 } 205 }
214 206
215 object.prototype.toJSModule = function() { 207 object.prototype.toJSModule = function() {
216 this.populateSymbols(toplevel); 208 this.populateSymbols(toplevel);
217 return '(function () {\n\tvar module = ' + indent(this.toJS()) + ';\n\treturn module;\n})' 209 return '(function () {\n\tvar module = ' + indent(this.toJS()) + ';\n\treturn module;\n})();'
218 } 210 }
219 211
220 lambda.prototype.toJS = function() { 212 lambda.prototype.toJS = function() {
221 var args = this.args ? this.args.slice(0, this.args.length) : []; 213 var args = this.args ? this.args.slice(0, this.args.length) : [];
222 if (args.length && args[0].cleanName() == 'self') { 214 if (args.length && args[0].cleanName() == 'self') {
237 if (exprs.length) { 229 if (exprs.length) {
238 exprs[exprs.length-1] = 'return ' + exprs[exprs.length-1] + ';'; 230 exprs[exprs.length-1] = 'return ' + exprs[exprs.length-1] + ';';
239 } 231 }
240 return 'function (' + args.join(', ') + ') {\n\t' + (this.symbols.needsSelfVar ? 'var self = this;\n\t' : '') + exprs.join(';\n\t') + '\n}' 232 return 'function (' + args.join(', ') + ') {\n\t' + (this.symbols.needsSelfVar ? 'var self = this;\n\t' : '') + exprs.join(';\n\t') + '\n}'
241 }; 233 };
234 lambda.prototype.nonSelfArgs = function() {
235 var args = this.args ? this.args.slice(0, this.args.length) : [];
236 if (args.length && args[0].cleanName() == 'self') {
237 args.splice(0, 1);
238 }
239 return args;
240 };
242 lambda.prototype.toJSModule = function() { 241 lambda.prototype.toJSModule = function() {
243 this.populateSymbols(toplevel); 242 this.populateSymbols(toplevel);
244 return this.toJS(); 243 return this.toJS() + '();';
244 }
245
246 modulefile.prototype.toJSModule = function(){
247 return this.ast.toJSModule();
248 };
249
250 function processUsedToplevelJS(toplevel)
251 {
252 var alwaysused = ['true', 'false'];
253 var ret = '';
254 var modulenum = 0;
255 var visited = {};
256 for (var i = 0; i < alwaysused.length; i++) {
257 toplevel.used[alwaysused[i]] = true;
258 }
259 var newused = Object.keys(toplevel.used);
260 var allused = newused;
261 while (newused.length) {
262 for (var i = 0; i < newused.length; i++) {
263 console.log(i, newused[i]);
264 toplevel.names[newused[i]].populateSymbols(toplevel);
265 visited[newused[i]] = true;
266 }
267 newused = [];
268 for (var symbol in toplevel.used) {
269 if (!(symbol in visited)) {
270 newused.push(symbol);
271 allused.push(symbol);
272 }
273 }
274 }
275
276 for (var i = allused.length-1; i >= 0; i--) {
277 var symbol = allused[i];
278 ret += 'var ' + toplevel.moduleVar(symbol) + ' = ' + toplevel.names[symbol].toJSModule() + '\n';
279 }
280 return ret;
281 }
282
283 function asyncProcessTopLevelJS(toplevel, whenDone)
284 {
285 var alwaysused = ['true', 'false'];
286 var ret = '';
287 var modulenum = 0;
288 var visited = {};
289 for (var i = 0; i < alwaysused.length; i++) {
290 toplevel.used[alwaysused[i]] = true;
291 }
292 var newused = Object.keys(toplevel.used);
293 var allused = newused;
294 var i = -1;
295 var handler = function() {
296 i++;
297 while(newused.length)
298 {
299 if (i < newused.length) {
300 visited[newused[i]] = true;
301 toplevel.names[newused[i]].popuplateSymbolsAsync(toplevel, handler);
302 return;
303 } else {
304 newused = [];
305 for (var symbol in toplevel.used) {
306 if (!(symbol in visited)) {
307 newused.push(symbol);
308 allused.push(symbol);
309 }
310 }
311 i = 0;
312 }
313 }
314 whenDone();
315 };
316 handler();
317 }
318
319 function makeJSProg(mainmodule)
320 {
321 return processUsedToplevelJS(toplevel) + 'main_module = ' + mainmodule.toJSModule() + '\n' +
322 'Number.prototype.__defineGetter__("string", function() { return "" + this; });\n' +
323 'String.prototype.__defineGetter__("string", function() { return this; });\n' +
324 'String.prototype.__defineGetter__("print", function() { write(this); });\n' +
325 'Object.defineProperty(Array.prototype, "foreach", {value: function(action) { var ret = module_false; for (var i = 0; i < this.length; i++) { ret = action(i, this[i]) }; return ret; }});\n' +
326 'Function.prototype.whileCN_do = function(action) { var ret = module_false; while(toobj(this()) == module_true) { ret = action(); } return ret; };\n' +
327 'module_true.valueOf = function() { return true; }\n' +
328 'module_false.valueOf = function() { return false; }\n' +
329 'function toobj(val) {\n' +
330 ' return (typeof val == "boolean") ? (val ? module_true : module_false) : val;\n' +
331 '}\n' +
332 'var m = main_module.main;\n' +
333 'if (m instanceof Function) {\n' +
334 ' m(arguments);\n' +
335 '}\n';
245 } 336 }
246 337
247 assignment.prototype.toJS = function() { 338 assignment.prototype.toJS = function() {
248 var existing = this.symbols.find(this.symbol.name); 339 var existing = this.symbols.find(this.symbol.name);
249 var prefix = ''; 340 var prefix = '';
250 if (!existing) { 341 /*if (!existing) {
251 prefix = 'var '; 342 prefix = 'var ';
252 } else { 343 } else {
253 switch (existing.type) 344 switch (existing.type)
254 { 345 {
255 case 'self': 346 case 'self':
256 prefix = 'this.'; 347 var self = new symbol('self', this.symbols);
348 prefix = self.toJS() + '.';
257 break; 349 break;
258 case 'parent': 350 case 'parent':
259 prefix = 'this.'; 351 var self = new symbol('self', this.symbols);
352 prefix = self.toJS() + '.';
260 for (var i = 0; i < existing.depth; ++i) { 353 for (var i = 0; i < existing.depth; ++i) {
261 prefix += 'parent.'; 354 prefix += 'parent.';
262 } 355 }
263 break; 356 break;
264 } 357 }
265 } 358 }*/
266 var val = this.expression.toJS(); 359 var val = this.expression.toJS();
267 if (val === null) { 360 if (val === null) {
268 return null; 361 return null;
269 } 362 }
363 if ((existing.type == 'local' || existing.type == 'closedover') && !existing.isdeclared) {
364 prefix = 'var ';
365 this.symbols.declareVar(this.symbol.name);
366 }
270 return prefix + this.symbol.toJS() + ' = ' + val; 367 return prefix + this.symbol.toJS() + ' = ' + val;
271 }; 368 };
369 function removeInitialFunction(str)
370 {
371 var f = 'function';
372 str = str.trim();
373 if (str.substr(0, f.length) == f) {
374 return str.substr(f.length);
375 }
376 return str;
377 }
272 assignment.prototype.toJSObject = function() { 378 assignment.prototype.toJSObject = function() {
273 var val = this.expression.toJS(); 379 var val = this.expression.toJS();
274 if (val === null) { 380 if (val === null) {
275 return null; 381 return null;
276 } 382 }
383 if (this.expression instanceof lambda) {
384 var args = this.expression.nonSelfArgs();
385 if (args.length == 0) {
386 return 'get ' + escapeJSName(this.symbol.name) + removeInitialFunction(val);
387 } else if(args.length == 1 && this.symbol.name[this.symbol.name.length-1] == '!') {
388 return 'set ' + escapeJSName(this.symbol.name.substr(0, this.symbol.name.length-1)) + removeInitialFunction(val);
389 }
390 }
277 return escapeJSName(this.symbol.name) + ': ' + val; 391 return escapeJSName(this.symbol.name) + ': ' + val;
278 }; 392 };