*** empty log message ***
[m17n/m17n-lib-cs.git] / XmlExpr.cs
index 2b4481d..a07ab65 100644 (file)
@@ -81,28 +81,27 @@ namespace System.Xml.Expression
       public override string ToString () { return name; }
     }
 
-    private static Symbol Nexpr = "expr";
-
-    private static Symbol Nnull = "";
-    private static Symbol Nfuncall = "funcall";
-    private static Symbol Nvarref = "varref";
-    private static Symbol Ninteger = "integer";
-    private static Symbol Nstring = "string";
-    private static Symbol Nsymbol = "symbol";
-    private static Symbol Nlist = "list";
-
-    private static Symbol Ndefun = "defun";
-    private static Symbol Nfname = "fname";
-    private static Symbol Nargs = "args";
-    private static Symbol Nargs_unevalled = "args-unevalled";
-    private static Symbol Nfixed = "fixed";
-    private static Symbol Noptional = "optional";
-    private static Symbol Nrest = "rest";
-
-    private static Symbol Ndefvar = "defvar";
-    private static Symbol Nvname = "vname";
-    private static Symbol Ndescription = "description";
-    private static Symbol Nrange = "range";
+    private static Symbol Qexpr = "expr";
+
+    private static Symbol Qnull = "";
+    private static Symbol Qfuncall = "funcall";
+    private static Symbol Qinteger = "integer";
+    private static Symbol Qstring = "string";
+    private static Symbol Qsymbol = "symbol";
+    private static Symbol Qlist = "list";
+
+    private static Symbol Qdefun = "defun";
+    private static Symbol Qfname = "fname";
+    private static Symbol Qargs = "args";
+    private static Symbol Qargs_unevalled = "args-unevalled";
+    private static Symbol Qfixed = "fixed";
+    private static Symbol Qoptional = "optional";
+    private static Symbol Qrest = "rest";
+
+    private static Symbol Qdefvar = "defvar";
+    private static Symbol Qvname = "vname";
+    private static Symbol Qdescription = "description";
+    private static Symbol Qrange = "range";
 
     public abstract class Function
     {
@@ -135,16 +134,20 @@ namespace System.Xml.Expression
          : base (name, min_arg, max_arg)
          {
            this.builtin = builtin;
+           this.setvar = setvar;
          }
 
        public override Term Call (Domain domain, Variable vari, Term[] args)
        {
-         args = (Term[]) args.Clone ();
-         for (int i = 0; i < args.Length; i++)
+         if (args != null)
            {
-             args[i] = args[i].Eval (domain);
-             if (domain.Thrown)
-               return args[i];
+             args = (Term[]) args.Clone ();
+             for (int i = 0; i < args.Length; i++)
+               {
+                 args[i] = args[i].Eval (domain);
+                 if (domain.Thrown)
+                   return args[i];
+               }
            }
          return builtin (domain, vari, args);
        }
@@ -178,21 +181,21 @@ namespace System.Xml.Expression
            int nfixed = 0;
            int noptional = 0;
            int nrest = 0;
-           name = node.Attributes[Nfname].Value;
+           name = node.Attributes[Qfname].Value;
            
            node = node.FirstChild;
            if (node != null
-               && (node.Name == Nargs || node.Name == Nargs_unevalled))
+               && (node.Name == Qargs || node.Name == Qargs_unevalled))
              {
                XmlNode n;
-               args_evalled = node.Name == Nargs;
+               args_evalled = node.Name == Qargs;
                for (n = node.FirstChild; n != null; n = n.NextSibling)
                  {
-                   if (n.Name == Nfixed)
+                   if (n.Name == Qfixed)
                      nfixed++;
-                   else if (n.Name == Noptional)
+                   else if (n.Name == Qoptional)
                      noptional++;
-                   else if (n.Name == Nrest)
+                   else if (n.Name == Qrest)
                      nrest++;
                    else
                      throw new Exception ("Invalid argument type: " + n);
@@ -212,7 +215,8 @@ namespace System.Xml.Expression
              }
          }
 
