*** empty log message ***
[m17n/m17n-lib-js.git] / xex.js
1 // -* coding: utf-8; -*
2
3 var Xex = {
4   LogNode: null,
5   LogNodeLen: 0,
6   Log: function (arg, indent, cont)
7   {
8     if (! Xex.LogNode)
9       return;
10     if (! arg)
11       {
12         while (Xex.LogNode.childNodes.length > 0)
13           Xex.LogNode.removeChild (Xex.LogNode.firstChild);
14         LogNodeLen = 0;
15       }
16     else
17       {
18         var node;
19         if (cont)
20           Xex.LogNode.lastChild.innerText += arg;
21         else
22           {
23             LogNodeLen++;
24             if (LogNodeLen >= 1000)
25               node = Xex.LogNode.firstElement ();
26             else
27               node = document.createElement ('div');
28             if (indent != undefined)
29               node.style.textIndent = (indent + 1) + 'em';
30             else
31               node.style.textIndent = '0px';
32             node.innerText = LogNodeLen + ': ' + arg;
33             Xex.LogNode.appendChild (node);
34             Xex.LogNode.scrollTop = Xex.LogNode.scrollHeight;
35           }
36       }
37   }
38 };
39
40 Xex.Error = {
41   UnknownError: "unknown-error",
42   WrongArgument: "wrong-argument",
43   // Load time errors.
44   InvalidInteger: "invalid-integer",
45   TermTypeInvalid: "term-type-invalid",
46   FunctionConflict: "function-conflict",
47   VariableTypeConflict: "variable-type-conflict",
48   VariableRangeConflict: "variable-range-conflict",
49   VariableWrongRange: "variable-wrong-range",
50   VariableWrongValue: "variable-wrong-value",
51
52   UnknownFunction: "unknown-function",
53   MacroExpansionError: "macro-expansion-error",
54   NoVariableName: "no-variable-name",
55   NoFunctionName: "no-funcion-name",
56
57   // Run time errors.
58   ArithmeticError: "arithmetic-error",
59   WrongType: "wrong-type",
60   IndexOutOfRange: "index-out-of-range",
61   ValueOutOfRange: "value-out-of-range",
62   NoLoopToBreak: "no-loop-to-break",
63   UncaughtThrow: "uncaught-throw"
64 };
65
66 Xex.Variable = function (domain, name, desc, val, range)
67 {
68   this.domain = domain;
69   this.name = name;
70   this.desc = desc;
71   this.val = val;
72   this.range = range;
73 }
74
75 Xex.Variable.prototype.clone = function ()
76 {
77   return new Xex.Variable (this.domain, this.name, this.desc,
78                            this.val, this.range);
79 }
80     
81 Xex.Variable.prototype.Equals = function (obj)
82 {
83   return ((obj instanceof Xex.Variable)
84           && obj.name == this.name);
85 }
86
87 Xex.Variable.prototype.SetValue = function (term)
88 {
89   this.val = term;
90   return term;
91 }
92
93 Xex.Function = function (name, with_var, min_args, max_args)
94 {
95   this.name = name;
96   this.with_var = with_var;
97   this.min_args = min_args;
98   this.max_args = max_args;
99 };  
100
101 Xex.Subrountine = function (builtin, name, with_var, min_args, max_args)
102 {
103   this.name = name;
104   this.with_var = with_var;
105   this.min_args = min_args;
106   this.max_args = max_args;
107   this.builtin = builtin;
108 }
109
110 Xex.Subrountine.prototype.Call = function (domain, vari, args)
111 {
112   var newargs = new Array ();
113   for (var i = 0; i < args.length; i++)
114     {
115       newargs[i] = args[i].Eval (domain);
116       if (domain.Thrown ())
117         return newargs[i];
118     }
119   return this.builtin (domain, vari, newargs)
120 }
121
122 Xex.SpecialForm = function (builtin, name, with_var, min_args, max_args)
123 {
124   this.name = name;
125   this.with_var = with_var;
126   this.min_args = min_args;
127   this.max_args = max_args;
128   this.builtin = builtin;
129 }
130
131 Xex.SpecialForm.prototype.Call = function (domain, vari, args)
132 {
133   return this.builtin (domain, vari, args)
134 }
135
136 Xex.Lambda = function (name, min_args, max_args, args, body)
137 {
138   this.name = name;
139   this.min_args = min_args;
140   this.max_args = max_args;
141   this.args = args;
142   this.body = body;
143 }
144
145 Xex.Lambda.prototype.Call = function (domain, vari, args)
146 {
147   var current = domain.bindings;
148   var result = Xex.Zero;
149   var limit = max_args >= 0 ? args.length : args.length - 1;
150   var i;
151   
152   try {
153     for (i = 0; i < limit; i++)
154       {
155         result = args[i].Eval (domain);
156         if (domain.Thrown ())
157           return result;
158         domain.Bind (this.args[i], result);
159       }
160     if (max_args < 0)
161       {
162         var list = new Array ();
163         for (i = 0; i < args[limit].length; i++)
164           {
165             result = args[limit].Eval (domain);
166             if (domain.Thrown ())
167               return result;
168             list[i] = result;
169           }
170         domain.Bind (this.args[limit], list);
171       }
172     try {
173       domain.Catch (Xex.CatchTag.Return);
174       for (var term in this.body)
175         {
176           result = term.Eval (domain);
177           if (domain.Thrown ())
178             return result;
179         }
180     } finally {
181       domain.Uncatch ();
182     }
183   } finally {
184     domain.UnboundTo (current);
185   }
186   return result;
187 }
188
189 Xex.Macro = function (name, min_args, max_args, args, body)
190 {
191   this.name = name;
192   this.min_args = min_args;
193   this.max_args = max_args;
194   this.args = args;
195   this.body = body;
196 }
197
198 Xex.Macro.prototype.Call = function (domain, vari, args)
199 {
200   var current = domain.bindings;
201   var result = Xex.Zero;
202   var i;
203
204   try {
205     for (i = 0; i < args.length; i++)
206       domain.Bind (this.args[i], args[i]);
207     try {
208       domain.Catch (Xex.CatchTag.Return);
209       for (var i in this.body)
210         {
211           result = this.body[i].Eval (domain);
212           if (domain.Thrown ())
213             break;
214         }
215     } finally {
216       domain.Uncatch ();
217     }
218   } finally {
219     domain.UnboundTo (current);
220   }
221   return result;
222 }
223
224 Xex.Bindings = function (vari)
225 {
226   this.vari = vari;
227   this.old_value = vari.val;
228 }
229
230 Xex.Bindings.prototype.UnboundTo = function (boundary)
231 {
232   for (var b = this; b != boundary; b = b.next)
233     b.vari.val = b.old_value;
234   return boundary;
235 }
236
237 Xex.Bind = function (bindings, vari, val)
238 {
239   var b = new Xex.Bindings (vari);
240   b.vari.val = val;
241   b.next = bindings;
242   return b;
243 }
244
245 Xex.CatchTag = {
246   Return: 0,
247   Break: 1
248 }
249
250 Xex.Domain = function (name, parent, context)
251 {
252   this.name = name;
253   this.context = context;
254   this.depth = 0;
255
256   if (name != 'basic' && ! parent)
257     parent = Xex.BasicDomain
258   this.parent = parent;
259   this.termtypes = {};
260   this.functions = {};
261   this.variables = {};
262   if (parent)
263     {
264       var elt;
265       for (elt in parent.termtypes)
266         this.termtypes[elt] = parent.termtypes[elt];
267       for (elt in parent.functions)
268         this.functions[elt] = parent.functions[elt];
269       for (elt in parent.variables)
270         {
271           var vari = parent.variables[elt];
272           this.variables[elt] = new Xex.Variable (this, vari.name, vari.desc,
273                                                   vari.val, vari.range);
274         }
275     }
276
277   this.call_stack = new Array ();
278   this.bindings = null;
279   this.catch_stack = new Array ();
280   this.catch_count = 0;
281   this.caught = false;
282 };
283
284 Xex.Domain.prototype = {
285   CallStackCount: function () { return this.call_stack.length; },
286   CallStackPush: function (term) { this.call_stack.push (term); },
287   CallStackPop: function () { this.call_stack.pop (); },
288   Bind: function (vari, val)
289   {
290     this.bindings = Xex.Bind (this.bindings, vari, val);
291   },
292   UnboundTo: function (boundary)
293   {
294     if (this.bindings)
295       this.bindings = this.bindings.UnboundTo (boundary);
296   },
297   Catch: function (tag) { this.catch_stack.push (tag); this.catch_count++; },
298   Uncatch: function ()
299   {
300     this.catch_stack.pop ();
301     if (this.catch_count > this.catch_stack.length)
302       this.catch_count--;
303   },
304   Thrown: function ()
305   {
306     if (this.catch_count < this.catch_stack.length)
307       {
308         this.caught = (this.catch_count == this.catch_stack.length - 1);
309         return true;
310       }
311     this.caught = false;
312     return false;
313   },
314   ThrowReturn: function ()
315   {
316     for (var i = this.catch_stack.length - 1; i >= 0; i--)
317       {
318         this.catch_count--;
319         if (this.catch_stack[i] == Xex.CatchTag.Return)
320           break;
321       }
322   },
323   ThrowBreak: function ()
324   {
325     if (this.catch_stack[this.catch_stack.length - 1] != Xex.CatchTag.Break)
326       throw new Xex.ErrTerm (Xex.Error.NoLoopToBreak,
327                            "No surrounding loop to break");
328     this.catch_count--;
329   },
330   ThrowSymbol: function (tag)
331   {
332     var i = this.catch_count;
333     for (var j = this.catch_stack.length - 1; j >= 0; j--)
334       {
335         i--;
336         if (Xex.CatchTag.Matches (this.catch_stack[i], tag))
337           {
338             this.catch_count = i;
339             return;
340           }
341       }
342     throw new Xex.ErrTerm (Xex.Error.UncaughtThrow,
343                          "No corresponding catch: " + tag);
344   },
345   DefType: function (obj)
346   {
347     var type = obj.type;
348     if (this.termtypes[type])
349       throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
350                            "Already defined: " + type);
351     if (this.functions[type])
352       throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
353                            "Already defined as a funciton or a macro: "
354                            + type);
355     this.termtypes[type] = obj.Parser;
356   },
357   DefSubr: function (builtin, name, with_var, min_args, max_args)
358   {
359     this.functions[name] = new Xex.Subrountine (builtin, name, with_var,
360                                                 min_args, max_args);
361   },
362   DefSpecial: function (builtin, name, with_var, min_args, max_args)
363   {
364     this.functions[name] = new Xex.SpecialForm (builtin, name, with_var,
365                                                 min_args, max_args);
366   },
367   Defun: function (name, min_args, max_args, args, body)
368   {
369     this.functions[name] =  new Xex.Lambda (name, min_args, max_args,
370                                             args, body);
371   },
372   DefunByFunc: function (func) { this.functions[func.name] = func; },
373   Defmacro: function (name, min_args, max_args, args, body)
374   {
375     this.functions[name] = new Xex.Macro (name, min_args, max_args,
376                                           args, body);
377   },
378   DefAlias: function (alias, fname)
379   {
380     var func = this.functions[fname];
381
382     if (! func)
383       throw new Xex.ErrTerm (Xex.Error.UnknownFunction, fname);
384     if (this.termtypes[alias])
385       throw new Xex.ErrTerm (Xex.Error.FunctionConflict,
386                            "Already defined as a term type: " + alias);
387     if (this.functions[alias])
388       throw new Xex.ErrTerm (Xex.Error.FunctionConflict,
389                            "Already defined as a function: " + alias);
390     this.functions[alias] = func;
391   },
392   Defvar: function (name, desc, val, range)
393   {
394     var vari = new Xex.Variable (this, name, desc, val, range);
395     this.variables[name] = vari;
396     return vari;
397   },
398   GetFunc: function (name)
399   {
400     var func = this.functions[name];
401     if (! func)
402       throw new Xex.ErrTerm (Xex.Error.UnknownFunction,
403                              "Unknown function: " + name);
404     return func;
405   },
406   CopyFunc: function (domain, name)
407   {
408     var func = this.functions[name];
409     domain.DefunByFunc (func);
410     return true;
411   },
412   CopyFuncAll: function (domain)
413   {
414     for (var elt in this.functions)
415       domain.DefunByFunc (this.functions[elt]);
416   },
417   GetVarCreate: function (name)
418   {
419     var vari = this.variables[name];
420     if (! vari)
421       vari = this.variables[name] = new Xex.Variable (this, name, null,
422                                                       Xex.Zero, null);
423     return vari;
424   },
425   GetVar: function (name) { return this.variables[name]; },
426   SaveValues: function ()
427   {
428     values = {};
429     for (var elt in this.variables)
430       values[elt] = this.variables[elt].val.Clone ();
431     return values;
432   },
433   RestoreValues: function (values)
434   {
435     var name;
436     for (name in values)
437       {
438         var vari = this.variables[name];
439         vari.val = values[name];
440       }
441   }
442 };
443
444 Xex.Term = function (type) { this.type = type; }
445 Xex.Term.prototype = {
446   IsTrue: function () { return true; },
447   Eval: function (domain) { return this.Clone (); },
448   Clone: function (domain) { return this; },
449   Equals: function (obj)
450   {
451     return (this.type == obj.type
452             && this.val != undefined
453             && obj.val == this.val);
454   },
455   Matches: function (obj) { return this.Equals (obj); },
456   toString: function ()
457   {
458     if (this.val != undefined)
459       return '<' + this.type + '>' + this.val + '</' + this.type + '>';
460     return '<' + this.type + '/>';
461   },
462   Intval: function () { throw new Xex.ErrTerm (Xex.Error.WrongType,
463                                                "Not an integer"); },
464   Strval: function () { throw new Xex.ErrTerm (Xex.Error.WrongType,
465                                                "Not a string"); }
466 };
467
468 Node.prototype.firstElement = function ()
469 {
470   for (var n = this.firstChild; n; n = n.nextSibling)
471     if (n.nodeType == 1)
472       return n;
473   return null;
474 }
475
476 Node.prototype.nextElement = function ()
477 {
478   for (var n = this.nextSibling; n; n = n.nextSibling)
479     if (n.nodeType == 1)
480       return n;
481   return null;
482 };
483
484 (function () {
485   function parse_defvar (domain, node)
486   {
487     var name = node.attributes['vname'].nodeValue;
488     if (! name)
489       throw new Xex.ErrTerm (Xex.Error.NoVariableName, node, '');
490     var vari = domain.variables[name];
491     var desc, val = null, range;
492     if (vari)
493       {
494         desc = vari.description;
495         val = vari.val;
496         range = vari.range;
497       }
498     node = node.firstElement ();
499     if (node && node.nodeName == 'description')
500       {
501         desc = node.firstChild.nodeValue;
502         node = node.nextElement ();
503       }
504     if (node)
505       {
506         val = Xex.Term.Parse (domain, node);
507         node = node.nextElement ();
508         if (node && node.nodeName == 'possible-values')
509           for (node = node.firstElement (); node; node = node.nextElement ())
510             {
511               var pval;
512               if (node.nodeName == 'range')
513                 {
514                   if (! val.IsInt)
515                     throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
516                                            'Range not allowed for ' + name);
517                   pval = new Array ();
518                   for (var n = node.firstElement (); n; n = n.nextElement ())
519                     {
520                       var v = Xex.Term.Parse (domain, n);
521                       if (! v.IsInt)
522                         throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
523                                                'Invalid range value: ' + val);
524                       pval.push (v);
525                     }
526                   }
527               else
528                 {
529                   pval = Xex.Term.Parse (domain, node);
530                   if (val.type != pval.type)
531                     throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
532                                            'Invalid possible value: ' + pval);
533                 }
534               if (! range)
535                 range = new Array ();
536               range.push (pval);
537           }
538       }
539     if (val == null)
540       val = Xex.Zero;
541     domain.Defvar (name, desc, val, range);
542     return name;
543   }
544
545   function parse_defun_head (domain, node)
546   {
547     var name = node.attributes['fname'].nodeValue;
548     if (! name)
549       throw new Xex.ErrTerm (Xex.Error.NoFunctionName, node, '');
550     var args = new Array ();
551     var nfixed = 0, noptional = 0, nrest = 0;
552
553     node = node.firstElement ();
554     if (node && node.nodeName == 'args')
555       {
556         var n;
557         for (n = n.firstElement (); n; n = n.nextElement ())
558           {
559             if (n.nodeName == 'fixed')
560               nfixed++;
561             else if (n.nodeName == 'optional')
562               noptional++;
563             else if (n.nodeName == 'rest')
564               nrest++;
565             else
566               throw new Xex.ErrTerm (Xex.Error.WrongType, n, n.nodeName);
567           }
568         if (nrest > 1)
569           throw new Xex.ErrTerm (Xex.Error.WrongType, n, 'Too many <rest>');
570         for (n = node.firstElement (); n; n = n.nextElement ())
571           args.push (domain.DefVar (n.attributes['vname'].nodeValue));
572       }
573     args.min_args = nfixed;
574     args.max_args = nrest == 0 ? nfixed + noptional : -1;
575
576     if (node.nodeName == 'defun')
577       domain.Defun (name, args, null);
578     else
579       domain.Defmacro (name, args, null);
580     return name;
581   }
582
583   function parse_defun_body (domain, node)
584   {
585     var name = node.attributes['fname'].nodeValue;
586     var func = domain.GetFunc (name);
587     var body;
588     for (node = node.firstElement (); node; node = node.nextElement ())
589       if (node.nodeName != 'description' && node.nodeName != 'args')
590         break;
591     body = Xex.Term.Parse (domain, node, null);
592     func.body = body;
593   }
594
595   Xex.Term.Parse = function (domain, node, stop)
596   {
597     if (arguments.length == 2)
598       {
599         var name = node.nodeName;
600         var parser = domain.termtypes[name];
601
602         if (parser)
603           return parser (domain, node);
604         if (name == 'defun' || name == 'defmacro')
605           {
606             name = parse_defun_head (domain, node);
607             parse_defun_body (domain, node);
608             return new Xex.StrTerm (name);
609           }
610         if (name == 'defvar')
611           {
612             name = parse_defvar (domain, node);
613             return new Xex.StrTerm (name);
614           }
615         return new Xex.Funcall.prototype.Parser (domain, node);
616       }
617     for (var n = node; n && n != stop; n = n.nextElement ())
618       if (n.nodeName == 'defun' || n.nodeName == 'defmacro')
619         parse_defun_head (domain, n);
620     var terms = null;
621     for (var n = node; n && n != stop; n = n.nextElement ())
622       {
623         if (n.nodeName == 'defun' || n.nodeName == 'defmacro')
624           parse_defun_body (domain, n);
625         else if (n.nodeName == 'defvar')
626           parse_defvar (domain, n);
627         else
628           {
629             if (! terms)
630               terms = new Array ();
631             terms.push (Xex.Term.Parse (domain, n));
632           }
633       }
634     return terms;
635   }
636 }) ();
637
638 Xex.Varref = function (vname)
639 {
640   this.val = vname;
641 };
642
643 (function () {
644   var proto = new Xex.Term ('varref');
645
646   proto.Clone = function () { return new Xex.Varref (this.val); }
647   proto.Eval = function (domain)
648   {
649     var vari = domain.GetVarCreate (this.val);
650     Xex.Log (this.ToString () + '=>' + vari.val, domain.depth);
651     return vari.val;
652   }
653
654   proto.Parser = function (domain, node)
655   {
656     return new Xex.Varref (node.attributes['vname'].nodeValue);
657   }
658
659   proto.ToString = function ()
660   {
661     return '<varref vname="' + this.val + '"/>';
662   }
663
664   Xex.Varref.prototype = proto;
665 }) ();
666
667 var null_args = new Array ();
668   
669 Xex.Funcall = function (func, vname, args)
670 {
671   this.func = func;
672   this.vname = vname;
673   this.args = args || null_args;
674 };
675
676 (function () {
677   var proto = new Xex.Term ('funcall');
678
679   proto.Parser = function (domain, node)
680   {
681     var fname = node.nodeName;
682     var attr;
683
684     if (fname == 'funcall')
685       fname = node.attributes['fname'].nodeValue;
686     var func = domain.GetFunc (fname);
687     var vname;
688     attr = node.attributes['vname'];
689     vname = attr != undefined ? attr.nodeValue : null;
690     var args = Xex.Term.Parse (domain, node.firstElement (), null);
691     return new Xex.Funcall (func, vname, args);
692   }
693
694   proto.New = function (domain, fname, vname, args)
695   {
696     var func = domain.GetFunc (fname);
697     var funcall = new Xex.Funcall (func, vname, args);
698     if (func instanceof Xex.Macro)
699       funcall = funcall.Eval (domain);
700     return funcall;
701   }
702
703   proto.Eval = function (domain)
704   {
705     Xex.Log (this, domain.depth);
706     var vari;
707     if (this.vname)
708       vari = domain.GetVarCreate (this.vname);
709     domain.depth++;
710     var result;
711     try {
712       result = this.func.Call (domain, vari, this.args);
713     } finally {
714       Xex.Log (' => ' + result, --domain.depth,
715                this.func instanceof Xex.Subrountine);
716     }
717     return result;
718   }
719
720   proto.Clone = function ()
721   {
722     return new Xex.Funcall (this.func, this.vari, this.args);
723   }
724
725   proto.Equals = function (obj)
726   {
727     return (obj.type == 'funcall'
728             && obj.func == this.func
729             && obj.vari.Equals (this.vari)
730             && obj.args.length == this.func.length);
731   }
732
733   proto.toString = function ()
734   {
735     var arglist = ''
736     var len = this.args.length;
737     var str = '<' + this.func.name;
738     if (this.vname)
739       str += ' vname="' + this.vname + '"';
740     if (len == 0)
741       return str + '/>';
742     if (this.func instanceof Xex.Subrountine)
743       for (var i = 0; i < len; i++)
744         arglist += this.args[i].toString ();
745     else
746       for (var i = 0; i < len; i++)
747         arglist += '.';
748     return str + '>' + arglist + '</' + this.func.name + '>';
749   }
750
751   Xex.Funcall.prototype = proto;
752 }) ();
753
754 Xex.ErrTerm = function (ename, message, stack)
755 {
756   this.ename = ename;
757   this.message = message;
758   this.stack = stack;
759 };
760
761 (function () {
762   var proto = new Xex.Term ('error');
763
764   proto.IsError = true;
765
766   proto.Parser = function (domain, node)
767   {
768     return new Xex.ErrTerm (node.attributes['ename'].nodeValue,
769                             node.innerText, false);
770   }
771
772   proto.CallStack = function () { return stack; }
773
774   proto.SetCallStack = function (value) { statck = value; }
775
776   proto.Clone = function ()
777   {
778     return new Xex.ErrTerm (ename, message, false);
779   }
780
781   proto.Equals = function (obj)
782   {
783     return (obj.IsError
784             && obj.ename == ename && obj.message == message
785             && (obj.stack ? (stack && stack.length == obj.stack.length)
786                 : ! stack));
787   }
788
789   proto.Matches = function (obj)
790   {
791     return (obj.IsError && obj.ename == ename);
792   }
793
794   proto.toString = function ()
795   {
796     return '<error ename="' + this.ename + '">' + this.message + '</error>';
797   }
798
799   Xex.ErrTerm.prototype = proto;
800 }) ();
801
802 Xex.IntTerm = function (num) { this.val = num; };
803 (function () {
804   var proto = new Xex.Term ('integer');
805   proto.IsInt = true;
806   proto.Intval = function () { return this.val; };
807   proto.IsTrue = function () { return this.val != 0; }
808   proto.Clone = function () { return new Xex.IntTerm (this.val); }
809   proto.Parser = function (domain, node)
810   {
811     var str = node.firstChild.nodeValue;
812
813     if (str.charAt (0) == '?' && str.length == 2)
814       return new Xex.IntTerm (str.charCodeAt (1));
815     return new Xex.IntTerm (parseInt (node.firstChild.nodeValue));
816   }
817   Xex.IntTerm.prototype = proto;
818 }) ();
819
820 Xex.StrTerm = function (str) { this.val = str; };
821 (function () {
822   var proto = new Xex.Term ('string');
823   proto.IsStr = true;
824   proto.Strval = function () { return this.val; };
825   proto.IsTrue = function () { return this.val.length > 0; }
826   proto.Clone = function () { return new Xex.StrTerm (this.val); }
827   proto.Parser = function (domain, node)
828   {
829     return new Xex.StrTerm (node.firstChild ? node.firstChild.nodeValue : '');
830   }
831   Xex.StrTerm.prototype = proto;
832 }) ();
833
834 Xex.SymTerm = function (str) { this.val = str; };
835 (function () {
836   var proto = new Xex.Term ('symbol');
837   proto.IsSymbol = true;
838   proto.IsTrue = function () { return this.val != 'nil'; }
839   proto.Clone = function () { return new Xex.SymTerm (this.val); }
840   proto.Parser = function (domain, node)
841   {
842     return new Xex.SymTerm (node.firstChild.nodeValue);
843   }
844   Xex.SymTerm.prototype = proto;
845 }) ();
846
847 Xex.LstTerm = function (list) { this.val = list; };
848 (function () {
849   var proto = new Xex.Term ('list');
850   proto.IsList = true;
851   proto.IsTrue = function () { return this.val.length > 0; }
852   proto.Clone = function () { return new Xex.LstTerm (this.val.slice (0)); }
853
854   proto.Equals = function (obj)
855   {
856     if (obj.type != 'list' || obj.val.length != this.val.length)
857       return false;
858     var i, len = this.val.length;
859     for (i = 0; i < len; i++)
860       if (! this.val[i].Equals (obj.val[i]))
861         return false;
862     return true;
863   }
864
865   proto.Parser = function (domain, node)
866   {
867     var list = Xex.Term.Parse (domain, node.firstElement (), null);
868     return new Xex.LstTerm (list);
869   }
870
871   proto.toString = function ()
872   {
873     var len = this.val.length;
874
875     if (len == 0)
876       return '<list/>';
877     var str = '<list>';
878     for (var i = 0; i < len; i++)
879       str += this.val[i].toString ();
880     return str + '</list>';
881   }
882   Xex.LstTerm.prototype = proto;
883 }) ();
884
885 (function () {
886   var basic = new Xex.Domain ('basic', null, null);
887
888   function Fset (domain, vari, args)
889   {
890     if (! vari)
891       throw new Xex.ErrTerm (Xex.Error.NoVariableName,
892                              'No variable name to set');
893     vari.SetValue (args[0]);
894     return args[0];
895   }
896
897   function Fnot (domain, vari, args)
898   {
899     return (args[0].IsTrue () ? Xex.Zero : Xex.One);
900   }
901
902   function maybe_set_intvar (vari, n)
903   {
904     var term = new Xex.IntTerm (n);
905     if (vari)
906       vari.SetValue (term);
907     return term;
908   }
909
910   function Fadd (domain, vari, args)
911   {
912     var n = vari ? vari.val.Intval () : 0;
913     var len = args.length;
914
915     for (var i = 0; i < len; i++)
916       n += args[i].Intval ();
917     return maybe_set_intvar (vari, n);
918   }
919
920   function Fmul (domain, vari, args)
921   {
922     var n = vari ? vari.val.Intval () : 1;
923     for (var i = 0; i < args.length; i++)
924       n *= args[i].Intval ();
925     return maybe_set_intvar (vari, n);
926   }
927
928   function Fsub (domain, vari, args)
929   {
930     var n, i;
931
932     if (! vari)
933       {
934         n = args[0].Intval ();
935         i = 1;
936       }
937     else
938       {
939         n = vari.val.Intval ();
940         i = 0;
941       }
942     while (i < args.length)
943       n -= args[i++].Intval ();
944     return maybe_set_intvar (vari, n);
945   }
946
947   function Fdiv (domain, vari, args)
948   {
949     var n, i;
950
951     if (! vari == null)
952       {
953         n = args[0].Intval ();
954         i = 1;
955       }
956     else
957       {
958         n = vari.val.Intval ();
959         i = 0;
960       }
961     while (i < args.length)
962       n /= args[i++].Intval ();
963     return maybe_set_intvar (vari, n);
964   }
965
966   function Fmod (domain, vari, args)
967   {
968     return maybe_set_intvar (vari, args[0].Intval () % args[1].Intval ());
969   }
970
971   function Flogior (domain, vari, args)
972   {
973     var n = vari == null ? 0 : vari.val;
974     for (var i = 0; i < args.length; i++)
975       n |= args[i].val;
976     return maybe_set_intvar (vari, n);
977   }
978
979   function Flogand (domain, vari, args)
980   {
981     var n, i;
982     if (vari == null)
983       {
984         Xex.Log ("logand arg args[0]" + args[0]);
985         n = args[0].Intval ()
986         i = 1;
987       }
988     else
989       {
990         Xex.Log ("logand arg var " + vari);
991         n = vari.val.Intval ();
992         i = 0;
993       }
994     while (n > 0 && i < args.length)
995       {
996         Xex.Log ("logand arg " + args[i]);
997         n &= args[i++].val;
998       }
999     return maybe_set_intvar (vari, n);
1000   }
1001
1002   function Flsh (domain, vari, args)
1003   {
1004     return maybe_set_intvar (vari, args[0].Intval () << args[1].Intval ());
1005   }
1006
1007   function Frsh (domain, vari, args)
1008   {
1009     return maybe_set_intvar (vari, args[0].Intval () >> args[1].Intval ());
1010   }
1011
1012   function Fand (domain, vari, args)
1013   {
1014     var len = args.length;
1015     for (var i = 0; i < len; i++)
1016     {
1017       var result = args[i].Eval (domain);
1018       if (domain.Thrown ())
1019         return result;
1020       if (! result.IsTrue ())
1021         return Xex.Zero;
1022     }
1023     return Xex.One;
1024   }
1025
1026   function For (domain, vari, args)
1027   {
1028     var len = args.length;
1029     for (var i = 0; i < len; i++)
1030     {
1031       var result = args[i].Eval (domain);
1032       if (domain.Thrown ())
1033         return result;
1034       if (result.IsTrue ())
1035         return Xex.One;
1036     }
1037     return Xex.Zero;
1038   }
1039
1040   function Feq (domain, vari, args)
1041   {
1042     for (var i = 1; i < args.length; i++)
1043       if (! args[i - 1].Equals (args[i]))
1044         return Xex.Zero;
1045     return Xex.One;
1046   }
1047
1048   function Fnoteq (domain, vari, args)
1049   {
1050     return (Feq (domain, vari, args) == Xex.One ? Xex.Zero : Xex.One);
1051   }
1052
1053   function Flt (domain, vari, args)
1054   {
1055     var n = args[0].Intval ();
1056
1057     for (var i = 1; i < args.length; i++)
1058       {
1059         var n1 = args[i].Intval ();
1060         if (n >= n1)
1061           return Xex.Zero;
1062         n = n1;
1063       }
1064     return Xex.One;
1065   }
1066
1067   function Fle (domain, vari, args)
1068   {
1069     var n = args[0].Intval ();
1070     for (var i = 1; i < args.length; i++)
1071       {
1072         var n1 = args[i].Intval ();
1073         if (n > n1)
1074           return Xex.Zero;
1075         n = n1;
1076       }
1077     return Xex.One;
1078   }
1079
1080   function Fgt (domain, vari, args)
1081   {
1082     var n = args[0].Intval ();
1083     for (var i = 1; i < args.length; i++)
1084       {
1085         var n1 = args[i].Intval ();
1086         if (n <= n1)
1087           return Xex.Zero;
1088         n = n1;
1089       }
1090     return Xex.One;
1091   }
1092
1093   function Fge (domain, vari, args)
1094   {
1095     var n = args[0].Intval ();
1096     for (var i = 1; i < args.length; i++)
1097       {
1098         var n1 = args[i].Intval ();
1099         if (n < n1)
1100           return Xex.Zero;
1101         n = n1;
1102       }
1103     return Xex.One;
1104   }
1105
1106   function Fprogn (domain, vari, args)
1107   {
1108     var result = Xex.One;
1109     var len = args.length;
1110
1111     for (var i = 0; i < len; i++)
1112       {
1113         result = args[i].Eval (domain);
1114         if (domain.Thrown ())
1115           return result;
1116       }
1117     return result;
1118   }
1119
1120   function Fif (domain, vari, args)
1121   {
1122     var result = args[0].Eval (domain);
1123
1124     if (domain.Thrown ())
1125       return result;
1126     if (result.IsTrue ())
1127       return args[1].Eval (domain);
1128     if (args.length == 2)
1129       return Xex.Zero;
1130     return args[2].Eval (domain);
1131   }
1132
1133   function Fcond (domain, vari, args)
1134   {
1135     for (var i = 0; i < args.length; i++)
1136       {
1137         var list = args[i];
1138         var result = list.val[0].Eval (domain);
1139         if (result.IsTrue ())
1140           {
1141             for (var j = 1; j < list.val.length; j++)
1142               {
1143                 domain.depth++;
1144                 result = list.val[j].Eval (domain);
1145                 domain.depth--;
1146                 if (domain.Thrown ())
1147                   return result;
1148                 }
1149             return result;
1150           }
1151       }
1152     return Xex.Zero;
1153   }
1154
1155   function eval_terms (domain, terms, idx)
1156   {
1157     var result = Xex.Zero;
1158     domain.caught = false;
1159     for (var i = idx; i < terms.length; i++)
1160       {
1161         result = terms[i].Eval (domain);
1162         if (domain.Thrown ())
1163           return result;
1164       }
1165     return result;
1166   }
1167
1168   function Fcatch (domain, vari, args)
1169   {
1170     var caught = false;
1171     var result;
1172
1173     if (args[0].IsError)
1174       {
1175         try {
1176           result = eval_terms (domain, args, 1);
1177         } catch (e) {
1178           if (e instanceof Xex.ErrTerm)
1179             {
1180               if (! args[0].Matches (e))
1181                 throw e;
1182               if (vari)
1183                 vari.SetValue (e);
1184               return Xex.One;
1185             }
1186         }
1187       }
1188     else if (args[0].IsSymbol)
1189       {
1190         try {
1191           domain.Catch (args[0].val);
1192           result = eval_terms (domain, args, 1);
1193           if (domain.caught)
1194             {
1195               if (vari != null)
1196                 vari.SetValue (result);
1197               return Xex.One;
1198             }
1199           return Xex.Zero;
1200         } finally {
1201           domain.Uncatch ();
1202         }
1203       }
1204     throw new Xex.ErrTerm (Xex.Error.WrongArgument,
1205                            "Not a symbol nor an error: " + args[0]);
1206   }
1207
1208   function Fthrow (domain, vari, args)
1209   {
1210     if (args[0].IsSymbl)
1211       {
1212         domain.ThrowSymbol (args[0]);
1213         return (args[args.length - 1]);
1214       }
1215     if (args[0].IsError)
1216       {
1217         throw args[0];
1218       }
1219     throw new Xex.ErrTerm (Xex.Error.WrongArgument,
1220                            "Not a symbol nor an error:" + args[0]);
1221   }
1222
1223   Xex.BasicDomain = basic;
1224
1225   basic.DefSubr (Fset, "set", true, 1, 1);
1226   basic.DefAlias ("=", "set");
1227   basic.DefSubr (Fnot, "not", false, 1, 1);
1228   basic.DefAlias ("!", "not");
1229   basic.DefSubr (Fadd, "add", true, 1, -1);
1230   basic.DefSubr (Fmul, "mul", true, 1, -1);
1231   basic.DefAlias ("*", "mul");
1232   basic.DefSubr (Fsub, "sub", true, 1, -1);
1233   basic.DefAlias ("-", "sub");
1234   basic.DefSubr (Fdiv, "div", true, 1, -1);
1235   basic.DefAlias ("/", "div");
1236   basic.DefSubr (Fmod, "mod", true, 1, 2);
1237   basic.DefAlias ("%", "mod");
1238   basic.DefSubr (Flogior, "logior", true, 1, -1);
1239   basic.DefAlias ('|', "logior");
1240   basic.DefSubr (Flogand, "logand", true, 1, -1);
1241   basic.DefAlias ("&", "logand");
1242   basic.DefSubr (Flsh, "lsh", true, 1, 2);
1243   basic.DefAlias ("<<", "lsh");
1244   basic.DefSubr (Frsh, "rsh", true, 1, 2);
1245   basic.DefAlias (">>", "rsh");
1246   basic.DefSubr (Feq, "eq", false, 2, -1);
1247   basic.DefAlias ("==", "eq");
1248   basic.DefSubr (Fnoteq, "noteq", false, 2, 2);
1249   basic.DefAlias ("!=", "noteq");
1250   basic.DefSubr (Flt, "lt", false, 2, -1);
1251   basic.DefAlias ("<", "lt");
1252   basic.DefSubr (Fle, "le", false, 2, -1);
1253   basic.DefAlias ("<=", "le");
1254   basic.DefSubr (Fgt, "gt", false, 2, -1);
1255   basic.DefAlias (">", "gt");
1256   basic.DefSubr (Fge, "ge", false, 2, -1);
1257   basic.DefAlias (">=", "ge");
1258   basic.DefSubr (Fthrow, "throw", false, 1, 2);
1259
1260   //basic.DefSubr (Fappend, "append", true, 0, -1);
1261   //basic.DefSubr (Fconcat, "concat", true, 0, -1);
1262   //basic.DefSubr (Fnth, "nth", false, 2, 2);
1263   //basic.DefSubr (Fcopy, "copy", false, 1, 1);
1264   //basic.DefSubr (Fins, "ins", true, 2, 2);
1265   //basic.DefSubr (Fdel, "del", true, 2, 2);
1266   //basic.DefSubr (Feval, "eval", false, 1, 1);
1267   //basic.DefSubr (Fbreak, "break", false, 0, 1);
1268   //basic.DefSubr (Freturn, "return", false, 0, 1);
1269   //basic.DefSubr (Fthrow, "throw", false, 1, 2);
1270
1271   basic.DefSpecial (Fand, "and", false, 1, -1);
1272   basic.DefAlias ("&&", "and");
1273   basic.DefSpecial (For, "or", false, 1, -1);
1274   basic.DefAlias ("||", "or");
1275   basic.DefSpecial (Fprogn, "progn", false, 1, -1);
1276   basic.DefAlias ("expr", "progn");
1277   basic.DefSpecial (Fif, "if", false, 2, 3);
1278   //basic.DefSpecial (Fwhen, "when", false, 1, -1);
1279   //basic.DefSpecial (Floop, "loop", false, 1, -1);
1280   //basic.DefSpecial (Fwhile, "while", false, 1, -1);
1281   basic.DefSpecial (Fcond, "cond", false, 1, -1);
1282   //basic.DefSpecial (Fforeach, "foreach", true, 2, -1);
1283   //basic.DefSpecial (Fquote, "quote", false, 1, 1);
1284   //basic.DefSpecial (Ftype, "type", false, 1, 1);
1285   basic.DefSpecial (Fcatch, "catch", true, 2, -1);
1286
1287   basic.DefType (Xex.Funcall.prototype);
1288   basic.DefType (Xex.Varref.prototype);
1289   basic.DefType (Xex.ErrTerm.prototype);
1290   basic.DefType (Xex.IntTerm.prototype);
1291   basic.DefType (Xex.StrTerm.prototype);
1292   basic.DefType (Xex.SymTerm.prototype);
1293   basic.DefType (Xex.LstTerm.prototype);
1294
1295 }) ();
1296
1297 Xex.Zero = new Xex.IntTerm (0);
1298 Xex.One = new Xex.IntTerm (1);
1299 Xex.nil = new Xex.SymTerm ('nil');
1300
1301 Xex.Load = function (server, file)
1302 {
1303   var obj = new XMLHttpRequest ();
1304   var url = server ? server + '/' + file : file;
1305   //alert ('loading ' + url);
1306   obj.open ('GET', url, false);
1307   obj.overrideMimeType ('text/xml');
1308   obj.send ('');
1309   return (obj.responseXML && obj.responseXML.firstChild);
1310 }