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