Mercurial > repos > tabletprog
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 }; |