-       public Lambda (Domain domain, Symbol name, bool args_evalled, Symbol[] args)
+       public Lambda (Domain domain, Symbol name,
+                      bool args_evalled, Symbol[] args)
          {
            int nfixed = 0;
            int noptional = 0;
@@ -224,14 +228,14 @@ namespace System.Xml.Expression
              {
                int i = 0;
                for (i = 0; i < args.Length; i++, nfixed++)
-                 if (args[i] == Noptional || args[i] == Nrest)
+                 if (args[i] == Qoptional || args[i] == Qrest)
                    break;
                if (i < args.Length)
                  {
-                   if (args[i] == Noptional)
+                   if (args[i] == Qoptional)
                      {
                        for (i++; i < args.Length; i++, noptional++)
-                         if (args[i] == Nrest)
+                         if (args[i] == Qrest)
                            break;
                        if (i < args.Length)
                          nrest = 1;
@@ -242,7 +246,7 @@ namespace System.Xml.Expression
                this.args = new Variable[max_arg];
                int j;
                for (i = j = 0; j < this.args.Length; i++)
-                 if (args[i] != Noptional || args[i] != Nrest)
+                 if (args[i] != Qoptional || args[i] != Qrest)
                    this.args[j++] = domain.Defvar (args[i]);
              }
            else
@@ -254,9 +258,9 @@ namespace System.Xml.Expression
        public void SetBody (Domain domain, XmlNode node)
        {
          for (node = node.FirstChild; node != null; node = node.NextSibling)
-           if (node.Name != Ndescription
-               && node.Name != Nargs
-               && node.Name != Nargs_unevalled)
+           if (node.Name != Qdescription
+               && node.Name != Qargs
+               && node.Name != Qargs_unevalled)
              break;
          int nterms = 0;
          for (XmlNode n = node; n != null; n = n.NextSibling)
@@ -314,26 +318,28 @@ namespace System.Xml.Expression
       }
     }
 
-    public class Variable : TermValue
+    public class Variable
     {
+      public Domain domain;
       public readonly Symbol name;
       public string desc;
-      internal Term default_val;
-      internal Term val;
+      protected Term default_val;
+      protected Term val;
       object range;
 
-      public Variable (Symbol name, Term value)
+      public Variable (Domain domain, Symbol name, Term val)
       {
+       this.domain = domain;
        this.name = name;
-       val = value;
+       this.val = val;
        default_val = Zero;
       }
 
       public virtual bool ValueP (Term val) { return true; }
 
-      public override TermValue Clone ()
+      public Variable Clone (Domain domain)
       {
-       Variable v = new Variable (name, val);
+       Variable v = new Variable (domain, name, val);
        v.desc = desc;
        v.default_val = default_val;
        v.range = range;
@@ -350,6 +356,19 @@ namespace System.Xml.Expression
        }
       }
 
+      public Term SetValue (int i)
+      {
+       val.intval = i;
+       val.objval = null;
+       return val;
+      }
+
+      public Term SetValue (string s)
+      {
+       val.objval = s;
+       return val;
+      }
+
       public Term DefaultValue
       {
        get { return default_val; }
@@ -366,8 +385,6 @@ namespace System.Xml.Expression
        set { range = value; }
       }
 
-      public override Term Eval (Domain domain) { return val; }
-
       public override string ToString () { return name + "(" + val + ")"; }
 
       public class Int : Variable
@@ -400,8 +417,9 @@ namespace System.Xml.Expression
            return false;
          }
 
-       public Int (Symbol name, string description, int value, int[] range)
-         : base (name, new Term (value))
+       public Int (Domain domain, Symbol name, string description,
+                   int value, int[] range)
+         : base (domain, name, new Term (value))
          {
            if (! SubsetP (value, range))
              throw new Exception ("Invalid value: " + value);
@@ -454,8 +472,9 @@ namespace System.Xml.Expression
            return false;
        }
 
-       public Str (Symbol name, string description, string value, string[] range)
-         : base (name, new Term (value))
+       public Str (Domain domain, Symbol name, string description,
+                   string value, string[] range)
+         : base (domain, name, new Term (value))
          {
            if (! SubsetP (value, range))
              throw new Exception ("Invalid value: " + value);
@@ -508,8 +527,9 @@ namespace System.Xml.Expression
            return false;
        }
 
-       public Sym (Symbol name, string description, Symbol value, Symbol[] range)
-         : base (name, new Term (value))
+       public Sym (Domain domain, Symbol name, string description,
+                   Symbol value, Symbol[] range)
+         : base (domain, name, new Term (value))
          {
            if (! SubsetP (value, range))
              throw new Exception ("Invalid value: " + value);
@@ -548,7 +568,7 @@ namespace System.Xml.Expression
       private Bindings (Variable vari)
       {
        this.vari = vari;
-       old_value = vari.val;
+       old_value = vari.Value;
       }
        
       public static Bindings Bind (Bindings bindings, Variable vari, Term val)
@@ -563,7 +583,7 @@ namespace System.Xml.Expression
       internal Bindings UnboundTo (Bindings boundary)
       {
        for (Bindings b = this; b != boundary; b = b.next)
-         b.vari.val = b.old_value;
+         b.vari.Value = b.old_value;
        return boundary;
       }
 
@@ -614,6 +634,7 @@ namespace System.Xml.Expression
 
     public class Domain
     {
+      public Symbol name;
       public object context;
       public int depth = 0;
 
@@ -627,11 +648,12 @@ namespace System.Xml.Expression
       private Stack<CatchTag> catch_stack = new Stack<CatchTag> ();
       private int catch_count = 0;
 
-      internal Domain () { }
+      internal Domain (Symbol name) { this.name = name; }
 
-      public Domain (object context) : this (basic, context) { }
+      public Domain (Symbol name, object context)
+        : this (name, basic, context) { }
 
-      public Domain (Domain parent, object context)
+      public Domain (Symbol name, Domain parent, object context) : this (name)
       {
        termtypes = new Dictionary<Symbol, TermType> (parent.termtypes);
        functions = new Dictionary<Symbol, Function> (parent.functions);
@@ -743,7 +765,7 @@ namespace System.Xml.Expression
 
       public void Defun (XmlNode node, bool prototype)
       {
-       Symbol name = node.Attributes[Nfname].Value;
+       Symbol name = node.Attributes[Qfname].Value;
        Function func;
 
        if (prototype || ! functions.TryGetValue (name, out func))
@@ -767,7 +789,7 @@ namespace System.Xml.Expression
        Variable vari;
 
        node = node.FirstChild;
-       if (node != null && node.Name == Ndescription)
+       if (node != null && node.Name == Qdescription)
          {
            desc = node.InnerText;
            node = node.NextSibling;
@@ -788,7 +810,7 @@ namespace System.Xml.Expression
                nranges = range_list.Count;
              }
 
-           if (type == Ninteger)
+           if (type == Qinteger)
              {
                int intval = parse_integer (val);
                int[] range = null;
@@ -798,7 +820,7 @@ namespace System.Xml.Expression
                    for (int i = 0; i < nranges; i++)
                      {
                        XmlNode n = range_list[i];
-                       if (n.Name == Nrange)
+                       if (n.Name == Qrange)
                          {
                            range[i * 2]
                              = parse_integer (n.FirstChild.InnerText);
@@ -818,7 +840,7 @@ namespace System.Xml.Expression
                  {
                    if (! (vari is Variable.Int))
                      throw new Exception ("Inalid value");
-                   vari = (Variable) vari.Clone ();
+                   vari = (Variable) vari.Clone (this);
                    Term v = new Term (intval);
                    vari.Value = v;
                    vari.DefaultValue = v;
@@ -826,9 +848,9 @@ namespace System.Xml.Expression
                      vari.Range = range;
                  }
                else
-                 vari = new Variable.Int (name, desc, intval, range);
+                 vari = new Variable.Int (this, name, desc, intval, range);
              }
-           else if (type == Nstring)
+           else if (type == Qstring)
              {
                string[] range = null;
                if (range_list != null)
@@ -842,7 +864,7 @@ namespace System.Xml.Expression
                  {
                    if (! (vari is Variable.Str))
                      throw new Exception ("Invalid value");
-                   vari = (Variable) vari.Clone ();
+                   vari = (Variable) vari.Clone (this);
                    Term v = new Term (val);
                    vari.Value = v;
                    vari.DefaultValue = v;
@@ -850,9 +872,9 @@ namespace System.Xml.Expression
                      vari.Range = range;
                  }
                else
-                 vari = new Variable.Str (name, desc, val, range);
+                 vari = new Variable.Str (this, name, desc, val, range);
              }
-           else if (type == Nsymbol)
+           else if (type == Qsymbol)
              {
                Symbol[] range = null;
                if (range_list != null)
@@ -866,7 +888,7 @@ namespace System.Xml.Expression
                  {
                    if (! (vari is Variable.Sym))
                      throw new Exception ("Invalid value");
-                   vari = (Variable) vari.Clone ();
+                   vari = (Variable) vari.Clone (this);
                    Term v = new Term (val);
                    vari.Value = v;
                    vari.DefaultValue = v;
@@ -874,7 +896,7 @@ namespace System.Xml.Expression
                      vari.Range = range;
                  }
                else
-                 vari = new Variable.Sym (name, desc, val, range);
+                 vari = new Variable.Sym (this, name, desc, val, range);
              }
            else
              throw new Exception ("Unknown type: " + type);
@@ -882,9 +904,9 @@ namespace System.Xml.Expression
        else
          {
            if (variables.TryGetValue (name, out vari))
-             vari = (Variable) vari.Clone ();
+             vari = (Variable) vari.Clone (this);
            else
-             vari = new Variable (name, Zero);
+             vari = new Variable (this, name, Zero);
          }
        variables[name] = vari;
        return vari;
@@ -892,13 +914,14 @@ namespace System.Xml.Expression
 
       public Variable Defvar (Variable vari)
       {
+       vari = vari.Clone (this);
        variables[vari.name] = vari;
        return vari;
       }
 
       internal Variable Defvar (Symbol name)
       {
-       Variable vari = new Variable (name, Zero);
+       Variable vari = new Variable (this, name, Zero);
        variables[name] = vari;
        return vari;
       }
@@ -934,7 +957,7 @@ namespace System.Xml.Expression
          {
            if (! create)
              return null;
-           variables[name] = vari = new Variable (name, Zero);
+           variables[name] = vari = new Variable (this, name, Zero);
          }
        return vari;
       }
@@ -946,7 +969,7 @@ namespace System.Xml.Expression
          str += " " + kv.Key;
        str += ") (variabls";
        foreach (KeyValuePair<Symbol, Variable> kv in variables)
-         str += " " + kv.Key;
+         str += " " + kv.Value;
        str += ")";
        if (bindings != null)
          str += " " + bindings;
@@ -975,7 +998,7 @@ namespace System.Xml.Expression
        Dictionary<Variable,Term> values = new Dictionary<Variable,Term> ();
 
        foreach (KeyValuePair<Symbol,Variable> kv in variables)
-         values[kv.Value] = kv.Value.val.Clone ();
+         values[kv.Value] = kv.Value.Value.Clone ();
        return values;
       }
 
@@ -983,17 +1006,18 @@ namespace System.Xml.Expression
       {
        foreach (KeyValuePair<Variable,Term> kv
                 in (Dictionary<Variable,Term>) values)
-         kv.Key.val = kv.Value;
+         kv.Key.Value = kv.Value;
       }
     }
 
     public delegate Term Builtin (Domain domain, Variable vari, Term[] args);
 
-    private static Domain basic = new Domain ();
+    private static Domain basic = new Domain ("basic");
 
     static Xexpression ()
     {
       basic.DefTerm ("funcall", Funcall.parser);
+      basic.DefTerm ("varref", Varref.parser);
 
       basic.DefSubr (Fset, "set", true, 1, 1, "=");
       basic.DefSubr (Fnot, "not", false, 1, 1, "!");
@@ -1040,7 +1064,7 @@ namespace System.Xml.Expression
     private static Term Fset (Domain domain, Variable vari, Term[] args)
     {
       vari.Value = args[0];
-      return vari.val;
+      return args[0];
     }
 
     private static Term Fnot (Domain domain, Variable vari, Term[] args)
@@ -1050,25 +1074,19 @@ namespace System.Xml.Expression
 
     private static Term Fadd (Domain domain, Variable vari, Term[] args)
     {
-      int n = vari == null ? 0 : vari.val.Intval;
+      int n = vari == null ? 0 : vari.Value.Intval;
 
       foreach (Term arg in args)
        n += arg.Intval;
-      if (vari == null)
-       return new Term (n);
-      vari.val.intval = n;
-      return vari.val;
+      return (vari == null ? new Term (n) : vari.SetValue (n));
     }
 
     private static Term Fmul (Domain domain, Variable vari, Term[] args)
     {
-      int n = vari == null ? 1 : vari.val.Intval;
+      int n = vari == null ? 1 : vari.Value.Intval;
       foreach (Term arg in args)
        n *= arg.Intval;
-      if (vari == null)
-       return new Term (n);
-      vari.val.intval = n;
-      return vari.val;
+      return (vari == null ? new Term (n) : vari.SetValue (n));
     }
 
     private static Term Fsub (Domain domain, Variable vari, Term[] args)
@@ -1082,15 +1100,12 @@ namespace System.Xml.Expression
        }
       else
        {
-         n = vari.val.Intval;
+         n = vari.Value.Intval;
          i = 0;
        }
       while (i < args.Length)
        n -= args[i++].Intval;
-      if (vari == null)
-       return new Term (n);
-      vari.val.intval = n;
-      return vari.val;
+      return (vari == null ? new Term (n) : vari.SetValue (n));
     }
 
     private static Term Fdiv (Domain domain, Variable vari, Term[] args)
@@ -1104,34 +1119,27 @@ namespace System.Xml.Expression
        }
       else
        {
-         n = vari.val.Intval;
+         n = vari.Value.Intval;
          i = 0;
        }
       while (i < args.Length)
        n /= args[i++].Intval;
-      if (vari == null)
-       return new Term (n);
-      vari.val.intval = n;
-      return vari.val;
+      return (vari == null ? new Term (n) : vari.SetValue (n));
     }
 
     private static Term Fmod (Domain domain, Variable vari, Term[] args)
     {
-      if (vari == null)
-       return new Term (args[0].Intval % args[1].Intval);
-      vari.val.intval = vari.val.Intval % args[0].Intval;
-      return vari.val;
+      int n = args[0].Intval % args[1].Intval;
+
+      return (vari == null ? new Term (n) : vari.SetValue (n));
     }
 
     private static Term Flogior (Domain domain, Variable vari, Term[] args)
     {
-      int n = vari == null ? 0 : vari.val.Intval;
+      int n = vari == null ? 0 : vari.Value.Intval;
       foreach (Term arg in args)
        n |= arg.Intval;
-      if (vari == null)
-       return new Term (n);
-      vari.val.intval = n;
-      return vari.val;
+      return (vari == null ? new Term (n) : vari.SetValue (n));
     }
 
     private static Term Flogand (Domain domain, Variable vari, Term[] args)
@@ -1145,31 +1153,24 @@ namespace System.Xml.Expression
        }
       else
        {
-         n = vari.val.Intval;
+         n = vari.Value.Intval;
          i = 0;
        }
       while (i < args.Length)
        n &= args[i++].Intval;
