Mercurial > repos > tabletprog
comparison jsbackend.js @ 25:4d87c38404d6
List literals, fixes to implicit self property lookup, import statement and editor improvements
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 02 Apr 2012 22:28:48 -0700 |
parents | 068d63627b16 |
children | 608eb70fe261 |
comparison
equal
deleted
inserted
replaced
24:fe3533494ce9 | 25:4d87c38404d6 |
---|---|
14 return mainModule.snumber(val); | 14 return mainModule.snumber(val); |
15 } | 15 } |
16 throw new Error("can't make val into object"); | 16 throw new Error("can't make val into object"); |
17 } | 17 } |
18 | 18 |
19 function importSym(obj, src, key) | |
20 { | |
21 if(!(key in src)) { | |
22 throw new Error(key +' not found in source object for import'); | |
23 } | |
24 if(key in obj) { | |
25 throw new Error(key +' already exists in target object for import') | |
26 } | |
27 obj[key] = src[key]; | |
28 } | |
29 | |
30 function doImport(obj, src, symlist) | |
31 { | |
32 if (symlist === undefined) { | |
33 each(src, function(key,val) { | |
34 if (key != 'parent') { | |
35 importSym(obj, src, key); | |
36 } | |
37 }); | |
38 } else { | |
39 for (var i = 0; i < symlist.length; ++i) { | |
40 importSym(obj, src, symlist[i]); | |
41 } | |
42 } | |
43 return obj; | |
44 } | |
45 | |
19 op.prototype.toJS = function(isReceiver) { | 46 op.prototype.toJS = function(isReceiver) { |
20 var ret = '(' + this.left.toJS() +' '+ (this.op == '=' ? '==' : this.op) +' '+ this.right.toJS() + ')'; | 47 var ret = '(' + this.left.toJS() +' '+ (this.op == '=' ? '==' : this.op) +' '+ this.right.toJS() + ')'; |
21 if (isReceiver) { | 48 if (isReceiver) { |
22 ret = 'toobj' + ret; | 49 ret = 'toobj' + ret; |
23 } | 50 } |
24 return ret; | 51 return ret; |
25 }; | 52 }; |
26 | 53 |
54 function escapeJSName(name) | |
55 { | |
56 name = name.replace("_", "UN_").replace(":", "CN_").replace("!", "EX_").replace('?', 'QS_').replace('@', 'AT_'); | |
57 var reserved = {'true': true, 'false': true, 'this': true, 'if': true, 'else': true, 'NaN': true}; | |
58 if (name in reserved) { | |
59 name = 's' + name; | |
60 } | |
61 return name; | |
62 } | |
63 | |
27 symbol.prototype.toJS = function() { | 64 symbol.prototype.toJS = function() { |
28 var name = this.cleanName(); | 65 var name = this.cleanName(); |
29 if (name == 'self') { | 66 if (name == 'self') { |
30 return this.symbols.selfVar(); | 67 return this.symbols.selfVar(); |
31 } | 68 } |
32 name = name.replace("_", "UN_").replace(":", "CN_").replace("!", "EX_").replace('?', 'QS_').replace('@', 'AT_'); | 69 var info = this.symbols.find(name); |
33 var reserved = {'true': true, 'false': true, 'this': true, 'if': true, 'else': true, 'NaN': true}; | 70 if (!info) { |
34 if (name in reserved) { | 71 throw new Error('symbol ' + name + ' not found'); |
35 name = 's' + name; | 72 } |
36 } | 73 var pre = ''; |
37 return name; | 74 if (info.type == 'self') { |
75 pre = this.symbols.selfVar() + '.'; | |
76 } else if(info.type == 'parent') { | |
77 pre = 'this'; | |
78 for (var i = 0; i < funinfo.depth; ++i) { | |
79 pre += '.parent'; | |
80 } | |
81 } | |
82 return pre + escapeJSName(name); | |
38 } | 83 } |
39 | 84 |
40 intlit.prototype.toJS = function() { | 85 intlit.prototype.toJS = function() { |
41 return this.val.toString(); | 86 return this.val.toString(); |
42 } | 87 } |
45 return this.val.toString(); | 90 return this.val.toString(); |
46 } | 91 } |
47 | 92 |
48 strlit.prototype.toJS = function() { | 93 strlit.prototype.toJS = function() { |
49 return '"' + this.val.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') + '"'; | 94 return '"' + this.val.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n').replace('\r', '\\r') + '"'; |
95 } | |
96 | |
97 listlit.prototype.toJS = function() { | |
98 var ret = '['; | |
99 each(this.val, function(idx, el) { | |
100 ret += (idx ? ', ' : '') + el.toJS(); | |
101 }); | |
102 return ret + ']'; | |
50 } | 103 } |
51 | 104 |
52 funcall.prototype.toJS = function() { | 105 funcall.prototype.toJS = function() { |
53 var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name; | 106 var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name; |
54 if (name == 'foreign') { | 107 if (name == 'foreign') { |
71 for (var i in args) { | 124 for (var i in args) { |
72 args[i] = args[i].toJS(); | 125 args[i] = args[i].toJS(); |
73 } | 126 } |
74 var rJS = receiver.toJS(true); | 127 var rJS = receiver.toJS(true); |
75 if ((name[name.length-1] == '!' && args.length == 1) || (funinfo && funinfo.def instanceof setter)) { | 128 if ((name[name.length-1] == '!' && args.length == 1) || (funinfo && funinfo.def instanceof setter)) { |
76 console.log(name.substr(0, name.length-1)); | 129 return '(' + rJS + '.' + escapeJSName(name.substr(0, name.length-1)) + ' = ' + args[0] + ', ' + rJS + ')'; |
77 return '(' + rJS + '.' + (new symbol(name.substr(0, name.length-1), this.symbols)).toJS() + ' = ' + args[0] + ', ' + rJS + ')' | 130 } else { |
78 } else { | 131 var callee = rJS + '.' + escapeJSName(name); |
79 var callee = rJS + '.' + (new symbol(name, this.symbols)).toJS(); | |
80 var callCode = callee + '(' + args.join(', ') + ')'; | 132 var callCode = callee + '(' + args.join(', ') + ')'; |
81 if (args.length == 0) { | 133 if (args.length == 0) { |
82 return '(' + callee + ' instanceof Function ? ' + callCode + ' : ' + callee + ')'; | 134 return '(' + callee + ' instanceof Function ? ' + callCode + ' : ' + callee + ')'; |
83 } else { | 135 } else { |
84 return callCode; | 136 return callCode; |
105 break; | 157 break; |
106 } | 158 } |
107 for (var i in args) { | 159 for (var i in args) { |
108 args[i] = args[i].toJS(); | 160 args[i] = args[i].toJS(); |
109 } | 161 } |
110 return ret + (new symbol(name, this.symbols)).toJS() + '(' + args.join(', ') + ')'; | 162 return ret + escapeJSName(name) + '(' + args.join(', ') + ')'; |
111 } | 163 } |
112 | 164 |
113 object.prototype.toJS = function() { | 165 object.prototype.toJS = function() { |
114 var messages = this.messages; | 166 var messages = this.messages; |
115 var compiled = [] | 167 var compiled = []; |
168 var imports = [] | |
116 for (var i in messages) { | 169 for (var i in messages) { |
117 var js = messages[i].toJSObject(); | 170 if (messages[i] instanceof funcall) { |
118 if (js) { | 171 if (messages[i].name == 'import:' && messages[i].args.length == 1) { |
119 compiled.push(indent(js)); | 172 imports.push({symbols: false, src: messages[i].args[0]}); |
120 } | 173 } else if(messages[i].name == 'import:from:' && messages[i].args.length == 2) { |
121 } | 174 var importsyms = []; |
122 return '{\n\tparent: ' + this.symbols.parentObject() + ',\n\t' + compiled.join(',\n\t') + '\n}'; | 175 each(messages[i].args[0].val, function(i, el) { |
176 if (!(el instanceof symbol)) { | |
177 throw new Error('Names in import:from statement must be symbols'); | |
178 } | |
179 importsyms.push(new strlit(el.name)); | |
180 }); | |
181 imports.push({symbols: new listlit(importsyms), src: messages[i].args[1]}); | |
182 } else { | |
183 throw new Error('Only import and import:from calls allowed in object context'); | |
184 } | |
185 } else { | |
186 var js = messages[i].toJSObject(); | |
187 if (js) { | |
188 compiled.push(indent(js)); | |
189 } | |
190 } | |
191 } | |
192 var pre = ''; | |
193 var post = ''; | |
194 for (var i = imports.length-1; i >= 0; i--) { | |
195 pre += 'doImport('; | |
196 post += ', ' + imports[i].src.toJS(); | |
197 if (imports[i].symbols) { | |
198 post += ', ' + imports[i].symbols.toJS(); | |
199 } | |
200 post += ')'; | |
201 } | |
202 return pre+'{\n\tparent: ' + this.symbols.parentObject() + ',\n\t' + compiled.join(',\n\t') + '\n}'+post; | |
123 } | 203 } |
124 | 204 |
125 object.prototype.toJSModule = function() { | 205 object.prototype.toJSModule = function() { |
126 this.populateSymbols(null); | 206 this.populateSymbols(null); |
127 return '(function () {\n\tvar module = ' + indent(this.toJS()) + ';\n\treturn module;\n})' | 207 return '(function () {\n\tvar module = ' + indent(this.toJS()) + ';\n\treturn module;\n})' |
182 assignment.prototype.toJSObject = function() { | 262 assignment.prototype.toJSObject = function() { |
183 var val = this.expression.toJS(); | 263 var val = this.expression.toJS(); |
184 if (val === null) { | 264 if (val === null) { |
185 return null; | 265 return null; |
186 } | 266 } |
187 return this.symbol.toJS() + ': ' + val; | 267 return escapeJSName(this.symbol.name) + ': ' + val; |
188 }; | 268 }; |