*** empty log message ***
[m17n/m17n-lib-cs.git] / XmlExpr.cs
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.IO;
5 using System.Xml;
6
7 namespace System.Xml.Expression
8 {
9   public class Xexpression
10   {
11     public static int debug_level = 0;
12
13     public struct Symbol : IEquatable<Symbol>
14     {
15       private static NameTable nt = new NameTable ();
16
17       internal string name;
18
19       public Symbol (string str)
20         {
21           name = nt.Add (str);
22         }
23
24       public static implicit operator Symbol (string str)
25       {
26         return new Symbol (str);
27       }
28
29       public static implicit operator string (Symbol name)
30       {
31         return name.name;
32       }
33
34       public static bool operator== (Symbol n1, Symbol n2)
35         {
36           return (object) n1.name == (object) n2.name;
37         }
38
39       public static bool operator!= (Symbol n1, Symbol n2)
40         {
41           return (object) n1.name != (object) n2.name;
42         }
43
44       public static bool operator== (Symbol n1, string n2)
45         {
46           return (object) n1.name == (object) n2;
47         }
48
49       public static bool operator!= (Symbol n1, string n2)
50         {
51           return (object) n1.name != (object) n2;
52         }
53
54       public static bool operator== (string n1, Symbol n2)
55         {
56           return (object) n1 == (object) n2.name;
57         }
58
59       public static bool operator!= (string n1, Symbol n2)
60         {
61           return (object) n1 != (object) n2.name;
62         }
63
64       public bool Equals (Symbol name)
65       {
66         return Object.ReferenceEquals (this.name, name.name);
67       }
68
69       public override bool Equals (object obj)
70       {
71         return Object.ReferenceEquals (this.name, obj);
72       }
73
74       public override int GetHashCode ()
75       {
76         return name.GetHashCode ();
77       }
78
79       public static NameTable Table { get { return nt; } }
80
81       public override string ToString () { return name; }
82     }
83
84     private static Symbol Nexpr = "expr";
85
86     private static Symbol Nfuncall = "funcall";
87     private static Symbol Nvarref = "varref";
88     private static Symbol Ninteger = "integer";
89     private static Symbol Nstring = "string";
90     private static Symbol Nsymbol = "symbol";
91     private static Symbol Nlist = "list";
92
93     private static Symbol Ndefun = "defun";
94     private static Symbol Nfname = "fname";
95     private static Symbol Nargs = "args";
96     private static Symbol Nargs_unevalled = "args-unevalled";
97     private static Symbol Nfixed = "fixed";
98     private static Symbol Noptional = "optional";
99     private static Symbol Nrest = "rest";
100
101     private static Symbol Ndefvar = "defvar";
102     private static Symbol Nvname = "vname";
103     private static Symbol Ndescription = "description";
104     private static Symbol Nrange = "range";
105
106     public abstract class Function
107     {
108       public Symbol name;
109       public int min_arg, max_arg;
110
111       public Function () { }
112
113       public Function (Symbol name, int min_arg, int max_arg)
114       {
115         this.name = name;
116         this.min_arg = min_arg;
117         this.max_arg = max_arg;
118       }
119
120       public abstract Term Call (Domain domain, Variable vari, Term[] args);
121
122       public override string ToString ()
123       {
124         return name;
125       }
126
127       internal class Subroutine : Function
128       {
129         public Builtin builtin;
130         public bool setvar;
131
132         public Subroutine (Builtin builtin, Symbol name, bool setvar,
133                            int min_arg, int max_arg)
134           : base (name, min_arg, max_arg)
135           {
136             this.builtin = builtin;
137           }
138
139         public override Term Call (Domain domain, Variable vari, Term[] args)
140         {
141           args = (Term[]) args.Clone ();
142           for (int i = 0; i < args.Length; i++)
143             {
144               args[i] = args[i].Eval (domain);
145               if (domain.Thrown)
146                 return args[i];
147             }
148           return builtin (domain, vari, args);
149         }
150       }
151
152       internal class SpecialForm : Function
153       {
154         public Builtin builtin;
155
156         public SpecialForm (Builtin builtin, Symbol name,
157                             int min_arg, int max_arg)
158           : base (name, min_arg, max_arg)
159           {
160             this.builtin = builtin;
161           }
162
163         public override Term Call (Domain domain, Variable vari, Term[] args)
164         {
165           return builtin (domain, vari, args);
166         }
167       }
168
169       internal class Lambda : Function
170       {
171         internal bool args_evalled;
172         internal Variable[] args;
173         internal Term[] body;
174
175         public Lambda (Domain domain, XmlNode node)
176           {
177             int nfixed = 0;
178             int noptional = 0;
179             int nrest = 0;
180             name = node.Attributes[Nfname].Value;
181             
182             node = node.FirstChild;
183             if (node != null
184                 && (node.Name == Nargs || node.Name == Nargs_unevalled))
185               {
186                 XmlNode n;
187                 args_evalled = node.Name == Nargs;
188                 for (n = node.FirstChild; n != null; n = n.NextSibling)
189                   {
190                     if (n.Name == Nfixed)
191                       nfixed++;
192                     else if (n.Name == Noptional)
193                       noptional++;
194                     else if (n.Name == Nrest)
195                       nrest++;
196                     else
197                       throw new Exception ("Invalid argument type: " + n);
198                   }
199                 min_arg = nfixed;
200                 max_arg = nfixed + noptional + nrest;
201                 args = new Variable[max_arg];
202                 n = node.FirstChild;
203                 for (int i = 0; i < max_arg; n = n.NextSibling)
204                   args[i++] = domain.Defvar ((Symbol) n.Attributes[0].Value);
205                 if (nrest == 1)
206                   max_arg = - max_arg;
207               }
208             else
209               {
210                 min_arg = max_arg = 0;
211               }
212           }
213
214         public Lambda (Domain domain, Symbol name, bool args_evalled, Symbol[] args)
215           {
216             int nfixed = 0;
217             int noptional = 0;
218             int nrest = 0;
219
220             this.name = name;
221             this.args_evalled = args_evalled;
222             if (args != null)
223               {
224                 int i = 0;
225                 for (i = 0; i < args.Length; i++, nfixed++)
226                   if (args[i] == Noptional || args[i] == Nrest)
227                     break;
228                 if (i < args.Length)
229                   {
230                     if (args[i] == Noptional)
231                       {
232                         for (i++; i < args.Length; i++, noptional++)
233                           if (args[i] == Nrest)
234                             break;
235                         if (i < args.Length)
236                           nrest = 1;
237                       }
238                   }
239                 min_arg = nfixed;
240                 max_arg = nfixed + noptional + nrest;
241                 this.args = new Variable[max_arg];
242                 int j;
243                 for (i = j = 0; j < this.args.Length; i++)
244                   if (args[i] != Noptional || args[i] != Nrest)
245                     this.args[j++] = domain.Defvar (args[i]);
246               }
247             else
248               {
249                 min_arg = max_arg = 0;
250               }
251           }
252
253         public void SetBody (Domain domain, XmlNode node)
254         {
255           for (node = node.FirstChild; node != null; node = node.NextSibling)
256             if (node.Name != Ndescription
257                 && node.Name != Nargs
258                 && node.Name != Nargs_unevalled)
259               break;
260           int nterms = 0;
261           for (XmlNode n = node; n != null; n = n.NextSibling)
262             nterms++;
263           if (nterms > 0)
264             {
265               body = new Term[nterms];
266               for (nterms = 0; node != null; node = node.NextSibling, nterms++)
267                 body[nterms] = new Term (node, domain);
268             }
269         }
270
271         public void SetBody (Term[] body)
272         {
273           this.body = body;
274         }
275
276         public override Term Call (Domain domain, Variable vari, Term[] args)
277         {
278           Bindings current = domain.bindings;
279           Term result = Zero;
280
281           try {
282             int i;
283             if (args_evalled)
284               {
285                 Term[] newargs = new Term[args.Length];
286                 for (i = 0; i < min_arg; i++)
287                   newargs[i] = args[i].Eval (domain);
288                 args = newargs;
289               }
290             for (i = 0; i < min_arg; i++)
291               domain.Bind (this.args[i], args[i]);
292             if (body != null)
293               {
294                 try {
295                   if (args_evalled)
296                     domain.Catch (CatchTag.Return);
297                   foreach (Term term in body)
298                     {
299                       result = term.Eval (domain);
300                       if (domain.Thrown)
301                         return result;
302                     }
303                 } finally {
304                   if (args_evalled)
305                     domain.Uncatch ();
306                 }
307               }
308           } finally {
309             domain.UnboundTo (current);
310           }
311           return result;
312         }
313       }
314     }
315
316     public class Variable : TermValue
317     {
318       public readonly Symbol name;
319       public string desc;
320       internal Term default_val;
321       internal Term val;
322       object range;
323
324       public Variable (Symbol name, Term value)
325       {
326         this.name = name;
327         val = value;
328         default_val = Zero;
329       }
330
331       public virtual bool ValueP (Term val) { return true; }
332
333       public override TermValue Clone ()
334       {
335         Variable v = new Variable (name, val);
336         v.desc = desc;
337         v.default_val = default_val;
338         v.range = range;
339         return v;
340       }
341
342       public Term Value
343       {
344         get { return val; }
345         set {
346           if (! ValueP (value))
347             throw new Exception ("Invalid value: " + value);
348           val = value;
349         }
350       }
351
352       public Term DefaultValue
353       {
354         get { return default_val; }
355         set {
356           if (! ValueP (value))
357             throw new Exception ("Invalid value: " + value);
358           default_val = value;
359         }
360       }
361
362       public virtual object Range
363       {
364         get { return range; }
365         set { range = value; }
366       }
367
368       public override Term Eval (Domain domain) { return val; }
369
370       public override string ToString () { return name + "(" + val + ")"; }
371
372       public class Int : Variable
373       {
374         public int[] range;
375
376         private static bool SubsetP (int[] r1, int[] r2)
377           {
378             if (r2 == null)
379               return true;
380             for (int i = 0; i < r1.Length; i += 2)
381               {
382                 int j;
383                 for (j = 0; j < r2.Length; j += 2)
384                   if (r2[j] <= r1[i] && r2[j + 1] >= r1[i + 1])
385                     break;
386                 if (j >= r2.Length)
387                   return false;
388               }
389             return true;
390           }
391
392         private static bool SubsetP (int val, int[] r)
393           {
394             if (r == null)
395               return true;
396             for (int i = 0; i < r.Length; i += 2)
397               if (r[i] <= val && r[i + 1] >= val)
398                 return true;
399             return false;
400           }
401
402         public Int (Symbol name, string description, int value, int[] range)
403           : base (name, new Term (value))
404           {
405             if (! SubsetP (value, range))
406               throw new Exception ("Invalid value: " + value);
407             desc = description;
408             default_val = val;
409             this.range = range;
410           }
411
412         public override bool ValueP (Term term)
413         {
414           if (! term.IsInt)
415             return false;
416           return SubsetP (term.Intval, range);
417         }
418
419         public override object Range {
420           get { return range; }
421           set {
422             int[] r = (int[]) value;
423             if (! SubsetP (r, range)
424                 || ! SubsetP (val.Intval, r)
425                 || ! SubsetP (default_val.Intval, r))
426               throw new Exception ("Invalid range");
427             range = r;
428           }
429         }
430       }
431
432       public class Str : Variable
433       {
434         public string[] range;
435
436         private static bool SubsetP (string[] r1, string[] r2)
437           {
438             if (r2 == null)
439               return true;
440             foreach (string s in r1)
441               if (! SubsetP (s, r2))
442                 return false;
443             return true;
444           }
445
446         private static bool SubsetP (string str, string[] r)
447           {
448             if (r == null)
449               return true;
450             foreach (string s in r)
451               if (str == s)
452                 return true;
453             return false;
454         }
455
456         public Str (Symbol name, string description, string value, string[] range)
457           : base (name, new Term (value))
458           {
459             if (! SubsetP (value, range))
460               throw new Exception ("Invalid value: " + value);
461             desc = description;
462             default_val = val;
463             this.range = range;
464           }
465
466         public override bool ValueP (Term term)
467         {
468           if (! (term.objval is string))
469             return false;
470           return SubsetP (term.Strval, range);
471         }
472
473         public override object Range {
474           get { return range; }
475           set {
476             string[] r = (string[]) value;
477             if (! SubsetP (r, range)
478                 || ! SubsetP (val.Strval, r)
479                 || ! SubsetP (default_val.Strval, r))
480               throw new Exception ("Invalid range");
481             range = r;
482           }
483         }
484       }
485
486       public class Sym : Variable
487       {
488         public Symbol[] range;
489
490         private static bool SubsetP (Symbol[] r1, Symbol[] r2)
491           {
492             if (r2 == null)
493               return true;
494             foreach (Symbol n in r1)
495               if (! SubsetP (n, r2))
496                 return false;
497             return true;
498           }
499
500         private static bool SubsetP (Symbol name, Symbol[] r)
501           {
502             if (r == null)
503               return true;
504             foreach (Symbol n in r)
505               if (name == n)
506                 return true;
507             return false;
508         }
509
510         public Sym (Symbol name, string description, Symbol value, Symbol[] range)
511           : base (name, new Term (value))
512           {
513             if (! SubsetP (value, range))
514               throw new Exception ("Invalid value: " + value);
515             desc = description;
516             default_val = val;
517             this.range = range;
518           }
519
520         public override bool ValueP (Term term)
521         {
522           if (! (term.objval is Symbol))
523             return false;
524           return SubsetP (term.Symval, range);
525         }
526
527         public override object Range {
528           get { return range; }
529           set {
530             Symbol[] r = (Symbol[]) value;
531             if (! SubsetP (r, range)
532                 || ! SubsetP (val.Symval, r)
533                 || ! SubsetP (default_val.Symval, r))
534               throw new Exception ("Invalid range");
535             range = r;
536           }
537         }
538       }
539     }
540
541     internal class Bindings
542     {
543       private Variable vari;
544       private Term old_value;
545       private Bindings next;
546         
547       private Bindings (Variable vari)
548       {
549         this.vari = vari;
550         old_value = vari.val;
551       }
552         
553       public static Bindings Bind (Bindings bindings, Variable vari, Term val)
554       {
555         Bindings b = new Bindings (vari);
556
557         b.vari.Value = val;
558         b.next = bindings;
559         return b;
560       }
561
562       internal Bindings UnboundTo (Bindings boundary)
563       {
564         for (Bindings b = this; b != boundary; b = b.next)
565           b.vari.val = b.old_value;
566         return boundary;
567       }
568
569       public override string ToString ()
570       {
571         string str = "(bindings";
572         for (Bindings b = this; b != null; b = b.next)
573           str += " " + vari.name + "=" + b.old_value;
574         return str + ")";
575       }
576     }
577
578 #if false
579     internal class ThrowException : Exception
580     {
581       Symbol tag;
582       public object value;
583
584       public ThrowException (Symbol tag, object value) : base ()
585         {
586           this.tag = tag;
587           this.value = value;
588         }
589     }
590 #endif
591
592     internal class CatchTag : IEquatable<CatchTag>
593     {
594       private object val;
595
596       public CatchTag (Symbol name) { val = name.name; }
597       private CatchTag (int i) { val = i; }
598
599       public static CatchTag Return = new CatchTag (0);
600       public static CatchTag Break = new CatchTag (1);
601
602       public static bool operator== (CatchTag t1, CatchTag t2)
603         { return t1.val == t2.val; }
604
605       public static bool operator!= (CatchTag t1, CatchTag t2)
606         { return t1.val != t2.val; }
607
608       public bool Equals (CatchTag tag) { return this.val == tag.val; }
609       public override bool Equals (object val) { return this.val == val; }
610
611       public override int GetHashCode () { return val.GetHashCode (); }
612     }
613
614     public class Domain
615     {
616       public object context;
617       public int depth = 0;
618
619       internal Dictionary<Symbol, Function> functions
620         = new Dictionary<Symbol, Function> ();
621       internal Dictionary<Symbol, Variable> variables
622         = new Dictionary<Symbol, Variable> ();
623       internal Bindings bindings;
624       private Stack<CatchTag> catch_stack = new Stack<CatchTag> ();
625       private int catch_count = 0;
626
627       internal Domain () { }
628
629       public Domain (object context) : this (basic, context) { }
630
631       public Domain (Domain parent, object context)
632       {
633         functions = new Dictionary<Symbol, Function> (parent.functions);
634         variables = new Dictionary<Symbol, Variable> (parent.variables);
635         this.context = context;
636       }
637
638       internal void Bind (Variable vari, Term value)
639       {
640         bindings = Bindings.Bind (bindings, vari, value);
641       }
642
643       internal void UnboundTo (Bindings boundary)
644       {
645         if (bindings != null)
646           bindings = bindings.UnboundTo (boundary);
647       }
648
649       internal void Catch (CatchTag tag)
650       {
651         catch_stack.Push (tag);
652         catch_count++;
653       }
654
655       internal void Uncatch ()
656       {
657         catch_stack.Pop ();
658         if (catch_count > catch_stack.Count)
659           catch_count--;
660       }
661
662       public bool Thrown {
663         get { return catch_count < catch_stack.Count; }
664       }
665
666       internal void ThrowReturn ()
667       {
668         foreach (CatchTag tag in catch_stack)
669           {
670             catch_count--;
671             if (tag == CatchTag.Return)
672               break;
673           }
674       }
675
676       internal void ThrowBreak ()
677       {
678         if (catch_stack.Peek () != CatchTag.Break)
679           throw new Exception ("No outer loop to break");
680         catch_count--;
681       }
682
683       internal void ThrowTag (CatchTag tag)
684       {
685         foreach (CatchTag elt in catch_stack)
686           {
687             catch_count--;
688             if (elt == tag)
689               break;
690           }
691       }
692
693       public void DefSubr (Builtin builtin, string str, bool setvar,
694                            int min_arg, int max_arg, params string[] aliases)
695       {
696         Symbol name = str;
697         Function func = new Function.Subroutine (builtin, name, setvar,
698                                                  min_arg, max_arg);
699         functions[name] = func;
700         foreach (string a in aliases)
701           functions[(Symbol) a] = func;
702       }
703
704       public void DefSpecial (Builtin builtin, string str,
705                               int min_arg, int max_arg,
706                               params string[] aliases)
707       {
708         Symbol name = str;
709         Function func = new Function.SpecialForm (builtin, name,
710                                                   min_arg, max_arg);
711         functions[name] = func;
712         foreach (string a in aliases)
713           functions[(Symbol) a] = func;
714       }
715
716       public void DefAlias (string alias, string str)
717       {
718         functions[(Symbol) alias] = functions[(Symbol) str];
719       }
720
721       public void Defun (Symbol name, bool args_evalled,
722                          Symbol[] args, Term[] body, bool prototype)
723       {
724         Function func;
725
726         if (prototype || ! functions.TryGetValue (name, out func))
727           {
728             func = new Function.Lambda (this, name, args_evalled, args);
729             functions[name] = func;
730           }
731         if (! prototype)
732           ((Function.Lambda) func).SetBody (body);
733       }
734
735       public void Defun (XmlNode node, bool prototype)
736       {
737         Symbol name = node.Attributes[Nfname].Value;
738         Function func;
739
740         if (prototype || ! functions.TryGetValue (name, out func))
741           {
742             func = new Function.Lambda (this, node);
743             functions[name] = func;
744           }
745         if (! prototype)
746           ((Function.Lambda) func).SetBody (this, node);
747       }
748
749       public void Defun (Function func)
750       {
751         functions[func.name] = func;
752       }
753
754       public Variable Defvar (XmlNode node)
755       {
756         Symbol name = node.Attributes[0].Value;
757         String desc;
758         Variable vari;
759
760         node = node.FirstChild;
761         if (node != null && node.Name == Ndescription)
762           {
763             desc = node.InnerText;
764             node = node.NextSibling;
765           }
766         else
767           desc = null;
768         if (node != null)
769           {
770             XmlNode nn;
771             if (node.Name == "value")
772               nn = node.FirstChild;
773             else
774               nn = node;
775             Symbol type = nn.Name;
776             XmlNodeList range_list = null;
777             int nranges = 0;
778             string val = nn.InnerText;
779
780             node = node.NextSibling;
781             if (node != null)
782               {
783                 range_list = node.ChildNodes;
784                 nranges = range_list.Count;
785               }
786
787             if (type == Ninteger)
788               {
789                 int intval = parse_integer (val);
790                 int[] range = null;
791                 if (range_list != null)
792                   {
793                     range = new int[nranges * 2];
794                     for (int i = 0; i < nranges; i++)
795                       {
796                         XmlNode n = range_list[i];
797                         if (n.Name == Nrange)
798                           {
799                             range[i * 2]
800                               = parse_integer (n.FirstChild.InnerText);
801                             range[i * 2 + 1]
802                               = parse_integer (n.LastChild.InnerText);
803                           }
804                         else
805                           {
806                             range[i * 2]
807                               = range[i * 2 + 1]
808                               = parse_integer (n.FirstChild.InnerText);
809                           }
810                       }
811                   }
812
813                 if (variables.TryGetValue (name, out vari))
814                   {
815                     if (! (vari is Variable.Int))
816                       throw new Exception ("Inalid value");
817                     vari = (Variable) vari.Clone ();
818                     Term v = new Term (intval);
819                     vari.Value = v;
820                     vari.DefaultValue = v;
821                     if (range != null)
822                       vari.Range = range;
823                   }
824                 else
825                   vari = new Variable.Int (name, desc, intval, range);
826               }
827             else if (type == Nstring)
828               {
829                 string[] range = null;
830                 if (range_list != null)
831                   {
832                     range = new string[nranges];
833                     for (int i = 0; i < nranges; i++)
834                       range[i] = range_list[i].FirstChild.InnerText;
835                   }
836
837                 if (variables.TryGetValue (name, out vari))
838                   {
839                     if (! (vari is Variable.Str))
840                       throw new Exception ("Invalid value");
841                     vari = (Variable) vari.Clone ();
842                     Term v = new Term (val);
843                     vari.Value = v;
844                     vari.DefaultValue = v;
845                     if (range != null)
846                       vari.Range = range;
847                   }
848                 else
849                   vari = new Variable.Str (name, desc, val, range);
850               }
851             else if (type == Nsymbol)
852               {
853                 Symbol[] range = null;
854                 if (range_list != null)
855                   {
856                     range = new Symbol[nranges];
857                     for (int i = 0; i < nranges; i++)
858                       range[i] = range_list[i].FirstChild.InnerText;
859                   }
860
861                 if (variables.TryGetValue (name, out vari))
862                   {
863                     if (! (vari is Variable.Sym))
864                       throw new Exception ("Invalid value");
865                     vari = (Variable) vari.Clone ();
866                     Term v = new Term (val);
867                     vari.Value = v;
868                     vari.DefaultValue = v;
869                     if (range != null)
870                       vari.Range = range;
871                   }
872                 else
873                   vari = new Variable.Sym (name, desc, val, range);
874               }
875             else
876               throw new Exception ("Unknown type: " + type);
877           }
878         else
879           {
880             if (variables.TryGetValue (name, out vari))
881               vari = (Variable) vari.Clone ();
882             else
883               vari = new Variable (name, Zero);
884           }
885         variables[name] = vari;
886         return vari;
887       }
888
889       public Variable Defvar (Variable vari)
890       {
891         variables[vari.name] = vari;
892         return vari;
893       }
894
895       internal Variable Defvar (Symbol name)
896       {
897         Variable vari = new Variable (name, Zero);
898         variables[name] = vari;
899         return vari;
900       }
901
902       internal Function GetFunc (Symbol name)
903       {
904         Function func;
905
906         if (! functions.TryGetValue (name, out func))
907           throw new Exception ("Unknown function: " + name);
908         return func;
909       }
910
911       public bool CopyFunc (Domain domain, Symbol name)
912       {
913         Function func = GetFunc (name);
914
915         domain.functions[name] = func;
916         return true;
917       }
918
919       public void CopyFunc (Domain domain)
920       {
921         foreach (KeyValuePair<Symbol, Function> kv in functions)
922           domain.functions[kv.Key] = kv.Value;
923       }
924
925       public Variable GetVar (Symbol name, bool create)
926       {
927         Variable vari;
928
929         if (! variables.TryGetValue (name, out vari))
930           {
931             if (! create)
932               return null;
933             variables[name] = vari = new Variable (name, Zero);
934           }
935         return vari;
936       }
937
938       public override string ToString ()
939       {
940         string str = "<(functions";
941         foreach (KeyValuePair<Symbol, Function> kv in functions)
942           str += " " + kv.Key;
943         str += ") (variabls";
944         foreach (KeyValuePair<Symbol, Variable> kv in variables)
945           str += " " + kv.Key;
946         str += ")";
947         if (bindings != null)
948           str += " " + bindings;
949         if (context != null)
950           str += " (" + context + ")";
951         str += ">";
952         return str;
953       }
954
955       internal void DebugWrite (bool head, string fmt, params string[] arg)
956       {
957         if (debug_level > depth)
958           {
959             if (head)
960               {
961                 Console.WriteLine ();
962                 for (int i = 0; i < depth; i++)
963                   Console.Write (" ");
964               }
965             Console.Write (fmt, arg);
966           }
967       }
968
969       public object SaveValues ()
970       {
971         Dictionary<Variable,Term> values = new Dictionary<Variable,Term> ();
972
973         foreach (KeyValuePair<Symbol,Variable> kv in variables)
974           values[kv.Value] = kv.Value.val.Clone ();
975         return values;
976       }
977
978       public void RestoreValues (object values)
979       {
980         foreach (KeyValuePair<Variable,Term> kv
981                  in (Dictionary<Variable,Term>) values)
982           kv.Key.val = kv.Value;
983       }
984     }
985
986     public delegate Term Builtin (Domain domain, Variable vari, Term[] args);
987
988     private static Domain basic = new Domain ();
989
990     static Xexpression ()
991     {
992       basic.DefSubr (Fset, "set", true, 1, 1, "=");
993       basic.DefSubr (Fnot, "not", false, 1, 1, "!");
994       basic.DefSubr (Fadd, "add", true, 1, -1, "+");
995       basic.DefSubr (Fmul, "mul", true, 1, -1, "*");
996       basic.DefSubr (Fsub, "sub", true, 1, -1, "-");
997       basic.DefSubr (Fdiv, "div", true, 1, -1, "/");
998       basic.DefSubr (Fmod, "mod", true, 1, 2, "%");
999       basic.DefSubr (Flogior, "logior", true, 1, -1, "|");
1000       basic.DefSubr (Flogand, "logand", true, 1, -1, "&");
1001       basic.DefSubr (Flsh, "lsh", true, 1, 2, "<<");
1002       basic.DefSubr (Frsh, "rsh", true, 1, 2, ">>");
1003       basic.DefSubr (Feq, "eq", false, 2, -1, "==");
1004       basic.DefSubr (Fnoteq, "noteq", false, 2, 2, "!=");
1005       basic.DefSubr (Flt, "lt", false, 2, -1, "<");
1006       basic.DefSubr (Fle, "le", false, 2, -1, "<=");
1007       basic.DefSubr (Fgt, "gt", false, 2, -1, ">");
1008       basic.DefSubr (Fge, "ge", false, 2, -1, ">=");
1009       basic.DefSubr (Fappend, "append", true, 0, -1);
1010       basic.DefSubr (Fconcat, "concat", true, 0, -1);
1011       basic.DefSubr (Fnth, "nth", false, 2, 2);
1012       basic.DefSubr (Fcopy, "copy", false, 1, 1);
1013       basic.DefSubr (Fins, "ins", true, 2, 2);
1014       basic.DefSubr (Fdel, "del", true, 2, 2);
1015       basic.DefSubr (Feval, "eval", false, 1, 1);
1016       basic.DefSubr (Fbreak, "break", false, 0, 1);
1017       basic.DefSubr (Freturn, "return", false, 0, 1);
1018       basic.DefSpecial (Fand, "and", 1, -1, "&&");
1019       basic.DefSpecial (For, "or", 1, -1, "||");
1020       basic.DefSpecial (Fprogn, "progn", 0, -1, "expr");
1021       basic.DefSpecial (Fif, "if", 2, 3);
1022       basic.DefSpecial (Fwhen, "when", 1, -1);
1023       basic.DefSpecial (Floop, "loop", 1, -1);
1024       basic.DefSpecial (Fwhile, "while", 1, -1);
1025       basic.DefSpecial (Fcond, "cond", 1, -1);
1026       basic.DefSpecial (Fforeach, "foreach", 2, -1);
1027       basic.DefSpecial (Fquote, "quote", 1, 1);
1028       basic.DefSpecial (Ftype, "type", 1, 1);
1029       basic.DefSpecial (Fcatch, "catch", 2, 2);
1030       basic.DefSpecial (Fthrow, "throw", 1, 2);
1031     }
1032
1033     private static Term Fset (Domain domain, Variable vari, Term[] args)
1034     {
1035       vari.Value = args[0];
1036       return vari.val;
1037     }
1038
1039     private static Term Fnot (Domain domain, Variable vari, Term[] args)
1040     {
1041       return args[0].IsTrue ? Zero : One;
1042     }
1043
1044     private static Term Fadd (Domain domain, Variable vari, Term[] args)
1045     {
1046       int n = vari == null ? 0 : vari.val.Intval;
1047
1048       foreach (Term arg in args)
1049         n += arg.Intval;
1050       if (vari == null)
1051         return new Term (n);
1052       vari.val.intval = n;
1053       return vari.val;
1054     }
1055
1056     private static Term Fmul (Domain domain, Variable vari, Term[] args)
1057     {
1058       int n = vari == null ? 1 : vari.val.Intval;
1059       foreach (Term arg in args)
1060         n *= arg.Intval;
1061       if (vari == null)
1062         return new Term (n);
1063       vari.val.intval = n;
1064       return vari.val;
1065     }
1066
1067     private static Term Fsub (Domain domain, Variable vari, Term[] args)
1068     {
1069       int n, i;
1070
1071       if (vari == null)
1072         {
1073           n = args[0].Intval;
1074           i = 1;
1075         }
1076       else
1077         {
1078           n = vari.val.Intval;
1079           i = 0;
1080         }
1081       while (i < args.Length)
1082         n -= args[i++].Intval;
1083       if (vari == null)
1084         return new Term (n);
1085       vari.val.intval = n;
1086       return vari.val;
1087     }
1088
1089     private static Term Fdiv (Domain domain, Variable vari, Term[] args)
1090     {
1091       int n, i;
1092
1093       if (vari == null)
1094         {
1095           n = args[0].Intval;
1096           i = 1;
1097         }
1098       else
1099         {
1100           n = vari.val.Intval;
1101           i = 0;
1102         }
1103       while (i < args.Length)
1104         n /= args[i++].Intval;
1105       if (vari == null)
1106         return new Term (n);
1107       vari.val.intval = n;
1108       return vari.val;
1109     }
1110
1111     private static Term Fmod (Domain domain, Variable vari, Term[] args)
1112     {
1113       if (vari == null)
1114         return new Term (args[0].Intval % args[1].Intval);
1115       vari.val.intval = vari.val.Intval % args[0].Intval;
1116       return vari.val;
1117     }
1118
1119     private static Term Flogior (Domain domain, Variable vari, Term[] args)
1120     {
1121       int n = vari == null ? 0 : vari.val.Intval;
1122       foreach (Term arg in args)
1123         n |= arg.Intval;
1124       if (vari == null)
1125         return new Term (n);
1126       vari.val.intval = n;
1127       return vari.val;
1128     }
1129
1130     private static Term Flogand (Domain domain, Variable vari, Term[] args)
1131     {
1132       int n, i;
1133
1134       if (vari == null)
1135         {
1136           n = args[0].Intval;
1137           i = 1;
1138         }
1139       else
1140         {
1141           n = vari.val.Intval;
1142           i = 0;
1143         }
1144       while (i < args.Length)
1145         n &= args[i++].Intval;
1146       if (vari == null)
1147         return new Term (n);
1148       vari.val.intval = n;
1149       return vari.val;
1150     }
1151
1152     private static Term Flsh (Domain domain, Variable vari, Term[] args)
1153     {
1154       if (vari == null)
1155         return new Term (args[0].Intval << args[1].Intval);
1156       vari.val.intval = vari.val.Intval << args[0].Intval;
1157       return vari.val;
1158     }
1159
1160     private static Term Frsh (Domain domain, Variable vari, Term[] args)
1161     {
1162       if (vari == null)
1163         return new Term (args[0].Intval >> args[1].Intval);
1164       vari.val.intval = vari.val.Intval >> args[0].Intval;
1165       return vari.val;
1166     }
1167
1168     private static Term Feq (Domain domain, Variable vari, Term[] args)
1169     {
1170       Term o = args[0];
1171
1172       if (o.objval == null)
1173         {
1174           for (int i = 1; i < args.Length; i++)
1175             if (args[i].objval != null || args[i].intval != o.intval)
1176               return Zero;
1177         }
1178       else
1179         {
1180           for (int i = 1; i < args.Length; i++)
1181             if (o.objval.Equals (args[i].objval))
1182               return Zero;
1183         }
1184       return One;
1185     }
1186
1187     private static Term Fnoteq (Domain domain, Variable vari, Term[] args)
1188     {
1189       return Feq (domain, vari, args);
1190     }
1191
1192     private static Term Flt (Domain domain, Variable vari, Term[] args)
1193     {
1194       int n = args[0].Intval;
1195
1196       for (int i = 1; i < args.Length; i++)
1197         {
1198           int n1 = args[i].Intval;
1199           if (n >= n1)
1200             return Zero;
1201           n = n1;
1202         }
1203       return One;
1204     }
1205
1206     private static Term Fle (Domain domain, Variable vari, Term[] args)
1207     {
1208       int n = args[0].Intval;
1209       for (int i = 1; i < args.Length; i++)
1210         {
1211           int n1 = args[i].Intval;
1212           if (n > n1)
1213             return Zero;
1214           n = n1;
1215         }
1216       return One;
1217     }
1218
1219     private static Term Fgt (Domain domain, Variable vari, Term[] args)
1220     {
1221       int n = args[0].Intval;
1222       for (int i = 1; i < args.Length; i++)
1223         {
1224           int n1 = args[i].Intval;
1225           if (n <= n1)
1226             return Zero;
1227           n = n1;
1228         }
1229       return One;
1230     }
1231
1232     private static Term Fge (Domain domain, Variable vari, Term[] args)
1233     {
1234       int n = args[0].Intval;
1235       for (int i = 1; i < args.Length; i++)
1236         {
1237           int n1 = args[i].Intval;
1238           if (n < n1)
1239             return Zero;
1240           n = n1;
1241         }
1242       return One;
1243     }
1244
1245     private static Term Fappend (Domain domain, Variable vari, Term[] args)
1246     {
1247       List<Term> list;
1248
1249       if (vari == null)
1250         list = new List<Term> ();
1251       else
1252         list = vari.val.Listval;
1253
1254       foreach (Term arg in args)
1255         {
1256           if (arg.IsList)
1257             list.AddRange ((List<Term>) arg.objval);
1258           else
1259             list.Add (arg);
1260         }
1261       if (vari == null)
1262         {
1263           Term result;
1264           result.intval = 0;
1265           result.objval = list;
1266           return result;
1267         }
1268       return vari.val;
1269     }
1270
1271     private static Term Fconcat (Domain domain, Variable vari, Term[] args)
1272     {
1273       string str;
1274
1275       if (vari == null)
1276         str = "";
1277       else
1278         str = vari.val.Strval;
1279
1280       foreach (Term arg in args)
1281         {
1282           if (arg.IsStr)
1283             str += (string) arg.objval;
1284           else if (arg.IsList)
1285             foreach (Term term in (List<Term>) arg.objval)
1286               str += (char) term.Intval;
1287           else
1288             str += (char) arg.Intval;
1289         }
1290       if (vari == null)
1291         {
1292           Term result;
1293           result.intval = 0;
1294           result.objval = str;
1295           return result;
1296         }
1297       vari.val.objval = str;
1298       return vari.val;
1299     }
1300
1301     private static Term Fnth (Domain domain, Variable vari, Term[] args)
1302     {
1303       Term result;
1304
1305       if (args[1].IsStr)
1306         {
1307           result.intval = ((string) args[1].objval)[args[0].Intval];
1308           result.objval = null;
1309         }
1310       else if (args[1].IsList)
1311         {
1312           result = ((List<Term>) args[1].objval)[args[0].Intval];
1313         }
1314       else
1315         throw new Exception ("Term is not enumelable: " + args[1]);
1316       return result;
1317     }
1318
1319     private static Term Fcopy (Domain domain, Variable vari, Term[] args)
1320     {
1321       Term result;
1322
1323       result.intval = 0;
1324       result.objval = new List<Term> (args[0].Listval);
1325       return result;
1326     }
1327
1328     private static Term Fins (Domain domain, Variable vari, Term[] args)
1329     {
1330       if (vari.val.IsStr)
1331         vari.val.objval
1332           = vari.val.Strval.Insert (args[0].Intval, args[1].Strval);
1333       else if (vari.val.IsList)
1334         vari.val.Listval.InsertRange (args[0].Intval, args[1].Listval);
1335       else
1336         throw new Exception ("term is not collection: " + vari.val);
1337       return vari.val;
1338     }
1339
1340     private static Term Fdel (Domain domain, Variable vari, Term[] args)
1341     {
1342       if (vari.val.IsStr)
1343         vari.val.objval
1344           = vari.val.Strval.Remove (args[0].Intval,
1345                                     args[1].Intval - args[0].Intval);
1346
1347       else if (vari.val.IsList)
1348         vari.val.Listval.RemoveRange (args[0].Intval,
1349                                       args[1].Intval - args[0].Intval);
1350       else
1351         throw new Exception ("term is not collection: " + vari.val);
1352       return vari.val;
1353     }
1354
1355     private static Term Fand (Domain domain, Variable vari, Term[] args)
1356     {
1357       foreach (Term arg in args)
1358         if (! arg.Eval (domain).IsTrue)
1359           return Zero;
1360       return One;
1361     }
1362
1363     private static Term For (Domain domain, Variable vari, Term[] args)
1364     {
1365       foreach (Term arg in args)
1366         if (arg.Eval (domain).IsTrue)
1367           return One;
1368       return Zero;
1369     }
1370
1371     private static Term Feval (Domain domain, Variable vari, Term[] args)
1372     {
1373       return (args[0].Eval (domain));
1374     }
1375
1376     private static Term Fprogn (Domain domain, Variable vari, Term[] args)
1377     {
1378       Term result = One;
1379
1380       foreach (Term arg in args)
1381         result = arg.Eval (domain);
1382       return result;
1383     }
1384
1385     private static Term Fif (Domain domain, Variable vari, Term[] args)
1386     {
1387       if (args[0].Eval (domain).IsTrue)
1388         return args[1].Eval (domain);
1389       if (args.Length == 2)
1390         return Zero;
1391       return args[2].Eval (domain);
1392     }
1393
1394     private static Term Fwhen (Domain domain, Variable vari, Term[] args)
1395     {
1396       if (! args[0].Eval (domain).IsTrue)
1397         return Zero;
1398       Term result = One;
1399       for (int i = 1; i < args.Length; i++)
1400         result = args[i].Eval (domain);
1401       return result;
1402     }
1403
1404     private static Term Freturn (Domain domain, Variable vari, Term[] args)
1405     {
1406       domain.ThrowReturn ();
1407       return args.Length == 0 ? Zero : args[0];
1408     }     
1409
1410     private static Term Fbreak (Domain domain, Variable vari, Term[] args)
1411     {
1412       domain.ThrowBreak ();
1413       return args.Length == 0 ? Zero : args[0];
1414     }     
1415
1416     private static Term Floop (Domain domain, Variable vari, Term[] args)
1417     {
1418       Term result = Zero;
1419       try {
1420         domain.Catch (CatchTag.Break);
1421         while (! domain.Thrown)
1422           foreach (Term arg in args)
1423             {
1424               result = arg.Eval (domain);
1425               if (domain.Thrown)
1426                 return result;
1427             }
1428       } finally {
1429         domain.Uncatch ();
1430       }
1431       return result;
1432     }
1433
1434     private static Term Fwhile (Domain domain, Variable vari, Term[] args)
1435     {
1436       Term result = Zero;
1437       try {
1438         domain.Catch (CatchTag.Break);
1439         while (! domain.Thrown && args[0].Eval (domain).IsTrue)
1440           for (int i = 1; i < args.Length; i++)
1441             {
1442               result = args[i].Eval (domain);
1443               if (domain.Thrown)
1444                 return result;
1445             }
1446       } finally {
1447         domain.Uncatch ();
1448       }
1449       return result;
1450     }
1451
1452     private static Term Fcond (Domain domain, Variable vari, Term[] args)
1453     {
1454       foreach (Term arg in args)
1455         {
1456           List<Term> list = arg.Listval;
1457           Term result = list[0].Eval (domain);
1458
1459           if (result.IsTrue)
1460             {
1461               for (int i = 1; i < list.Count; i++)
1462                 result = list[i].Eval (domain);
1463               return result;
1464             }
1465         }
1466       return Zero;
1467     }
1468
1469     private static Term Fforeach (Domain domain, Variable vari,
1470                                         Term[] args)
1471     {
1472       Term result = args[0].Eval (domain);
1473       if (domain.Thrown)
1474         return result;
1475       List<Term> list = result.Listval;
1476       Bindings current = domain.bindings;
1477
1478       try {
1479         domain.Catch (CatchTag.Break);
1480         foreach (Term term in list)
1481           {
1482             domain.Bind (vari, term);
1483             try {
1484               for (int i = 1; i < args.Length; i++)
1485                 {
1486                   result = args[i].Eval (domain);
1487                   if (domain.Thrown)
1488                     return result;
1489                 }
1490             } finally {
1491               domain.UnboundTo (current);
1492             }
1493           }
1494       } finally {
1495         domain.Uncatch ();
1496       }
1497       return result;
1498     }
1499
1500     private static Term Fquote (Domain domain, Variable vari, Term[] args)
1501     {
1502       return new Term (args[0]);
1503     }
1504
1505     private static Term Ftype (Domain domain, Variable vari, Term[] args)
1506     {
1507       if (args[0].IsInt)
1508         return TermInt;
1509       if (args[0].IsStr)
1510         return TermStr;
1511       if (args[0].IsSymbol)
1512         return TermSymbol;
1513       if (args[0].IsList)
1514         return TermList;
1515       return TermTerm;
1516     }
1517
1518     public static Term Fcatch (Domain domain, Variable vari, Term[] args)
1519     {
1520       Term result = Zero;
1521       try {
1522         domain.Catch (new CatchTag (args[0].Symval));
1523         result = args[1].Eval (domain);
1524       } finally {
1525         domain.Uncatch ();
1526       }
1527       return result;
1528     }
1529
1530     public static Term Fthrow (Domain domain, Variable vari, Term[] args)
1531     {
1532       domain.ThrowTag (new CatchTag (args[0].Symval));
1533       return (args.Length == 1 ? Zero : args[1]);
1534     }
1535
1536     public abstract class TermValue
1537     {
1538       public virtual Term Eval (Domain domain) { return new Term (this); }
1539       public abstract TermValue Clone ();
1540     }
1541
1542     private class Funcall : TermValue
1543     {
1544       internal Function func;
1545       internal Variable vari;
1546       internal Term[] args;
1547
1548       private Funcall (Function func, Variable vari, Term[] args)
1549         {
1550           this.func = func;
1551           this.vari = vari;
1552           this.args = args;
1553         }
1554
1555       public Funcall (XmlNode node, Domain domain)
1556         {
1557           vari = null;
1558           Symbol name = node.Name;
1559
1560           if (name == Nfuncall)
1561             name = node.Attributes[0].Value;
1562           else if (node.Attributes[Nvname] != null)
1563             vari = domain.GetVar (node.Attributes[Nvname].Value, true);
1564           func = domain.GetFunc (name);
1565           XmlNodeList nlist = node.ChildNodes;
1566           int nargs = nlist.Count;
1567
1568           if (nargs < func.min_arg
1569               || (func.max_arg >= 0 && nargs > func.max_arg))
1570             throw new Exception ("Invalid number of arguments to: "
1571                                  + name + " " + nargs);
1572           args = new Term[nargs];
1573           for (int i = 0; i < nlist.Count; i++)
1574             args[i] = new Term (nlist[i], domain);
1575         }
1576
1577       public Funcall (Domain domain, Symbol fname, Term[] args)
1578         {
1579           func = domain.GetFunc (fname);
1580           this.args = args;
1581         }
1582
1583       public Funcall (Domain domain, Symbol fname, Symbol vname, Term[] args)
1584         {
1585           func = domain.GetFunc (fname);
1586           vari = domain.GetVar (vname, true);
1587           this.args = args;
1588         }
1589
1590       public override Term Eval (Domain domain)
1591       {
1592         domain.DebugWrite (true, "(({0}", func.name);
1593         for (int i = 0; i < args.Length; i++)
1594           domain.DebugWrite (false, " {0}", args[i].ToString ());
1595         domain.DebugWrite (false, ")");
1596         domain.depth++;
1597         Term result = func.Call (domain, vari, args);
1598         domain.depth--;
1599         domain.DebugWrite (true, " ==> {0})", result.ToString ());
1600         return result;
1601       }
1602
1603       public override TermValue Clone ()
1604       {
1605         return new Funcall (func, vari, args);
1606       }
1607
1608       public override string ToString ()
1609       {
1610         string str = "<funcall fname=\"" + func.name;
1611         if (args == null)
1612           return str + "\"/>";
1613         str += "\">";
1614         foreach (Term e in args)
1615           str += e;
1616         return (str + "</funcall>");
1617       }
1618     }
1619
1620     public struct Term
1621     {
1622       public int intval;
1623       public object objval;
1624
1625       public Term (int i) { intval = i; objval = null; }
1626       public Term (Symbol name) { intval = 0; objval = name; }
1627       public Term (string str) { intval = 0; objval = str; }
1628       public Term (List<Term> list) { intval = 0; objval = list; }
1629       public Term (Term term) { intval = term.intval; objval = term.objval; }
1630       public Term (TermValue obj) { intval = 0; objval = obj; }
1631
1632       public Term (XmlNode node, Domain domain)
1633         {
1634           Symbol name = node.Name;
1635
1636           if (name == Ninteger)
1637             {
1638               intval = parse_integer (node.InnerText);
1639               objval = null;
1640             }
1641           else
1642             {
1643               intval = 0;
1644               if (name == Nsymbol)
1645                 objval = (Symbol) node.InnerText;
1646               else if (name == Nstring)
1647                 objval = node.InnerText.Clone ();
1648               else if (name == Nvarref)
1649                 objval = domain.GetVar ((Symbol) node.Attributes[0].Value, true);
1650               else if (name == Nlist)
1651                 {
1652                   List<Term> list = new List<Term> ();
1653                   for (node = node.FirstChild; node != null;
1654                        node = node.NextSibling)
1655                     list.Add (new Term (node, domain));
1656                   objval = list;
1657                 }
1658               else
1659                 objval = new Funcall (node, domain);
1660             }
1661         }
1662
1663       public Term (Domain domain, Symbol fname, Term[] args)
1664         {
1665           intval = 0;
1666           objval = new Funcall (domain, fname, args);
1667         }
1668
1669       public Term (Domain domain, Symbol fname, Symbol vname, Term[] args)
1670         {
1671           intval = 0;
1672           objval = new Funcall (domain, fname, vname, args);
1673         }
1674
1675       public object Objval {
1676         get {
1677           if (objval == null)
1678             throw new Exception ("term is an integer: " + this);
1679           return objval;
1680         }
1681       }
1682
1683       public int Intval {
1684         get {
1685           if (objval != null)
1686             throw new Exception ("term is not integer: " + this);
1687           return intval;
1688         }
1689       }
1690
1691       public string Strval {
1692         get {
1693           if (! IsStr)
1694             throw new Exception ("term is not string: " + this);
1695           return (string) objval;
1696         }
1697       }
1698
1699       public string Symval {
1700         get {
1701           if (! IsSymbol)
1702             throw new Exception ("term is not symbol: " + this);
1703           return (Symbol) objval;
1704         }
1705       }
1706
1707       public List<Term> Listval {
1708         get {
1709           if (! IsList)
1710             throw new Exception ("term is not list: " + this);
1711           return (List<Term>) objval;
1712         }
1713       }
1714
1715       public bool IsTrue {
1716         get {
1717           return (objval == null
1718                   ? (intval != 0)
1719                   : objval is List<Term>
1720                   ? (((List<Term>) objval).Count != 0)
1721                   : true);
1722         }
1723       }
1724       public bool IsInt { get { return (objval == null); } }
1725       public bool IsStr { get { return (objval is string); } }
1726       public bool IsSymbol { get { return (objval is Symbol); } }
1727       public bool IsList { get { return (objval is List<Term>); } }
1728
1729       public bool IsType (Type type)
1730       {
1731         return (objval == null ? type == typeof (int)
1732                 : type == objval.GetType ());
1733       }
1734
1735       public Term Eval (Domain domain)
1736       {
1737         if (objval == null || objval is Symbol || objval is string)
1738           return this;
1739         if (objval is List<Term>)
1740           return new Term ((List<Term>) objval);
1741         return ((TermValue) objval).Eval (domain);
1742       }
1743
1744       public Term Clone ()
1745       {
1746         if (objval == null || objval is Symbol || objval is string)
1747           return this;
1748         if (objval is List<Term>)
1749           {
1750             List<Term> list = new List<Term> ();
1751             list.InsertRange (0, ((List<Term>) objval));
1752             return new Term (list);
1753           }
1754         return new Term (((TermValue) objval).Clone ());
1755       }
1756
1757       public override string ToString ()
1758       {
1759         string str;
1760
1761         if (objval == null)
1762           str = "<integer>" + intval + "</integer>";
1763         else if (objval is Symbol)
1764           str = "<symbol>" + objval + "</symbol>";
1765         else if (objval is string)
1766           str = "<string>" + objval + "</string>";
1767         else if (objval is List<Term>)
1768           {
1769             str = "<list>";
1770             foreach (Term e in (List<Term>) objval)
1771               str += e;
1772             str += "</list>";
1773           }
1774         else if (objval is Funcall)
1775           str = "<funcall fname=\"" + ((Funcall) objval).func.name + "\"/>";
1776         else if (objval is Variable)
1777           str = "<variable vname=\"" + ((Variable) objval).name + "\"/>";
1778         else if (objval is Term)
1779           str = "<quote>" + objval + "</quote>";
1780         else
1781           throw new Exception ("invalid Term object: " + objval);
1782         return str;
1783       }
1784     }
1785
1786     static private Term Zero = new Term (0);
1787     static private Term One = new Term (1);
1788     static private Term TermInt = new Term (Ninteger);
1789     static private Term TermStr = new Term (Nstring);
1790     static private Term TermSymbol = new Term (Nsymbol);
1791     static private Term TermList = new Term (Nlist);
1792     static private Term TermTerm = new Term ((Symbol) "term");
1793
1794     internal static int parse_integer (string str)
1795     {
1796       int len = str.Length;
1797       bool negative = false;
1798
1799       if (len <= 1)
1800         return (len == 0 ? 0 : str[0] - '0');
1801
1802       int c = str[0];
1803       int i;
1804
1805       if (c == '?')
1806         return str[1];
1807       if ((c == '0' || c == '#') && str[1] == 'x')
1808         {
1809           i = 0;
1810           for (int idx = 2; idx < len; idx++)
1811             {
1812               c = str[idx];
1813               if (c < '0')
1814                 break;
1815               else if (c <= '9')
1816                 i = i * 16 + (c - '0');
1817               else if (c < 'A')
1818                 break;
1819               else if (c <= 'F')
1820                 i = i * 16 + (c - 'A');
1821               else if (c < 'a')
1822                 break;
1823               else if (c <= 'f')
1824                 i = i * 16 + (c - 'a');
1825               else
1826                 break;
1827             }
1828           return i;
1829         }
1830       if (c == '-')
1831         negative = true;
1832       i = c - '0';
1833       for (int idx = 1; idx < len; idx++)
1834         {
1835           c = str[idx];
1836           if (c < '0' || c > '9')
1837             break;
1838           i = i * 10 + (c - '0');
1839         }
1840       return negative ? - i : i;
1841     }
1842
1843     private Term[] terms;
1844
1845     private void parse_terms (Domain domain, XmlNode node)
1846     {
1847       int nterms = 0;
1848       for (XmlNode n = node; n != null; n = n.NextSibling)
1849         if (n.NodeType == XmlNodeType.Element)
1850           {
1851             if (n.Name == Ndefun)
1852               domain.Defun (n, true);
1853             else if (n.Name == Ndefvar)
1854               domain.Defvar (n);
1855             else
1856               nterms++;
1857           }
1858
1859       terms = new Term[nterms];
1860       int i = 0;
1861       for (XmlNode n = node; n != null; n = n.NextSibling)
1862         if (n.NodeType == XmlNodeType.Element)
1863           {
1864             if (n.Name == Ndefun)
1865               domain.Defun (n, false);
1866             else if (n.Name != Ndefvar)
1867               terms[i++]= new Term (n, domain);
1868           }
1869     }
1870
1871     public Xexpression (Domain domain, XmlNode node)
1872     {
1873       parse_terms (domain, node);
1874     }
1875
1876     public Xexpression (Domain domain, string url)
1877     {
1878       XmlDocument doc = new XmlDocument (Symbol.Table);
1879       XmlNode node;
1880
1881       using (XmlTextReader reader = new XmlTextReader (url, Symbol.Table))
1882         {
1883           do {
1884             reader.Read ();
1885           } while (reader.NodeType != XmlNodeType.None
1886                    && (reader.NodeType != XmlNodeType.Element
1887                        || reader.Name != Nexpr));
1888           if (reader.NodeType == XmlNodeType.None)
1889             throw new Exception ("Node <expr> not found");
1890           node = doc.ReadNode (reader);
1891         }
1892       parse_terms (domain, node.FirstChild);
1893     }
1894
1895     public Term Eval (Domain domain)
1896     {
1897       Term result = Zero;
1898
1899       domain.depth = 0;
1900       try {
1901         domain.Catch (CatchTag.Return);
1902         foreach (Term term in terms)
1903           {
1904             result = term.Eval (domain);
1905             if (domain.Thrown)
1906               return result;
1907           }
1908       } finally {
1909         domain.Uncatch ();
1910       }
1911       return result;
1912     }
1913
1914     public override string ToString ()
1915     {
1916       string str = "";
1917       for (int i = 0; i < terms.Length; i++)
1918         str += terms[i];
1919       return str;
1920     }
1921   }
1922 }