-      if (vari == null)
-       return new Term (n);
-      vari.val.intval = n;
-      return vari.val;
+      return (vari == null ? new Term (n) : vari.SetValue (n));
     }
 
     private static Term Flsh (Domain domain, Variable vari, Term[] args)
     {
-      if (vari == null)
-       return new Term (args[0].Intval << args[1].Intval);
-      vari.val.intval = vari.val.Intval << args[0].Intval;
-      return vari.val;
+      int n = args[0].Intval << args[1].Intval;
+      return (vari == null ? new Term (n) : vari.SetValue (n));
     }
 
     private static Term Frsh (Domain domain, Variable vari, Term[] args)
     {
-      if (vari == null)
-       return new Term (args[0].Intval >> args[1].Intval);
-      vari.val.intval = vari.val.Intval >> args[0].Intval;
-      return vari.val;
+      int n = args[0].Intval >> args[1].Intval;
+      return (vari == null ? new Term (n) : vari.SetValue (n));
     }
 
     private static Term Feq (Domain domain, Variable vari, Term[] args)
@@ -1256,7 +1257,7 @@ namespace System.Xml.Expression
       if (vari == null)
        list = new List<Term> ();
       else
-       list = vari.val.Listval;
+       list = vari.Value.Listval;
 
       foreach (Term arg in args)
        {
@@ -1272,7 +1273,7 @@ namespace System.Xml.Expression
          result.objval = list;
          return result;
        }
