3efb27d500108c891207c99859fcb21b1f8348d3
[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         catch_list.Peek ().count = catchcount;
455       }
456
457       internal void ThrowBreak ()
458       {
459         catch_list.Peek ().count = catchcount;
460       }
461
462       internal void Uncatch ()
463       {
464         catch_list.Pop ();
465       }
466
467       public void DefSubr (Builtin builtin, string str, bool setvar,
468                            int min_arg, int max_arg, params string[] aliases)
469       {
470         Name name = str;
471         Function func = new Function.Subroutine (builtin, name, setvar,
472                                                  min_arg, max_arg);
473         functions[name] = func;
474         foreach (string a in aliases)
475           functions[(Name) a] = func;
476       }
477
478       public void DefSpecial (Builtin builtin, string str,
479                               int min_arg, int max_arg,
480                               params string[] aliases)
481       {
482         Name name = str;
483         Function func = new Function.SpecialForm (builtin, name,
484                                                   min_arg, max_arg);
485         functions[name] = func;
486         foreach (string a in aliases)
487           functions[(Name) a] = func;
488       }
489
490       public void DefAlias (string alias, string str)
491       {
492         functions[(Name) alias] = functions[(Name) str];
493       }
494
495       internal Function.Lambda RegisterFunction (XmlNode node)
496       {
497         Function.Lambda lambda = new Function.Lambda (node, this);
498
499         functions[lambda.name] = lambda;        
500         return lambda;
501       }
502
503       internal Function Defun (XmlNode node)
504       {
505         Name name = node.Attributes[Nfname].Value;
506         Function func;
507
508         if (! functions.TryGetValue (name, out func))
509           func = RegisterFunction (node);
510         ((Function.Lambda) func).SetBody (node, this);
511         return func;
512       }
513
514       public void Defvar (XmlNode node)
515       {
516         Name name = node.Attributes[0].Value;
517         Variable vari;
518
519         node = node.FirstChild;
520         if (node.Name == Ndescription)
521           node = node.NextSibling;
522         if (node != null)
523           {
524             Name type = node.Name;
525             XmlNodeList range_list = null;
526             int nranges = 0;
527             string val = node.InnerText;
528
529             node = node.NextSibling;
530             if (node != null)
531               {
532                 range_list = node.ChildNodes;
533                 nranges = range_list.Count;
534               }
535
536             if (type == Ninteger)
537               {
538                 Variable.Int vi = new Variable.Int (name, parse_integer (val));
539                 if (range_list != null)
540                   {
541                     vi.ranges = new Variable.Int.Range[nranges];
542
543                     for (int i = 0; i < nranges; i++)
544                       {
545                         XmlNode n = range_list[i];
546
547                         if (n.Name == Nrange)
548                           {
549                             vi.ranges[i].from =
550                               parse_integer (n.FirstChild.InnerText);
551                             vi.ranges[i].to =
552                               parse_integer (n.LastChild.InnerText);
553                           }
554                         else
555                           {
556                             int num = parse_integer (n.InnerText);
557                             vi.ranges[i].from = vi.ranges[i].to = num;
558                           }
559                       }
560                   }
561                 vari = vi;
562               }
563             else if (type == Nstring)
564               {
565                 Variable.Str vs = new Variable.Str (name, val);
566                 if (range_list != null)
567                   vs.ranges = new string[nranges];
568                 for (int i = 0; i < nranges; i++)
569                   vs.ranges[i] = range_list[i].Value;
570                 vari = vs;
571               }
572             else
573               throw new Exception ("Unknown type: " + type);
574           }
575         else
576           vari = new Variable.Misc (name, Zero);
577         variables[name] = vari;
578       }
579
580       internal Variable Defvar (Name name)
581       {
582         Variable vari = new Variable.Misc (name, Zero);
583         variables[name] = vari;
584         return vari;
585       }
586
587       internal Function GetFunc (Name name)
588       {
589         Function func;
590
591         if (! functions.TryGetValue (name, out func))
592           throw new Exception ("Unknown function: " + name);
593         return func;
594       }
595
596       public bool CopyFunc (Domain domain, Name name)
597       {
598         Function func = GetFunc (name);
599
600         domain.functions[name] = func;
601         return true;
602       }
603
604       public void CopyFunc (Domain domain)
605       {
606         foreach (KeyValuePair<Name, Function> kv in functions)
607           domain.functions[kv.Key] = kv.Value;
608       }
609
610       internal Variable GetVar (Name name)
611       {
612         Variable vari;
613
614         if (! variables.TryGetValue (name, out vari))
615           variables[name] = vari = new Variable.Misc (name, Zero);
616         return vari;
617       }
618
619       public override string ToString ()
620       {
621         string str = "<(functions";
622         foreach (KeyValuePair<Name, Function> kv in functions)
623           str += " " + kv.Key;
624         str += ") (variabls";
625         foreach (KeyValuePair<Name, Variable> kv in variables)
626           str += " " + kv.Key;
627         str += ")";
628         if (bindings != null)
629           str += " " + bindings;
630         if (context != null)
631           str += " (" + context + ")";
632         str += ">";
633         return str;
634       }
635
636       internal void DebugWrite (bool head, string fmt, params string[] arg)
637       {
638         if (debug_level > depth)
639           {
640             if (head)
641               {
642                 Console.WriteLine ();
643                 for (int i = 0; i < depth; i++)
644                   Console.Write (" ");
645               }
646             Console.Write (fmt, arg);
647           }
648       }
649     }
650
651     public delegate Term Builtin (Domain domain, Variable vari, Term[] args);
652
653     private static Domain basic = new Domain ();
654
655     internal static Function Fprogn;
656
657     static Xexpression ()
658     {
659       basic.DefSubr (set_value, "set", true, 1, 1, "=");
660       basic.DefSubr (not, "not", false, 1, 1, "!");
661       basic.DefSubr (add, "add", true, 1, -1, "+");
662       basic.DefSubr (mul, "mul", true, 1, -1, "*");
663       basic.DefSubr (sub, "sub", true, 1, -1, "-");
664       basic.DefSubr (div, "div", true, 1, -1, "/");
665       basic.DefSubr (mod, "mod", true, 1, 2, "%");
666       basic.DefSubr (logior, "logior", true, 1, -1, "|");
667       basic.DefSubr (logand, "logand", true, 1, -1, "&");
668       basic.DefSubr (lsh, "lsh", true, 1, 2, "<<");
669       basic.DefSubr (rsh, "rsh", true, 1, 2, ">>");
670       basic.DefSubr (eq, "eq", false, 2, -1, "==");
671       basic.DefSubr (noteq, "noteq", false, 2, 2, "!=");
672       basic.DefSubr (less_than, "lt", false, 2, -1, "<");
673       basic.DefSubr (less_eq, "le", false, 2, -1, "<=");
674       basic.DefSubr (greater_than, "gt", false, 2, -1, ">");
675       basic.DefSubr (greater_eq, "ge", false, 2, -1, ">=");
676       basic.DefSubr (append, "append", true, 0, -1);
677       basic.DefSubr (concat, "concat", true, 0, -1);
678       basic.DefSubr (nth, "nth", false, 2, 2);
679       basic.DefSubr (copy, "copy", false, 1, 1);
680       basic.DefSubr (ins, "ins", true, 2, 2);
681       basic.DefSubr (del, "del", true, 2, 2);
682       basic.DefSubr (eval_clause, "eval", false, 1, 1);
683       basic.DefSubr (break_clause, "break", false, 0, 1);
684       basic.DefSubr (return_clause, "return", false, 1, 1);
685       basic.DefSpecial (and, "and", 1, -1, "&&");
686       basic.DefSpecial (or, "or", 1, -1, "||");
687       basic.DefSpecial (progn_clause, "progn", 0, -1, "expr");
688       basic.DefSpecial (if_clause, "if", 2, 3);
689       basic.DefSpecial (when_clause, "when", 1, -1);
690       basic.DefSpecial (loop_clause, "loop", 1, -1);
691       basic.DefSpecial (while_clause, "while", 1, -1);
692       basic.DefSpecial (cond_clause, "cond", 1, -1);
693       basic.DefSpecial (foreach_clause, "foreach", 2, -1);
694       basic.DefSpecial (quote_clause, "quote", 1, 1);
695       basic.DefSpecial (type_clause, "type", 1, 1);
696
697       Fprogn = basic.GetFunc (Nprogn);
698     }
699
700     private static Term set_value (Domain domain, Variable vari, Term[] args)
701     {
702       vari.Value = args[0];
703       return vari.val;
704     }
705
706     private static Term not (Domain domain, Variable vari, Term[] args)
707     {
708       return args[0].IsTrue ? Zero : One;
709     }
710
711     private static Term add (Domain domain, Variable vari, Term[] args)
712     {
713       int n = vari == null ? 0 : vari.val.Intval;
714
715       foreach (Term arg in args)
716         n += (int) arg;
717       if (vari == null)
718         return n;
719       vari.val.intval = n;
720       return vari.val;
721     }
722
723     private static Term mul (Domain domain, Variable vari, Term[] args)
724     {
725       int n = vari == null ? 1 : vari.val.Intval;
726       foreach (Term arg in args)
727         n *= (int) arg;
728       if (vari == null)
729         return n;
730       vari.val.intval = n;
731       return vari.val;
732     }
733
734     private static Term sub (Domain domain, Variable vari, Term[] args)
735     {
736       int n, i;
737
738       if (vari == null)
739         {
740           n = args[0].Intval;
741           i = 1;
742         }
743       else
744         {
745           n = vari.val.Intval;
746           i = 0;
747         }
748       while (i < args.Length)
749         n -= (int) args[i++];
750       if (vari == null)
751         return n;
752       vari.val.intval = n;
753       return vari.val;
754     }
755
756     private static Term div (Domain domain, Variable vari, Term[] args)
757     {
758       int n, i;
759
760       if (vari == null)
761         {
762           n = args[0].Intval;
763           i = 1;
764         }
765       else
766         {
767           n = vari.val.Intval;
768           i = 0;
769         }
770       while (i < args.Length)
771         n /= args[i++].Intval;
772       if (vari == null)
773         return n;
774       vari.val.intval = n;
775       return vari.val;
776     }
777
778     private static Term mod (Domain domain, Variable vari, Term[] args)
779     {
780       if (vari == null)
781         return (args[0].Intval % args[1].Intval);
782       vari.val.intval = vari.val.Intval % args[0].Intval;
783       return vari.val;
784     }
785
786     private static Term logior (Domain domain, Variable vari, Term[] args)
787     {
788       int n = vari == null ? 0 : vari.val.Intval;
789       foreach (Term arg in args)
790         n |= (int) arg;
791       if (vari == null)
792         return n;
793       vari.val.intval = n;
794       return vari.val;
795     }
796
797     private static Term logand (Domain domain, Variable vari, Term[] args)
798     {
799       int n, i;
800
801       if (vari == null)
802         {
803           n = args[0].Intval;
804           i = 1;
805         }
806       else
807         {
808           n = vari.val.Intval;
809           i = 0;
810         }
811       while (i < args.Length)
812         n &= (int) args[i++];
813       if (vari == null)
814         return n;
815       vari.val.intval = n;
816       return vari.val;
817     }
818
819     private static Term lsh (Domain domain, Variable vari, Term[] args)
820     {
821       if (vari == null)
822         return args[0].Intval << args[1].Intval;
823       vari.val.intval = vari.val.Intval << args[0].Intval;
824       return vari.val;
825     }
826
827     private static Term rsh (Domain domain, Variable vari, Term[] args)
828     {
829       if (vari == null)
830         return args[0].Intval >> args[1].Intval;
831       vari.val.intval = vari.val.Intval >> args[0].Intval;
832       return vari.val;
833     }
834
835     private static Term eq (Domain domain, Variable vari, Term[] args)
836     {
837       Term o = args[0];
838
839       if (o.objval == null)
840         {
841           for (int i = 1; i < args.Length; i++)
842             if (args[i].objval != null || args[i].intval != o.intval)
843               return Zero;
844         }
845       else
846         {
847           for (int i = 1; i < args.Length; i++)
848             if (o.objval.Equals (args[i].objval))
849               return Zero;
850         }
851       return One;
852     }
853
854     private static Term noteq (Domain domain, Variable vari, Term[] args)
855     {
856       return eq (domain, vari, args);
857     }
858
859     private static Term less_than (Domain domain, Variable vari, Term[] args)
860     {
861       int n = (int) args[0];
862
863       for (int i = 1; i < args.Length; i++)
864         {
865           int n1 = (int) args[i];
866           if (n >= n1)
867             return Zero;
868           n = n1;
869         }
870       return One;
871     }
872
873     private static Term less_eq (Domain domain, Variable vari, Term[] args)
874     {
875       int n = (int) args[0];
876       for (int i = 1; i < args.Length; i++)
877         {
878           int n1 = (int) args[i];
879           if (n > n1)
880             return Zero;
881           n = n1;
882         }
883       return One;
884     }
885
886     private static Term greater_than (Domain domain, Variable vari, Term[] args)
887     {
888       int n = (int) args[0];
889       for (int i = 1; i < args.Length; i++)
890         {
891           int n1 = (int) args[i];
892           if (n <= n1)
893             return Zero;
894           n = n1;
895         }
896       return One;
897     }
898
899     private static Term greater_eq (Domain domain, Variable vari, Term[] args)
900     {
901       int n = (int) args[0];
902       for (int i = 1; i < args.Length; i++)
903         {
904           int n1 = (int) args[i];
905           if (n < n1)
906             return Zero;
907           n = n1;
908         }
909       return One;
910     }
911
912     private static Term append (Domain domain, Variable vari, Term[] args)
913     {
914       List<Term> list;
915
916       if (vari == null)
917         list = new List<Term> ();
918       else
919         list = vari.val.Listval;
920
921       foreach (Term arg in args)
922         {
923           if (arg.IsList)
924             list.AddRange ((List<Term>) arg.objval);
925           else
926             list.Add (arg);
927         }
928       if (vari == null)
929         {
930           Term result;
931           result.intval = 0;
932           result.objval = list;
933           return result;
934         }
935       vari.val.objval = list;
936       return vari.val;
937     }
938
939     private static Term concat (Domain domain, Variable vari, Term[] args)
940     {
941       string str;
942
943       if (vari == null)
944         str = "";
945       else
946         str = vari.val.Strval;
947
948       foreach (Term arg in args)
949         {
950           if (arg.IsStr)
951             str += (string) arg.objval;
952           else if (arg.IsList)
953             foreach (Term term in (List<Term>) arg.objval)
954               str += (char) term.Intval;
955           else
956             str += (char) arg.Intval;
957         }
958       if (vari == null)
959         {
960           Term result;
961           result.intval = 0;
962           result.objval = str;
963           return result;
964         }
965       vari.val.objval = str;
966       return vari.val;
967     }
968
969     private static Term nth (Domain domain, Variable vari, Term[] args)
970     {
971       Term result;
972
973       if (args[1].IsStr)
974         {
975           result.intval = ((string) args[1].objval)[args[0].Intval];
976           result.objval = null;
977         }
978       else if (args[1].IsList)
979         {
980           result = ((List<Term>) args[1].objval)[args[0].Intval];
981         }
982       else
983         throw new Exception ("Term is not enumelable: " + args[1]);
984       return result;
985     }
986
987     private static Term copy (Domain domain, Variable vari, Term[] args)
988     {
989       Term result;
990
991       result.intval = 0;
992       result.objval = new List<Term> (args[0].Listval);
993       return result;
994     }
995
996     private static Term ins (Domain domain, Variable vari, Term[] args)
997     {
998       if (vari.val.IsStr)
999         vari.val.objval
1000           = vari.val.Strval.Insert (args[0].Intval, args[1].Strval);
1001       else if (vari.val.IsList)
1002         vari.val.Listval.InsertRange (args[0].Intval, args[1].Listval);
1003       else
1004         throw new Exception ("term is not collection: " + vari.val);
1005       return vari.val;
1006     }
1007
1008     private static Term del (Domain domain, Variable vari, Term[] args)
1009     {
1010       if (vari.val.IsStr)
1011         vari.val.objval
1012           = vari.val.Strval.Remove (args[0].Intval,
1013                                     args[1].Intval - args[0].Intval);
1014
1015       else if (vari.val.IsList)
1016         vari.val.Listval.RemoveRange (args[0].Intval,
1017                                       args[1].Intval - args[0].Intval);
1018       else
1019         throw new Exception ("term is not collection: " + vari.val);
1020       return vari.val;
1021     }
1022
1023     private static Term and (Domain domain, Variable vari, Term[] args)
1024     {
1025       foreach (Term arg in args)
1026         if (! arg.Eval (domain).IsTrue)
1027           return Zero;
1028       return One;
1029     }
1030
1031     private static Term or (Domain domain, Variable vari, Term[] args)
1032     {
1033       foreach (Term arg in args)
1034         if (arg.Eval (domain).IsTrue)
1035           return One;
1036       return Zero;
1037     }
1038
1039     private static Term eval_clause (Domain domain, Variable vari, Term[] args)
1040     {
1041       return (args[0].Eval (domain));
1042     }
1043
1044     private static Term progn_clause (Domain domain, Variable vari, Term[] args)
1045     {
1046       Term result = One;
1047
1048       foreach (Term arg in args)
1049         result = arg.Eval (domain);
1050       return result;
1051     }
1052
1053     private static Term if_clause (Domain domain, Variable vari, Term[] args)
1054     {
1055       if (args[0].Eval (domain).IsTrue)
1056         return args[1].Eval (domain);
1057       if (args.Length == 2)
1058         return Zero;
1059       return args[2].Eval (domain);
1060     }
1061
1062     private static Term when_clause (Domain domain, Variable vari, Term[] args)
1063     {
1064       if (! args[0].Eval (domain).IsTrue)
1065         return Zero;
1066       Term result = One;
1067       for (int i = 1; i < args.Length; i++)
1068         result = args[i].Eval (domain);
1069       return result;
1070     }
1071
1072     private static Term break_clause (Domain domain, Variable vari, Term[] args)
1073     {
1074       Stack<CatchTag> clist = domain.catch_list;
1075       if (clist.Count == 0)
1076         throw new Exception ("No outer loop to break");
1077       CatchTag tag = clist.Peek ();
1078       if (tag.name != Nloop)
1079         throw new Exception ("No outer loop to break");
1080       domain.depth = tag.depth;
1081       return args.Length == 0 ? Zero : args[0];
1082     }     
1083
1084     private static Term return_clause (Domain domain, Variable vari, Term[] args)
1085     {
1086       Stack<CatchTag> clist = domain.catch_list;
1087
1088       while (clist.Count > 0)
1089         {
1090           CatchTag tag = clist.Pop ();
1091           if (tag.name == Nfunction)
1092             {
1093               domain.depth = tag.depth;
1094               return = args.Length == 0 ? Zero : args[0];
1095             }
1096         }
1097       return args.Length == 0 ? Zero : args[0];
1098     }     
1099
1100     private static Term loop_clause (Domain domain, Variable vari, Term[] args)
1101     {
1102       domain.Catch (Nloop);
1103       Term result = Zero;
1104       try {
1105         while (! domain.Catched)
1106           foreach (Term arg in args)
1107             {
1108               result = arg.Eval (domain);
1109               if (domain.Catched)
1110                 break;
1111             }
1112       } finally {
1113         domain.Uncatch ();
1114       }
1115       return result;
1116     }
1117
1118     private static Term while_clause (Domain domain, Variable vari, Term[] args)
1119     {
1120       while (args[0].Eval (domain).IsTrue)
1121         for (int i = 1; i < args.Length; i++)
1122           args[i].Eval (domain);
1123       return Zero;
1124     }
1125
1126     private static Term cond_clause (Domain domain, Variable vari, Term[] args)
1127     {
1128       foreach (Term arg in args)
1129         {
1130           List<Term> list = arg.Listval;
1131           Term result = list[0].Eval (domain);
1132
1133           if (result.IsTrue)
1134             {
1135               for (int i = 1; i < list.Count; i++)
1136                 result = list[i].Eval (domain);
1137               return result;
1138             }
1139         }
1140       return Zero;
1141     }
1142
1143     private static Term foreach_clause (Domain domain, Variable vari,
1144                                         Term[] args)
1145     {
1146       List<Term> list = args[0].Listval;
1147       Bindings current = domain.bindings;
1148
1149       foreach (Term term in list)
1150         {
1151           domain.Bind (vari, term);
1152           try {
1153             for (int i = 1; i < args.Length; i++)
1154               args[i].Eval (domain);
1155           } finally {
1156             domain.UnboundTo (current);
1157           }
1158         }
1159       return Zero;
1160     }
1161
1162     private static Term quote_clause (Domain domain, Variable vari, Term[] args)
1163     {
1164       return new Term (args[0]);
1165     }
1166
1167     private static Term type_clause (Domain domain, Variable vari, Term[] args)
1168     {
1169       if (args[0].IsInt)
1170         return TermInt;
1171       if (args[0].IsStr)
1172         return TermStr;
1173       if (args[0].IsName)
1174         return TermName;
1175       if (args[0].IsList)
1176         return TermList;
1177       return TermTerm;
1178     }
1179
1180     public struct Term
1181     {
1182       public int intval;
1183       public object objval;
1184
1185       public Term (int i) { intval = i; objval = null; }
1186       public Term (Name name) { intval = 0; objval = name; }
1187       public Term (string str) { intval = 0; objval = str; }
1188       public Term (List<Term> list) { intval = 0; objval = list; }
1189       public Term (Term term) { intval = 0; objval = term; }
1190
1191       public Term (XmlNode node, Domain domain)
1192         {
1193           Name name = node.Name;
1194
1195           if (name == Ninteger)
1196             {
1197               intval = parse_integer (node.InnerText);
1198               objval = null;
1199             }
1200           else
1201             {
1202               intval = 0;
1203               if (name == Nsymbol)
1204                 objval = (Name) node.InnerText;
1205               else if (name == Nstring)
1206                 objval = node.InnerText.Clone ();
1207               else if (name == Nvarref)
1208                 objval = domain.GetVar ((Name) node.Attributes[0].Value);
1209               else if (name == Nlist)
1210                 {
1211                   List<Term> list = new List<Term> ();
1212                   for (node = node.FirstChild; node != null;
1213                        node = node.NextSibling)
1214                     list.Add (new Term (node, domain));
1215                   objval = list;
1216                 }
1217               else
1218                 {
1219                   Function func;
1220                   Variable vari = null;
1221                   Term[] args;
1222
1223                   if (name == Nfuncall)
1224                     name = node.Attributes[0].Value;
1225                   else if (node.Attributes[Nvname] != null)
1226                     vari = domain.GetVar (node.Attributes[Nvname].Value);
1227                   func = domain.GetFunc (name);
1228                   XmlNodeList nlist = node.ChildNodes;
1229                   int nargs = nlist.Count;
1230
1231                   if (nargs < func.min_arg
1232                       || (func.max_arg >= 0 && nargs > func.max_arg))
1233                     throw new Exception ("Invalid number of arguments to: "
1234                                          + name + " " + nargs);
1235                   args = new Term[nargs];
1236                   for (int i = 0; i < nlist.Count; i++)
1237                     args[i] = new Term (nlist[i], domain);
1238                   objval = new Funcall (func, vari, args);
1239                 }
1240             }
1241         }
1242
1243       private class Funcall
1244       {
1245         internal Function func;
1246         internal Variable vari;
1247         internal Term[] args;
1248
1249         public Funcall (Function func, Variable vari, Term[] args)
1250         {
1251           this.func = func;
1252           this.vari = vari;
1253           this.args = args;
1254         }
1255
1256         public Term Eval (Domain domain)
1257         {
1258           domain.DebugWrite (true, "(({0}", func.name);
1259           for (int i = 0; i < args.Length; i++)
1260             domain.DebugWrite (false, " {0}", args[i].ToString ());
1261           domain.DebugWrite (false, ")");
1262           domain.depth++;
1263           Term result = func.Call (domain, vari, args);
1264           domain.depth--;
1265           domain.DebugWrite (true, " ==> {0})", result.ToString ());
1266           return result;
1267         }
1268
1269         public override string ToString ()
1270         {
1271           string str = "<funcall fname=\"" + func.name;
1272           if (args == null)
1273             return str + "\"/>";
1274           str += "\">";
1275           foreach (Term e in args)
1276             str += e;
1277           return (str + "</funcall>");
1278         }
1279       }
1280
1281       public int Intval {
1282         get {
1283           if (objval != null)
1284             throw new Exception ("term is not integer: " + this);
1285           return intval;
1286         }
1287       }
1288
1289       public string Strval {
1290         get {
1291           if (! IsStr)
1292             throw new Exception ("term is not string: " + this);
1293           return (string) objval;
1294         }
1295       }
1296
1297       public List<Term> Listval {
1298         get {
1299           if (! IsList)
1300             throw new Exception ("term is not list: " + this);
1301           return (List<Term>) objval;
1302         }
1303       }
1304
1305       public bool IsTrue {
1306         get {
1307           return (objval == null
1308                   ? (intval != 0)
1309                   : objval is List<Term>
1310                   ? (((List<Term>) objval).Count != 0)
1311                   : true);
1312         }
1313       }
1314       public bool IsInt { get { return (objval == null); } }
1315       public bool IsStr { get { return (objval is string); } }
1316       public bool IsName { get { return (objval is Name); } }
1317       public bool IsList { get { return (objval is List<Term>); } }
1318
1319       public Term Eval (Domain domain)
1320       {
1321         if (objval == null || objval is Name || objval is string)
1322           return this;
1323         if (objval is List<Term>)
1324           return new Term ((List<Term>) objval);
1325         if (objval is Funcall)
1326           return ((Funcall) objval).Eval (domain);
1327         if (objval is Variable)
1328           return ((Variable) objval).val;
1329         if (objval is Term)
1330           return (Term) objval;
1331         throw new Exception ("invalid Term object: " + objval);
1332       }
1333
1334       public static explicit operator int (Term term)
1335       {
1336         if (term.objval != null)
1337           throw new Exception ("Not an integer term: " + term);
1338         return term.intval;
1339       }
1340
1341       public static explicit operator Name (Term term)
1342       {
1343         return (Name) term.objval;
1344       }
1345
1346       public static implicit operator Term (int i)
1347       {
1348         return new Term (i);
1349       }
1350
1351       public override string ToString ()
1352       {
1353         string str;
1354
1355         if (objval == null)
1356           str = "<integer>" + intval + "</integer>";
1357         else if (objval is Name)
1358           str = "<symbol>" + objval + "</symbol>";
1359         else if (objval is string)
1360           str = "<string>" + objval + "</string>";
1361         else if (objval is List<Term>)
1362           {
1363             str = "<list>";
1364             foreach (Term e in (List<Term>) objval)
1365               str += e;
1366             str += "</list>";
1367           }
1368         else if (objval is Funcall)
1369           str = "<funcall fname=\"" + ((Funcall) objval).func.name + "\"/>";
1370         else if (objval is Variable)
1371           str = "<variable vname=\"" + ((Variable) objval).name + "\"/>";
1372         else if (objval is Term)
1373           str = "<quote>" + objval + "</quote>";
1374         else
1375           throw new Exception ("invalid Term object: " + objval);
1376         return str;
1377       }
1378     }
1379
1380     static Term Zero = new Term (0);
1381     static Term One = new Term (1);
1382     static Term TermInt = new Term (Ninteger);
1383     static Term TermStr = new Term (Nstring);
1384     static Term TermName = new Term (Nsymbol);
1385     static Term TermList = new Term (Nlist);
1386     static Term TermTerm = new Term ((Name) "term");
1387
1388     internal static int parse_integer (string str)
1389     {
1390       int len = str.Length;
1391       bool negative = false;
1392
1393       if (len <= 1)
1394         return (len == 0 ? 0 : str[0] - '0');
1395
1396       int c = str[0];
1397       int i;
1398
1399       if (c == '0' && str[1] == 'x')
1400         {
1401           i = 0;
1402           for (int idx = 2; idx < len; idx++)
1403             {
1404               c = str[idx];
1405               if (c < '0')
1406                 break;
1407               else if (c <= '9')
1408                 i = i * 16 + (c - '0');
1409               else if (c < 'A')
1410                 break;
1411               else if (c <= 'F')
1412                 i = i * 16 + (c - 'A');
1413               else if (c < 'a')
1414                 break;
1415               else if (c <= 'f')
1416                 i = i * 16 + (c - 'a');
1417               else
1418                 break;
1419             }
1420           return i;
1421         }
1422       if (c == '-')
1423         negative = true;
1424       i = c - '0';
1425       for (int idx = 1; idx < len; idx++)
1426         {
1427           c = str[idx];
1428           if (c < '0' || c > '9')
1429             break;
1430           i = i * 10 + (c - '0');
1431         }
1432       return negative ? - i : i;
1433     }
1434
1435     private Term[] terms;
1436
1437     public Xexpression (string url, Domain domain)
1438     {
1439       XmlDocument doc = new XmlDocument (Name.Table);
1440       XmlNode node;
1441
1442       using (XmlTextReader reader = new XmlTextReader (url, Name.Table))
1443         {
1444           do {
1445             reader.Read ();
1446           } while (reader.NodeType != XmlNodeType.None
1447                    && (reader.NodeType != XmlNodeType.Element
1448                        || reader.Name != Nexpr));
1449           if (reader.NodeType == XmlNodeType.None)
1450             throw new Exception ("Node <expr> not found");
1451           node = doc.ReadNode (reader);
1452         }
1453
1454       int nterms = 0;
1455       for (XmlNode n = node.FirstChild; n != null; n = n.NextSibling)
1456         if (n.NodeType == XmlNodeType.Element)
1457           {
1458             if (n.Name == Ndefun)
1459               domain.RegisterFunction (n);
1460             else if (n.Name == Ndefvar)
1461               domain.Defvar (n);
1462             else
1463               nterms++;
1464           }
1465
1466       terms = new Term[nterms];
1467       int i = 0;
1468       for (XmlNode n = node.FirstChild; n != null; n = n.NextSibling)
1469         if (n.NodeType == XmlNodeType.Element)
1470           {
1471             if (n.Name == Ndefun)
1472               domain.Defun (n);
1473             else if (n.Name != Ndefvar)
1474               terms[i++]= new Term (n, domain);
1475           }
1476     }
1477
1478     public Term Eval (Domain domain)
1479     {
1480       Term result = Zero;
1481
1482       domain.depth = 0;
1483       foreach (Term term in terms)
1484         result = term.Eval (domain);
1485       return result;
1486     }
1487
1488     public override string ToString ()
1489     {
1490       string str = "";
1491       for (int i = 0; i < terms.Length; i++)
1492         str += terms[i];
1493       return str;
1494     }
1495   }
1496 }