yhara-tickets 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +20 -0
- data/TODO +61 -0
- data/bin/tickets-server +101 -0
- data/db/migrate/001_create_tickets.rb +14 -0
- data/db/migrate/002_add_deleted_to_tickets.rb +13 -0
- data/db/migrate/003_add_timeouted_to_tickets.rb +13 -0
- data/dot.tickets.conf.sample +9 -0
- data/model/ticket.rb +36 -0
- data/public/biwascheme/MIT-LICENSE.txt +20 -0
- data/public/biwascheme/README +38 -0
- data/public/biwascheme/lib/biwascheme.js +101 -0
- data/public/biwascheme/lib/extra_lib.js +513 -0
- data/public/biwascheme/lib/io.js +326 -0
- data/public/biwascheme/lib/prototype.js +4320 -0
- data/public/biwascheme/lib/r6rs_lib.js +2388 -0
- data/public/biwascheme/lib/stackbase.js +1798 -0
- data/public/biwascheme/lib/webscheme_lib.js +762 -0
- data/public/js/builder.js +136 -0
- data/public/js/controls.js +965 -0
- data/public/js/dragdrop.js +975 -0
- data/public/js/effects.js +1130 -0
- data/public/js/scriptaculous.js +60 -0
- data/public/js/slider.js +275 -0
- data/public/js/sound.js +55 -0
- data/public/js/unittest.js +568 -0
- data/public/scm/main.scm +65 -0
- data/public/scm/ticket.scm +98 -0
- data/tickets.gemspec +41 -0
- data/view/index.xhtml +61 -0
- metadata +121 -0
@@ -0,0 +1,1798 @@
|
|
1
|
+
//
|
2
|
+
// Heap based scheme from 3imp.pdf
|
3
|
+
//
|
4
|
+
|
5
|
+
// default definition of puts: should be overriden for console interpreters
|
6
|
+
function puts(str, no_newline){
|
7
|
+
var text = (str + (no_newline ? "" : "\n")).escapeHTML();
|
8
|
+
var span = document.createElement("span");
|
9
|
+
span.innerHTML = text.replace(/\n/g,"<br>").replace(/ /g," ");
|
10
|
+
$('bs-console').insert(span);
|
11
|
+
}
|
12
|
+
function p(/*args*/){
|
13
|
+
puts("p> "+$A(arguments).map(Object.inspect).join(" "));
|
14
|
+
}
|
15
|
+
|
16
|
+
if( typeof(BiwaScheme)!='object' ) BiwaScheme={}; with(BiwaScheme) {
|
17
|
+
/* --------------------------------------- namespace webscheme */
|
18
|
+
|
19
|
+
//
|
20
|
+
// javascript extention
|
21
|
+
//
|
22
|
+
|
23
|
+
// Object.prototype.inspect = function() {
|
24
|
+
// var a = [];
|
25
|
+
// for(var k in this){
|
26
|
+
// //if(this.prototype[k]) continue;
|
27
|
+
// a.push( k.toString() );//+" => "+this[k].toString() );
|
28
|
+
// }
|
29
|
+
// return "#<Object{"+a.join(",")+"}>";
|
30
|
+
// }
|
31
|
+
Function.prototype.to_write = function() {
|
32
|
+
return "#<Function "+(this.fname ? this.fname : this.toSource().truncate(40))+">";
|
33
|
+
}
|
34
|
+
String.prototype.to_write = function(){
|
35
|
+
return '"' +
|
36
|
+
this.replace(/\\|\"/g,function($0){return'\\'+$0;})
|
37
|
+
.replace(/\x07/g, "\\a")
|
38
|
+
.replace(/\x08/g, "\\b")
|
39
|
+
.replace(/\t/g, "\\t")
|
40
|
+
.replace(/\n/g, "\\n")
|
41
|
+
.replace(/\v/g, "\\v")
|
42
|
+
.replace(/\f/g, "\\f")
|
43
|
+
.replace(/\r/g, "\\r") +
|
44
|
+
'"';
|
45
|
+
}
|
46
|
+
//Number.prototype.inspect = function() { return this.toString(); }
|
47
|
+
Array.prototype.to_write = function(){
|
48
|
+
var a = [];
|
49
|
+
for(var i=0; i<this.length; i++)
|
50
|
+
a.push(to_write(this[i]));
|
51
|
+
return '#(' + a.join(" ") + ')';
|
52
|
+
}
|
53
|
+
Array.prototype.to_list = function(){
|
54
|
+
var list = nil;
|
55
|
+
for(var i=this.length-1; i>=0; i--){
|
56
|
+
list = new Pair(this[i], list);
|
57
|
+
}
|
58
|
+
return list;
|
59
|
+
}
|
60
|
+
// Array.prototype.memq = function(x){
|
61
|
+
// for(var i=this.length-1; i>=0; i--){
|
62
|
+
// if(this[i] === x)
|
63
|
+
// return true;
|
64
|
+
// }
|
65
|
+
// return false;
|
66
|
+
// }
|
67
|
+
|
68
|
+
//
|
69
|
+
// utility functions
|
70
|
+
//
|
71
|
+
BiwaScheme.to_write = function(obj){
|
72
|
+
if(obj === undefined)
|
73
|
+
return "undefined";
|
74
|
+
else if(typeof(obj.to_write) == 'function')
|
75
|
+
return obj.to_write();
|
76
|
+
else if(isNaN(obj) && typeof(obj) == 'number')
|
77
|
+
return "+nan.0";
|
78
|
+
else{
|
79
|
+
switch(obj){
|
80
|
+
case true: return "#t";
|
81
|
+
case false: return "#f";
|
82
|
+
case nil: return "()";
|
83
|
+
case Infinity: return "+inf.0";
|
84
|
+
case -Infinity: return "-inf.0";
|
85
|
+
}
|
86
|
+
}
|
87
|
+
return Object.inspect(obj);
|
88
|
+
}
|
89
|
+
BiwaScheme.to_display = function(obj){
|
90
|
+
if(typeof(obj.valueOf()) == "string")
|
91
|
+
return obj;
|
92
|
+
else if(obj instanceof Symbol)
|
93
|
+
return obj.name;
|
94
|
+
else if(obj instanceof Array)
|
95
|
+
return '#(' + obj.map(function(x){ return to_display(x) }).join(' ') + ')';
|
96
|
+
else if(obj instanceof Pair)
|
97
|
+
return obj.inspect(to_display);
|
98
|
+
else if(obj instanceof Char)
|
99
|
+
return obj.value;
|
100
|
+
else
|
101
|
+
return to_write(obj);
|
102
|
+
}
|
103
|
+
|
104
|
+
// write/ss (write with substructure)
|
105
|
+
// example: > (let ((x (list 'a))) (list x x)) // (#0=(a) #0#)
|
106
|
+
// 2-pass algorithm.
|
107
|
+
// (1) detect all the objects which appears more than once
|
108
|
+
// (find_cyclic, reduce_cyclic_info)
|
109
|
+
// (2) write object using this information
|
110
|
+
// * add prefix '#n=' for first appearance
|
111
|
+
// * just write '#n#' for other appearance
|
112
|
+
|
113
|
+
//TODO: support Values
|
114
|
+
BiwaScheme.write_ss = function(obj, array_mode){
|
115
|
+
var known = [obj], used = [false];
|
116
|
+
find_cyclic(obj, known, used);
|
117
|
+
var cyclic = reduce_cyclic_info(known, used);
|
118
|
+
var appeared = new Array(cyclic.length);
|
119
|
+
for(var i=cyclic.length-1; i>=0; i--) appeared[i] = false;
|
120
|
+
|
121
|
+
return to_write_ss(obj, cyclic, appeared, array_mode);
|
122
|
+
}
|
123
|
+
BiwaScheme.to_write_ss = function(obj, cyclic, appeared, array_mode){
|
124
|
+
var ret = "";
|
125
|
+
var i = cyclic.indexOf(obj);
|
126
|
+
if(i >= 0){
|
127
|
+
if(appeared[i]){
|
128
|
+
return "#"+i+"#";
|
129
|
+
}
|
130
|
+
else{
|
131
|
+
appeared[i] = true;
|
132
|
+
ret = "#"+i+"=";
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
if(obj instanceof Pair && obj != nil){
|
137
|
+
var a = [];
|
138
|
+
a.push(to_write_ss(obj.car, cyclic, appeared, array_mode));
|
139
|
+
for(var o=obj.cdr; o != nil; o=o.cdr){
|
140
|
+
if(!(o instanceof Pair) || cyclic.indexOf(o) >= 0){
|
141
|
+
a.push(".");
|
142
|
+
a.push(to_write_ss(o, cyclic, appeared, array_mode));
|
143
|
+
break;
|
144
|
+
}
|
145
|
+
a.push(to_write_ss(o.car, cyclic, appeared, array_mode));
|
146
|
+
}
|
147
|
+
ret += "(" + a.join(" ") + ")";
|
148
|
+
}
|
149
|
+
else if(obj instanceof Array){
|
150
|
+
var a = obj.map(function(item){
|
151
|
+
return to_write_ss(item, cyclic, appeared, array_mode);
|
152
|
+
})
|
153
|
+
if(array_mode)
|
154
|
+
ret += "[" + a.join(", ") + "]";
|
155
|
+
else
|
156
|
+
ret += "#(" + a.join(" ") + ")";
|
157
|
+
}
|
158
|
+
else{
|
159
|
+
ret += to_write(obj);
|
160
|
+
}
|
161
|
+
return ret;
|
162
|
+
}
|
163
|
+
BiwaScheme.reduce_cyclic_info = function(known, used){
|
164
|
+
var n_used = 0;
|
165
|
+
for(var i=0; i<used.length; i++){
|
166
|
+
if(used[i]){
|
167
|
+
known[n_used] = known[i];
|
168
|
+
n_used++;
|
169
|
+
}
|
170
|
+
}
|
171
|
+
return known.slice(0, n_used);
|
172
|
+
}
|
173
|
+
BiwaScheme.find_cyclic = function(obj, known, used){
|
174
|
+
var items = (obj instanceof Pair) ? [obj.car, obj.cdr] :
|
175
|
+
(obj instanceof Array) ? obj :
|
176
|
+
null;
|
177
|
+
if(!items) return;
|
178
|
+
|
179
|
+
items.each(function(item){
|
180
|
+
if(typeof(item)=='number' || typeof(item)=='string' ||
|
181
|
+
item === undef || item === true || item === false ||
|
182
|
+
item === nil || item instanceof Symbol) return;
|
183
|
+
|
184
|
+
var i = known.indexOf(item);
|
185
|
+
if(i >= 0)
|
186
|
+
used[i] = true;
|
187
|
+
else{
|
188
|
+
known.push(item);
|
189
|
+
used.push(false);
|
190
|
+
find_cyclic(item, known, used);
|
191
|
+
}
|
192
|
+
});
|
193
|
+
}
|
194
|
+
|
195
|
+
//
|
196
|
+
// variables
|
197
|
+
//
|
198
|
+
BiwaScheme.TopEnv = {};
|
199
|
+
BiwaScheme.CoreEnv = {};
|
200
|
+
|
201
|
+
// (eof-object)
|
202
|
+
BiwaScheme.eof = new Object;
|
203
|
+
|
204
|
+
//
|
205
|
+
// Set - set of string
|
206
|
+
// contents must be string (or at least sortable)
|
207
|
+
//
|
208
|
+
BiwaScheme.Set = Class.create({
|
209
|
+
initialize : function(/*args*/){
|
210
|
+
this.arr = [];
|
211
|
+
var i;
|
212
|
+
for(i=0; i<arguments.length; i++)
|
213
|
+
this.arr[i] = arguments[i];
|
214
|
+
},
|
215
|
+
|
216
|
+
equals : function(other){
|
217
|
+
if(this.arr.length != other.arr.length)
|
218
|
+
return false;
|
219
|
+
|
220
|
+
var a1 = this.arr.clone();
|
221
|
+
var a2 = other.arr.clone();
|
222
|
+
a1.sort();
|
223
|
+
a2.sort();
|
224
|
+
for(var i=0; i<this.arr.length; i++){
|
225
|
+
if(a1[i] != a2[i]) return false;
|
226
|
+
}
|
227
|
+
return true;
|
228
|
+
},
|
229
|
+
set_cons : function(item){
|
230
|
+
var o = new Set(item);
|
231
|
+
o.arr = this.arr.clone();
|
232
|
+
o.arr.push(item);
|
233
|
+
return o;
|
234
|
+
},
|
235
|
+
set_union : function(/*args*/){
|
236
|
+
var o = new Set();
|
237
|
+
o.arr = this.arr.clone();
|
238
|
+
|
239
|
+
for(var k=0; k<arguments.length; k++){
|
240
|
+
var s2 = arguments[k];
|
241
|
+
if(!s2 instanceof Set) throw new Error("set_union: arguments must be a set");
|
242
|
+
for(var i=0; i<s2.arr.length; i++)
|
243
|
+
o.add(s2.arr[i]);
|
244
|
+
}
|
245
|
+
return o;
|
246
|
+
},
|
247
|
+
set_intersect : function(s2){
|
248
|
+
if(!s2 instanceof Set) throw new Error("set_union: arguments must be a set");
|
249
|
+
var o = new Set();
|
250
|
+
for(var i=0; i<this.arr.length; i++)
|
251
|
+
if(s2.member(this.arr[i]))
|
252
|
+
o.add(this.arr[i]);
|
253
|
+
return o;
|
254
|
+
},
|
255
|
+
set_minus : function(s2){
|
256
|
+
if(!s2 instanceof Set) throw new Error("set_union: arguments must be a set");
|
257
|
+
var o = new Set();
|
258
|
+
for(var i=0; i<this.arr.length; i++)
|
259
|
+
if(!s2.member(this.arr[i]))
|
260
|
+
o.add(this.arr[i]);
|
261
|
+
return o;
|
262
|
+
},
|
263
|
+
add : function(item){
|
264
|
+
if(!this.member(item)){
|
265
|
+
this.arr.push(item);
|
266
|
+
}
|
267
|
+
},
|
268
|
+
member : function(item){
|
269
|
+
for(var i=0; i<this.arr.length; i++)
|
270
|
+
if(this.arr[i] == item) return true;
|
271
|
+
|
272
|
+
return false;
|
273
|
+
},
|
274
|
+
rindex : function(item){
|
275
|
+
for(var i=this.arr.length-1; i>=0 ; i--)
|
276
|
+
if(this.arr[i] == item) return (this.arr.length-1-i);
|
277
|
+
|
278
|
+
return null;
|
279
|
+
},
|
280
|
+
index : function(item){
|
281
|
+
for(var i=0; i<this.arr.length; i++)
|
282
|
+
if(this.arr[i] == item) return i;
|
283
|
+
|
284
|
+
return null;
|
285
|
+
},
|
286
|
+
inspect : function(){
|
287
|
+
return "Set(" + this.arr.join(", ") + ")";
|
288
|
+
},
|
289
|
+
toString : function(){
|
290
|
+
return this.inspect();
|
291
|
+
},
|
292
|
+
size : function(){
|
293
|
+
return this.arr.length;
|
294
|
+
}
|
295
|
+
});
|
296
|
+
|
297
|
+
//
|
298
|
+
// Classes
|
299
|
+
//
|
300
|
+
|
301
|
+
BiwaScheme.Error = Class.create({
|
302
|
+
initialize: function(msg){
|
303
|
+
this.message = "Error: "+msg;
|
304
|
+
},
|
305
|
+
toString: function(){
|
306
|
+
return this.message;
|
307
|
+
}
|
308
|
+
});
|
309
|
+
|
310
|
+
BiwaScheme.Bug = Class.create(Object.extend(new Error(), {
|
311
|
+
initialize: function(msg){
|
312
|
+
this.message = "[BUG] "+msg;
|
313
|
+
}
|
314
|
+
}));
|
315
|
+
|
316
|
+
//
|
317
|
+
// Pair
|
318
|
+
// cons cell
|
319
|
+
//
|
320
|
+
|
321
|
+
BiwaScheme.Pair = Class.create({
|
322
|
+
initialize: function(car, cdr){
|
323
|
+
this.car = car;
|
324
|
+
this.cdr = cdr;
|
325
|
+
},
|
326
|
+
|
327
|
+
caar: function(){ return this.car.car; },
|
328
|
+
cadr: function(){ return this.cdr.car; },
|
329
|
+
cdar: function(){ return this.cdr.car; },
|
330
|
+
cddr: function(){ return this.cdr.cdr; },
|
331
|
+
|
332
|
+
first: function(){ return this.car; },
|
333
|
+
second: function(){ return this.cdr.car; },
|
334
|
+
third: function(){ return this.cdr.cdr.car; },
|
335
|
+
fourth: function(){ return this.cdr.cdr.cdr.car; },
|
336
|
+
fifth: function(){ return this.cdr.cdr.cdr.cdr.car; },
|
337
|
+
|
338
|
+
// returns array containing all the car's of list
|
339
|
+
// '(1 2 3) => [1,2,3]
|
340
|
+
// '(1 2 . 3) => [1,2]
|
341
|
+
to_array: function(){
|
342
|
+
var ary = [];
|
343
|
+
for(var o = this; o instanceof Pair && o != nil; o=o.cdr){
|
344
|
+
ary.push(o.car);
|
345
|
+
}
|
346
|
+
return ary;
|
347
|
+
},
|
348
|
+
|
349
|
+
to_set: function(){
|
350
|
+
var set = new Set();
|
351
|
+
for(var o = this; o instanceof Pair && o != nil; o=o.cdr){
|
352
|
+
set.add(o.car);
|
353
|
+
}
|
354
|
+
return set;
|
355
|
+
},
|
356
|
+
|
357
|
+
length: function(){
|
358
|
+
var n = 0;
|
359
|
+
for(var o = this; o instanceof Pair && o != nil; o=o.cdr){
|
360
|
+
n++;
|
361
|
+
}
|
362
|
+
return n;
|
363
|
+
},
|
364
|
+
|
365
|
+
// calls the given func passing each car of list
|
366
|
+
// returns cdr of last Pair
|
367
|
+
foreach: function(func){
|
368
|
+
for(var o = this; o instanceof Pair && o != nil; o=o.cdr){
|
369
|
+
func(o.car);
|
370
|
+
}
|
371
|
+
return o;
|
372
|
+
},
|
373
|
+
|
374
|
+
// returns human-redable string of pair
|
375
|
+
inspect: function(conv){
|
376
|
+
conv || (conv = Object.inspect);
|
377
|
+
var a = [];
|
378
|
+
var last = this.foreach(function(o){
|
379
|
+
a.push(conv(o));
|
380
|
+
});
|
381
|
+
if(last != nil){
|
382
|
+
a.push(".");
|
383
|
+
a.push(conv(last));
|
384
|
+
}
|
385
|
+
return "(" + a.join(" ") + ")";
|
386
|
+
},
|
387
|
+
toString : function(){
|
388
|
+
return this.inspect();
|
389
|
+
},
|
390
|
+
|
391
|
+
to_write: function(){
|
392
|
+
return this.inspect(BiwaScheme.to_write);
|
393
|
+
}
|
394
|
+
});
|
395
|
+
BiwaScheme.List = function(){
|
396
|
+
return $A(arguments).to_list();
|
397
|
+
}
|
398
|
+
|
399
|
+
//
|
400
|
+
// Values
|
401
|
+
//
|
402
|
+
BiwaScheme.Values = Class.create({
|
403
|
+
initialize: function(values){
|
404
|
+
this.content = values;
|
405
|
+
},
|
406
|
+
to_write: function(){
|
407
|
+
return "#<Values " + this.content.map(function(x){ return to_write(x) }).join(" ") + ">";
|
408
|
+
}
|
409
|
+
});
|
410
|
+
|
411
|
+
//
|
412
|
+
// Dumper - graphical state dumper
|
413
|
+
//
|
414
|
+
|
415
|
+
BiwaScheme.Dumper = Class.create({
|
416
|
+
initialize: function(){
|
417
|
+
},
|
418
|
+
|
419
|
+
is_opc: function(obj){
|
420
|
+
return (obj instanceof Array && typeof(obj[0]) == 'string');
|
421
|
+
},
|
422
|
+
|
423
|
+
dump_pad: " ",
|
424
|
+
dump_opc: function(obj, level){
|
425
|
+
var s="";
|
426
|
+
var pad1="", pad2="";
|
427
|
+
var level = level || 0;
|
428
|
+
level.times(function(){ pad1 += this.dump_pad; }.bind(this));
|
429
|
+
(level+1).times(function(){ pad2 += this.dump_pad; }.bind(this));
|
430
|
+
|
431
|
+
s += pad1 + '[<span class="dump_opecode">' + obj[0] + '</span>';
|
432
|
+
var i = 1;
|
433
|
+
while(!(obj[i] instanceof Array) && i<obj.length){
|
434
|
+
if(obj[0] == "constant")
|
435
|
+
s += " <span class='dump_constant'>" + this.dump_obj(obj[i]) + "</span>";
|
436
|
+
else
|
437
|
+
s += " " + this.dump_obj(obj[i]);
|
438
|
+
i++;
|
439
|
+
}
|
440
|
+
if(i < obj.length) s += '<br>\n';
|
441
|
+
for(; i<obj.length; i++){
|
442
|
+
if(this.is_opc(obj[i])){
|
443
|
+
s += this.dump_opc(obj[i], (i == obj.length-1 ? level : level+1));
|
444
|
+
}
|
445
|
+
else{
|
446
|
+
s += (i == obj.length-1) ? pad1 : pad2;
|
447
|
+
s += this.dump_obj(obj[i]); //String(obj[i]).escapeHTML();
|
448
|
+
}
|
449
|
+
if(i != obj.length-1) s += "<br>\n";
|
450
|
+
}
|
451
|
+
s += "]";
|
452
|
+
return (level==0 ? this.add_fold(s) : s);
|
453
|
+
},
|
454
|
+
|
455
|
+
fold_limit: 20,
|
456
|
+
n_folds: 0,
|
457
|
+
add_fold: function(s){
|
458
|
+
var lines = s.split(/<br>/gmi);
|
459
|
+
|
460
|
+
if(lines.length > this.fold_limit){
|
461
|
+
var fold_btn = " <span style='text-decoration:underline; color:blue; cursor:pointer;'" +
|
462
|
+
"onclick='BiwaScheme.Dumper.toggle_fold("+this.n_folds+")'>more</span>"
|
463
|
+
var fold_start = "<div style='display:none' id='fold"+this.n_folds+"'>";
|
464
|
+
var fold_end = "</div>"
|
465
|
+
this.n_folds++;
|
466
|
+
return lines.slice(0, this.fold_limit).join("<br>") + fold_btn +
|
467
|
+
fold_start + lines.slice(this.fold_limit+1).join("<br>") + fold_end;
|
468
|
+
}
|
469
|
+
else{
|
470
|
+
return s;
|
471
|
+
}
|
472
|
+
},
|
473
|
+
|
474
|
+
stack_max_len: 80,
|
475
|
+
dump_stack: function(stk, size){
|
476
|
+
if(stk === null || stk === undefined) return Object.inspect(stk)
|
477
|
+
var s = "<table>";
|
478
|
+
for(var i=stk.length-1; i >= 0; i--){
|
479
|
+
if(i < size){
|
480
|
+
s += "<tr><td class='dump_stknum'>[" + i + "]</td>" +
|
481
|
+
"<td>" + this.dump_obj(stk[i]).truncate(this.stack_max_len) + "</td></tr>";
|
482
|
+
}
|
483
|
+
else{
|
484
|
+
s += "<tr><td class='dump_dead'>[" + i + "]</td>" +
|
485
|
+
"<td class='dump_dead'>" + this.dump_obj(stk[i]).truncate(this.stack_max_len) + "</td></tr>";
|
486
|
+
}
|
487
|
+
}
|
488
|
+
return s + "</table>";
|
489
|
+
},
|
490
|
+
|
491
|
+
dump_object: function(obj){
|
492
|
+
var a = [];
|
493
|
+
for(var k in obj){
|
494
|
+
//if(this.prototype[k]) continue;
|
495
|
+
a.push( k.toString() );//+" => "+this[k].toString() );
|
496
|
+
}
|
497
|
+
return "#<Object{"+a.join(",")+"}>";
|
498
|
+
},
|
499
|
+
|
500
|
+
closures: [],
|
501
|
+
dump_closure: function(cls){
|
502
|
+
if(cls.length == 0) return "[]";
|
503
|
+
|
504
|
+
var cls_num = null;
|
505
|
+
for(var i=0; i<this.closures.length; i++){
|
506
|
+
if(this.closures[i] == cls) cls_num = i;
|
507
|
+
}
|
508
|
+
if(cls_num == null){
|
509
|
+
cls_num = this.closures.length;
|
510
|
+
this.closures.push(cls);
|
511
|
+
}
|
512
|
+
|
513
|
+
var c = cls.clone ? cls.clone() : [c];
|
514
|
+
var body = c.shift();
|
515
|
+
return "c"+cls_num+" <span class='dump_closure'>free vars :</span> " + this.dump_obj(c) + " <span class='dump_closure'>body :</span> " + this.dump_obj(body).truncate(100);
|
516
|
+
},
|
517
|
+
|
518
|
+
dump_obj: function(obj){
|
519
|
+
if(obj && typeof(obj.to_html) == 'function')
|
520
|
+
return obj.to_html();
|
521
|
+
else{
|
522
|
+
var s = write_ss(obj, true); //true=Array mode
|
523
|
+
if(s == "[object Object]") s = this.dump_object(obj);
|
524
|
+
return s.escapeHTML();
|
525
|
+
}
|
526
|
+
},
|
527
|
+
|
528
|
+
n_dumps: 0,
|
529
|
+
dump: function(obj){
|
530
|
+
var dumpitem = document.createElement("div");
|
531
|
+
var s = "";
|
532
|
+
if(obj instanceof Hash){
|
533
|
+
s += "<table>"
|
534
|
+
s += "<tr><td colspan='4'>#"+this.n_dumps+"</td></tr>"
|
535
|
+
obj.each(function(pair){
|
536
|
+
if(pair.key!="x" && pair.key != "stack"){
|
537
|
+
var value = (pair.key=="c" ? this.dump_closure(pair.value) : this.dump_obj(pair.value))
|
538
|
+
s += "<tr><td>" + pair.key + ": </td><td colspan='3'>" + value + "</td></tr>";
|
539
|
+
}
|
540
|
+
}.bind(this));
|
541
|
+
s += "<tr><td>x:</td><td>" + (this.is_opc(obj.get("x")) ? this.dump_opc(obj.get("x")) : this.dump_obj(obj.get("x"))) + "</td>";
|
542
|
+
s += "<td style='border-left: 1px solid black'>stack:</td><td>" + this.dump_stack(obj.get("stack"), obj.get("s")) + "</td></tr>";
|
543
|
+
s += "</table>";
|
544
|
+
}
|
545
|
+
else{
|
546
|
+
s = Object.inspect(obj).escapeHTML() + "<br>\n";
|
547
|
+
}
|
548
|
+
dumpitem.id = "dump" + this.n_dumps;
|
549
|
+
dumpitem.innerHTML = s;
|
550
|
+
$('dumparea').appendChild(dumpitem);
|
551
|
+
Element.hide(dumpitem);
|
552
|
+
this.n_dumps++;
|
553
|
+
},
|
554
|
+
|
555
|
+
cur: -1,
|
556
|
+
dump_move: function(dir){
|
557
|
+
if(0 <= this.cur && this.cur < this.n_dumps)
|
558
|
+
Element.hide($("dump"+this.cur));
|
559
|
+
|
560
|
+
if(0 <= this.cur+dir && this.cur+dir < this.n_dumps)
|
561
|
+
this.cur += dir;
|
562
|
+
|
563
|
+
Element.show($("dump"+this.cur));
|
564
|
+
},
|
565
|
+
|
566
|
+
is_folded: true,
|
567
|
+
dump_toggle_fold: function(){
|
568
|
+
if(this.is_folded){ //open all
|
569
|
+
for(var i=0; i<this.n_dumps; i++)
|
570
|
+
Element.show($("dump"+i));
|
571
|
+
}
|
572
|
+
else{ //close all
|
573
|
+
for(var i=0; i<this.n_dumps; i++)
|
574
|
+
if(i!=this.cur) Element.hide($("dump"+i));
|
575
|
+
}
|
576
|
+
this.is_folded = (!this.is_folded);
|
577
|
+
}
|
578
|
+
})
|
579
|
+
BiwaScheme.Dumper.toggle_fold = function(n){
|
580
|
+
Element.toggle("fold"+n);
|
581
|
+
}
|
582
|
+
|
583
|
+
|
584
|
+
//
|
585
|
+
// Nil
|
586
|
+
// javascript representation of empty list( '() )
|
587
|
+
//
|
588
|
+
BiwaScheme.nil = new Pair(null, null);
|
589
|
+
BiwaScheme.nil.toString = function(){ return "nil"; }
|
590
|
+
|
591
|
+
//
|
592
|
+
// #<undef> (The undefined value)
|
593
|
+
//
|
594
|
+
BiwaScheme.undef = new Object();
|
595
|
+
BiwaScheme.undef.toString = function(){ return "#<undef>"; }
|
596
|
+
|
597
|
+
//
|
598
|
+
// Symbol
|
599
|
+
//
|
600
|
+
|
601
|
+
BiwaScheme.Symbol = Class.create({
|
602
|
+
initialize: function(str){
|
603
|
+
this.name = str;
|
604
|
+
Symbols[ str ] = this;
|
605
|
+
},
|
606
|
+
|
607
|
+
inspect: function(){
|
608
|
+
return "'"+this.name;
|
609
|
+
//return "#<Symbol '"+this.name+"'>";
|
610
|
+
},
|
611
|
+
|
612
|
+
toString: function(){
|
613
|
+
return "'"+this.name;
|
614
|
+
},
|
615
|
+
|
616
|
+
to_write: function(){
|
617
|
+
return this.name;
|
618
|
+
}
|
619
|
+
});
|
620
|
+
BiwaScheme.Symbols = {};
|
621
|
+
BiwaScheme.Sym = function(name,leaveCase){
|
622
|
+
if( Symbols[name] === undefined ){
|
623
|
+
return new Symbol(name);
|
624
|
+
}
|
625
|
+
else if( ! (Symbols[name] instanceof Symbol) ){ //pre-defined member (like 'eval' in Firefox)
|
626
|
+
return new Symbol(name);
|
627
|
+
}
|
628
|
+
else{
|
629
|
+
return Symbols[name];
|
630
|
+
}
|
631
|
+
}
|
632
|
+
|
633
|
+
BiwaScheme.gensyms = 0;
|
634
|
+
BiwaScheme.gensym = function(){
|
635
|
+
BiwaScheme.gensyms++;
|
636
|
+
return Sym("__gensym_" + BiwaScheme.gensyms);
|
637
|
+
}
|
638
|
+
|
639
|
+
//
|
640
|
+
// Char
|
641
|
+
//
|
642
|
+
|
643
|
+
BiwaScheme.Char = Class.create({
|
644
|
+
initialize: function(c){
|
645
|
+
Chars[ this.value = c ] = this;
|
646
|
+
},
|
647
|
+
to_write: function(){
|
648
|
+
switch(this.value){
|
649
|
+
case '\n': return "#\\newline";
|
650
|
+
case ' ': return "#\\space";
|
651
|
+
case '\t': return "#\\tab";
|
652
|
+
default: return "#\\"+this.value;
|
653
|
+
}
|
654
|
+
},
|
655
|
+
inspect: function(){
|
656
|
+
return this.to_write();
|
657
|
+
}
|
658
|
+
});
|
659
|
+
BiwaScheme.Chars = {};
|
660
|
+
BiwaScheme.Char.get = function(c) {
|
661
|
+
if(typeof(c) != "string") {
|
662
|
+
throw new Bug("Char.get: " + Object.inspect(c) + " is not a string");
|
663
|
+
}
|
664
|
+
if( Chars[c] === undefined )
|
665
|
+
return new Char(c);
|
666
|
+
else
|
667
|
+
return Chars[c];
|
668
|
+
}
|
669
|
+
|
670
|
+
//
|
671
|
+
// Port
|
672
|
+
//
|
673
|
+
BiwaScheme.Port = Class.create({
|
674
|
+
initialize: function(is_in, is_out){
|
675
|
+
this.is_binary = false; //??
|
676
|
+
this.is_input = is_in;
|
677
|
+
this.is_output = is_out;
|
678
|
+
},
|
679
|
+
close: function(){
|
680
|
+
// close port
|
681
|
+
},
|
682
|
+
inspect: function(){
|
683
|
+
return "#<Port>";
|
684
|
+
},
|
685
|
+
to_write: function(){
|
686
|
+
return "#<Port>";
|
687
|
+
}
|
688
|
+
});
|
689
|
+
BiwaScheme.Port.BrowserInput = Class.create(Port, {
|
690
|
+
initialize: function($super){
|
691
|
+
$super(true, false);
|
692
|
+
},
|
693
|
+
get_string: function(after){
|
694
|
+
var form = document.createElement("div")
|
695
|
+
form.innerHTML = "<input id='webscheme-read-line' type='text'><input id='webscheme-read-line-submit' type='button' value='ok'>";
|
696
|
+
$('bs-console').appendChild(form)
|
697
|
+
|
698
|
+
return new BiwaScheme.Pause(function(pause){
|
699
|
+
Event.observe($('webscheme-read-line-submit'), 'click', function(){
|
700
|
+
var input = $('webscheme-read-line').value;
|
701
|
+
form.parentNode.removeChild(form);
|
702
|
+
puts(input);
|
703
|
+
pause.resume(after(input));
|
704
|
+
});
|
705
|
+
});
|
706
|
+
}
|
707
|
+
})
|
708
|
+
BiwaScheme.Port.DefaultOutput = Class.create(Port, {
|
709
|
+
initialize: function($super){
|
710
|
+
$super(false, true);
|
711
|
+
},
|
712
|
+
put_string: function(str){
|
713
|
+
puts(str, true);
|
714
|
+
}
|
715
|
+
})
|
716
|
+
BiwaScheme.Port.current_input = new Port.BrowserInput();
|
717
|
+
BiwaScheme.Port.current_output = new Port.DefaultOutput();
|
718
|
+
BiwaScheme.Port.current_error = new Port.DefaultOutput();
|
719
|
+
|
720
|
+
//
|
721
|
+
// Syntax
|
722
|
+
//
|
723
|
+
BiwaScheme.Syntax = Class.create({
|
724
|
+
initialize: function(func){
|
725
|
+
this.func = func;
|
726
|
+
},
|
727
|
+
transform: function(x){
|
728
|
+
return this.func(x);
|
729
|
+
}
|
730
|
+
})
|
731
|
+
|
732
|
+
//
|
733
|
+
// Parser
|
734
|
+
// copied from jsScheme - should be rewrriten (support #0=, etc)
|
735
|
+
//
|
736
|
+
BiwaScheme.Parser = Class.create({
|
737
|
+
initialize: function(txt){
|
738
|
+
this.tokens = this.tokenize(txt);
|
739
|
+
this.i = 0;
|
740
|
+
},
|
741
|
+
|
742
|
+
inspect: function(){
|
743
|
+
return [
|
744
|
+
"#<Parser:",
|
745
|
+
this.i, "/", this.tokens.length, " ",
|
746
|
+
Object.inspect(this.tokens),
|
747
|
+
">"
|
748
|
+
].join("");
|
749
|
+
},
|
750
|
+
|
751
|
+
tokenize: function(txt) {
|
752
|
+
var tokens = new Array(), oldTxt=null;
|
753
|
+
var in_srfi_30_comment = 0;
|
754
|
+
|
755
|
+
while( txt != "" && oldTxt != txt ) {
|
756
|
+
oldTxt = txt;
|
757
|
+
txt = txt.replace( /^\s*(;[^\r\n]*(\r|\n|$)|#;|#\||#\\[^\w]|#?(\(|\[|{)|\)|\]|}|\'|`|,@|,|\+inf\.0|-inf\.0|\+nan\.0|\"(\\(.|$)|[^\"\\])*(\"|$)|[^\s()\[\]{}]+)/,
|
758
|
+
function($0,$1) {
|
759
|
+
var t = $1;
|
760
|
+
|
761
|
+
if (t == "#|") {
|
762
|
+
in_srfi_30_comment++;
|
763
|
+
return "";
|
764
|
+
}
|
765
|
+
else if (in_srfi_30_comment > 0) {
|
766
|
+
if ( /(.*\|#)/.test(t) ) {
|
767
|
+
in_srfi_30_comment--;
|
768
|
+
if (in_srfi_30_comment < 0) {
|
769
|
+
throw new Error("Found an extra comment terminator: `|#'")
|
770
|
+
}
|
771
|
+
// Push back the rest substring to input stream.
|
772
|
+
return t.substring(RegExp.$1.length, t.length);
|
773
|
+
}
|
774
|
+
else {
|
775
|
+
return "";
|
776
|
+
}
|
777
|
+
}
|
778
|
+
else {
|
779
|
+
if( t.charAt(0) != ';' ) tokens[tokens.length]=t;
|
780
|
+
return "";
|
781
|
+
}
|
782
|
+
} );
|
783
|
+
}
|
784
|
+
return tokens;
|
785
|
+
},
|
786
|
+
|
787
|
+
sexpCommentMarker: new Object,
|
788
|
+
getObject: function() {
|
789
|
+
var r = this.getObject0();
|
790
|
+
|
791
|
+
if (r != this.sexpCommentMarker)
|
792
|
+
return r;
|
793
|
+
|
794
|
+
r = this.getObject();
|
795
|
+
if (r == null)
|
796
|
+
throw new Error("Readable object not found after S exression comment");
|
797
|
+
|
798
|
+
r = this.getObject();
|
799
|
+
return r;
|
800
|
+
},
|
801
|
+
|
802
|
+
getList: function( close ) {
|
803
|
+
var list = nil, prev = list;
|
804
|
+
while( this.i < this.tokens.length ) {
|
805
|
+
|
806
|
+
this.eatObjectsInSexpComment("Input stream terminated unexpectedly(in list)");
|
807
|
+
|
808
|
+
if( this.tokens[ this.i ] == ')' || this.tokens[ this.i ] == ']' || this.tokens[ this.i ] == '}' ) {
|
809
|
+
this.i++; break;
|
810
|
+
}
|
811
|
+
|
812
|
+
if( this.tokens[ this.i ] == '.' ) {
|
813
|
+
this.i++;
|
814
|
+
var o = this.getObject();
|
815
|
+
if( o != null && list != nil ) {
|
816
|
+
prev.cdr = o;
|
817
|
+
}
|
818
|
+
} else {
|
819
|
+
var cur = new Pair( this.getObject(), nil);
|
820
|
+
if( list == nil ) list = cur;
|
821
|
+
else prev.cdr = cur;
|
822
|
+
prev = cur;
|
823
|
+
}
|
824
|
+
}
|
825
|
+
return list;
|
826
|
+
},
|
827
|
+
|
828
|
+
getVector: function( close ) {
|
829
|
+
var arr = new Array();
|
830
|
+
while( this.i < this.tokens.length ) {
|
831
|
+
|
832
|
+
this.eatObjectsInSexpComment("Input stream terminated unexpectedly(in vector)");
|
833
|
+
|
834
|
+
if( this.tokens[ this.i ] == ')' ||
|
835
|
+
this.tokens[ this.i ] == ']' ||
|
836
|
+
this.tokens[ this.i ] == '}' ) { this.i++; break; }
|
837
|
+
arr[ arr.length ] = this.getObject();
|
838
|
+
}
|
839
|
+
return arr;
|
840
|
+
},
|
841
|
+
|
842
|
+
eatObjectsInSexpComment: function(err_msg) {
|
843
|
+
while( this.tokens[ this.i ] == '#;' ) {
|
844
|
+
this.i++;
|
845
|
+
if ((this.getObject() == null) || (this.i >= this.tokens.length))
|
846
|
+
throw new Error(err_msg);
|
847
|
+
}
|
848
|
+
},
|
849
|
+
|
850
|
+
getObject0: function() {
|
851
|
+
if( this.i >= this.tokens.length )
|
852
|
+
return Parser.EOS;
|
853
|
+
|
854
|
+
var t = this.tokens[ this.i++ ];
|
855
|
+
// if( t == ')' ) return null;
|
856
|
+
|
857
|
+
if (t == '#;')
|
858
|
+
return this.sexpCommentMarker;
|
859
|
+
|
860
|
+
var s = t == "'" ? 'quote' :
|
861
|
+
t == "`" ? 'quasiquote' :
|
862
|
+
t == "," ? 'unquote' :
|
863
|
+
t == ",@" ? 'unquote-splicing' : false;
|
864
|
+
|
865
|
+
if( s || t == '(' || t == '#(' || t == '[' || t == '#[' || t == '{' || t == '#{' ) {
|
866
|
+
return s ? new Pair( Sym(s), new Pair( this.getObject(), nil ))
|
867
|
+
: (t=='(' || t=='[' || t=='{') ? this.getList(t) : this.getVector(t);
|
868
|
+
}
|
869
|
+
else {
|
870
|
+
switch(t){
|
871
|
+
case "+inf.0" : return Infinity;
|
872
|
+
case "-inf.0" : return -Infinity;
|
873
|
+
case "+nan.0" : return NaN;
|
874
|
+
}
|
875
|
+
|
876
|
+
var n;
|
877
|
+
if( /^#x[0-9a-z]+$/i.test(t) ) { // #x... Hex
|
878
|
+
n = new Number('0x'+t.substring(2,t.length) );
|
879
|
+
}
|
880
|
+
else if( /^#d[0-9\.]+$/i.test(t) ) { // #d... Decimal
|
881
|
+
n = new Number( t.substring(2,t.length) );
|
882
|
+
}
|
883
|
+
else{
|
884
|
+
n = new Number(t); // use constrictor as parser
|
885
|
+
}
|
886
|
+
|
887
|
+
if( ! isNaN(n) ) {
|
888
|
+
return n.valueOf();
|
889
|
+
} else if( t == '#f' || t == '#F' ) {
|
890
|
+
return false;
|
891
|
+
} else if( t == '#t' || t == '#T' ) {
|
892
|
+
return true;
|
893
|
+
} else if( t.toLowerCase() == '#\\newline' ) {
|
894
|
+
return Char.get('\n');
|
895
|
+
} else if( t.toLowerCase() == '#\\space' ) {
|
896
|
+
return Char.get(' ');
|
897
|
+
} else if( t.toLowerCase() == '#\\tab' ) {
|
898
|
+
return Char.get('\t');
|
899
|
+
} else if( /^#\\.$/.test(t) ) {
|
900
|
+
return Char.get( t.charAt(2) );
|
901
|
+
} else if( /^\"(\\(.|$)|[^\"\\])*\"?$/.test(t) ) {
|
902
|
+
return t.replace(/(\r?\n|\\n)/g, "\n").replace( /^\"|\\(.|$)|\"$/g, function($0,$1) {
|
903
|
+
return $1 ? $1 : '';
|
904
|
+
} );
|
905
|
+
} else return Sym(t); // 2Do: validate !!
|
906
|
+
}
|
907
|
+
}
|
908
|
+
});
|
909
|
+
// indicates end of source file
|
910
|
+
BiwaScheme.Parser.EOS = new Object();
|
911
|
+
|
912
|
+
///
|
913
|
+
/// Compiler
|
914
|
+
///
|
915
|
+
|
916
|
+
BiwaScheme.Compiler = Class.create({
|
917
|
+
initialize: function(){
|
918
|
+
},
|
919
|
+
|
920
|
+
is_tail: function(x){
|
921
|
+
return (x[0] == "return");
|
922
|
+
},
|
923
|
+
|
924
|
+
//free: set
|
925
|
+
//e: env(= [locals, frees])
|
926
|
+
//next: opc
|
927
|
+
//ret: opc["refer_*", n, ["argument",
|
928
|
+
// ["refer_*", n, ... ["argument", next]
|
929
|
+
collect_free: function(free, e, next){
|
930
|
+
var vars = free;
|
931
|
+
var opc = next;
|
932
|
+
var arr = vars.arr;
|
933
|
+
for(var i=0; i<arr.length; i++){
|
934
|
+
opc = this.compile_refer(arr[i], e, ["argument", opc]);
|
935
|
+
}
|
936
|
+
//puts("collect_free "+free.inspect()+" / "+e.inspect()+" => "+opc.inspect());
|
937
|
+
return opc;
|
938
|
+
},
|
939
|
+
|
940
|
+
//x: Symbol
|
941
|
+
//e: env [set of locals, set of frees]
|
942
|
+
//ret: opc
|
943
|
+
compile_refer: function(x, e, next){
|
944
|
+
return this.compile_lookup(x, e,
|
945
|
+
function(n){ return ["refer-local", n, next] },
|
946
|
+
function(n){ return ["refer-free", n, next] },
|
947
|
+
function(sym){ return ["refer-global", sym, next] });
|
948
|
+
},
|
949
|
+
|
950
|
+
compile_lookup: function(x, e, return_local, return_free, return_global){
|
951
|
+
var locals = e[0], free = e[1];
|
952
|
+
if((n = locals.index(x)) != null){
|
953
|
+
//puts("compile_refer:"+x.inspect()+" in "+e.inspect()+" results refer-local "+n);
|
954
|
+
return return_local(n);
|
955
|
+
}
|
956
|
+
else if((n = free.index(x)) != null){
|
957
|
+
//puts("compile_refer:"+x.inspect()+" in "+e.inspect()+" results refer-free "+n);
|
958
|
+
return return_free(n);
|
959
|
+
}
|
960
|
+
else{
|
961
|
+
var sym = x.name;
|
962
|
+
return return_global(sym);
|
963
|
+
}
|
964
|
+
//throw new Error("undefined symbol `" + sym + "'");
|
965
|
+
},
|
966
|
+
|
967
|
+
//generate boxing code (intersection of sets & vars)
|
968
|
+
//if no need of boxing, just returns next
|
969
|
+
// sets(Set): assigned variables
|
970
|
+
// vars(List): used variables
|
971
|
+
// next(opc):
|
972
|
+
// ret(opc):
|
973
|
+
make_boxes: function(sets, vars, next){
|
974
|
+
var vars = vars;
|
975
|
+
var n = 0;
|
976
|
+
var a = [];
|
977
|
+
while(vars instanceof Pair && vars != nil){
|
978
|
+
if(sets.member(vars.car))
|
979
|
+
a.push(n);
|
980
|
+
n++;
|
981
|
+
vars = vars.cdr;
|
982
|
+
}
|
983
|
+
var opc = next;
|
984
|
+
for(var i=a.length-1; i>=0; i--)
|
985
|
+
opc = ["box", a[i], opc];
|
986
|
+
return opc;
|
987
|
+
},
|
988
|
+
|
989
|
+
// Enumerate variables which (could be assigned && included in v)
|
990
|
+
// x: exp
|
991
|
+
// v: set(vars)
|
992
|
+
// ret: set
|
993
|
+
find_sets: function(x, v){
|
994
|
+
//puts("find_sets: " + to_write(x) + " " + to_write(v))
|
995
|
+
var ret=null;
|
996
|
+
if(x instanceof Symbol){
|
997
|
+
ret = new Set();
|
998
|
+
}
|
999
|
+
else if(x instanceof Pair){
|
1000
|
+
switch(x.first()){
|
1001
|
+
case Sym("define"):
|
1002
|
+
var exp=x.third();
|
1003
|
+
ret = this.find_sets(exp, v);
|
1004
|
+
case Sym("begin"):
|
1005
|
+
ret = this.find_sets(x.cdr, v); //(ignores improper list)
|
1006
|
+
break;
|
1007
|
+
case Sym("quote"):
|
1008
|
+
ret = new Set();
|
1009
|
+
break;
|
1010
|
+
case Sym("lambda"):
|
1011
|
+
var vars=x.second(), body=x.cdr.cdr;
|
1012
|
+
ret = this.find_sets(body, v.set_minus(vars.to_set()));
|
1013
|
+
break;
|
1014
|
+
case Sym("if"):
|
1015
|
+
var testc=x.second(), thenc=x.third(), elsec=x.fourth();
|
1016
|
+
ret = this.find_sets(testc, v).set_union(
|
1017
|
+
this.find_sets(thenc, v),
|
1018
|
+
this.find_sets(elsec, v));
|
1019
|
+
break;
|
1020
|
+
case Sym("set!"):
|
1021
|
+
var vari=x.second(), xx=x.third();
|
1022
|
+
if(v.member(vari))
|
1023
|
+
ret = this.find_sets(xx, v).set_cons(vari);
|
1024
|
+
else
|
1025
|
+
ret = this.find_sets(xx, v);
|
1026
|
+
break;
|
1027
|
+
case Sym("call/cc"):
|
1028
|
+
var exp=x.second();
|
1029
|
+
ret = this.find_sets(exp, v);
|
1030
|
+
break;
|
1031
|
+
default:
|
1032
|
+
var set = new Set();
|
1033
|
+
for(var p=x; p instanceof Pair && p != nil; p=p.cdr){
|
1034
|
+
set = set.set_union(this.find_sets(p.car, v));
|
1035
|
+
}
|
1036
|
+
ret = set;
|
1037
|
+
break;
|
1038
|
+
}
|
1039
|
+
}
|
1040
|
+
else{
|
1041
|
+
ret = new Set();
|
1042
|
+
}
|
1043
|
+
|
1044
|
+
if(ret == null)
|
1045
|
+
throw new Bug("find_sets() exited in unusual way");
|
1046
|
+
else
|
1047
|
+
return ret;
|
1048
|
+
},
|
1049
|
+
|
1050
|
+
// find_free(): find free variables in x
|
1051
|
+
// these variables are collected by collect_free().
|
1052
|
+
// x: expression
|
1053
|
+
// b: set of local vars (= variables which are not free)
|
1054
|
+
// f: set of free var candidates
|
1055
|
+
// (local vars of outer lambdas)
|
1056
|
+
// ret: set of free vars
|
1057
|
+
find_free: function(x, b, f){
|
1058
|
+
var ret=null;
|
1059
|
+
if(x instanceof Symbol){
|
1060
|
+
if(f.member(x))
|
1061
|
+
ret = new Set(x);
|
1062
|
+
else
|
1063
|
+
ret = new Set();
|
1064
|
+
}
|
1065
|
+
else if(x instanceof Pair){
|
1066
|
+
switch(x.first()){
|
1067
|
+
case Sym("define"):
|
1068
|
+
var exp=x.third();
|
1069
|
+
ret = this.find_free(exp, b, f);
|
1070
|
+
break;
|
1071
|
+
case Sym("begin"):
|
1072
|
+
ret = this.find_free(x.cdr, b, f); //(ignores improper list)
|
1073
|
+
break;
|
1074
|
+
case Sym("quote"):
|
1075
|
+
ret = new Set();
|
1076
|
+
break;
|
1077
|
+
case Sym("lambda"):
|
1078
|
+
var vars=x.second(), body=x.cdr.cdr;
|
1079
|
+
ret = this.find_free(body, b.set_union(vars.to_set()), f);
|
1080
|
+
break;
|
1081
|
+
case Sym("if"):
|
1082
|
+
var testc=x.second(), thenc=x.third(), elsec=x.fourth();
|
1083
|
+
ret = this.find_free(testc, b, f).set_union(
|
1084
|
+
this.find_free(thenc, b, f),
|
1085
|
+
this.find_free(elsec, b, f));
|
1086
|
+
break;
|
1087
|
+
case Sym("set!"):
|
1088
|
+
var vari=x.second(), exp=x.third();
|
1089
|
+
if(f.member(vari))
|
1090
|
+
ret = this.find_free(exp, b, f).set_cons(vari);
|
1091
|
+
else
|
1092
|
+
ret = this.find_free(exp, b, f)
|
1093
|
+
break;
|
1094
|
+
case Sym("call/cc"):
|
1095
|
+
var exp=x.second();
|
1096
|
+
ret = this.find_free(exp, b, f);
|
1097
|
+
break;
|
1098
|
+
default:
|
1099
|
+
var set = new Set();
|
1100
|
+
for(var p=x; p instanceof Pair && p != nil; p=p.cdr){
|
1101
|
+
set = set.set_union(this.find_free(p.car, b, f));
|
1102
|
+
}
|
1103
|
+
ret = set;
|
1104
|
+
break;
|
1105
|
+
}
|
1106
|
+
}
|
1107
|
+
else{
|
1108
|
+
ret = new Set();
|
1109
|
+
}
|
1110
|
+
//p("find_free "+x.inspect()+" / "+b.inspect()+" => "+ret.inspect());
|
1111
|
+
|
1112
|
+
if(ret == null)
|
1113
|
+
throw new Bug("find_free() exited in unusual way");
|
1114
|
+
else
|
1115
|
+
return ret;
|
1116
|
+
},
|
1117
|
+
|
1118
|
+
find_dot_pos: function(x){
|
1119
|
+
var idx = 0;
|
1120
|
+
for (; x instanceof Pair && x != nil; x = x.cdr, ++idx)
|
1121
|
+
;
|
1122
|
+
if (x != nil) {
|
1123
|
+
return idx;
|
1124
|
+
} else {
|
1125
|
+
return -1;
|
1126
|
+
}
|
1127
|
+
},
|
1128
|
+
|
1129
|
+
last_pair: function(x){
|
1130
|
+
if (x instanceof Pair && x != nil){
|
1131
|
+
for (; x.cdr instanceof Pair && x.cdr != nil; x = x.cdr)
|
1132
|
+
;
|
1133
|
+
}
|
1134
|
+
return x;
|
1135
|
+
},
|
1136
|
+
|
1137
|
+
// dotted list -> proper list
|
1138
|
+
dotted2proper: function(ls){
|
1139
|
+
var nreverse = function(ls){
|
1140
|
+
var res = nil;
|
1141
|
+
for (; ls instanceof Pair && ls != nil; ){
|
1142
|
+
var d = ls.cdr;
|
1143
|
+
ls.cdr = res;
|
1144
|
+
res = ls;
|
1145
|
+
ls = d;
|
1146
|
+
}
|
1147
|
+
return res;
|
1148
|
+
}
|
1149
|
+
var copy_list = function(ls){
|
1150
|
+
var res = nil;
|
1151
|
+
for (; ls instanceof Pair && ls != nil; ls = ls.cdr){
|
1152
|
+
res = new Pair(ls.car, res);
|
1153
|
+
}
|
1154
|
+
return nreverse(res);
|
1155
|
+
}
|
1156
|
+
|
1157
|
+
if (ls instanceof Pair) {
|
1158
|
+
var last = this.last_pair(ls);
|
1159
|
+
if (last instanceof Pair && last.cdr == nil){
|
1160
|
+
return ls;
|
1161
|
+
} else {
|
1162
|
+
var copied = copy_list(ls);
|
1163
|
+
this.last_pair(copied).cdr = new Pair(last.cdr, nil);
|
1164
|
+
return copied;
|
1165
|
+
}
|
1166
|
+
} else {
|
1167
|
+
return new Pair(ls, nil);
|
1168
|
+
}
|
1169
|
+
},
|
1170
|
+
|
1171
|
+
// x: exp(list of symbol or integer or..)
|
1172
|
+
// e: env (= [locals, frees])
|
1173
|
+
// s: vars might be set!
|
1174
|
+
// next: opc
|
1175
|
+
// ret: opc
|
1176
|
+
compile: function(x, e, s, f, next){
|
1177
|
+
//p(x);
|
1178
|
+
var ret = null;
|
1179
|
+
|
1180
|
+
while(1){
|
1181
|
+
if(x instanceof Symbol){
|
1182
|
+
return this.compile_refer(x, e, (s.member(x) ? ["indirect", next] : next));
|
1183
|
+
}
|
1184
|
+
else if(x instanceof Pair){
|
1185
|
+
switch(x.first()){
|
1186
|
+
case Sym("define"):
|
1187
|
+
var left = x.cdr.car;
|
1188
|
+
var exp = x.cdr.cdr;
|
1189
|
+
|
1190
|
+
//define variable
|
1191
|
+
if(left instanceof Symbol){
|
1192
|
+
x = exp.car;
|
1193
|
+
TopEnv[left.name] = BiwaScheme.undef;
|
1194
|
+
next = ["assign-global", left.name, next]; //should raise for improper list?
|
1195
|
+
}
|
1196
|
+
//define function
|
1197
|
+
else if(left instanceof Pair){
|
1198
|
+
var fname=left.car, args=left.cdr;
|
1199
|
+
var lambda = new Pair(Sym("lambda"), new Pair(args, exp));
|
1200
|
+
x = lambda;
|
1201
|
+
TopEnv[fname.name] = BiwaScheme.undef;
|
1202
|
+
next = ["assign-global", fname.name, next];
|
1203
|
+
}
|
1204
|
+
//error
|
1205
|
+
else{
|
1206
|
+
throw new Error("compile: define needs a leftbol or pair: got "+left);
|
1207
|
+
}
|
1208
|
+
break;
|
1209
|
+
case Sym("begin"):
|
1210
|
+
var a = [];
|
1211
|
+
for(var p=x.cdr; p instanceof Pair && p!=nil; p=p.cdr)
|
1212
|
+
a.push(p.car);
|
1213
|
+
|
1214
|
+
//compile each expression (in reverse order)
|
1215
|
+
var c = next;
|
1216
|
+
for(var i=a.length-1; i>=0; i--){
|
1217
|
+
c = this.compile(a[i], e, s, f, c);
|
1218
|
+
}
|
1219
|
+
return c;
|
1220
|
+
case Sym("quote"):
|
1221
|
+
var obj=x.second();
|
1222
|
+
return ["constant", obj, next];
|
1223
|
+
case Sym("lambda"):
|
1224
|
+
// x = '(lambda (x y) x y)
|
1225
|
+
// x = '(lambda vars x y)
|
1226
|
+
var vars = x.cdr.car;
|
1227
|
+
var body = new Pair(Sym("begin"), x.cdr.cdr); //tenuki
|
1228
|
+
|
1229
|
+
var dotpos = this.find_dot_pos(vars);
|
1230
|
+
var proper = this.dotted2proper(vars);
|
1231
|
+
var free = this.find_free(body, proper.to_set(), f); //free variables
|
1232
|
+
var sets = this.find_sets(body, proper.to_set()); //local variables
|
1233
|
+
|
1234
|
+
var do_body = this.compile(body,
|
1235
|
+
[proper.to_set(), free],
|
1236
|
+
sets.set_union(s.set_intersect(free)),
|
1237
|
+
f.set_union(proper.to_set()),
|
1238
|
+
["return"]);
|
1239
|
+
var do_close = ["close",
|
1240
|
+
free.size(),
|
1241
|
+
this.make_boxes(sets, proper, do_body),
|
1242
|
+
next,
|
1243
|
+
dotpos];
|
1244
|
+
return this.collect_free(free, e, do_close);
|
1245
|
+
case Sym("if"):
|
1246
|
+
var testc=x.second(), thenc=x.third(), elsec=x.fourth();
|
1247
|
+
var thenc = this.compile(thenc, e, s, f, next);
|
1248
|
+
var elsec = this.compile(elsec, e, s, f, next);
|
1249
|
+
x = testc;
|
1250
|
+
next = ["test", thenc, elsec];
|
1251
|
+
break;
|
1252
|
+
case Sym("set!"):
|
1253
|
+
var v=x.second(), x=x.third();
|
1254
|
+
var do_assign = this.compile_lookup(v, e,
|
1255
|
+
function(n){ return ["assign-local", n, next]; },
|
1256
|
+
function(n){ return ["assign-free", n, next]; },
|
1257
|
+
function(sym){ return ["assign-global",sym, next]; });
|
1258
|
+
next = do_assign;
|
1259
|
+
break;
|
1260
|
+
case Sym("call/cc"):
|
1261
|
+
var x=x.second();
|
1262
|
+
var c = ["conti",
|
1263
|
+
(this.is_tail(next) ? (e[0].size() + 1) : 0), //number of args for outer lambda
|
1264
|
+
["argument",
|
1265
|
+
["constant", 1,
|
1266
|
+
["argument",
|
1267
|
+
this.compile(x, e, s,f,
|
1268
|
+
(this.is_tail(next) ? ["shift", 1, ["apply"]]
|
1269
|
+
: ["apply"]))]]]];
|
1270
|
+
//note: proc for call/cc takes 1 argument (= ["apply", 1])
|
1271
|
+
return this.is_tail(next) ? c : ["frame", c, next];
|
1272
|
+
default:
|
1273
|
+
//apply
|
1274
|
+
//x = (func 1 2)
|
1275
|
+
//x.car = func = '(lambda (x) ..) or Symbol
|
1276
|
+
//x.cdr = args = '(1 2)
|
1277
|
+
var func = x.car;
|
1278
|
+
var args = x.cdr;
|
1279
|
+
var c = this.compile(func, e, s,f,
|
1280
|
+
this.is_tail(next) ? ["shift", args.length(), ["apply"]]
|
1281
|
+
: ["apply"]);
|
1282
|
+
|
1283
|
+
// VM will push the number of arguments to the stack.
|
1284
|
+
c = this.compile(args.length(), e, s, f, ["argument", c]);
|
1285
|
+
for(var p=args; p instanceof Pair && p!=nil; p=p.cdr){
|
1286
|
+
c = this.compile(p.car, e, s, f, ["argument", c]);
|
1287
|
+
}
|
1288
|
+
return this.is_tail(next) ? c : ["frame", c, next];
|
1289
|
+
}
|
1290
|
+
}
|
1291
|
+
else{
|
1292
|
+
return ["constant", x, next];
|
1293
|
+
}
|
1294
|
+
}
|
1295
|
+
//p("result of " + x.inspect() + ":");
|
1296
|
+
//p(ret);
|
1297
|
+
//dump(new Hash({"ret":ret, "x":x, "e":e, "s":s, "next":next, "stack":[]}));
|
1298
|
+
// if(ret == null)
|
1299
|
+
// throw new Bug("compile() exited in unusual way");
|
1300
|
+
// else
|
1301
|
+
// return ret;
|
1302
|
+
},
|
1303
|
+
run: function(expr){
|
1304
|
+
return this.compile(expr, [new Set(), new Set()], new Set(), new Set(), ["halt"]);
|
1305
|
+
}
|
1306
|
+
});
|
1307
|
+
BiwaScheme.Compiler.compile = function(expr, next){
|
1308
|
+
expr = (new Interpreter).expand(expr);
|
1309
|
+
return (new Compiler).run(expr, next);
|
1310
|
+
}
|
1311
|
+
|
1312
|
+
///
|
1313
|
+
/// Interpreter
|
1314
|
+
///
|
1315
|
+
|
1316
|
+
//
|
1317
|
+
// pause object (facility to stop/resume interpreting)
|
1318
|
+
//
|
1319
|
+
BiwaScheme.Pause = Class.create({
|
1320
|
+
//new (on_pause: javascript function calling setTimeout, Ajax.Request, ..)
|
1321
|
+
initialize: function(on_pause){
|
1322
|
+
this.on_pause = on_pause;
|
1323
|
+
},
|
1324
|
+
|
1325
|
+
//save state of interpreter
|
1326
|
+
set_state: function(intp, x, f, c, s){
|
1327
|
+
this.interpreter = intp;
|
1328
|
+
this.x = x;
|
1329
|
+
this.f = f;
|
1330
|
+
this.c = c;
|
1331
|
+
this.s = s;
|
1332
|
+
},
|
1333
|
+
|
1334
|
+
//call this when ready (to fire setTimeout, Ajax.Request..)
|
1335
|
+
ready: function(){
|
1336
|
+
this.on_pause(this);
|
1337
|
+
},
|
1338
|
+
|
1339
|
+
//restart calculation
|
1340
|
+
resume: function(value){
|
1341
|
+
return this.interpreter.resume(true, value, this.x, this.f, this.c, this.s)
|
1342
|
+
}
|
1343
|
+
});
|
1344
|
+
|
1345
|
+
BiwaScheme.Call = Class.create({
|
1346
|
+
initialize: function(proc, args, after){
|
1347
|
+
this.proc = proc;
|
1348
|
+
this.args = args;
|
1349
|
+
this.after = after || function(ar){
|
1350
|
+
// just return result which closure returned
|
1351
|
+
return ar[0];
|
1352
|
+
};
|
1353
|
+
}
|
1354
|
+
})
|
1355
|
+
|
1356
|
+
BiwaScheme.Interpreter = Class.create({
|
1357
|
+
initialize: function(on_error){
|
1358
|
+
this.stack = [] //(make-vector 1000)
|
1359
|
+
this.on_error = on_error || function(e){};
|
1360
|
+
this.after_evaluate = Prototype.emptyFunction;
|
1361
|
+
},
|
1362
|
+
|
1363
|
+
inspect: function(){
|
1364
|
+
return [
|
1365
|
+
"#<Interpreter: stack size=>",
|
1366
|
+
this.stack.length, " ",
|
1367
|
+
"after_evaluate=",
|
1368
|
+
Object.inspect(this.after_evaluate),
|
1369
|
+
">"
|
1370
|
+
].join("");
|
1371
|
+
},
|
1372
|
+
|
1373
|
+
push: function(x, s){
|
1374
|
+
this.stack[s] = x;
|
1375
|
+
return s+1;
|
1376
|
+
},
|
1377
|
+
|
1378
|
+
//s: depth of stack to save
|
1379
|
+
//ret: saved(copied) stack
|
1380
|
+
save_stack: function(s){
|
1381
|
+
var v = [];
|
1382
|
+
for(var i=0; i<s; i++){
|
1383
|
+
v[i] = this.stack[i];
|
1384
|
+
}
|
1385
|
+
return v;
|
1386
|
+
},
|
1387
|
+
|
1388
|
+
//v: stack array to restore
|
1389
|
+
//ret: lenght of restored stack
|
1390
|
+
restore_stack: function(v){
|
1391
|
+
var s = v.length;
|
1392
|
+
for(var i=0; i<s; i++){
|
1393
|
+
this.stack[i] = v[i];
|
1394
|
+
}
|
1395
|
+
return s;
|
1396
|
+
},
|
1397
|
+
|
1398
|
+
//s: depth of stack to save
|
1399
|
+
//n: number of args(for outer lambda) to remove (= 0 unless tail position)
|
1400
|
+
//ret: closure array
|
1401
|
+
continuation: function(s, n){
|
1402
|
+
// note: implementation of this function for final version doesn't exist in 3imp.pdf..
|
1403
|
+
var ss = this.push(n, s);
|
1404
|
+
return this.closure(["refer-local", 0,
|
1405
|
+
["nuate", this.save_stack(ss),
|
1406
|
+
["return"]]],
|
1407
|
+
0, //n (number of frees)
|
1408
|
+
null, //s (stack position to get frees)
|
1409
|
+
-1); // dotpos
|
1410
|
+
},
|
1411
|
+
|
1412
|
+
// shift stack
|
1413
|
+
// n: number of items to skip (from stack top)
|
1414
|
+
// m: number of items to shift
|
1415
|
+
// s: stack pointer (= index of stack top + 1)
|
1416
|
+
shift_args: function(n, m, s){
|
1417
|
+
for(var i = n-1; i >= -1; i--){
|
1418
|
+
this.index_set(s, i+m+1, this.index(s, i));
|
1419
|
+
}
|
1420
|
+
return s-m-1;
|
1421
|
+
},
|
1422
|
+
|
1423
|
+
index: function(s, i){
|
1424
|
+
return this.stack[s-i-2];
|
1425
|
+
},
|
1426
|
+
|
1427
|
+
index_set: function(s, i, v){
|
1428
|
+
this.stack[s-i-2] = v;
|
1429
|
+
},
|
1430
|
+
|
1431
|
+
//ret: [body, stack[s-1], stack[s-2], .., stack[s-n], dotpos]
|
1432
|
+
closure: function(body, n, s, dotpos){
|
1433
|
+
var v = []; //(make-vector n+1+1)
|
1434
|
+
v[0] = body;
|
1435
|
+
for(var i=0; i<n; i++)
|
1436
|
+
v[i+1] = this.index(s, i-1);
|
1437
|
+
v[n+1] = dotpos;
|
1438
|
+
|
1439
|
+
v.closure_p = true;
|
1440
|
+
|
1441
|
+
return v;
|
1442
|
+
},
|
1443
|
+
|
1444
|
+
execute: function(a, x, f, c, s){
|
1445
|
+
var ret = null;
|
1446
|
+
try{
|
1447
|
+
ret = this._execute(a, x, f, c, s);
|
1448
|
+
}
|
1449
|
+
catch(e){
|
1450
|
+
return this.on_error(e);
|
1451
|
+
}
|
1452
|
+
return ret;
|
1453
|
+
},
|
1454
|
+
|
1455
|
+
_execute: function(a, x, f, c, s){
|
1456
|
+
var ret = null;
|
1457
|
+
//puts("executing "+x[0]);
|
1458
|
+
|
1459
|
+
while(true){ //x[0] != "halt"){
|
1460
|
+
dump(new Hash({"a":a, "f":f, "c":c, "s":s, "x":x, "stack":this.stack}))
|
1461
|
+
switch(x[0]){
|
1462
|
+
case "halt":
|
1463
|
+
return a;
|
1464
|
+
case "refer-local":
|
1465
|
+
var n=x[1], x=x[2];
|
1466
|
+
a = this.index(f, n);
|
1467
|
+
break;
|
1468
|
+
case "refer-free":
|
1469
|
+
var n=x[1], x=x[2];
|
1470
|
+
a = c[n+1];
|
1471
|
+
break;
|
1472
|
+
case "refer-global":
|
1473
|
+
var sym=x[1], x=x[2];
|
1474
|
+
if(TopEnv.hasOwnProperty(sym)) var val = TopEnv[sym];
|
1475
|
+
else if(CoreEnv.hasOwnProperty(sym)) var val = CoreEnv[sym];
|
1476
|
+
else throw new Error("execute: unbound symbol: "+Object.inspect(sym));
|
1477
|
+
|
1478
|
+
a = val;
|
1479
|
+
break;
|
1480
|
+
case "indirect":
|
1481
|
+
var x=x[1];
|
1482
|
+
a = a[0]; //unboxing
|
1483
|
+
break;
|
1484
|
+
case "constant":
|
1485
|
+
var obj=x[1], x=x[2];
|
1486
|
+
a = obj;
|
1487
|
+
break;
|
1488
|
+
case "close":
|
1489
|
+
var ox=x;
|
1490
|
+
var n=ox[1], body=ox[2], x=ox[3], dotpos=ox[4];
|
1491
|
+
a = this.closure(body, n, s, dotpos);
|
1492
|
+
s -= n;
|
1493
|
+
break;
|
1494
|
+
case "box":
|
1495
|
+
var n=x[1], x=x[2];
|
1496
|
+
this.index_set(s, n, [this.index(s, n)]); //boxing
|
1497
|
+
break;
|
1498
|
+
case "test":
|
1499
|
+
var thenc=x[1], elsec=x[2];
|
1500
|
+
x = ((a!==false) ? thenc : elsec);
|
1501
|
+
break;
|
1502
|
+
case "assign-global":
|
1503
|
+
var name=x[1], x=x[2];
|
1504
|
+
if(!TopEnv.hasOwnProperty(name))
|
1505
|
+
throw new Error("global variable '"+name+"' is not defined");
|
1506
|
+
|
1507
|
+
TopEnv[name] = a;
|
1508
|
+
a = name;
|
1509
|
+
break;
|
1510
|
+
case "assign-local":
|
1511
|
+
var n=x[1], x=x[2];
|
1512
|
+
var box = this.index(f, n);
|
1513
|
+
box[0] = a;
|
1514
|
+
break;
|
1515
|
+
case "assign-free":
|
1516
|
+
var n=x[1], x=x[2];
|
1517
|
+
var box = c[n+1];
|
1518
|
+
box[0] = a;
|
1519
|
+
break;
|
1520
|
+
case "conti":
|
1521
|
+
var n=x[1], x=x[2];
|
1522
|
+
a = this.continuation(s, n);
|
1523
|
+
break;
|
1524
|
+
case "nuate":
|
1525
|
+
var stack=x[1], x=x[2];
|
1526
|
+
s = this.restore_stack(stack);
|
1527
|
+
break;
|
1528
|
+
case "frame":
|
1529
|
+
var ret = x[2];
|
1530
|
+
x = x[1];
|
1531
|
+
s = this.push(ret, this.push(f, this.push(c, s)));
|
1532
|
+
break;
|
1533
|
+
case "argument":
|
1534
|
+
var x=x[1];
|
1535
|
+
s = this.push(a, s);
|
1536
|
+
break;
|
1537
|
+
case "shift":
|
1538
|
+
var n=x[1], x=x[2];
|
1539
|
+
|
1540
|
+
// the number of arguments in the last call
|
1541
|
+
var n_args = this.index(s, n);
|
1542
|
+
|
1543
|
+
s = this.shift_args(n, n_args, s);
|
1544
|
+
break;
|
1545
|
+
case "apply": //extended: n_args as second argument
|
1546
|
+
var func = a; //, n_args = x[1];
|
1547
|
+
|
1548
|
+
// the number of arguments in the last call is
|
1549
|
+
// pushed to the stack.
|
1550
|
+
var n_args = this.index(s, -1);
|
1551
|
+
if(func instanceof Array){ //closure
|
1552
|
+
a = func;
|
1553
|
+
x = func[0];
|
1554
|
+
|
1555
|
+
// The position of dot in the parameter list.
|
1556
|
+
var dotpos = func[func.length-1];
|
1557
|
+
|
1558
|
+
if (dotpos >= 0) {
|
1559
|
+
// The dot is found
|
1560
|
+
// ----------------
|
1561
|
+
// => Process the &rest args: packing the rest args into a list.
|
1562
|
+
var ls = nil;
|
1563
|
+
for (var i=n_args; --i>=dotpos; ) {
|
1564
|
+
ls = new Pair(this.index(s, i), ls);
|
1565
|
+
}
|
1566
|
+
if (dotpos >= n_args) {
|
1567
|
+
// No rest argument is passed to this closure.
|
1568
|
+
// However, the closure expects the caller passes the rest argument.
|
1569
|
+
// In such case this VM prepares an empty list as the rest argument.
|
1570
|
+
// --------------------------------------------------------------
|
1571
|
+
// => We extend the stack to put the empty list.
|
1572
|
+
for(var i = -1; i < n_args; i++){
|
1573
|
+
this.index_set(s, i-1, this.index(s, i));
|
1574
|
+
}
|
1575
|
+
s++;
|
1576
|
+
// => Update the number of arguments
|
1577
|
+
this.index_set(s, -1, this.index(s, -1) + 1);
|
1578
|
+
}
|
1579
|
+
this.index_set(s, dotpos, ls);
|
1580
|
+
}
|
1581
|
+
f = s;
|
1582
|
+
c = a;
|
1583
|
+
}
|
1584
|
+
else if(func instanceof Function){
|
1585
|
+
var args = [];
|
1586
|
+
for(var i=0; i<n_args; i++)
|
1587
|
+
args.push(this.index(s, i));
|
1588
|
+
|
1589
|
+
var result = func(args, this);
|
1590
|
+
|
1591
|
+
if(result instanceof Pause){
|
1592
|
+
var pause = result;
|
1593
|
+
pause.set_state(this, ["return"], f, c, s);
|
1594
|
+
pause.ready();
|
1595
|
+
return pause;
|
1596
|
+
}
|
1597
|
+
else if(result instanceof Call){
|
1598
|
+
// [frame,
|
1599
|
+
// [constant... (args)
|
1600
|
+
// [constant, proc
|
1601
|
+
// [apply]]]]
|
1602
|
+
// [frame,
|
1603
|
+
// [constant, after
|
1604
|
+
// [apply 1]]]]
|
1605
|
+
// x
|
1606
|
+
var call_after = ["frame",
|
1607
|
+
["argument",
|
1608
|
+
["constant", 1,
|
1609
|
+
["argument",
|
1610
|
+
["constant", result.after,
|
1611
|
+
["apply"]]]]],
|
1612
|
+
["return"]];
|
1613
|
+
var call_proc = ["constant", result.args.length,
|
1614
|
+
["argument",
|
1615
|
+
["constant", result.proc,
|
1616
|
+
["apply", result.args.length]]]];
|
1617
|
+
var push_args = result.args.inject(call_proc, function(opc, arg){
|
1618
|
+
// (foo 1 2) => first push 2, then 1
|
1619
|
+
// [constant 2 ... [constant 1 ... ]
|
1620
|
+
return ["constant", arg,
|
1621
|
+
["argument",
|
1622
|
+
opc]];
|
1623
|
+
})
|
1624
|
+
x = ["frame",
|
1625
|
+
push_args,
|
1626
|
+
call_after]
|
1627
|
+
}
|
1628
|
+
else{
|
1629
|
+
a = result;
|
1630
|
+
x = ["return"];
|
1631
|
+
}
|
1632
|
+
}
|
1633
|
+
else{
|
1634
|
+
throw new Error("execute: unknown function type: "+Object.inspect(func));
|
1635
|
+
}
|
1636
|
+
break;
|
1637
|
+
case "return":
|
1638
|
+
var n=this.index(s, -1);
|
1639
|
+
var ss=s-n;
|
1640
|
+
x = this.index(ss, 0),
|
1641
|
+
f = this.index(ss, 1),
|
1642
|
+
c = this.index(ss, 2),
|
1643
|
+
s = ss-3-1;
|
1644
|
+
break;
|
1645
|
+
default:
|
1646
|
+
throw new Bug("unknown opecode type: "+x[0]);
|
1647
|
+
}
|
1648
|
+
}
|
1649
|
+
|
1650
|
+
// if(ret === null)
|
1651
|
+
// throw new Bug("interpreter exited in unusual way");
|
1652
|
+
// else
|
1653
|
+
// return ret;
|
1654
|
+
return a
|
1655
|
+
},
|
1656
|
+
|
1657
|
+
// expand macro forms (recursively)
|
1658
|
+
expand: function(x, flag){
|
1659
|
+
flag || (flag = {})
|
1660
|
+
var ret = null;
|
1661
|
+
if(x instanceof Symbol){
|
1662
|
+
ret = x;
|
1663
|
+
}
|
1664
|
+
else if(x instanceof Pair){
|
1665
|
+
switch(x.car){
|
1666
|
+
case Sym("define"):
|
1667
|
+
var left = x.cdr.car, exp = x.cdr.cdr;
|
1668
|
+
ret = new Pair(Sym("define"),
|
1669
|
+
new Pair(left, this.expand(exp, flag)));
|
1670
|
+
break;
|
1671
|
+
case Sym("begin"):
|
1672
|
+
ret = new Pair(Sym("begin"), this.expand(x.cdr, flag));
|
1673
|
+
break;
|
1674
|
+
case Sym("quote"):
|
1675
|
+
ret = x;
|
1676
|
+
break;
|
1677
|
+
case Sym("lambda"):
|
1678
|
+
var vars=x.cdr.car, body=x.cdr.cdr;
|
1679
|
+
ret = new Pair(Sym("lambda"),
|
1680
|
+
new Pair(vars, this.expand(body, flag)));
|
1681
|
+
break;
|
1682
|
+
case Sym("if"):
|
1683
|
+
var testc=x.second(), thenc=x.third(), elsec=x.fourth();
|
1684
|
+
ret = [Sym("if"), this.expand(testc, flag), this.expand(thenc, flag), this.expand(elsec, flag)].to_list();
|
1685
|
+
break;
|
1686
|
+
case Sym("set!"):
|
1687
|
+
var v=x.second(), x=x.third();
|
1688
|
+
ret = [Sym("set!"), v, this.expand(x, flag)].to_list();
|
1689
|
+
break;
|
1690
|
+
case Sym("call-with-current-continuation"):
|
1691
|
+
case Sym("call/cc"):
|
1692
|
+
var x=x.second();
|
1693
|
+
ret = [Sym("call/cc"), this.expand(x, flag)].to_list();
|
1694
|
+
break;
|
1695
|
+
default: //apply
|
1696
|
+
// if x is a macro call ...
|
1697
|
+
if(x.car instanceof Symbol && TopEnv[x.car.name] instanceof Syntax){
|
1698
|
+
var transformer = TopEnv[x.car.name];
|
1699
|
+
flag["modified"] = true;
|
1700
|
+
ret = transformer.transform(x);
|
1701
|
+
|
1702
|
+
if(BiwaScheme.Debug){
|
1703
|
+
var before = to_write(x), after = to_write(ret);
|
1704
|
+
if(before != after) puts("expand: " + before + " => " + after)
|
1705
|
+
}
|
1706
|
+
|
1707
|
+
var fl;
|
1708
|
+
for(;;){
|
1709
|
+
ret = this.expand(ret, fl={});
|
1710
|
+
if(!fl["modified"])
|
1711
|
+
break;
|
1712
|
+
}
|
1713
|
+
}
|
1714
|
+
else if(x == nil)
|
1715
|
+
ret = nil;
|
1716
|
+
else{
|
1717
|
+
ret = new Pair(this.expand(x.car, flag), x.cdr.to_array().map(function(item){return this.expand(item, flag)}.bind(this)).to_list());
|
1718
|
+
}
|
1719
|
+
}
|
1720
|
+
}
|
1721
|
+
else{
|
1722
|
+
ret = x;
|
1723
|
+
}
|
1724
|
+
return ret;
|
1725
|
+
},
|
1726
|
+
|
1727
|
+
evaluate: function(str, after_evaluate){
|
1728
|
+
this.parser = new Parser(str);
|
1729
|
+
this.compiler = new Compiler();
|
1730
|
+
if(after_evaluate)
|
1731
|
+
this.after_evaluate = after_evaluate;
|
1732
|
+
|
1733
|
+
if(BiwaScheme.Debug) puts("executing: " + str);
|
1734
|
+
|
1735
|
+
this.is_top = true;
|
1736
|
+
this.file_stack = [];
|
1737
|
+
return this.resume(false);
|
1738
|
+
},
|
1739
|
+
|
1740
|
+
resume: function(is_resume, a, x, f, c, s){
|
1741
|
+
var ret = BiwaScheme.undef;
|
1742
|
+
|
1743
|
+
for(;;){
|
1744
|
+
if(is_resume){
|
1745
|
+
ret = this.execute(a, x, f, c, s);
|
1746
|
+
is_resume = false;
|
1747
|
+
}
|
1748
|
+
else{
|
1749
|
+
if(!this.parser) break; // adhoc: when Pause is used via invoke_closure
|
1750
|
+
var expr = this.parser.getObject();
|
1751
|
+
if(expr === Parser.EOS) break;
|
1752
|
+
|
1753
|
+
// expand
|
1754
|
+
expr = this.expand(expr);
|
1755
|
+
|
1756
|
+
// compile
|
1757
|
+
var opc = this.compiler.run(expr);
|
1758
|
+
//if(BiwaScheme.Debug) p(opc);
|
1759
|
+
|
1760
|
+
// execute
|
1761
|
+
ret = this.execute(expr, opc, 0, [], 0);
|
1762
|
+
}
|
1763
|
+
|
1764
|
+
if(ret instanceof Pause){ //suspend evaluation
|
1765
|
+
return ret;
|
1766
|
+
}
|
1767
|
+
}
|
1768
|
+
|
1769
|
+
// finished executing all forms
|
1770
|
+
this.after_evaluate(ret);
|
1771
|
+
return ret;
|
1772
|
+
},
|
1773
|
+
|
1774
|
+
invoke_closure: function(closure, args){
|
1775
|
+
args || (args = []);
|
1776
|
+
var n_args = args.length;
|
1777
|
+
|
1778
|
+
var x = ["constant", n_args, ["argument", ["constant", closure, ["apply"]]]]
|
1779
|
+
for(var i=0; i<n_args; i++)
|
1780
|
+
x = ["constant", args[i], ["argument", x]]
|
1781
|
+
|
1782
|
+
return this.execute(closure, ["frame", x, ["halt"]], 0, closure, 0);
|
1783
|
+
},
|
1784
|
+
|
1785
|
+
// only compiling (for debug use only)
|
1786
|
+
compile: function(str){
|
1787
|
+
var obj = new Parser(str).getObject();
|
1788
|
+
var opc = Compiler.compile(obj);
|
1789
|
+
return opc;
|
1790
|
+
}
|
1791
|
+
});
|
1792
|
+
BiwaScheme.Interpreter.read = function(str){
|
1793
|
+
var parser = new Parser(str);
|
1794
|
+
return parser.getObject();
|
1795
|
+
}
|
1796
|
+
|
1797
|
+
/* --------------------------------------- namespace webscheme */
|
1798
|
+
}
|