comparison jsbackend.js @ 95:926b65fe92b4

Do some cleanup on JS backend
author Mike Pavone <pavone@retrodev.com>
date Tue, 24 Jul 2012 19:13:38 -0700
parents 668f533e5284
children 648659961e0e
comparison
equal deleted inserted replaced
90:b5152f5ac138 95:926b65fe92b4
43 } 43 }
44 return obj; 44 return obj;
45 } 45 }
46 46
47 op.prototype.toJS = function(isReceiver) { 47 op.prototype.toJS = function(isReceiver) {
48 var ret = '(' + this.left.toJS() +' '+ (this.op == '=' ? '==' : this.op) +' '+ this.right.toJS() + ')'; 48 var opmap = {'=': '==', '.': '+'};
49 if (isReceiver) { 49 var ret = '(' + this.left.toJS() +' '+ (this.op in opmap ? opmap[this.op] : this.op) +' '+ this.right.toJS() + ')';
50 ret = 'toobj' + ret;
51 }
52 return ret; 50 return ret;
53 }; 51 };
54 52
55 function escapeJSName(name) 53 function escapeJSName(name)
56 { 54 {
78 pre = 'this'; 76 pre = 'this';
79 for (var i = 0; i < funinfo.depth; ++i) { 77 for (var i = 0; i < funinfo.depth; ++i) {
80 pre += '.parent'; 78 pre += '.parent';
81 } 79 }
82 } else if (info.type == 'toplevel') { 80 } else if (info.type == 'toplevel') {
83 pre = 'modules.'; 81 return toplevel.moduleVar(name);
84 modules[name] = false;
85 } 82 }
86 return pre + escapeJSName(name); 83 return pre + escapeJSName(name);
87 } 84 }
88 85
89 intlit.prototype.toJS = function() { 86 intlit.prototype.toJS = function() {
120 var args = this.args.slice(0, this.args.length); 117 var args = this.args.slice(0, this.args.length);
121 if (this.receiver) { 118 if (this.receiver) {
122 args.splice(0, 0, this.receiver); 119 args.splice(0, 0, this.receiver);
123 } 120 }
124 var funinfo = this.symbols.find(name); 121 var funinfo = this.symbols.find(name);
125 if (!funinfo || funinfo.def instanceof setter) { 122 if (!funinfo || funinfo.def instanceof setter || funinfo.type == 'toplevel') {
126 var receiver = args[0]; 123 var receiver = args[0];
127 args.splice(0, 1); 124 args.splice(0, 1);
128 for (var i in args) { 125 for (var i in args) {
129 args[i] = args[i].toJS(); 126 args[i] = args[i].toJS();
130 } 127 }
131 var rJS = receiver.toJS(true); 128 var rJS = (funinfo ? '' : 'toobj(') + receiver.toJS(true) + (funinfo ? '' : ')') ;
132 if ((name[name.length-1] == '!' && args.length == 1) || (funinfo && funinfo.def instanceof setter)) { 129 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 + ')'; 130 return '(' + rJS + '.' + escapeJSName(name.substr(0, name.length-1)) + ' = ' + args[0] + ', ' + rJS + ')';
134 } else { 131 } else {
135 var callee = rJS + '.' + escapeJSName(name); 132 var callee = rJS + '.' + escapeJSName(name);
136 var callCode = callee + '(' + args.join(', ') + ')';
137 if (args.length == 0) { 133 if (args.length == 0) {
138 return '(' + callee + ' instanceof Function ? ' + callCode + ' : ' + callee + ')'; 134 return callee;
139 } else { 135 } else {
140 return callCode; 136 return callee + '(' + args.join(', ') + ')';
141 } 137 }
142 } 138 }
143 } 139 }
144 var ret = ''; 140 var ret = '';
145 switch(funinfo.type) 141 switch(funinfo.type)
212 return pre+'{\n\tparent: ' + this.symbols.parentObject() + ',\n\t' + compiled.join(',\n\t') + '\n}'+post; 208 return pre+'{\n\tparent: ' + this.symbols.parentObject() + ',\n\t' + compiled.join(',\n\t') + '\n}'+post;
213 } 209 }
214 210
215 object.prototype.toJSModule = function() { 211 object.prototype.toJSModule = function() {
216 this.populateSymbols(toplevel); 212 this.populateSymbols(toplevel);
217 return '(function () {\n\tvar module = ' + indent(this.toJS()) + ';\n\treturn module;\n})' 213 return '(function () {\n\tvar module = ' + indent(this.toJS()) + ';\n\treturn module;\n})();'
218 } 214 }
219 215
220 lambda.prototype.toJS = function() { 216 lambda.prototype.toJS = function() {
221 var args = this.args ? this.args.slice(0, this.args.length) : []; 217 var args = this.args ? this.args.slice(0, this.args.length) : [];
222 if (args.length && args[0].cleanName() == 'self') { 218 if (args.length && args[0].cleanName() == 'self') {
237 if (exprs.length) { 233 if (exprs.length) {
238 exprs[exprs.length-1] = 'return ' + exprs[exprs.length-1] + ';'; 234 exprs[exprs.length-1] = 'return ' + exprs[exprs.length-1] + ';';
239 } 235 }
240 return 'function (' + args.join(', ') + ') {\n\t' + (this.symbols.needsSelfVar ? 'var self = this;\n\t' : '') + exprs.join(';\n\t') + '\n}' 236 return 'function (' + args.join(', ') + ') {\n\t' + (this.symbols.needsSelfVar ? 'var self = this;\n\t' : '') + exprs.join(';\n\t') + '\n}'
241 }; 237 };
238 lambda.prototype.nonSelfArgs = function() {
239 var args = this.args ? this.args.slice(0, this.args.length) : [];
240 if (args.length && args[0].cleanName() == 'self') {
241 args.splice(0, 1);
242 }
243 return args;
244 };
242 lambda.prototype.toJSModule = function() { 245 lambda.prototype.toJSModule = function() {
243 this.populateSymbols(toplevel); 246 this.populateSymbols(toplevel);
244 return this.toJS(); 247 return this.toJS() + '();';
248 }
249
250 modulefile.prototype.toJSModule = function(){
251 return this.ast.toJSModule();
252 };
253
254 function processUsedToplevelJS(toplevel)
255 {
256 var alwaysused = ['true', 'false'];
257 var ret = '';
258 var modulenum = 0;
259 var visited = {};
260 for (var i in alwaysused) {
261 toplevel.used[alwaysused[i]] = true;
262 }
263 var newused = Object.keys(toplevel.used);
264 var allused = newused;
265 while (newused.length) {
266 for (var i in newused) {
267 toplevel.names[newused[i]].populateSymbols(toplevel);
268 visited[newused[i]] = true;
269 }
270 newused = [];
271 for (var symbol in toplevel.used) {
272 if (!(symbol in visited)) {
273 newused.push(symbol);
274 allused.push(symbol);
275 }
276 }
277 }
278
279 for (var i = allused.length-1; i >= 0; i--) {
280 var symbol = allused[i];
281 ret += 'var ' + toplevel.moduleVar(symbol) + ' = ' + toplevel.names[symbol].toJSModule() + '\n';
282 }
283 return ret;
284 }
285
286 function makeJSProg(mainmodule)
287 {
288 return processUsedToplevelJS(toplevel) + 'main_module = ' + mainmodule.toJSModule() + '\n' +
289 'Number.prototype.__defineGetter__("string", function() { return "" + this; });\n' +
290 'String.prototype.__defineGetter__("string", function() { return this; });\n' +
291 'String.prototype.__defineGetter__("print", function() { write(this); });\n' +
292 'Array.prototype.foreach = function(action) { var ret = module_false; for (var i = 0; i < this.length; i++) { ret = action(i, this[i]) }; return ret; };\n' +
293 'Function.prototype.whileCN_do = function(action) { var ret = module_false; while(toobj(this()) == module_true) { ret = action(); } return ret; };\n' +
294 'function toobj(val) {\n' +
295 ' return (typeof val == "boolean") ? (val ? module_true : module_false) : val;\n' +
296 '}\n' +
297 'var m = main_module.main;\n' +
298 'if (m instanceof Function) {\n' +
299 ' m(arguments);\n' +
300 '}\n';
245 } 301 }
246 302
247 assignment.prototype.toJS = function() { 303 assignment.prototype.toJS = function() {
248 var existing = this.symbols.find(this.symbol.name); 304 var existing = this.symbols.find(this.symbol.name);
249 var prefix = ''; 305 var prefix = '';
267 if (val === null) { 323 if (val === null) {
268 return null; 324 return null;
269 } 325 }
270 return prefix + this.symbol.toJS() + ' = ' + val; 326 return prefix + this.symbol.toJS() + ' = ' + val;
271 }; 327 };
328 function removeInitialFunction(str)
329 {
330 var f = 'function';
331 str = str.trim();
332 if (str.substr(0, f.length) == f) {
333 return str.substr(f.length);
334 }
335 return str;
336 }
272 assignment.prototype.toJSObject = function() { 337 assignment.prototype.toJSObject = function() {
273 var val = this.expression.toJS(); 338 var val = this.expression.toJS();
274 if (val === null) { 339 if (val === null) {
275 return null; 340 return null;
276 } 341 }
342 if (this.expression instanceof lambda) {
343 var args = this.expression.nonSelfArgs();
344 if (args.length == 0) {
345 return 'get ' + escapeJSName(this.symbol.name) + removeInitialFunction(val);
346 } else if(args.length == 1 && this.symbol.name[this.symbol.name.length-1] == '!') {
347 return 'set ' + escapeJSName(this.symbol.name.substr(0, this.symbol.name.length-1)) + removeInitialFunction(val);
348 }
349 }
277 return escapeJSName(this.symbol.name) + ': ' + val; 350 return escapeJSName(this.symbol.name) + ': ' + val;
278 }; 351 };