-      return vari.val;
+      return vari.Value;
     }
 
     private static Term Fconcat (Domain domain, Variable vari, Term[] args)
@@ -1282,7 +1283,7 @@ namespace System.Xml.Expression
       if (vari == null)
        str = "";
       else
-       str = vari.val.Strval;
+       str = vari.Value.Strval;
 
       foreach (Term arg in args)
        {
@@ -1294,15 +1295,15 @@ namespace System.Xml.Expression
          else
            str += (char) arg.Intval;
        }
+
       if (vari == null)
        {
-         Term result;
-         result.intval = 0;
-         result.objval = str;
-         return result;
+         Term term;
+         term.intval = 0;
+         term.objval = str;
+         return term;
        }
-      vari.val.objval = str;
-      return vari.val;
+      return vari.SetValue (str);
     }
 
     private static Term Fnth (Domain domain, Variable vari, Term[] args)
@@ -1334,29 +1335,35 @@ namespace System.Xml.Expression
 
     private static Term Fins (Domain domain, Variable vari, Term[] args)
     {
-      if (vari.val.IsStr)
-       vari.val.objval
-         = vari.val.Strval.Insert (args[0].Intval, args[1].Strval);
-      else if (vari.val.IsList)
-       vari.val.Listval.InsertRange (args[0].Intval, args[1].Listval);
+      Term term = vari.Value;
+
+      if (term.IsStr)
+       {
+         string str = term.Strval.Insert (args[0].Intval, args[1].Strval);
+         vari.SetValue (str);
+       }
+      else if (vari.Value.IsList)
+       vari.Value.Listval.InsertRange (args[0].Intval, args[1].Listval);
       else
-       throw new Exception ("term is not collection: " + vari.val);
-      return vari.val;
+       throw new Exception ("term is not collection: " + vari.Value);
+      return vari.Value;
     }
 
     private static Term Fdel (Domain domain, Variable vari, Term[] args)
     {
-      if (vari.val.IsStr)
-       vari.val.objval
-         = vari.val.Strval.Remove (args[0].Intval,
-                                   args[1].Intval - args[0].Intval);
-
-      else if (vari.val.IsList)
-       vari.val.Listval.RemoveRange (args[0].Intval,
+      if (vari.Value.IsStr)
+       {
+         string str
+           = vari.Value.Strval.Remove (args[0].Intval,
+                                       args[1].Intval - args[0].Intval);
+         vari.SetValue (str);
+       }
+      else if (vari.Value.IsList)
+       vari.Value.Listval.RemoveRange (args[0].Intval,
                                      args[1].Intval - args[0].Intval);
       else
-       throw new Exception ("term is not collection: " + vari.val);
-      return vari.val;
+       throw new Exception ("term is not collection: " + vari.Value);
+      return vari.Value;
     }
 
     private static Term Fand (Domain domain, Variable vari, Term[] args)
@@ -1557,7 +1564,32 @@ namespace System.Xml.Expression
     public abstract class TermValue
     {
       public virtual Term Eval (Domain domain) { return new Term (this); }
-      public abstract TermValue Clone ();
+      public virtual TermValue Clone () { return this; }
+    }
+
+    private class Varref : TermValue
+    {
+      private Symbol name;
+      private Variable vari;
+
+      public Varref (Symbol name) { this.name = name; }
+
+      public override Term Eval (Domain domain)
+      {
+       if (vari == null || vari.domain != domain)
+         vari = domain.GetVar (name, true);
+       return vari.Value;
+      }
+
+      internal static TermValue parser (Domain domain, XmlNode node)
+      {
+       return new Varref ((Symbol) node.Attributes[Qvname].Value);
+      }
+
+      public override string ToString ()
+      {
+       return "<varref vname=\"" + name + "\"/>";
+      }
     }
 
     private class Funcall : TermValue
@@ -1576,31 +1608,42 @@ namespace System.Xml.Expression
       public Funcall (Domain domain, Symbol fname, Term[] args)
        {
          func = domain.GetFunc (fname);
+         if (args != null)
+           {
+             int nargs = args.Length;
+             if (nargs < func.min_arg
+                 || (func.max_arg >= 0 && nargs > func.max_arg))
+               throw new Exception ("Invalid number of arguments to: "
+                                    + fname + " " + nargs);
+           }
          this.args = args;
        }
 
       public Funcall (Domain domain, Symbol fname, Symbol vname, Term[] args)
        {
          func = domain.GetFunc (fname);
-         int nargs = args.Length;
-         if (nargs < func.min_arg
-             || (func.max_arg >= 0 && nargs > func.max_arg))
-           throw new Exception ("Invalid number of arguments to: "
-                                + fname + " " + nargs);
+         if (args != null)
+           {
+             int nargs = args.Length;
+             if (nargs < func.min_arg
+                 || (func.max_arg >= 0 && nargs > func.max_arg))
+               throw new Exception ("Invalid number of arguments to: "
+                                    + fname + " " + nargs);
+           }
          this.args = args;
-         if (vname != Nnull)
+         if (vname != Qnull)
            vari = domain.GetVar (vname, true);
        }
 
       internal static TermValue parser (Domain domain, XmlNode node)
        {
          Symbol fname = node.Name;
-         Symbol vname = Nnull;
+         Symbol vname = Qnull;
          XmlAttribute attr;
 
-         if (fname == Nfuncall)
-           fname = node.Attributes[Nfname].Value;
-         attr = node.Attributes[Nvname];
+         if (fname == Qfuncall)
+           fname = node.Attributes[Qfname].Value;
+         attr = node.Attributes[Qvname];
          if (attr != null)
            vname = attr.Value;
 
@@ -1614,14 +1657,11 @@ namespace System.Xml.Expression
 
       public override Term Eval (Domain domain)
       {
-       domain.DebugWrite (true, "(({0}", func.name);
-       for (int i = 0; i < args.Length; i++)
-         domain.DebugWrite (false, " {0}", args[i].ToString ());
-       domain.DebugWrite (false, ")");
+       domain.DebugWrite (true, ToString ());
        domain.depth++;
        Term result = func.Call (domain, vari, args);
        domain.depth--;
-       domain.DebugWrite (true, " ==> {0})", result.ToString ());
+       domain.DebugWrite (true, " ==> {0}", result.ToString ());
        return result;
       }
 
@@ -1632,13 +1672,18 @@ namespace System.Xml.Expression
 
       public override string ToString ()
       {
-       string str = "<funcall fname=\"" + func.name;
+       string str = "<" + func.name;
+       if (vari != null)
+         str += " vname=\"" + vari.name + "\"";
        if (args == null)
-         return str + "\"/>";
-       str += "\">";
-       foreach (Term e in args)
-         str += e;
-       return (str + "</funcall>");
+         return str + "/>";
+       str += ">";
+       if (func is Function.SpecialForm)
+         str += String.Format ("({0})...", args.Length);
+       else
+         foreach (Term e in args)
+           str += e;
+       return (str + "</" + func.name + ">");
       }
     }
 
@@ -1647,10 +1692,15 @@ namespace System.Xml.Expression
       public int intval;
       public object objval;
 
+      // <integer>...</integer>
       public Term (int i) { intval = i; objval = null; }
+      // <symbol>...</symbol>
       public Term (Symbol name) { intval = 0; objval = name; }
+      // <string>...</string>
       public Term (string str) { intval = 0; objval = str; }
+      // <list>...</list>
       public Term (List<Term> list) { intval = 0; objval = list; }
+
       public Term (Term term) { intval = term.intval; objval = term.objval; }
       public Term (TermValue obj) { intval = 0; objval = obj; }
 
@@ -1658,7 +1708,7 @@ namespace System.Xml.Expression
        {
          Symbol name = node.Name;
 
-         if (name == Ninteger)
+         if (name == Qinteger)
            {
              intval = parse_integer (node.InnerText);
              objval = null;
@@ -1666,13 +1716,11 @@ namespace System.Xml.Expression
          else
            {
              intval = 0;
-             if (name == Nsymbol)
+             if (name == Qsymbol)
                objval = (Symbol) node.InnerText;
-             else if (name == Nstring)
+             else if (name == Qstring)
                objval = node.InnerText.Clone ();
-             else if (name == Nvarref)
-               objval = domain.GetVar ((Symbol) node.Attributes[0].Value, true);
-             else if (name == Nlist)
+             else if (name == Qlist)
                {
                  List<Term> list = new List<Term> ();
                  for (node = node.FirstChild; node != null;
@@ -1692,12 +1740,21 @@ namespace System.Xml.Expression
            }
        }
 
+      // <varref vname="VNAME"/>
+      public Term (Domain domain, Symbol vname)
+       {
+         intval = 0;
+         objval = new Varref (vname);
+       }
+
+      // <funcall fname="FNAME">...</funcall>
       public Term (Domain domain, Symbol fname, Term[] args)
        {
          intval = 0;
          objval = new Funcall (domain, fname, args);
        }
 
+      // <funcall fname="FNAME" vname="VNAME">...</funcall>
       public Term (Domain domain, Symbol fname, Symbol vname, Term[] args)
        {
          intval = 0;
@@ -1803,12 +1860,10 @@ namespace System.Xml.Expression
              str += e;
            str += "</list>";
          }
-       else if (objval is Funcall)
-         str = "<funcall fname=\"" + ((Funcall) objval).func.name + "\"/>";
-       else if (objval is Variable)
-         str = "<variable vname=\"" + ((Variable) objval).name + "\"/>";
        else if (objval is Term)
          str = "<quote>" + objval + "</quote>";
+       else if (objval is TermValue)
+         str = ((TermValue) objval).ToString ();
        else
          throw new Exception ("invalid Term object: " + objval);
        return str;
@@ -1817,10 +1872,10 @@ namespace System.Xml.Expression
 
     static private Term Zero = new Term (0);
     static private Term One = new Term (1);
-    static private Term TermInt = new Term (Ninteger);
-    static private Term TermStr = new Term (Nstring);
-    static private Term TermSymbol = new Term (Nsymbol);
-    static private Term TermList = new Term (Nlist);
+    static private Term TermInt = new Term (Qinteger);
+    static private Term TermStr = new Term (Qstring);
+    static private Term TermSymbol = new Term (Qsymbol);
+    static private Term TermList = new Term (Qlist);
     static private Term TermTerm = new Term ((Symbol) "term");
 
     internal static int parse_integer (string str)
@@ -1874,35 +1929,48 @@ namespace System.Xml.Expression
 
     private Term[] terms;
 
-    private void parse_terms (Domain domain, XmlNode node)
+    public static Term[] ParseTerms (Domain domain, XmlNode node)
     {
       int nterms = 0;
       for (XmlNode n = node; n != null; n = n.NextSibling)
        if (n.NodeType == XmlNodeType.Element)
          {
-           if (n.Name == Ndefun)
+           if (n.Name == Qdefun)
              domain.Defun (n, true);
-           else if (n.Name == Ndefvar)
+           else if (n.Name == Qdefvar)
              domain.Defvar (n);
            else
              nterms++;
          }
-
-      terms = new Term[nterms];
+      Term[] terms = new Term[nterms];
       int i = 0;
       for (XmlNode n = node; n != null; n = n.NextSibling)
        if (n.NodeType == XmlNodeType.Element)
          {
-           if (n.Name == Ndefun)
+           if (n.Name == Qdefun)
              domain.Defun (n, false);
-           else if (n.Name != Ndefvar)
+           else if (n.Name != Qdefvar)
              terms[i++]= new Term (domain, n);
          }
+      return terms;
+    }
+
+    public static Term Eval (Domain domain, Term[] terms)
+    {
+      Term result = new Term (0);
+      foreach (Term term in terms)
+       {
+         result = term;
+         if (result.Objval is Funcall)
+           while ((result = result.Eval (domain)).Objval is Funcall);
+       }
+      return result;
     }
 
+
     public Xexpression (Domain domain, XmlNode node)
     {
-      parse_terms (domain, node);
+      terms = ParseTerms (domain, node);
     }
 
     public Xexpression (Domain domain, string url)
@@ -1916,12 +1984,12 @@ namespace System.Xml.Expression
            reader.Read ();
          } while (reader.NodeType != XmlNodeType.None
                   && (reader.NodeType != XmlNodeType.Element
-                      || reader.Name != Nexpr));
+                      || reader.Name != Qexpr));
          if (reader.NodeType == XmlNodeType.None)
            throw new Exception ("Node <expr> not found");
          node = doc.ReadNode (reader);
        }
-      parse_terms (domain, node.FirstChild);
+      terms = ParseTerms (domain, node.FirstChild);
     }
 
     public Term Eval (Domain domain)