*** 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 Name : IEquatable<Name>
14     {
15       private static NameTable nt = new NameTable ();
16
17       private string name;
18
19       public Name (string str)
20         {
21           name = nt.Add (str);
22         }
23
24       public static implicit operator Name (string str)
25       {
26         return new Name (str);
27       }
28
29       public static implicit operator string (Name name)
30       {
31         return name.name;
32       }
33
34       public static bool operator== (Name n1, Name n2)
35         {
36           return (object) n1.name == (object) n2.name;
37         }
38
39       public static bool operator!= (Name n1, Name n2)
40         {
41           return (object) n1.name != (object) n2.name;
42         }
43
44       public static bool operator== (Name n1, string n2)
45         {
46           return (object) n1.name == (object) n2;
47         }
48
49       public static bool operator!= (Name n1, string n2)
50         {
51           return (object) n1.name != (object) n2;
52         }
53
54       public static bool operator== (string n1, Name n2)
55         {
56           return (object) n1 == (object) n2.name;
57         }
58
59       public static bool operator!= (string n1, Name n2)
60         {
61           return (object) n1 != (object) n2.name;
62         }
63
64       public bool Equals (Name 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 Name Nexpr = "expr";
85
86     private static Name Nfuncall = "funcall";
87     private static Name Nvarref = "varref";
88     private static Name Ninteger = "integer";
89     private static Name Nstring = "string";
90     private static Name Nsymbol = "symbol";
91     private static Name Nlist = "list";
92
93     private static Name Ndefun = "defun";
94     private static Name Nfname = "fname";
95     private static Name Nargs = "args";
96     private static Name Nargs_unevalled = "args-unevalled";
97     private static Name Nfixed = "fixed";
98     private static Name Noptional = "optional";
99     private static Name Nrest = "rest";
100
101     private static Name Ndefvar = "defvar";
102     private static Name Nvname = "vname";
103     private static Name Ndescription = "description";
104     private static Name Nrange = "range";
105
106     private static Name Nprogn = "progn";
107     private static Name Nloop = "loop";
108     private static Name Nfunction = "function";
109
110     internal abstract class Function
111     {
112       public Name name;
113       public int min_arg, max_arg;
114
115       public Function () { }
116
117       public Function (Name name, int min_arg, int max_arg)
118       {
119         this.name = name;
120         this.min_arg = min_arg;
121         this.max_arg = max_arg;
122       }
123
124       public abstract Term Call (Domain domain, Variable vari, Term[] args);
125
126       public override string ToString ()
127       {
128         return name;
129       }
130
131       internal class Subroutine : Function
132       {
133         public Builtin builtin;
134         public bool setvar;
135
136         public Subroutine (Builtin builtin, Name name, bool setvar,
137                            int min_arg, int max_arg)
138           : base (name, min_arg, max_arg)
139           {
140             this.builtin = builtin;
141           }
142
143         public override Term Call (Domain domain, Variable vari, Term[] args)
144         {
145           Term[] newargs = new Term[args.Length];
146
147           for (int i = 0; i < args.Length; i++)
148             newargs[i] = args[i].Eval (domain);
149           return builtin (domain, vari, newargs);
150         }
151       }
152
153       internal class SpecialForm : Function
154       {
155         public Builtin builtin;
156
157         public SpecialForm (Builtin builtin, Name name,
158                             int min_arg, int max_arg)
159           : base (name, min_arg, max_arg)
160           {
161             this.builtin = builtin;
162           }
163
164         public override Term Call (Domain domain, Variable vari, Term[] args)
165         {
166           return builtin (domain, vari, args);
167         }
168       }
169
170       internal class Lambda : Function
171       {
172         internal bool args_evalled;
173         internal Variable[] args;
174         internal Term[] body;
175
176         public Lambda (XmlNode node, Domain domain)
177         {
178           int nfixed = 0;
179           int noptional = 0;
180           int nrest = 0;
181           name = node.Attributes[Nfname].Value;
182             
183           node = node.FirstChild;
184           if (node != null
185               && (node.Name == Nargs || node.Name == Nargs_unevalled))
186             {
187               XmlNode n;
188               args_evalled = node.Name == Nargs;
189               for (n = node.FirstChild; n != null; n = n.NextSibling)
190                 {
191                   if (n.Name == Nfixed)
192                     nfixed++;
193                   else if (n.Name == Noptional)
194                     noptional++;
195                   else if (n.Name == Nrest)
196                     nrest++;
197                   else
198                     throw new Exception ("Invalid argument type: " + n);
199                 }
200               min_arg = nfixed;
201               max_arg = nfixed + noptional + nrest;
202               args = new Variable[max_arg];
203               n = node.FirstChild;
204               for (int i = 0; i < max_arg; n = n.NextSibling)
205                 args[i++] = domain.Defvar ((Name) n.Attributes[0].Value);
206               if (nrest == 1)
207                 max_arg = - max_arg;
208             }
209           else
210             {
211               min_arg = max_arg = 0;
212             }
213         }
214
215         public void SetBody (XmlNode node, Domain domain)
216         {
217           for (node = node.FirstChild; node != null; node = node.NextSibling)
218             if (node.Name != Ndescription
219                 && node.Name != Nargs
220                 && node.Name != Nargs_unevalled)
221               break;
222           int nterms = 0;
223           for (XmlNode n = node; n != null; n = n.NextSibling)
224             nterms++;
225           if (nterms > 0)
226             {
227               body = new Term[nterms];
228               for (nterms = 0; node != null; node = node.NextSibling, nterms++)
229                 body[nterms] = new Term (node, domain);
230             }
231         }
232
233         public override Term Call (Domain domain, Variable vari, Term[] args)
234         {
235           Bindings current = domain.bindings;
236           Term result = Zero;
237
238           try {
239             int i;
240             if (args_evalled)
241               {
242                 Term[] newargs = new Term[args.Length];
243                 for (i = 0; i < min_arg; i++)
244                   newargs[i] = args[i].Eval (domain);
245                 args = newargs;
246               }
247             for (i = 0; i < min_arg; i++)
248               domain.Bind (this.args[i], args[i]);
249             if (body != null)
250               foreach (Term term in body)
251                 result = term.Eval (domain);
252           } finally {
253             domain.UnboundTo (current);
254           }
255           return result;
256         }
257       }
258     }
259
260     public abstract class Variable
261     {
262       public readonly Name name;
263       internal Term val;
264
265       public Variable (Name name, Term term)
266       {
267         this.name = name;
268         Value = term;
269       }
270
271       public Term Value
272       {
273         get { return val; }
274         set
275           {
276             if (! ValueP (value))
277               throw new Exception ("Invalid value of " + name + ": " + value);
278             val = value;
279           }
280       }
281
282       public abstract bool ValueP (Term term);
283
284       public override string ToString () { return name + "(" + val + ")"; }
285
286       internal class Int : Variable
287       {
288         public struct Range
289         {
290           public int from, to;
291         }
292
293         public Range[] ranges;
294
295         public Int (Name name, int i) : base (name, new Term (i)) { }
296
297         public override bool ValueP (Term term)
298         {
299           int i;
300
301           if (term.objval != null)
302             return false;
303           if (ranges == null)
304             return true;
305           i = term.intval;
306           foreach (Range r in ranges)
307             if (i >= r.from && i <= r.to)
308               return true;
309           return false;
310         }
311       }
312
313       internal class Str : Variable
314       {
315         public string[] ranges;
316
317         public Str (Name name, string str) : base (name, new Term (str)) { }
318
319         public override bool ValueP (Term term)
320         {
321           if (! (term.objval is string))
322             return false;
323           if (ranges == null)
324             return true;
325           string str = (string) term.objval;
326           foreach (string s in ranges)
327             if (s == str)
328               return true;
329           return false;
330         }
331       }
332
333       internal class Misc : Variable
334       {
335         public Misc (Name name, Term term) : base (name, term) { }
336
337         public override bool ValueP (Term term) { return true; }
338       }
339     }
340
341     internal class Bindings
342     {
343       private Variable vari;
344       private Term old_value;
345       private Bindings next;
346         
347       private Bindings (Variable vari)
348       {
349         this.vari = vari;
350         old_value = vari.val;
351       }
352         
353       public static Bindings Bind (Bindings bindings, Variable vari, Term val)
354       {
355         Bindings b = new Bindings (vari);
356
357         b.vari.Value = val;
358         b.next = bindings;
359         return b;
360       }
361
362       internal Bindings UnboundTo (Bindings boundary)
363       {
364         for (Bindings b = this; b != boundary; b = b.next)
365           b.vari.val = b.old_value;
366         return boundary;
367       }
368
369       public override string ToString ()
370       {
371         string str = "(bindings";
372         for (Bindings b = this; b != null; b = b.next)
373           str += " " + vari.name + "=" + b.old_value;
374         return str + ")";
375       }
376     }
377
378 #if false
379     internal class ThrowException : Exception
380     {
381       Name tag;
382       public object value;
383
384       public ThrowException (Name tag, object value) : base ()
385         {
386           this.tag = tag;
387           this.value = value;
388         }
389     }
390 #endif
391
392     internal struct CatchTag
393     {
394       public readonly Name name;
395       public readonly int count;
396
397       public CatchTag (Name name, int count)
398         {
399           this.name = name;
400           this.count = count;
401         }
402     }
403
404     public class Domain
405     {
406       public object context;
407       public int depth = 0;
408
409       internal Dictionary<Name, Function> functions;
410       internal Dictionary<Name, Variable> variables;
411       internal Bindings bindings;
412       internal Stack<CatchTag> catch_list = new Stack<CatchTag> ();
413       private int catch_count = 0;
414
415       internal Domain ()
416       {
417         functions = new Dictionary<Name, Function> ();
418         variables = new Dictionary<Name, Variable> ();
419       }
420
421       public Domain (object context) : this (basic, context)
422       {
423       }
424
425       public Domain (Domain parent, object context)
426       {
427         functions = new Dictionary<Name, Function> (parent.functions);
428         variables = new Dictionary<Name, Variable> (parent.variables);
429         this.context = context;
430       }
431
432       internal void Bind (Variable vari, Term value)
433       {
434         bindings = Bindings.Bind (bindings, vari, value);
435       }
436
437       internal void UnboundTo (Bindings boundary)
438       {
439         if (bindings != null)
440           bindings = bindings.UnboundTo (boundary);
441       }
442
443       internal void Catch (Name name)
444       {
445         catch_list.Push (new CatchTag (name, catchcount++));
446       }
447
448       internal bool Catched {
449         get { return catch_list.Peek ().count == catchcount; }
450       }
451
452       internal void ThrowReturn ()
453       {
454         CatchTag tag = catch_list.Peek ();
455         while (tag.name != Nreturn)
456           {
457             catch_list.Pop ();
458             tag = catch_list.Peek ();
459           }
460         catchcount = tag.count;
461       }
462
463       internal void ThrowBreak ()
464       {
465         catch_list.Peek ().count = catchcount;
466       }
467
468       internal void Uncatch ()
469       {
470         catch_list.Pop ();
471       }
472
473       public void DefSubr (Builtin builtin, string str, bool setvar,
474                            int min_arg, int max_arg, params string[] aliases)
475       {
476         Name name = str;
477         Function func = new Function.Subroutine (builtin, name, setvar,
478                                                  min_arg, max_arg);
479         functions[name] = func;
480         foreach (string a in aliases)
481           functions[(Name) a] = func;
482       }
483
484       public void DefSpecial (Builtin builtin, string str,
485                               int min_arg, int max_arg,
486                               params string[] aliases)
487       {
488         Name name = str;
489         Function func = new Function.SpecialForm (builtin, name,
490                                                   min_arg, max_arg);
491         functions[name] = func;
492         foreach (string a in aliases)
493           functions[(Name) a] = func;
494       }
495
496       public void DefAlias (string alias, string str)
497       {
498         functions[(Name) alias] = functions[(Name) str];
499       }
500
501       internal Function.Lambda RegisterFunction (XmlNode node)
502       {
503         Function.Lambda lambda = new Function.Lambda (node, this);
504
505         functions[lambda.name] = lambda;        
506         return lambda;
507       }
508
509       internal Function Defun (XmlNode node)
510       {
511         Name name = node.Attributes[Nfname].Value;
512         Function func;
513
514         if (! functions.TryGetValue (name, out func))
515           func = RegisterFunction (node);
516         ((Function.Lambda) func).SetBody (node, this);
517         return func;
518       }
519
520       public void Defvar (XmlNode node)
521       {
522         Name name = node.Attributes[0].Value;
523         Variable vari;
524
525         node = node.FirstChild;
526         if (node.Name == Ndescription)
527           node = node.NextSibling;
528         if (node != null)
529           {
530             Name type = node.Name;
531             XmlNodeList range_list = null;
532             int nranges = 0;
533             string val = node.InnerText;
534
535             node = node.NextSibling;
536             if (node != null)
537               {
538                 range_list = node.ChildNodes;
539                 nranges = range_list.Count;
540               }
541
542             if (type == Ninteger)
543               {
544                 Variable.Int vi = new Variable.Int (name, parse_integer (val));
545                 if (range_list != null)
546                   {
547                     vi.ranges = new Variable.Int.Range[nranges];
548
549                     for (int i = 0; i < nranges; i++)
550                       {
551                         XmlNode n = range_list[i];
552
553                         if (n.Name == Nrange)
554                           {
555                             vi.ranges[i].from =
556                               parse_integer (n.FirstChild.InnerText);
557                             vi.ranges[i].to =
558                               parse_integer (n.LastChild.InnerText);
559                           }
560                         else
561                           {
562                             int num = parse_integer (n.InnerText);
563                             vi.ranges[i].from = vi.ranges[i].to = num;
564                           }
565                       }
566                   }
567                 vari = vi;
568               }
569             else if (type == Nstring)
570               {
571                 Variable.Str vs = new Variable.Str (name, val);
572                 if (range_list != null)
573                   vs.ranges = new string[nranges];
574                 for (int i = 0; i < nranges; i++)
575                   vs.ranges[i] = range_list[i].Value;
576                 vari = vs;
577               }
578             else
579               throw new Exception ("Unknown type: " + type);
580           }
581         else
582           vari = new Variable.Misc (name, Zero);
583         variables[name] = vari;
584       }
585
586       internal Variable Defvar (Name name)
587       {
588         Variable vari = new Variable.Misc (name, Zero);
589         variables[name] = vari;
590         return vari;
591       }
592
593       internal Function GetFunc (Name name)
594       {
595         Function func;
596
597         if (! functions.TryGetValue (name, out func))
598           throw new Exception ("Unknown function: " + name);
599         return func;
600       }
601
602       public bool CopyFunc (Domain domain, Name name)
603       {
604         Function func = GetFunc (name);
605
606         domain.functions[name] = func;
607         return true;
608       }
609
610       public void CopyFunc (Domain domain)
611       {
612         foreach (KeyValuePair<Name, Function> kv in functions)
613           domain.functions[kv.Key] = kv.Value;
614       }
615
616       internal Variable GetVar (Name name)
617       {
618         Variable vari;
619
620         if (! variables.TryGetValue (name, out vari))
621           variables[name] = vari = new Variable.Misc (name, Zero);
622         return vari;
623       }
624
625       public override string ToString ()
626       {
627         string str = "<(functions";
628         foreach (KeyValuePair<Name, Function> kv in functions)
629           str += " " + kv.Key;
630         str += ") (variabls";
631         foreach (KeyValuePair<Name, Variable> kv in variables)
632           str += " " + kv.Key;
633         str += ")";
634         if (bindings != null)
635           str += " " + bindings;
636         if (context != null)
637           str += " (" + context + ")";
638         str += ">";
639         return str;
640       }
641
642       internal void DebugWrite (bool head, string fmt, params string[] arg)
643       {
644         if (debug_level > depth)
645           {
646             if (head)
647               {
648                 Console.WriteLine ();
649                 for (int i = 0; i < depth; i++)
650                   Console.Write (" ");
651               }
652             Console.Write (fmt, arg);
653           }
654       }
655     }
656
657     public delegate Term Builtin (Domain domain, Variable vari, Term[] args);
658
659     private static Domain basic = new Domain ();
660
661     internal static Function Fprogn;
662
663     static Xexpression ()
664     {
665       basic.DefSubr (set_value, "set", true, 1, 1, "=");
666       basic.DefSubr (not, "not", false, 1, 1, "!");
667       basic.DefSubr (add, "add", true, 1, -1, "+");
668       basic.DefSubr (mul, "mul", true, 1, -1, "*");
669       basic.DefSubr (sub, "sub", true, 1, -1, "-");
670       basic.DefSubr (div, "div", true, 1, -1, "/");
671       basic.DefSubr (mod, "mod", true, 1, 2, "%");
672       basic.DefSubr (logior, "logior", true, 1, -1, "|");
673       basic.DefSubr (logand, "logand", true, 1, -1, "&");
674       basic.DefSubr (lsh, "lsh", true, 1, 2, "<<");
675       basic.DefSubr (rsh, "rsh", true, 1, 2, ">>");
676       basic.DefSubr (eq, "eq", false, 2, -1, "==");
677       basic.DefSubr (noteq, "noteq", false, 2, 2, "!=");
678       basic.DefSubr (less_than, "lt", false, 2, -1, "<");
679       basic.DefSubr (less_eq, "le", false, 2, -1, "<=");
680       basic.DefSubr (greater_than, "gt", false, 2, -1, ">");
681       basic.DefSubr (greater_eq, "ge", false, 2, -1, ">=");
682       basic.DefSubr (append, "append", true, 0, -1);
683       basic.DefSubr (concat, "concat", true, 0, -1);
684       basic.DefSubr (nth, "nth", false, 2, 2);
685       basic.DefSubr (copy, "copy", false, 1, 1);
686       basic.DefSubr (ins, "ins", true, 2, 2);
687       basic.DefSubr (del, "del", true, 2, 2);
688       basic.DefSubr (eval_clause, "eval", false, 1, 1);
689       basic.DefSubr (break_clause, "break", false, 0, 1);
690       basic.DefSubr (return_clause, "return", false, 1, 1);
691       basic.DefSpecial (and, "and", 1, -1, "&&");
692       basic.DefSpecial (or, "or", 1, -1, "||");
693       basic.DefSpecial (progn_clause, "progn", 0, -1, "expr");
694       basic.DefSpecial (if_clause, "if", 2, 3);
695       basic.DefSpecial (when_clause, "when", 1, -1);
696       basic.DefSpecial (loop_clause, "loop", 1, -1);
697       basic.DefSpecial (while_clause, "while", 1, -1);
698       basic.DefSpecial (cond_clause, "cond", 1, -1);
699       basic.DefSpecial (foreach_clause, "foreach", 2, -1);
700       basic.DefSpecial (quote_clause, "quote", 1, 1);
701       basic.DefSpecial (type_clause, "type", 1, 1);
702
703       Fprogn = basic.GetFunc (Nprogn);
704     }
705
706     private static Term set_value (Domain domain, Variable vari, Term[] args)
707     {
708       vari.Value = args[0];
709       return vari.val;
710     }
711
712     private static Term not (Domain domain, Variable vari, Term[] args)
713     {
714       return args[0].IsTrue ? Zero : One;
715     }
716
717     private static Term add (Domain domain, Variable vari, Term[] args)
718     {
719       int n = vari == null ? 0 : vari.val.Intval;
720
721       foreach (Term arg in args)
722         n += (int) arg;
723       if (vari == null)
724         return n;
725       vari.val.intval = n;
726       return vari.val;
727     }
728
729     private static Term mul (Domain domain, Variable vari, Term[] args)
730     {
731       int n = vari == null ? 1 : vari.val.Intval;
732       foreach (Term arg in args)
733         n *= (int) arg;
734       if (vari == null)
735         return n;
736       vari.val.intval = n;
737       return vari.val;
738     }
739
740     private static Term sub (Domain domain, Variable vari, Term[] args)
741     {
742       int n, i;
743
744       if (vari == null)
745         {
746           n = args[0].Intval;
747           i = 1;
748         }
749       else
750         {
751           n = vari.val.Intval;
752           i = 0;
753         }
754       while (i < args.Length)
755         n -= (int) args[i++];
756       if (vari == null)
757         return n;
758       vari.val.intval = n;
759       return vari.val;
760     }
761
762     private static Term div (Domain domain, Variable vari, Term[] args)
763     {
764       int n, i;
765
766       if (vari == null)
767         {
768           n = args[0].Intval;
769           i = 1;
770         }
771       else
772         {
773           n = vari.val.Intval;
774           i = 0;
775         }
776       while (i < args.Length)
777         n /= args[i++].Intval;
778       if (vari == null)
779         return n;
780       vari.val.intval = n;
781       return vari.val;
782     }
783
784     private static Term mod (Domain domain, Variable vari, Term[] args)
785     {
786       if (vari == null)
787         return (args[0].Intval % args[1].Intval);
788       vari.val.intval = vari.val.Intval % args[0].Intval;
789       return vari.val;
790     }
791
792     private static Term logior (Domain domain, Variable vari, Term[] args)
793     {
794       int n = vari == null ? 0 : vari.val.Intval;
795       foreach (Term arg in args)
796         n |= (int) arg;
797       if (vari == null)
798         return n;
799       vari.val.intval = n;
800       return vari.val;
801     }
802
803     private static Term logand (Domain domain, Variable vari, Term[] args)
804     {
805       int n, i;
806
807       if (vari == null)
808         {
809           n = args[0].Intval;
810           i = 1;
811         }
812       else
813         {
814           n = vari.val.Intval;
815           i = 0;
816         }
817       while (i < args.Length)
818         n &= (int) args[i++];
819       if (vari == null)
820         return n;
821       vari.val.intval = n;
822       return vari.val;
823     }
824
825     private static Term lsh (Domain domain, Variable vari, Term[] args)
826     {
827       if (vari == null)
828         return args[0].Intval << args[1].Intval;
829       vari.val.intval = vari.val.Intval << args[0].Intval;
830       return vari.val;
831     }
832
833     private static Term rsh (Domain domain, Variable vari, Term[] args)
834     {
835       if (vari == null)
836         return args[0].Intval >> args[1].Intval;
837       vari.val.intval = vari.val.Intval >> args[0].Intval;
838       return vari.val;
839     }
840
841     private static Term eq (Domain domain, Variable vari, Term[] args)
842     {
843       Term o = args[0];
844
845       if (o.objval == null)
846         {
847           for (int i = 1; i < args.Length; i++)
848             if (args[i].objval != null || args[i].intval != o.intval)
849               return Zero;
850         }
851       else
852         {
853           for (int i = 1; i < args.Length; i++)
854             if (o.objval.Equals (args[i].objval))
855               return Zero;
856         }
857       return One;
858     }
859
860     private static Term noteq (Domain domain, Variable vari, Term[] args)
861     {
862       return eq (domain, vari, args);
863     }
864
865     private static Term less_than (Domain domain, Variable vari, Term[] args)
866     {
867       int n = (int) args[0];
868
869       for (int i = 1; i < args.Length; i++)
870         {
871           int n1 = (int) args[i];
872           if (n >= n1)
873             return Zero;
874           n = n1;
875         }
876       return One;
877     }
878
879     private static Term less_eq (Domain domain, Variable vari, Term[] args)
880     {
881       int n = (int) args[0];
882       for (int i = 1; i < args.Length; i++)
883         {
884           int n1 = (int) args[i];
885           if (n > n1)
886             return Zero;
887           n = n1;
888         }
889       return One;
890     }
891
892     private static Term greater_than (Domain domain, Variable vari, Term[] args)
893     {
894       int n = (int) args[0];
895       for (int i = 1; i < args.Length; i++)
896         {
897           int n1 = (int) args[i];
898           if (n <= n1)
899             return Zero;
900           n = n1;
901         }
902       return One;
903     }
904
905     private static Term greater_eq (Domain domain, Variable vari, Term[] args)
906     {
907       int n = (int) args[0];
908       for (int i = 1; i < args.Length; i++)
909         {
910           int n1 = (int) args[i];
911           if (n < n1)
912             return Zero;
913           n = n1;
914         }
915       return One;
916     }
917
918     private static Term append (Domain domain, Variable vari, Term[] args)
919     {
920       List<Term> list;
921
922       if (vari == null)
923         list = new List<Term> ();
924       else
925         list = vari.val.Listval;
926
927       foreach (Term arg in args)
928         {
929           if (arg.IsList)
930             list.AddRange ((List<Term>) arg.objval);
931           else
932             list.Add (arg);
933         }
934       if (vari == null)
935         {
936           Term result;
937           result.intval = 0;
938           result.objval = list;
939           return result;
940         }
941       vari.val.objval = list;
942       return vari.val;
943     }
944
945     private static Term concat (Domain domain, Variable vari, Term[] args)
946     {
947       string str;
948
949       if (vari == null)
950         str = "";
951       else
952         str = vari.val.Strval;
953
954       foreach (Term arg in args)
955         {
956           if (arg.IsStr)
957             str += (string) arg.objval;
958           else if (arg.IsList)
959             foreach (Term term in (List<Term>) arg.objval)
960               str += (char) term.Intval;
961           else
962             str += (char) arg.Intval;
963         }
964       if (vari == null)
965         {
966           Term result;
967           result.intval = 0;
968           result.objval = str;
969           return result;
970         }
971       vari.val.objval = str;
972       return vari.val;
973     }
974
975     private static Term nth (Domain domain, Variable vari, Term[] args)
976     {
977       Term result;
978
979       if (args[1].IsStr)
980         {
981           result.intval = ((string) args[1].objval)[args[0].Intval];
982           result.objval = null;
983         }
984       else if (args[1].IsList)
985         {
986           result = ((List<Term>) args[1].objval)[args[0].Intval];
987         }
988       else
989         throw new Exception ("Term is not enumelable: " + args[1]);
990       return result;
991     }
992
993     private static Term copy (Domain domain, Variable vari, Term[] args)
994     {
995       Term result;
996
997       result.intval = 0;
998       result.objval = new List<Term> (args[0].Listval);
999       return result;
1000     }
1001
1002     private static Term ins (Domain domain, Variable vari, Term[] args)
1003     {
1004       if (vari.val.IsStr)
1005         vari.val.objval
1006           = vari.val.Strval.Insert (args[0].Intval, args[1].Strval);
1007       else if (vari.val.IsList)
1008         vari.val.Listval.InsertRange (args[0].Intval, args[1].Listval);
1009       else
1010         throw new Exception ("term is not collection: " + vari.val);
1011       return vari.val;
1012     }
1013
1014     private static Term del (Domain domain, Variable vari, Term[] args)
1015     {
1016       if (vari.val.IsStr)
1017         vari.val.objval
1018           = vari.val.Strval.Remove (args[0].Intval,
1019                                     args[1].Intval - args[0].Intval);
1020
1021       else if (vari.val.IsList)
1022         vari.val.Listval.RemoveRange (args[0].Intval,
1023                                       args[1].Intval - args[0].Intval);
1024       else
1025         throw new Exception ("term is not collection: " + vari.val);
1026       return vari.val;
1027     }
1028
1029     private static Term and (Domain domain, Variable vari, Term[] args)
1030     {
1031       foreach (Term arg in args)
1032         if (! arg.Eval (domain).IsTrue)
1033           return Zero;
1034       return One;
1035     }
1036
1037     private static Term or (Domain domain, Variable vari, Term[] args)
1038     {
1039       foreach (Term arg in args)
1040         if (arg.Eval (domain).IsTrue)
1041           return One;
1042       return Zero;
1043     }
1044
1045     private static Term eval_clause (Domain domain, Variable vari, Term[] args)
1046     {
1047       return (args[0].Eval (domain));
1048     }
1049
1050     private static Term progn_clause (Domain domain, Variable vari, Term[] args)
1051     {
1052       Term result = One;
1053
1054       foreach (Term arg in args)
1055         result = arg.Eval (domain);
1056       return result;
1057     }
1058
1059     private static Term if_clause (Domain domain, Variable vari, Term[] args)
1060     {
1061       if (args[0].Eval (domain).IsTrue)
1062         return args[1].Eval (domain);
1063       if (args.Length == 2)
1064         return Zero;
1065       return args[2].Eval (domain);
1066     }
1067
1068     private static Term when_clause (Domain domain, Variable vari, Term[] args)
1069     {
1070       if (! args[0].Eval (domain).IsTrue)
1071         return Zero;
1072       Term result = One;
1073       for (int i = 1; i < args.Length; i++)
1074         result = args[i].Eval (domain);
1075       return result;
1076     }
1077
1078     private static Term break_clause (Domain domain, Variable vari, Term[] args)
1079     {
1080       Stack<CatchTag> clist = domain.catch_list;
1081       if (clist.Count == 0)
1082         throw new Exception ("No outer loop to break");
1083       CatchTag tag = clist.Peek ();
1084       if (tag.name != Nloop)
1085         throw new Exception ("No outer loop to break");
1086       domain.depth = tag.depth;
1087       return args.Length == 0 ? Zero : args[0];
1088     }     
1089
1090     private static Term return_clause (Domain domain, Variable vari, Term[] args)
1091     {
1092       Stack<CatchTag> clist = domain.catch_list;
1093
1094       while (clist.Count > 0)
1095         {
1096           CatchTag tag = clist.Pop ();
1097           if (tag.name == Nfunction)
1098             {
1099               domain.depth = tag.depth;
1100               return = args.Length == 0 ? Zero : args[0];
1101             }
1102         }
1103       return args.Length == 0 ? Zero : args[0];
1104     }     
1105
1106     private static Term loop_clause (Domain domain, Variable vari, Term[] args)
1107     {
1108       domain.Catch (Nloop);
1109       Term result = Zero;
1110       try {
1111         while (! domain.Catched)
1112           foreach (Term arg in args)
1113             {
1114               result = arg.Eval (domain);
1115               if (domain.Catched)
1116                 break;
1117             }
1118       } finally {
1119         domain.Uncatch ();
1120       }
1121       return result;
1122     }
1123
1124     private static Term while_clause (Domain domain, Variable vari, Term[] args)
1125     {
1126       while (args[0].Eval (domain).IsTrue)
1127         for (int i = 1; i < args.Length; i++)
1128           args[i].Eval (domain);
1129       return Zero;
1130     }
1131
1132     private static Term cond_clause (Domain domain, Variable vari, Term[] args)
1133     {
1134       foreach (Term arg in args)
1135         {
1136           List<Term> list = arg.Listval;
1137           Term result = list[0].Eval (domain);
1138
1139           if (result.IsTrue)
1140             {
1141               for (int i = 1; i < list.Count; i++)
1142                 result = list[i].Eval (domain);
1143               return result;
1144             }
1145         }
1146       return Zero;
1147     }
1148
1149     private static Term foreach_clause (Domain domain, Variable vari,
1150                                         Term[] args)
1151     {
1152       List<Term> list = args[0].Listval;
1153       Bindings current = domain.bindings;
1154
1155       foreach (Term term in list)
1156         {
1157           domain.Bind (vari, term);
1158           try {
1159             for (int i = 1; i < args.Length; i++)
1160               args[i].Eval (domain);
1161           } finally {
1162             domain.UnboundTo (current);
1163           }
1164         }
1165       return Zero;
1166     }
1167
1168     private static Term quote_clause (Domain domain, Variable vari, Term[] args)
1169     {
1170       return new Term (args[0]);
1171     }
1172
1173     private static Term type_clause (Domain domain, Variable vari, Term[] args)
1174     {
1175       if (args[0].IsInt)
1176         return TermInt;
1177       if (args[0].IsStr)
1178         return TermStr;
1179       if (args[0].IsName)
1180         return TermName;
1181       if (args[0].IsList)
1182         return TermList;
1183       return TermTerm;
1184     }
1185
1186     public struct Term
1187     {
1188       public int intval;
1189       public object objval;
1190
1191       public Term (int i) { intval = i; objval = null; }
1192       public Term (Name name) { intval = 0; objval = name; }
1193       public Term (string str) { intval = 0; objval = str; }
1194       public Term (List<Term> list) { intval = 0; objval = list; }
1195       public Term (Term term) { intval = 0; objval = term; }
1196
1197       public Term (XmlNode node, Domain domain)
1198         {
1199           Name name = node.Name;
1200
1201           if (name == Ninteger)
1202             {
1203               intval = parse_integer (node.InnerText);
1204               objval = null;
1205             }
1206           else
1207             {
1208               intval = 0;
1209               if (name == Nsymbol)
1210                 objval = (Name) node.InnerText;
1211               else if (name == Nstring)
1212                 objval = node.InnerText.Clone ();
1213               else if (name == Nvarref)
1214                 objval = domain.GetVar ((Name) node.Attributes[0].Value);
1215               else if (name == Nlist)
1216                 {
1217                   List<Term> list = new List<Term> ();
1218                   for (node = node.FirstChild; node != null;
1219                        node = node.NextSibling)
1220                     list.Add (new Term (node, domain));
1221                   objval = list;
1222                 }
1223               else
1224                 {
1225                   Function func;
1226                   Variable vari = null;
1227                   Term[] args;
1228
1229                   if (name == Nfuncall)
1230                     name = node.Attributes[0].Value;
1231                   else if (node.Attributes[Nvname] != null)
1232                     vari = domain.GetVar (node.Attributes[Nvname].Value);
1233                   func = domain.GetFunc (name);
1234                   XmlNodeList nlist = node.ChildNodes;
1235                   int nargs = nlist.Count;
1236
1237                   if (nargs < func.min_arg
1238                       || (func.max_arg >= 0 && nargs > func.max_arg))
1239                     throw new Exception ("Invalid number of arguments to: "
1240                                          + name + " " + nargs);
1241                   args = new Term[nargs];
1242                   for (int i = 0; i < nlist.Count; i++)
1243                     args[i] = new Term (nlist[i], domain);
1244                   objval = new Funcall (func, vari, args);
1245                 }
1246             }
1247         }
1248
1249       private class Funcall
1250       {
1251         internal Function func;
1252         internal Variable vari;
1253         internal Term[] args;
1254
1255         public Funcall (Function func, Variable vari, Term[] args)
1256         {
1257           this.func = func;
1258           this.vari = vari;
1259           this.args = args;
1260         }
1261
1262         public Term Eval (Domain domain)
1263         {
1264           domain.DebugWrite (true, "(({0}", func.name);
1265           for (int i = 0; i < args.Length; i++)
1266             domain.DebugWrite (false, " {0}", args[i].ToString ());
1267           domain.DebugWrite (false, ")");
1268           domain.depth++;
1269           Term result = func.Call (domain, vari, args);
1270           domain.depth--;
1271           domain.DebugWrite (true, " ==> {0})", result.ToString ());
1272           return result;
1273         }
1274
1275         public override string ToString ()
1276         {
1277           string str = "<funcall fname=\"" + func.name;
1278           if (args == null)
1279             return str + "\"/>";
1280           str += "\">";
1281           foreach (Term e in args)
1282             str += e;
1283           return (str + "</funcall>");
1284         }
1285       }
1286
1287       public int Intval {
1288         get {
1289           if (objval != null)
1290             throw new Exception ("term is not integer: " + this);
1291           return intval;
1292         }
1293       }
1294
1295       public string Strval {
1296         get {
1297           if (! IsStr)
1298             throw new Exception ("term is not string: " + this);
1299           return (string) objval;
1300         }
1301       }
1302
1303       public List<Term> Listval {
1304         get {
1305           if (! IsList)
1306             throw new Exception ("term is not list: " + this);
1307           return (List<Term>) objval;
1308         }
1309       }
1310
1311       public bool IsTrue {
1312         get {
1313           return (objval == null
1314                   ? (intval != 0)
1315                   : objval is List<Term>
1316                   ? (((List<Term>) objval).Count != 0)
1317                   : true);
1318         }
1319       }
1320       public bool IsInt { get { return (objval == null); } }
1321       public bool IsStr { get { return (objval is string); } }
1322       public bool IsName { get { return (objval is Name); } }
1323       public bool IsList { get { return (objval is List<Term>); } }
1324
1325       public Term Eval (Domain domain)
1326       {
1327         if (objval == null || objval is Name || objval is string)
1328           return this;
1329         if (objval is List<Term>)
1330           return new Term ((List<Term>) objval);
1331         if (objval is Funcall)
1332           return ((Funcall) objval).Eval (domain);
1333         if (objval is Variable)
1334           return ((Variable) objval).val;
1335         if (objval is Term)
1336           return (Term) objval;
1337         throw new Exception ("invalid Term object: " + objval);
1338       }
1339
1340       public static explicit operator int (Term term)
1341       {
1342         if (term.objval != null)
1343           throw new Exception ("Not an integer term: " + term);
1344         return term.intval;
1345       }
1346
1347       public static explicit operator Name (Term term)
1348       {
1349         return (Name) term.objval;
1350       }
1351
1352       public static implicit operator Term (int i)
1353       {
1354         return new Term (i);
1355       }
1356
1357       public override string ToString ()
1358       {
1359         string str;
1360
1361         if (objval == null)
1362           str = "<integer>" + intval + "</integer>";
1363         else if (objval is Name)
1364           str = "<symbol>" + objval + "</symbol>";
1365         else if (objval is string)
1366           str = "<string>" + objval + "</string>";
1367         else if (objval is List<Term>)
1368           {
1369             str = "<list>";
1370             foreach (Term e in (List<Term>) objval)
1371               str += e;
1372             str += "</list>";
1373           }
1374         else if (objval is Funcall)
1375           str = "<funcall fname=\"" + ((Funcall) objval).func.name + "\"/>";
1376         else if (objval is Variable)
1377           str = "<variable vname=\"" + ((Variable) objval).name + "\"/>";
1378         else if (objval is Term)
1379           str = "<quote>" + objval + "</quote>";
1380         else
1381           throw new Exception ("invalid Term object: " + objval);
1382         return str;
1383       }
1384     }
1385
1386     static Term Zero = new Term (0);
1387     static Term One = new Term (1);
1388     static Term TermInt = new Term (Ninteger);
1389     static Term TermStr = new Term (Nstring);
1390     static Term TermName = new Term (Nsymbol);
1391     static Term TermList = new Term (Nlist);
1392     static Term TermTerm = new Term ((Name) "term");
1393
1394     internal static int parse_integer (string str)
1395     {
1396       int len = str.Length;
1397       bool negative = false;
1398
1399       if (len <= 1)
1400         return (len == 0 ? 0 : str[0] - '0');
1401
1402       int c = str[0];
1403       int i;
1404
1405       if (c == '0' && str[1] == 'x')
1406         {
1407           i = 0;
1408           for (int idx = 2; idx < len; idx++)
1409             {
1410               c = str[idx];
1411               if (c < '0')
1412                 break;
1413               else if (c <= '9')
1414                 i = i * 16 + (c - '0');
1415               else if (c < 'A')
1416                 break;
1417               else if (c <= 'F')
1418                 i = i * 16 + (c - 'A');
1419               else if (c < 'a')
1420                 break;
1421               else if (c <= 'f')
1422                 i = i * 16 + (c - 'a');
1423               else
1424                 break;
1425             }
1426           return i;
1427         }
1428       if (c == '-')
1429         negative = true;
1430       i = c - '0';
1431       for (int idx = 1; idx < len; idx++)
1432         {
1433           c = str[idx];
1434           if (c < '0' || c > '9')
1435             break;
1436           i = i * 10 + (c - '0');
1437         }
1438       return negative ? - i : i;
1439     }
1440
1441     private Term[] terms;
1442
1443     public Xexpression (string url, Domain domain)
1444     {
1445       XmlDocument doc = new XmlDocument (Name.Table);
1446       XmlNode node;
1447
1448       using (XmlTextReader reader = new XmlTextReader (url, Name.Table))
1449         {
1450           do {
1451             reader.Read ();
1452           } while (reader.NodeType != XmlNodeType.None
1453                    && (reader.NodeType != XmlNodeType.Element
1454                        || reader.Name != Nexpr));
1455           if (reader.NodeType == XmlNodeType.None)
1456             throw new Exception ("Node <expr> not found");
1457           node = doc.ReadNode (reader);
1458         }
1459
1460       int nterms = 0;
1461       for (XmlNode n = node.FirstChild; n != null; n = n.NextSibling)
1462         if (n.NodeType == XmlNodeType.Element)
1463           {
1464             if (n.Name == Ndefun)
1465               domain.RegisterFunction (n);
1466             else if (n.Name == Ndefvar)
1467               domain.Defvar (n);
1468             else
1469               nterms++;
1470           }
1471
1472       terms = new Term[nterms];
1473       int i = 0;
1474       for (XmlNode n = node.FirstChild; n != null; n = n.NextSibling)
1475         if (n.NodeType == XmlNodeType.Element)
1476           {
1477             if (n.Name == Ndefun)
1478               domain.Defun (n);
1479             else if (n.Name != Ndefvar)
1480               terms[i++]= new Term (n, domain);
1481           }
1482     }
1483
1484     public Term Eval (Domain domain)
1485     {
1486       Term result = Zero;
1487
1488       domain.depth = 0;
1489       foreach (Term term in terms)
1490         result = term.Eval (domain);
1491       return result;
1492     }
1493
1494     public override string ToString ()
1495     {
1496       string str = "";
1497       for (int i = 0; i < terms.Length; i++)
1498         str += terms[i];
1499       return str;
1500     }
1501   }
1502 }