*** 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 Xex
10   {
11     public struct Name : IEquatable<Name>
12     {
13       private static NameTable nt = new NameTable ();
14
15       private string name;
16
17       public Name (string str)
18         {
19           name = nt.Add (str);
20         }
21
22       public static implicit operator Name (string str)
23       {
24         return new Name (str);
25       }
26
27       public static implicit operator string (Name name)
28       {
29         return name.name;
30       }
31
32       public static bool operator== (Name n1, Name n2)
33         {
34           return (object) n1.name == (object) n2.name;
35         }
36
37       public static bool operator!= (Name n1, Name n2)
38         {
39           return (object) n1.name != (object) n2.name;
40         }
41
42       public static bool operator== (Name n1, string n2)
43         {
44           return (object) n1.name == (object) n2;
45         }
46
47       public static bool operator!= (Name n1, string n2)
48         {
49           return (object) n1.name != (object) n2;
50         }
51
52       public static bool operator== (string n1, Name n2)
53         {
54           return (object) n1 == (object) n2.name;
55         }
56
57       public static bool operator!= (string n1, Name n2)
58         {
59           return (object) n1 != (object) n2.name;
60         }
61
62       public bool Equals (Name name)
63       {
64         return Object.ReferenceEquals (this.name, name.name);
65       }
66
67       public override bool Equals (object obj)
68       {
69         return Object.ReferenceEquals (this.name, obj);
70       }
71
72       public override int GetHashCode ()
73       {
74         return name.GetHashCode ();
75       }
76
77       public static NameTable Table { get { return nt; } }
78
79       public override string ToString () { return name; }
80     }
81
82     private static Name Nexpr = "expr";
83     private static Name Ntype = "type";
84
85     private static Name Ninteger = "integer";
86     private static Name Nstring = "string";
87     private static Name Nboolean = "boolean";
88     private static Name Nsymbol = "symbol";
89     private static Name Nlist = "list";
90     private static Name Nobject = "object";
91
92     private static Name Ndefun = "defun";
93     private static Name Nfname = "fname";
94     private static Name Nargs = "args";
95     private static Name Noptional = "optional";
96     private static Name Nrest = "rest";
97     private static Name Nbody = "body";
98
99     private static Name Ndefvar = "defvar";
100     private static Name Nconst = "const";
101     private static Name Nvariable = "variable";
102     private static Name Ndescription = "description";
103     private static Name Npossible_value = "possible-value";
104
105     private static Name Nfuncall = "funcall";
106     private static Name Nprogn = "progn";
107
108     internal class Function
109     {
110       internal class Lambda
111       {
112         internal Xex[] args;
113         internal Xex[] body;
114
115         public void SetArgs (XmlNode node, int nargs, Domain domain)
116         {
117           args = new Xex[nargs];
118           node = node.FirstChild;
119           for (int i = 0; i < nargs; node = node.NextSibling)
120             if (node.Name != Noptional && node.Name != Nrest)
121               args[i++] = new Xex (node, domain);
122         }
123
124         public void SetBody (XmlNode node, Domain domain)
125         {
126           XmlNodeList nlist = node.ChildNodes;
127
128           body = new Xex[nlist.Count];
129           for (int i = 0; i < nlist.Count; i++)
130             body[i] = new Xex (nlist[i], domain);
131         }
132       }
133
134       public readonly Name name;
135       public Builtin builtin;
136       public int min_arg, max_arg;
137       internal Lambda lambda;
138       public bool specialp = false;
139
140       public Function (Name name, Builtin builtin,
141                        int min_arg, int max_arg, bool specialp)
142       {
143         this.name = name;
144         this.builtin = builtin;
145         this.min_arg = min_arg;
146         this.max_arg = max_arg;
147         this.specialp = specialp;
148       }
149
150       public Function (Name name, int min_arg, int max_arg)
151       {
152         this.name = name;
153         this.min_arg = min_arg;
154         this.max_arg = max_arg;
155       }
156
157       public void Setup (XmlNode node, Domain domain)
158       {
159         lambda = new Lambda ();
160         node = node.FirstChild;
161         if (node.Name == Nargs)
162           {
163             lambda.SetArgs (node, max_arg, domain);
164             node = node.NextSibling;
165           }
166         if (node.Name == Nbody)
167           lambda.SetBody (node, domain);
168       }
169
170       public static Name ParseHead (XmlNode node,
171                                     out int min_arg, out int max_arg)
172       {
173         Name name = node.Attributes[Nfname].Value;
174         int nargs = 0, noptions = 0, nrest = 0;
175         XmlNode n;
176             
177         for (n = node.FirstChild; n != null; n = n.NextSibling)
178           {
179             if (n.Name == Noptional || n.Name == Nrest)
180               break;
181             nargs++;
182           }
183         if (n != null && n.Name == Noptional)
184           for (n = n.NextSibling; n != null; n = n.NextSibling)
185             {
186               if (n.Name == Nrest)
187                 break;
188               noptions++;
189             }
190         if (n != null && n.Name == Nrest)
191           for (n = n.NextSibling; n != null; n = n.NextSibling)
192             nrest++;
193         min_arg = nargs;
194         max_arg = nargs + noptions + nrest;
195         if (nrest == 1)
196           max_arg = - max_arg;
197         return name;
198       }
199
200       public object Call (Xex[] args, Domain domain)
201       {
202         Bindings current = domain.bindings;
203         object result = false;
204
205         Console.Write ("calling (" + this);
206         try {
207           foreach (Xex e in args)
208             Console.Write (" " + e);
209           Console.Write (") => ");
210           if (builtin != null)
211             {
212               if (! specialp)
213                 foreach (Xex a in args)
214                   if (a.Eval (domain) == null)
215                     throw new Exception ("evaled to null");
216               result = builtin (args, domain);
217               Console.WriteLine (result);
218               return result;
219             }
220
221           int i;
222           for (i = 0; i < min_arg; i++)
223             {
224               Xex a = lambda.args[i];
225               bool isdirect = a.args == null;
226               Name name = isdirect ? (Name) a.val : (Name) a.args[0].val;
227               Variable var = new VarMisc (name, null);
228
229               domain.variables[name] = var;
230               if (isdirect)
231                 domain.Bind (var, args[i]);
232               else
233                 domain.Bind (var, args[i].Eval (domain));
234             }
235           foreach (Xex e in lambda.body)
236             result = e.Eval (domain);
237           Console.WriteLine (result);
238         } finally {
239           domain.UnboundTo (current);
240         }
241         return result;
242       }
243
244       public override string ToString ()
245       {
246         return name;
247       }
248     }
249
250     internal abstract class Variable
251     {
252       public readonly Name name;
253       public readonly Name type;
254       internal object val;
255
256       public Variable (Name name, Name type, object value)
257       {
258         if (value != null)
259           Value = value;
260         this.name = name;
261         this.type = type;
262       }
263
264       public object Value
265       {
266         get { return val; }
267         set
268           {
269             if (! ValueP (value))
270               throw new Exception ("Invalid value type: " + value);
271             val = value;
272           }
273       }
274
275       public abstract bool ValueP (object value);
276
277       public override string ToString () { return name + "(" + type + ")"; }
278     }
279
280     internal class VarInt : Variable
281     {
282       public struct Range
283       {
284         public int from, to;
285       }
286
287       public Range[] ranges;
288
289       public VarInt (Name name, object value) : base (name, Ninteger, value) { }
290
291       public override bool ValueP (object value)
292       {
293         int i;
294
295         if (! (value is int))
296           return false;
297         if (ranges == null)
298           return true;
299         i = (int) value;
300         foreach (Range r in ranges)
301           if (i >= r.from && i <= r.to)
302             return true;
303         return false;
304       }
305     }
306
307     internal class VarStr : Variable
308     {
309       public string[] ranges;
310
311       public VarStr (Name name, object value) : base (name, Nstring, value) { }
312
313       public override bool ValueP (object value)
314       {
315         string str;
316
317         if (! (value is string))
318           return false;
319         if (ranges == null)
320           return true;
321         str = (string) value;
322         foreach (string s in ranges)
323           if (s == str)
324             return true;
325         return false;
326       }
327     }
328
329     internal class VarBool : Variable
330     {
331       public VarBool (Name name, object value)
332         : base (name, Nboolean, value) { }
333
334       public override bool ValueP (object value)
335       {
336         if (! (value is bool))
337           return false;
338         return true;
339       }
340     }
341
342     internal class VarMisc : Variable
343     {
344       public VarMisc (Name name, object value) : base (name, Nobject, value) { }
345
346       public override bool ValueP (object value)
347       {
348         return true;
349       }
350     }
351
352     internal class Bindings
353     {
354       private Variable vari;
355       private object old_value;
356       private Bindings next;
357         
358       private Bindings (Variable vari, object value)
359       {
360         this.vari = vari;
361         old_value = value;
362       }
363         
364       public static Bindings Bind (Bindings bindings,
365                                    Variable vari, object value)
366       {
367         Bindings b = new Bindings (vari, vari.val);
368
369         b.vari.Value = value;
370         b.next = bindings;
371         return b;
372       }
373
374       internal Bindings UnboundTo (Bindings boundary)
375       {
376         for (Bindings b = this; b != boundary; b = b.next)
377           vari.val = b.old_value;
378         return boundary;
379       }
380
381       public override string ToString ()
382       {
383         string str = "(bindings";
384         for (Bindings b = this; b != null; b = b.next)
385           str += " " + vari;
386         return str + ")";
387       }
388     }
389
390 #if false
391     internal class ThrowException : Exception
392     {
393       Name tag;
394       public object value;
395
396       public ThrowException (Name tag, object value) : base ()
397         {
398           this.tag = tag;
399           this.value = value;
400         }
401     }
402 #endif
403
404     public class Domain
405     {
406       public object context;
407
408       internal Dictionary<Name, Function> functions;
409       internal Dictionary<Name, Variable> variables;
410       internal Bindings bindings;
411
412       internal Domain ()
413       {
414         functions = new Dictionary<Name, Function> ();
415         variables = new Dictionary<Name, Variable> ();
416       }
417
418       public Domain (object context) : this (basic, context)
419       {
420       }
421
422       public Domain (Domain parent, object context)
423       {
424         functions = new Dictionary<Name, Function> (parent.functions);
425         variables = new Dictionary<Name, Variable> (parent.variables);
426         this.context = context;
427       }
428
429       internal void Bind (Variable vari, object value)
430       {
431         bindings = Bindings.Bind (bindings, vari, value);
432       }
433
434       internal void UnboundTo (Bindings boundary)
435       {
436         if (bindings != null)
437           bindings = bindings.UnboundTo (boundary);
438       }
439
440       public void Defun (Name name, Builtin builtin, int min_arg, int max_arg)
441       {
442         Defun (name, builtin, min_arg, max_arg, false);
443       }
444
445       public void Defun (Name name, Builtin builtin,
446                          int min_arg, int max_arg, bool specialp)
447       {
448         Function func;
449
450         if (functions.TryGetValue (name, out func))
451           {
452             if (func.min_arg < min_arg || func.max_arg > max_arg)
453               throw new Exception ("Incompatible argument numbers to override: "
454                                    + name);
455             func.builtin = builtin;
456             func.lambda = null;
457             func.min_arg = min_arg;
458             func.max_arg = max_arg;
459             func.specialp = specialp;
460           }
461         else
462           {
463             functions[name]
464               = new Function (name, builtin, min_arg, max_arg, specialp);
465           }
466       }
467
468       internal Function RegisterFunction (XmlNode node)
469       {
470         int min_arg, max_arg;
471         Name name = Function.ParseHead (node, out min_arg, out max_arg);
472         Function func = new Function (name, min_arg, max_arg);
473
474         functions[name] = func; 
475         return func;
476       }
477
478       internal Function Defun (XmlNode node)
479       {
480         Name name = node.Attributes[Nfname].Value;
481         Function func;
482
483         if (! functions.TryGetValue (name, out func))
484           func = RegisterFunction (node);
485         func.Setup (node, this);
486         return func;
487       }
488
489       public void Defvar (Name name, XmlNode node)
490       {
491         Variable vari;
492
493         if (node.Name == Ndescription)
494           node = node.NextSibling;
495         if (node.Name == Nconst)
496           {
497             Name type = (Name) node.Attributes[Ntype].Value;
498             string val = node.Value;
499             XmlNodeList range_list = null;
500             int nranges = 0;
501
502             node = node.NextSibling;
503             if (node.Name == Npossible_value)
504               {
505                 range_list = node.ChildNodes;
506                 nranges = range_list.Count;
507               }
508
509             if (type == Ninteger)
510               {
511                 VarInt vi = new VarInt (name, parse_integer (val));
512                 if (range_list != null)
513                   {
514                     vi.ranges = new VarInt.Range[nranges];
515
516                     for (int i = 0; i < nranges; i++)
517                       {
518                         XmlNode n = range_list[i];
519
520                         if (n.Name == Nconst)
521                           {
522                             int num = parse_integer (n.Value);
523                             vi.ranges[i].from = vi.ranges[i].to = num;
524                           }
525                         else    // range_list[i].Name == "range"
526                           {
527                             vi.ranges[i].from =
528                               parse_integer (n.FirstChild.Value);
529                             vi.ranges[i].to =
530                               parse_integer (n.LastChild.Value);
531                           }
532                       }
533                   }
534                 vari = vi;
535               }
536             else if (type == Nstring)
537               {
538                 VarStr vs = new VarStr (name, val);
539                 if (range_list != null)
540                   vs.ranges = new string[nranges];
541                 for (int i = 0; i < nranges; i++)
542                   vs.ranges[i] = range_list[i].Value;
543                 vari = vs;
544               }
545             else if (type == Nboolean)
546               {
547                 vari = new VarBool (name, val == "true");
548               }
549             else
550               throw new Exception ("Unknown type: " + type);
551           }
552         else
553           vari = new VarMisc (name, null);
554         variables[name] = vari;
555       }
556
557       internal Function GetFunc (Name name)
558       {
559         Function func;
560
561         if (! functions.TryGetValue (name, out func))
562           throw new Exception ("Unknown function: " + name);
563         return func;
564       }
565
566       public bool CopyFunc (Domain domain, Name name)
567       {
568         Function func = GetFunc (name);
569
570         domain.functions[name] = func;
571         return true;
572       }
573
574       public void CopyFunc (Domain domain)
575       {
576         foreach (KeyValuePair<Name, Function> kv in functions)
577           domain.functions[kv.Key] = kv.Value;
578       }
579
580       internal Variable GetVar (Name name)
581       {
582         Variable vari;
583
584         if (! variables.TryGetValue (name, out vari))
585           variables[name] = vari = new VarMisc (name, null);
586         return vari;
587       }
588
589       internal Variable GetVar (Xex e)
590       {
591         if (! (e.val is Name))
592           throw new Exception ("Not a symbol" + e.val);
593         return GetVar ((Name) e.val);
594       }
595
596       public override string ToString ()
597       {
598         string str = "<(functions";
599         foreach (KeyValuePair<Name, Function> kv in functions)
600           str += " " + kv.Key;
601         str += ") (variabls";
602         foreach (KeyValuePair<Name, Variable> kv in variables)
603           str += " " + kv.Key;
604         str += ")";
605         if (bindings != null)
606           str += " " + bindings;
607         if (context != null)
608           str += " (" + context + ")";
609         str += ">";
610         return str;
611       }
612     }
613
614     public delegate object Builtin (Xex[] args, Domain domain);
615
616     private static Domain basic = new Domain ();
617
618     internal static Function Fprogn;
619
620     static Xex ()
621     {
622       basic.Defun ("set", set_value, 2, 2, false);
623       basic.Defun ("=", set_value, 2, 2, false);
624       basic.Defun ("and", and, 1, -1, false);
625       basic.Defun ("&&", and, 1, -1, false);
626       basic.Defun ("or", or, 1, -1, false);
627       basic.Defun ("||", or, 1, -1, false);
628       basic.Defun ("not", not, 1, 1, false);
629       basic.Defun ("!", not, 1, 1, false);
630       basic.Defun ("add", add, 2, -1, false);
631       basic.Defun ("+", add, 2, -1, false);
632       basic.Defun ("mul", mul, 2, -1, false);
633       basic.Defun ("*", mul, 2, -1, false);
634       basic.Defun ("sub", sub, 1, -1, false);
635       basic.Defun ("-", sub, 1, -1, false);
636       basic.Defun ("div", div, 2, -1, false);
637       basic.Defun ("/", div, 2, -1, false);
638       basic.Defun ("mod", mod, 2, 2, false);
639       basic.Defun ("%", mod, 2, 2, false);
640       basic.Defun ("logior", logior, 2, -1, false);
641       basic.Defun ("|", logior, 2, -1, false);
642       basic.Defun ("logand", logand, 2, -1, false);
643       basic.Defun ("&", logand, 2, -1, false);
644       basic.Defun ("add-set", add_set, 2, -1, true);
645       basic.Defun ("+=", add_set, 2, -1, true);
646       basic.Defun ("mul-set", mul_set, 2, -1, true);
647       basic.Defun ("*=", mul_set, 2, -1, true);
648       basic.Defun ("sub-set", sub_set, 2, -1, true);
649       basic.Defun ("-=", sub_set, 2, -1, true);
650       basic.Defun ("div-set", div_set, 2, -1, true);
651       basic.Defun ("/=", div_set, 2, -1, true);
652       basic.Defun ("mod-set", mod_set, 2, 2, true);
653       basic.Defun ("%=", mod_set, 2, 2, true);
654       basic.Defun ("logior-set", logior_set, 2, -1, true);
655       basic.Defun ("|=", logior_set, 2, -1, true);
656       basic.Defun ("logand-set", logand_set, 2, -1, true);
657       basic.Defun ("&=", logand_set, 2, -1, true);
658       basic.Defun ("lsh", lsh, 2, 2, false);
659       basic.Defun ("<<", lsh, 2, 2, false);
660       basic.Defun ("rsh", rsh, 2, 2, false);
661       basic.Defun (">>", rsh, 2, 2, false);
662       basic.Defun ("lsh-set", lsh_set, 2, 2, true);
663       basic.Defun ("<<=", lsh_set, 2, 2, true);
664       basic.Defun ("rsh-set", rsh_set, 2, 2, true);
665       basic.Defun (">>=", rsh_set, 2, 2, true);
666       basic.Defun ("eq", eq, 2, -1, false);
667       basic.Defun ("==", eq, 2, -1, false);
668       basic.Defun ("noteq", noteq, 2, 2, false);
669       basic.Defun ("!=", noteq, 2, 2, false);
670       basic.Defun ("lt", less_than, 2, -1, false);
671       basic.Defun ("<", less_than, 2, -1, false);
672       basic.Defun ("le", less_eq, 2, -1, false);
673       basic.Defun ("<=", less_eq, 2, -1, false);
674       basic.Defun ("gt", greater_than, 2, -1, false);
675       basic.Defun (">", greater_than, 2, -1, false);
676       basic.Defun ("ge", greater_eq, 2, -1, false);
677       basic.Defun (">=", greater_eq, 2, -1, false);
678       basic.Defun ("eval", eval_clause, 1, 1, true);
679       basic.Defun ("progn", progn_clause, 0, -1, true);
680       basic.Defun ("expr", progn_clause, 0, -1, true);
681       basic.Defun ("if", if_clause, 2, -1, true);
682       basic.Defun ("when", when_clause, 1, -1, true);
683       basic.Defun ("while", while_clause, 1, -1, true);
684
685       Fprogn = basic.GetFunc (Nprogn);
686     }
687
688     private static bool is_true (object val)
689     {
690       return (val is bool ? (bool) val
691               : val is int ? (int) val == 0
692               : true);
693     }
694
695     private static object set_value (Xex[] args, Domain domain)
696     {
697       Variable vari = domain.GetVar (args[0]);
698
699       vari.Value = args[1].val;
700       return vari.val;
701     }
702
703     private static object and (Xex[] args, Domain domain)
704     {
705       foreach (Xex arg in args)
706         if (! is_true (arg.val))
707           return false;
708       return true;
709     }
710
711     private static object or (Xex[] args, Domain domain)
712     {
713       foreach (Xex arg in args)
714         if (is_true (arg.val))
715           return true;
716       return false;
717     }
718
719     private static object not (Xex[] args, Domain domain)
720     {
721       return ! is_true (args[0].val);
722     }
723
724     private static object add (Xex[] args, Domain domain)
725     {
726       int n = 0;
727       foreach (Xex e in args)
728         n += (int) e.val;
729       return n;
730     }
731
732     private static object mul (Xex[] args, Domain domain)
733     {
734       int n = 1;
735       foreach (Xex e in args)
736         n *= (int) e.val;
737       return n;
738     }
739
740     private static object sub (Xex[] args, Domain domain)
741     {
742       int n = (int) args[0].val;
743       if (args.Length == 1)
744         return - n;
745       for (int i = 1; i < args.Length; i++)
746         n -= (int) args[i].val;
747       return n;
748     }
749
750     private static object div (Xex[] args, Domain domain)
751     {
752       int n = (int) args[0].val;
753       for (int i = 1; i < args.Length; i++)
754         n /= (int) args[i].val;
755       return n;
756     }
757
758     private static object mod (Xex[] args, Domain domain)
759     {
760       return ((int) args[0].val % (int) args[1].val);
761     }
762
763     private static object logior (Xex[] args, Domain domain)
764     {
765       int n = 0;
766       foreach (Xex e in args)
767         n |= (int) e.val;
768       return n;
769     }
770
771     private static object logand (Xex[] args, Domain domain)
772     {
773       int n = (int) args[0].val;
774       for (int i = 1; i < args.Length; i++)
775         n &= (int) args[i].val;
776       return n;
777     }
778
779     private static object add_set (Xex[] args, Domain domain)
780     {
781       Variable vari = domain.GetVar (args[0]);
782       int n = (int) vari.val;
783
784       for (int i = 1; i < args.Length; i++)
785         n += (int) args[i].val;
786       vari.val = n;
787       return n;
788     }
789
790     private static object mul_set (Xex[] args, Domain domain)
791     {
792       Variable vari = domain.GetVar (args[0]);
793       int n = (int) vari.val;
794
795       for (int i = 1; i < args.Length; i++)
796         n *= (int) args[i].val;
797       vari.val = n;
798       return n;
799     }
800
801     private static object sub_set (Xex[] args, Domain domain)
802     {
803       Variable vari = domain.GetVar (args[0]);
804       int n = (int) vari.val;
805
806       for (int i = 1; i < args.Length; i++)
807         n -= (int) args[i].val;
808       vari.val = n;
809       return n;
810     }
811
812     private static object div_set (Xex[] args, Domain domain)
813     {
814       Variable vari = domain.GetVar (args[0]);
815       int n = (int) vari.val;
816
817       for (int i = 1; i < args.Length; i++)
818         n /= (int) args[i].val;
819       vari.val = n;
820       return n;
821     }
822
823     private static object mod_set (Xex[] args, Domain domain)
824     {
825       Variable vari = domain.GetVar (args[0]);
826       int n = (int) vari.val;
827
828       for (int i = 1; i < args.Length; i++)
829         n %= (int) args[i].val;
830       vari.val = n;
831       return n;
832     }
833
834     private static object logior_set (Xex[] args, Domain domain)
835     {
836       Variable vari = domain.GetVar (args[0]);
837       int n = (int) vari.val;
838
839       for (int i = 1; i < args.Length; i++)
840         n |= (int) args[i].val;
841       vari.val = n;
842       return n;
843     }
844
845     private static object logand_set (Xex[] args, Domain domain)
846     {
847       Variable vari = domain.GetVar (args[0]);
848       int n = (int) vari.val;
849
850       for (int i = 1; i < args.Length; i++)
851         n &= (int) args[i].val;
852       vari.val = n;
853       return n;
854     }
855
856     private static object lsh (Xex[] args, Domain domain)
857     {
858       return (int) args[0].val << (int) args[1].val;
859     }
860
861     private static object lsh_set (Xex[] args, Domain domain)
862     {
863       Variable vari = domain.GetVar (args[0]);
864       int n = (int) vari.val;
865
866       n <<= (int) args[1].val;
867       vari.val = n;
868       return n;
869     }
870
871     private static object rsh (Xex[] args, Domain domain)
872     {
873       return (int) args[0].val >> (int) args[1].val;
874     }
875
876     private static object rsh_set (Xex[] args, Domain domain)
877     {
878       Variable vari = domain.GetVar (args[0]);
879       int n = (int) vari.val;
880
881       n >>= (int) args[1].val;
882       vari.val = n;
883       return n;
884     }
885
886     private static object eq (Xex[] args, Domain domain)
887     {
888       int n = (int) args[0].val;
889
890       for (int i = 1; i < args.Length; i++)
891         if (n != (int) args[i].val)
892           return false;
893       return true;
894     }
895
896     private static object noteq (Xex[] args, Domain domain)
897     {
898       return ((int) args[0].val != (int) args[1].val);
899     }
900
901     private static object less_than (Xex[] args, Domain domain)
902     {
903       int n = (int) args[0].val;
904
905       for (int i = 1; i < args.Length; i++)
906         {
907           int n1 = (int) args[i].val;
908           if (n >= n1)
909             return false;
910           n = n1;
911         }
912       return true;
913     }
914
915     private static object less_eq (Xex[] args, Domain domain)
916     {
917       int n = (int) args[0].val;
918       for (int i = 1; i < args.Length; i++)
919         {
920           int n1 = (int) args[i].val;
921           if (n > n1)
922             return false;
923           n = n1;
924         }
925       return true;
926     }
927
928     private static object greater_than (Xex[] args, Domain domain)
929     {
930       int n = (int) args[0].val;
931       for (int i = 1; i < args.Length; i++)
932         {
933           int n1 = (int) args[i].val;
934           if (n <= n1)
935             return false;
936           n = n1;
937         }
938       return true;
939     }
940
941     private static object greater_eq (Xex[] args, Domain domain)
942     {
943       int n = (int) args[0].val;
944       for (int i = 1; i < args.Length; i++)
945         {
946           int n1 = (int) args[i].val;
947           if (n < n1)
948             return false;
949           n = n1;
950         }
951       return true;
952     }
953
954     private static object eval_clause (Xex[] args, Domain domain)
955     {
956       return args[0].Eval (domain);
957     }
958
959     private static object progn_clause (Xex[] args, Domain domain)
960     {
961       object result = true;
962
963       foreach (Xex e in args)
964         result = e.Eval (domain);
965       return result;
966     }
967
968     private static object if_clause (Xex[] args, Domain domain)
969     {
970       object result;
971
972       if (is_true (args[0].Eval (domain)))
973         result = args[1].Eval (domain);
974       else
975         {
976           result = false;
977           for (int i = 2; i < args.Length; i++)
978             result = args[i].Eval (domain);
979         }
980       return result;
981     }
982
983     private static object when_clause (Xex[] args, Domain domain)
984     {
985       if (! is_true (args[0].Eval (domain)))
986         return false;
987
988       object result = true;
989       for (int i = 1; i < args.Length; i++)
990         result = args[i].Eval (domain);
991       return result;
992     }
993
994     private static object while_clause (Xex[] args, Domain domain)
995     {
996       while (is_true (args[0].Eval (domain)))
997         for (int i = 1; i < args.Length; i++)
998           args[i].Eval (domain);
999       return false;
1000     }
1001
1002     // FUNCALL: function != null
1003     // VARREF:  function == null, args[0] = DIRECT-SYMBOL
1004     // DIRECT:  function == null, args == null
1005
1006     private Function function;
1007     private Xex[] args;
1008     private object val;
1009
1010     public Xex[] Args { get { return args; } }
1011     public object Val { get { return val; } }
1012
1013     private Xex () { }
1014
1015     private Xex (object val)
1016     {
1017       this.val = val;
1018     }
1019
1020     internal static int parse_integer (string str)
1021     {
1022       int len = str.Length;
1023       bool negative = false;
1024
1025       if (len <= 1)
1026         return (len == 0 ? 0 : str[0] - '0');
1027
1028       int c = str[0];
1029       int i;
1030
1031       if (c == '0' && str[1] == 'x')
1032         {
1033           i = 0;
1034           for (int idx = 2; idx < len; idx++)
1035             {
1036               c = str[idx];
1037               if (c < '0')
1038                 break;
1039               else if (c <= '9')
1040                 i = i * 16 + (c - '0');
1041               else if (c < 'A')
1042                 break;
1043               else if (c <= 'F')
1044                 i = i * 16 + (c - 'A');
1045               else if (c < 'a')
1046                 break;
1047               else if (c <= 'f')
1048                 i = i * 16 + (c - 'a');
1049               else
1050                 break;
1051             }
1052           return i;
1053         }
1054       if (c == '-')
1055         negative = true;
1056       i = c - '0';
1057       for (int idx = 1; idx < len; idx++)
1058         {
1059           c = str[idx];
1060           if (c < '0' || c > '9')
1061             break;
1062           i = i * 10 + (c - '0');
1063         }
1064       return negative ? - i : i;
1065     }
1066
1067     private int pre_parse (XmlNodeList nlist, Domain domain)
1068     {
1069       int len = 0;
1070       foreach (XmlNode node in nlist)
1071         {
1072           if (node.Name == Ndefun)
1073             domain.RegisterFunction (node);
1074           else if (node.Name == Ndefvar)
1075             domain.Defvar ((Name) node.Attributes[0].Value, node.FirstChild);
1076           else
1077             len++;
1078         }
1079       return len;
1080     }
1081
1082     private void post_parse (XmlNodeList nlist, Domain domain)
1083     {
1084       for (int i = 0, j = 0; i < nlist.Count; i++)
1085         {
1086           XmlNode node = nlist[i];
1087
1088           if (node.Name == Ndefun)
1089             domain.Defun (node);
1090           else if (node.Name != Ndefvar)
1091             args[j++] = new Xex (node, domain);
1092         }
1093     }
1094
1095     private void Setup (XmlNode node, Domain domain)
1096     {
1097       Name name = node.Name;
1098
1099       if (name == Nconst)
1100         {
1101           Name type = node.Attributes[Ntype].Value;
1102
1103           if (type == Ninteger)
1104             val = parse_integer (node.InnerText);
1105           else if (type == Nstring)
1106             val = node.InnerText;
1107           else if (type == Nsymbol)
1108             val = (Name) node.InnerText;
1109           else if (type == Nboolean)
1110             val = node.InnerText == "true";
1111           else if (type == Nlist)
1112             {
1113               List<Xex> list = new List<Xex> ();
1114               for (XmlNode n = node.FirstChild; n != null; n = n.NextSibling)
1115                 list.Add (new Xex (n, domain));
1116               val = list;
1117             }
1118           else
1119             throw new Exception ("Unknown type: " + type);
1120         }
1121       else if (name == Nvariable)
1122         {
1123           args = new Xex[1];
1124           args[0] = new Xex ((Name) node.Attributes[0].Value);
1125         }
1126       else
1127         {
1128           if (name == Nfuncall)
1129             name = node.Attributes[0].Value;
1130           function = domain.GetFunc (name);
1131
1132           XmlNodeList nlist = node.ChildNodes;
1133           int nargs = nlist.Count;
1134
1135           if (nargs < function.min_arg
1136               || (function.max_arg >= 0 && nargs > function.max_arg))
1137             throw new Exception ("Invalid number of arguments to: "
1138                                  + name + " " + nargs);
1139           nargs =  pre_parse (nlist, domain);
1140           args = new Xex[nargs];
1141           post_parse (nlist, domain);
1142         }
1143     }
1144
1145     public Xex (string url, Domain domain)
1146     {
1147       XmlDocument doc = new XmlDocument (Name.Table);
1148       XmlNode node;
1149
1150       using (XmlTextReader reader = new XmlTextReader (url, Name.Table))
1151         {
1152           do {
1153             reader.Read ();
1154           } while (reader.NodeType != XmlNodeType.None
1155                    && (reader.NodeType != XmlNodeType.Element
1156                        || Nexpr != reader.Name));
1157           if (reader.NodeType == XmlNodeType.None)
1158             throw new Exception ("Node <expr> not found");
1159           node = doc.ReadNode (reader);
1160         }
1161
1162       Setup (node, domain);
1163     }
1164
1165     // EXPR = SYMBOL | MTEXT | INTEGER | FUNCALL | PROGN
1166     // FUNCALL = '(' SYMBOL EXPR* ')'
1167     // PROGN = '(' EXPR * ')'
1168     public Xex (XmlNode node, Domain domain)
1169     {
1170       Setup (node, domain);
1171     }
1172
1173     public object Eval (Domain domain)
1174     {
1175       if (function == null)
1176         {
1177           if (args != null)
1178             {
1179               Variable vari = domain.GetVar ((Name) args[0].val);
1180               val = vari.val;
1181             }
1182           return val;
1183         }
1184       else
1185         val = function.Call (args, domain);
1186       return val;
1187     }
1188
1189     public override string ToString ()
1190     {
1191       string str;
1192
1193       if (function != null)
1194         {
1195           str = "(" + function.name;
1196           if (args != null)
1197             foreach (Xex e in args)
1198               str += " " + e.ToString ();
1199           str += ")";
1200         }
1201       else if (args != null)
1202         {
1203           str = (Name) args[0].val;
1204         }
1205       else if (val != null)
1206         {
1207           if (val is string)
1208             str = "\"" + ((string) val) + "\"";
1209           else
1210             str = val.ToString ();
1211         }
1212       else
1213         str = "()";
1214       return str;
1215     }
1216   }
1217 }