yhara-ticketmap 0.3.1

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