Mercurial > repos > tabletprog
comparison compiler.js @ 126:a2d2d8e09291
Merge
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 05 Aug 2013 23:37:17 -0700 |
parents | d715fb3c39ab |
children | d6e79885bd3b 18598163e3ef |
comparison
equal
deleted
inserted
replaced
125:6f8d868e8da0 | 126:a2d2d8e09291 |
---|---|
7 | 7 |
8 function modulefile(path, file) | 8 function modulefile(path, file) |
9 { | 9 { |
10 this.path = path; | 10 this.path = path; |
11 this.file = file; | 11 this.file = file; |
12 } | |
13 | |
14 modulefile.prototype.populateSymbols = function (toplevel) { | |
15 if (!this.ast) { | |
16 this.ast = parseFile(this.path + '/' + this.file); | |
17 this.ast.populateSymbols(toplevel); | |
18 } | |
19 }; | |
20 | |
21 modulefile.prototype.popuplateSymbolsAsync = function(toplevel, whenDone) { | |
22 if (!this.ast) { | |
23 var self = this; | |
24 get(this.path + '/' + this.file, function(data) { | |
25 self.ast = parser.parse(data.responseText); | |
26 self.ast.populateSymbols(toplevel); | |
27 whenDone(); | |
28 }); | |
29 } else { | |
30 whenDone(); | |
31 } | |
32 }; | |
33 | |
34 function getfileshtml(path, data, names) | |
35 { | |
36 var fakeEl = newEl("div", { | |
37 innerHTML: data.response | |
38 }); | |
39 each(qall('a', fakeEl), function(idx, a) { | |
40 var tpidx = a.textContent.indexOf('.tp'); | |
41 var modname = a.textContent.substr(0, tpidx); | |
42 if (tpidx > -1) { | |
43 names[modname] = new modulefile(path, modname + '.tp'); | |
44 } | |
45 }); | |
12 } | 46 } |
13 | 47 |
14 var toplevel = new topsymbols([]); | 48 var toplevel = new topsymbols([]); |
15 function topsymbols(moduledirs) | 49 function topsymbols(moduledirs) |
16 { | 50 { |
17 this.names = null; | 51 this.names = null; |
18 this.used = {}; | 52 this.used = {}; |
19 this.nextmodulenum = 0; | 53 this.nextmodulenum = 0; |
54 this.onready = null; | |
20 var self = this; | 55 var self = this; |
21 if (typeof window === "object") { | 56 if (typeof window === "object") { |
22 get('/src/', function(data) { | 57 get('/modules/', function(data) { |
23 self.names = {}; | 58 var names = {} |
24 var fakeEl = newEl("div", { | 59 getfileshtml('/modules', data, names); |
25 innerHTML: data.response | 60 get('/src/', function(data) { |
26 }); | 61 getfileshtml('/src', data, names); |
27 each(qall('a', fakeEl), function(idx, a) { | 62 self.names = names; |
28 var tpidx = a.textContent.indexOf('.tp'); | 63 if (self.onready) { |
29 if (tpidx > -1) { | 64 self.onready(); |
30 self.names[a.textContent.substr(0, tpidx)] = true; | |
31 } | 65 } |
32 }); | 66 }); |
33 }); | 67 }); |
34 } else { | 68 } else { |
35 this.names = {}; | 69 this.names = {}; |
55 type: 'toplevel', | 89 type: 'toplevel', |
56 def: this.names[name] | 90 def: this.names[name] |
57 }; | 91 }; |
58 } | 92 } |
59 return null; | 93 return null; |
60 } | 94 }; |
61 topsymbols.prototype.getEnvType = function() { | 95 topsymbols.prototype.getEnvType = function() { |
62 return 'void'; | 96 return 'void'; |
63 } | 97 }; |
64 topsymbols.prototype.moduleVar = function(name) { | 98 topsymbols.prototype.moduleVar = function(name) { |
65 if (!(name in this.names)) { | 99 if (!(name in this.names)) { |
66 throw new Error('symbol ' + name + ' not found at toplevel'); | 100 throw new Error('symbol ' + name + ' not found at toplevel'); |
67 } | 101 } |
68 if (name == 'true' || name == 'false') { | 102 if (name == 'true' || name == 'false') { |
70 } | 104 } |
71 if (!this.names[name].modulevar) { | 105 if (!this.names[name].modulevar) { |
72 this.names[name].modulevar = 'module_' + this.nextmodulenum++ | 106 this.names[name].modulevar = 'module_' + this.nextmodulenum++ |
73 } | 107 } |
74 return this.names[name].modulevar; | 108 return this.names[name].modulevar; |
75 } | 109 }; |
110 topsymbols.prototype.onReady = function(fun) { | |
111 if (this.names) { | |
112 fun(); | |
113 return; | |
114 } | |
115 if (!this.onready) { | |
116 this.onready = fun; | |
117 } else { | |
118 var oldready = this.onready; | |
119 this.onready = function() { | |
120 oldready(); | |
121 fun(); | |
122 }; | |
123 } | |
124 }; | |
76 | 125 |
77 function osymbols(parent) | 126 function osymbols(parent) |
78 { | 127 { |
79 this.parent = parent; | 128 this.parent = parent; |
80 this.names = {}; | 129 this.names = {}; |
130 this.llnames = {}; | |
81 this.needsenv = false; | 131 this.needsenv = false; |
82 this.typename = null; | 132 this.typename = null; |
83 this.needsparent = false; | 133 this.needsparent = false; |
84 } | 134 } |
85 osymbols.prototype.find = function(name, nestedcall) { | 135 osymbols.prototype.find = function(name, nestedcall, allowll) { |
86 debugprint('//osymbols.find', name + ', exists?:', name in this.names, ', nested?:', nestedcall); | 136 debugprint('//osymbols.find', name + ', exists?:', name in this.names, ', nested?:', nestedcall); |
87 if (name in this.names) { | 137 if (name in this.names) { |
88 if (this.names[name] instanceof funcall && this.names[name].name == 'foreign:') { | 138 if (this.names[name] instanceof funcall && this.names[name].name == 'foreign:') { |
89 return { | 139 return { |
90 type: 'foreign', | 140 type: 'foreign', |
91 def: this.names[name] | 141 def: this.names[name] |
92 }; | 142 }; |
93 } | 143 } |
94 var ret = { | 144 var ret = { |
95 type: 'self', | 145 type: 'self', |
146 isll: false, | |
96 def: this.names[name], | 147 def: this.names[name], |
97 selftype: this.typename | 148 selftype: this.typename |
98 }; | 149 }; |
150 } else if(allowll && name in this.llnames) { | |
151 return { | |
152 type: 'self', | |
153 isll: true, | |
154 selftype: this.typename | |
155 }; | |
99 } else if(this.parent) { | 156 } else if(this.parent) { |
100 var ret = this.parent.find(name, nestedcall); | 157 var ret = this.parent.find(name, nestedcall, allowll); |
101 if (ret) { | 158 if (ret) { |
102 if(ret.type == 'self') { | 159 if(ret.type == 'self') { |
103 ret.type = 'parent'; | 160 ret.type = 'parent'; |
104 ret.depth = 1; | 161 ret.depth = 1; |
105 this.needsparent = true; | 162 this.needsparent = true; |
117 return ret; | 174 return ret; |
118 }; | 175 }; |
119 osymbols.prototype.defineMsg = function(name, def) { | 176 osymbols.prototype.defineMsg = function(name, def) { |
120 this.names[name] = def; | 177 this.names[name] = def; |
121 } | 178 } |
179 osymbols.prototype.defineLLProperty = function(name) { | |
180 this.llnames[name] = true; | |
181 } | |
122 osymbols.prototype.parentObject = function() { | 182 osymbols.prototype.parentObject = function() { |
123 if (!this.parent) { | 183 if (!this.parent) { |
124 return 'null'; | 184 return 'null'; |
125 } | 185 } |
126 return 'this'; | 186 return 'this'; |
158 this.needsSelfVar = false; | 218 this.needsSelfVar = false; |
159 this.passthruenv = false; | 219 this.passthruenv = false; |
160 this.envtype = 'void'; | 220 this.envtype = 'void'; |
161 this.needsParentEnv = false; | 221 this.needsParentEnv = false; |
162 } | 222 } |
163 lsymbols.prototype.find = function(name, nestedcall) { | 223 lsymbols.prototype.find = function(name, nestedcall, allowll) { |
164 debugprint('//lsymbols.find', name + ', exists?:', name in this.names, ', nested?:', nestedcall); | 224 debugprint('//lsymbols.find', name + ', exists?:', name in this.names, ', nested?:', nestedcall); |
165 if (name in this.names) { | 225 if (name in this.names) { |
166 if (this.names[name] instanceof funcall && this.names[name].name == 'foreign:') { | 226 if (this.names[name] instanceof funcall && this.names[name].name == 'foreign:') { |
167 var ret = { | 227 var ret = { |
168 type: 'foreign', | 228 type: 'foreign', |
185 isdeclared: (name in this.declared) | 245 isdeclared: (name in this.declared) |
186 }; | 246 }; |
187 } | 247 } |
188 } | 248 } |
189 } else if(this.parent) { | 249 } else if(this.parent) { |
190 var ret = this.parent.find(name, true); | 250 var ret = this.parent.find(name, true, allowll); |
191 if (ret) { | 251 if (ret) { |
192 if (ret.type == 'closedover') { | 252 if (ret.type == 'closedover') { |
193 ret.type = 'upvar'; | 253 ret.type = 'upvar'; |
194 ret.depth = 0; | 254 ret.depth = 0; |
195 } | 255 } |
260 | 320 |
261 var mainModule; | 321 var mainModule; |
262 | 322 |
263 function toobj(val) | 323 function toobj(val) |
264 { | 324 { |
265 switch(typeof val) | 325 return (typeof val == "boolean") ? (val ? module_true : module_false) : val; |
266 { | |
267 case 'boolean': | |
268 if(val) { | |
269 return mainModule.strue; | |
270 } else { | |
271 return mainModule.sfalse; | |
272 } | |
273 case 'number': | |
274 return mainModule.snumber(val); | |
275 } | |
276 throw new Error("can't make val into object"); | |
277 } | 326 } |
278 | 327 |
279 op.prototype.populateSymbols = function(symbols, isReceiver) { | 328 op.prototype.populateSymbols = function(symbols, isReceiver) { |
280 this.left.populateSymbols(symbols); | 329 this.left.populateSymbols(symbols); |
330 if (this.op == '&&' || this.op == '||') { | |
331 //&& and || are syntactic sugar for if and ifnot with | |
332 //the second argument transformed into a lambda to | |
333 //achieve short-circuit evalutation | |
334 this.right = new lambda([], [this.right]); | |
335 } | |
281 this.right.populateSymbols(symbols); | 336 this.right.populateSymbols(symbols); |
282 }; | 337 }; |
283 | 338 |
284 symbol.prototype.populateSymbols = function(symbols) { | 339 symbol.prototype.populateSymbols = function(symbols) { |
285 this.symbols = symbols; | 340 this.symbols = symbols; |
309 this.val[i].populateSymbols(symbols); | 364 this.val[i].populateSymbols(symbols); |
310 } | 365 } |
311 } | 366 } |
312 | 367 |
313 funcall.prototype.populateSymbols = function(symbols) { | 368 funcall.prototype.populateSymbols = function(symbols) { |
369 var isll = false; | |
314 if (this.name == 'foreign:') { | 370 if (this.name == 'foreign:') { |
315 if ((this.args[0] instanceof lambda) || (this.args[0] instanceof object) || (this.args[0] instanceof symbol)) { | 371 if ((this.args[0] instanceof lambda) || (this.args[0] instanceof object) || (this.args[0] instanceof symbol)) { |
316 return; | 372 return; |
317 } else { | 373 } else { |
318 throw new Error("Unexpected AST type for foreign:"); | 374 throw new Error("Unexpected AST type for foreign:"); |
319 } | 375 } |
376 } else if (this.name == 'llProperty:withType:') { | |
377 if (this.args[0] instanceof symbol) { | |
378 if ((this.args[1] instanceof symbol) || (this.args[1] instanceof funcall)) { | |
379 symbols.defineLLProperty(this.args[0].name); | |
380 return; | |
381 } else { | |
382 throw new Error("Second argument to llProperty:withType: must be a symbol or funcall"); | |
383 } | |
384 } else { | |
385 throw new Error("First argument to llProperty:withType: must be a symbol"); | |
386 } | |
387 } else if (this.name == 'llMessage:withVars:andCode:') { | |
388 if (this.args[0] instanceof symbol) { | |
389 if (this.args[1] instanceof lambda) { | |
390 if (this.args[2] instanceof lambda) { | |
391 symbols.defineMsg(this.args[0].name, this.args[2]); | |
392 isll = true; | |
393 } else { | |
394 throw new Error("Third argument to llMessage:withVars:andCode: must be a lambda"); | |
395 } | |
396 } else { | |
397 throw new Error("Second argument to llMessage:withVars:andCode: must be a lambda"); | |
398 } | |
399 } else { | |
400 throw new Error("First argument to llMessage:withVars:andCode: must be a symbol"); | |
401 } | |
320 } | 402 } |
321 this.symbols = symbols; | 403 this.symbols = symbols; |
322 var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name; | 404 var name = this.name[this.name.length-1] == ':' ? this.name.substr(0, this.name.length-1) : this.name; |
323 var funinfo = symbols.find(name); | 405 var funinfo = symbols.find(name); |
324 if (funinfo && (funinfo.type == 'self' || funinfo.type == 'parent')) { | 406 if (funinfo && (funinfo.type == 'self' || funinfo.type == 'parent')) { |
325 symbols.find('self'); | 407 symbols.find('self'); |
326 } | 408 } |
327 for (var i in this.args) { | 409 for (var i in this.args) { |
328 this.args[i].populateSymbols(symbols); | 410 this.args[i].populateSymbols(symbols, undefined, isll); |
329 } | 411 } |
330 if (this.receiver) { | 412 if (this.receiver) { |
331 this.receiver.populateSymbols(symbols); | 413 this.receiver.populateSymbols(symbols, undefined, isll); |
332 } | 414 } |
333 } | 415 } |
334 | 416 |
335 funcall.prototype.populateSymbolsObject = function(symbols) { | 417 funcall.prototype.populateSymbolsObject = function(symbols) { |
336 this.populateSymbols(symbols.parent); | 418 this.populateSymbols(symbols); |
337 } | 419 } |
338 | 420 |
339 object.prototype.populateSymbols = function(symbols) { | 421 object.prototype.populateSymbols = function(symbols) { |
340 symbols = new osymbols(symbols); | 422 var symbols = new osymbols(symbols); |
341 for (var i in this.messages) { | 423 for (var i in this.messages) { |
342 this.messages[i].populateSymbolsObject(symbols); | 424 this.messages[i].populateSymbolsObject(symbols); |
343 } | 425 } |
344 this.symbols = symbols; | 426 this.symbols = symbols; |
345 } | 427 } |
346 | 428 var lambdanum = 0; |
347 lambda.prototype.populateSymbols = function(symbols, isobject) { | 429 lambda.prototype.populateSymbols = function(symbols, isobject, isll) { |
430 if (!isll) { | |
431 this.name = 'lambda_' + lambdanum++; | |
432 } | |
348 var args = this.args ? this.args.slice(0, this.args.length) : []; | 433 var args = this.args ? this.args.slice(0, this.args.length) : []; |
349 var exprs = this.expressions; | 434 var exprs = this.expressions; |
350 var symbols = new lsymbols(symbols); | 435 var symbols = new lsymbols(symbols); |
351 for (var i in args) { | 436 for (var i in args) { |
352 symbols.defineVar(args[i].cleanName(), null); | 437 symbols.defineVar(args[i].cleanName(), null); |
392 function getter(fun) | 477 function getter(fun) |
393 { | 478 { |
394 this.fun = fun; | 479 this.fun = fun; |
395 } | 480 } |
396 getter.prototype.args = [new symbol('self')]; | 481 getter.prototype.args = [new symbol('self')]; |
482 |