X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=XmlExpr.cs;h=53c764182e5d58486a937efc58929d09175e92fb;hb=30c120fd525ae9e62a5ff580f23f3c5594379f45;hp=2e143a21293a4b8bf0430f10333150c66a791a8c;hpb=0f44ed40ba80ef72d6a8a835f4b980d6e3db4e50;p=m17n%2Fm17n-lib-cs.git diff --git a/XmlExpr.cs b/XmlExpr.cs index 2e143a2..53c7641 100644 --- a/XmlExpr.cs +++ b/XmlExpr.cs @@ -2,34 +2,34 @@ using System; using System.Collections; using System.Collections.Generic; using System.IO; +using System.Reflection; using System.Xml; -namespace System.Xml.Expression +namespace System.Xml { public class Xexpression { - public static int debug_level = 0; + private static int trace_depth = 0; + + public static int TraceDepth { + get { return trace_depth; } + set { trace_depth = value; } + } public struct Symbol : IEquatable { private static NameTable nt = new NameTable (); - internal string name; + private string name; - public Symbol (string str) - { - name = nt.Add (str); - } + public Symbol (string str) { name = nt.Add (str); } public static implicit operator Symbol (string str) { return new Symbol (str); } - public static implicit operator string (Symbol name) - { - return name.name; - } + public static implicit operator string (Symbol sym) { return sym.name; } public static bool operator== (Symbol n1, Symbol n2) { @@ -68,7 +68,9 @@ namespace System.Xml.Expression public override bool Equals (object obj) { - return Object.ReferenceEquals (this.name, obj); + return (obj is Symbol ? this == (Symbol) obj + : obj is string ? this.name == (string) obj + : false); } public override int GetHashCode () @@ -76,7 +78,7 @@ namespace System.Xml.Expression return name.GetHashCode (); } - public static NameTable Table { get { return nt; } } + public static NameTable NameTable { get { return nt; } } public override string ToString () { return name; } } @@ -85,37 +87,60 @@ namespace System.Xml.Expression private static Symbol Qnull = ""; private static Symbol Qfuncall = "funcall"; - private static Symbol Qvarref = "varref"; 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"; + public static Symbol Qdefun = "defun"; + public static Symbol Qdefmacro = "defmacro"; 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"; + public static Symbol Qdefvar = "defvar"; private static Symbol Qvname = "vname"; private static Symbol Qdescription = "description"; private static Symbol Qrange = "range"; + private static Symbol Qename = "ename"; + + public static partial class Error + { + // Load time errors. + public static Symbol UnknownFunction = "unknown function"; + public static Symbol InvalidArgumentNumber = "invalid argument number"; + public static Symbol VariableNotAcceptable = "variable not acceptable"; + } + + public static partial class Error + { + // Run time errors. + public static Symbol ArithmeticError = "arithmetic error"; + public static Symbol InvalidArgumentType = "invalid argument type"; + public static Symbol NoVariable = "no-variable"; + public static Symbol InvalidVariableType = "invalid variable type"; + public static Symbol NoOuterLoop = "no outer loop"; + public static Symbol UnknownError = "unknown error"; + } + + public abstract class Function { public Symbol name; public int min_arg, max_arg; + public bool setvar; public Function () { } - public Function (Symbol name, int min_arg, int max_arg) + public Function (Symbol name, int min_arg, int max_arg, bool setvar) { this.name = name; this.min_arg = min_arg; this.max_arg = max_arg; + this.setvar = setvar; } public abstract Term Call (Domain domain, Variable vari, Term[] args); @@ -128,25 +153,23 @@ namespace System.Xml.Expression internal class Subroutine : Function { public Builtin builtin; - public bool setvar; public Subroutine (Builtin builtin, Symbol name, bool setvar, int min_arg, int max_arg) - : base (name, min_arg, max_arg) + : base (name, min_arg, max_arg, setvar) { this.builtin = builtin; - this.setvar = setvar; } public override Term Call (Domain domain, Variable vari, Term[] args) { - if (args != null) + if (args.Length > 0) { args = (Term[]) args.Clone (); for (int i = 0; i < args.Length; i++) { args[i] = args[i].Eval (domain); - if (domain.Thrown) + if (domain.Thrown ()) return args[i]; } } @@ -158,9 +181,9 @@ namespace System.Xml.Expression { public Builtin builtin; - public SpecialForm (Builtin builtin, Symbol name, + public SpecialForm (Builtin builtin, Symbol name, bool setvar, int min_arg, int max_arg) - : base (name, min_arg, max_arg) + : base (name, min_arg, max_arg, setvar) { this.builtin = builtin; } @@ -171,61 +194,140 @@ namespace System.Xml.Expression } } + private static void parse_head (Domain domain, XmlNode node, + out Symbol name, + out int min_arg, out int max_arg, + out Variable[] args) + { + int nfixed = 0; + int noptional = 0; + int nrest = 0; + name = node.Attributes[Qfname].Value; + + node = node.FirstChild; + if (node != null && node.Name == Qargs) + { + XmlNode n; + for (n = node.FirstChild; n != null; n = n.NextSibling) + { + if (n.Name == Qfixed) + nfixed += n.ChildNodes.Count; + else if (n.Name == Qoptional) + noptional += n.ChildNodes.Count; + else if (n.Name == Qrest) + nrest++; + else + throw new Exception ("Invalid argument type: " + n); + } + min_arg = nfixed; + max_arg = nfixed + noptional + nrest; + args = new Variable[max_arg]; + n = node.FirstChild; + for (int i = 0; i < max_arg; n = n.NextSibling) + { + for (XmlNode nn = n.FirstChild; nn != null; nn = nn.NextSibling) + args[i++] = domain.Defvar ((Symbol) nn.Attributes[0].Value); + } + if (nrest == 1) + max_arg = - max_arg; + } + else + { + min_arg = max_arg = 0; + args = new Variable[0]; + } + } + + private static void parse_body (Domain domain, XmlNode node, + out Term[] body) + { + for (node = node.FirstChild; node != null; node = node.NextSibling) + if (node.Name != Qdescription + && node.Name != Qargs) + break; + int nterms = 0; + for (XmlNode n = node; n != null; n = n.NextSibling) + nterms++; + if (nterms > 0) + { + body = new Term[nterms]; + for (nterms = 0; node != null; node = node.NextSibling, nterms++) + body[nterms] = new Term (domain, node); + } + else + body = null; + } + + internal class Macro : Function + { + internal Variable[] args; + internal Term[] body; + + public Macro (Domain domain, XmlNode node) + { + parse_head (domain, node, out name, out min_arg, out max_arg, + out args); + setvar = false; + } + + public void SetBody (Domain domain, XmlNode node) + { + parse_body (domain, node, out body); + } + + public override Term Call (Domain domain, Variable vari, Term[] args) + { + Bindings current = domain.bindings; + Term result = Zero; + int rest_idx = max_idx < 0 ? - max_idx : args.Length; + + for (int i = 0; i < rest_idx; i++) + domain.Bind (this.args[i], args[i]); + if (i < args.Length) + { + List rest = new List (); + + for (; i < args.Length; i++) + rest.Add (args[i]); + domain.Bind (this.args[rest_idx], rest); + } + + if (body != null) + { + domain.Catch (CatchTag.Return); + foreach (Term term in body) + { + result = term.Eval (domain); + if (domain.Thrown ()) + break; + } + domain.Uncatch (); + } + domain.UnboundTo (current); + return result; + } + } + internal class Lambda : Function { - internal bool args_evalled; internal Variable[] args; internal Term[] body; public Lambda (Domain domain, XmlNode node) { - int nfixed = 0; - int noptional = 0; - int nrest = 0; - name = node.Attributes[Qfname].Value; - - node = node.FirstChild; - if (node != null - && (node.Name == Qargs || node.Name == Qargs_unevalled)) - { - XmlNode n; - args_evalled = node.Name == Qargs; - for (n = node.FirstChild; n != null; n = n.NextSibling) - { - if (n.Name == Qfixed) - nfixed++; - else if (n.Name == Qoptional) - noptional++; - else if (n.Name == Qrest) - nrest++; - else - throw new Exception ("Invalid argument type: " + n); - } - min_arg = nfixed; - max_arg = nfixed + noptional + nrest; - args = new Variable[max_arg]; - n = node.FirstChild; - for (int i = 0; i < max_arg; n = n.NextSibling) - args[i++] = domain.Defvar ((Symbol) n.Attributes[0].Value); - if (nrest == 1) - max_arg = - max_arg; - } - else - { - min_arg = max_arg = 0; - } + parse_head (domain, node, out name, out min_arg, out max_arg, + out args); + setvar = false; } - public Lambda (Domain domain, Symbol name, - bool args_evalled, Symbol[] args) + public Lambda (Domain domain, Symbol name, Symbol[] args) { int nfixed = 0; int noptional = 0; int nrest = 0; this.name = name; - this.args_evalled = args_evalled; - if (args != null) + if (args.Length > 0) { int i = 0; for (i = 0; i < args.Length; i++, nfixed++) @@ -254,24 +356,12 @@ namespace System.Xml.Expression { min_arg = max_arg = 0; } + setvar = false; } public void SetBody (Domain domain, XmlNode node) { - for (node = node.FirstChild; node != null; node = node.NextSibling) - if (node.Name != Qdescription - && node.Name != Qargs - && node.Name != Qargs_unevalled) - break; - int nterms = 0; - for (XmlNode n = node; n != null; n = n.NextSibling) - nterms++; - if (nterms > 0) - { - body = new Term[nterms]; - for (nterms = 0; node != null; node = node.NextSibling, nterms++) - body[nterms] = new Term (domain, node); - } + parse_body (domain, node, out body); } public void SetBody (Term[] body) @@ -286,7 +376,7 @@ namespace System.Xml.Expression try { int i; - if (args_evalled) + if (args.Length > 0) { Term[] newargs = new Term[args.Length]; for (i = 0; i < min_arg; i++) @@ -298,17 +388,15 @@ namespace System.Xml.Expression if (body != null) { try { - if (args_evalled) - domain.Catch (CatchTag.Return); + domain.Catch (CatchTag.Return); foreach (Term term in body) { result = term.Eval (domain); - if (domain.Thrown) + if (domain.Thrown ()) return result; } } finally { - if (args_evalled) - domain.Uncatch (); + domain.Uncatch (); } } } finally { @@ -319,32 +407,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; - object range; + protected Term val; - public Variable (Symbol name, Term value) + public Variable (Domain domain, Symbol name, Term val) { + this.domain = domain; this.name = name; - val = value; - default_val = Zero; + this.val = val; } public virtual bool ValueP (Term val) { return true; } - public override TermValue Clone () + public virtual Variable Clone (Domain domain) { - Variable v = new Variable (name, val); - v.desc = desc; - v.default_val = default_val; - v.range = range; - return v; + return new Variable (domain, name, val); } + public virtual void Reset () { val = Zero; } + public Term Value { get { return val; } @@ -355,192 +439,190 @@ namespace System.Xml.Expression } } - public Term DefaultValue + public Term SetValue (int i) { - get { return default_val; } - set { - if (! ValueP (value)) - throw new Exception ("Invalid value: " + value); - default_val = value; - } + val.intval = i; + val.objval = null; + return val; } - public virtual object Range + public Term SetValue (string s) { - get { return range; } - set { range = value; } + val.objval = s; + return val; } - public override Term Eval (Domain domain) { return val; } - public override string ToString () { return name + "(" + val + ")"; } - public class Int : Variable + public abstract class Typed : Variable + { + protected string desc; + private Term default_val; + + protected Typed (Domain domain, Symbol name, Term val, string desc) + : base (domain, name, val) + { + this.desc = desc; + default_val = val; + } + + public override void Reset () { val = default_val; } + + public string Description { + get { return desc; } + set { desc = value; } + } + } + + public class Int : Typed { - public int[] range; + private int[] range; - private static bool SubsetP (int[] r1, int[] r2) + public bool IsSubrange (int[] r) { - if (r2 == null) + if (range == null) return true; - for (int i = 0; i < r1.Length; i += 2) + for (int i = 0; i < r.Length; i += 2) { int j; - for (j = 0; j < r2.Length; j += 2) - if (r2[j] <= r1[i] && r2[j + 1] >= r1[i + 1]) + for (j = 0; j < range.Length; j += 2) + if (range[j] <= r[i] && range[j + 1] >= r[i + 1]) break; - if (j >= r2.Length) + if (j >= range.Length) return false; } return true; } - private static bool SubsetP (int val, int[] r) + public Int (Domain domain, Symbol name, int n, string desc, int[] range) + : base (domain, name, new Term (n), desc) { - if (r == null) - return true; - for (int i = 0; i < r.Length; i += 2) - if (r[i] <= val && r[i + 1] >= val) - return true; - return false; - } - - public Int (Symbol name, string description, int value, int[] range) - : base (name, new Term (value)) - { - if (! SubsetP (value, range)) - throw new Exception ("Invalid value: " + value); - desc = description; - default_val = val; + if (range != null && range.Length % 2 == 1) + throw_exception ("Range length for {0} not even", name); this.range = range; + if (! ValueP (val)) + throw_exception ("Invalid integer value for {0}: {1}", name, val); } public override bool ValueP (Term term) { if (! term.IsInt) return false; - return SubsetP (term.Intval, range); + if (range == null) + return true; + int n = term.Intval; + for (int i = 0; i < range.Length; i += 2) + if (range[i] <= n && range[i + 1] >= n) + return true; + return false; } - public override object Range { - get { return range; } - set { - int[] r = (int[]) value; - if (! SubsetP (r, range) - || ! SubsetP (val.Intval, r) - || ! SubsetP (default_val.Intval, r)) - throw new Exception ("Invalid range"); - range = r; - } + public override Variable Clone (Domain domain) + { + return new Int (domain, name, val.Intval, desc, range); } + + public int[] Range { get { return range; } set { range = value; } } } - public class Str : Variable + public class Str : Typed { - public string[] range; + private string[] range; - private static bool SubsetP (string[] r1, string[] r2) + public bool IsSubrange (string[] r) { - if (r2 == null) + if (range == null) return true; - foreach (string s in r1) - if (! SubsetP (s, r2)) - return false; + for (int i = 0; i < r.Length; i++) + { + int j; + for (j = 0; j < range.Length; j++) + if (range[j] == r[i]) + break; + if (j >= range.Length) + return false; + } return true; } - private static bool SubsetP (string str, string[] r) + public Str (Domain domain, Symbol name, string str, string desc, + string[] range) + : base (domain, name, new Term (str), desc) { - if (r == null) - return true; - foreach (string s in r) - if (str == s) - return true; - return false; - } - - public Str (Symbol name, string description, string value, string[] range) - : base (name, new Term (value)) - { - if (! SubsetP (value, range)) - throw new Exception ("Invalid value: " + value); - desc = description; - default_val = val; this.range = range; + if (! ValueP (val)) + throw_exception ("Invalid string value for {0}: {1}", name, val); } public override bool ValueP (Term term) { - if (! (term.objval is string)) + if (! term.IsStr) return false; - return SubsetP (term.Strval, range); + if (range == null) + return true; + string str = term.Strval; + foreach (string s in range) + if (str == s) + return true; + return false; } - public override object Range { - get { return range; } - set { - string[] r = (string[]) value; - if (! SubsetP (r, range) - || ! SubsetP (val.Strval, r) - || ! SubsetP (default_val.Strval, r)) - throw new Exception ("Invalid range"); - range = r; - } + public override Variable Clone (Domain domain) + { + return new Str (domain, name, val.Strval, desc, range); } + + public string[] Range { get { return range; } set { range = value; } } } - public class Sym : Variable + public class Sym : Typed { public Symbol[] range; - private static bool SubsetP (Symbol[] r1, Symbol[] r2) + public bool IsSubrange (Symbol[] r) { - if (r2 == null) + if (range == null) return true; - foreach (Symbol n in r1) - if (! SubsetP (n, r2)) - return false; + for (int i = 0; i < r.Length; i++) + { + int j; + for (j = 0; j < range.Length; j++) + if (range[j] == r[i]) + break; + if (j >= range.Length) + return false; + } return true; } - private static bool SubsetP (Symbol name, Symbol[] r) + public Sym (Domain domain, Symbol name, Symbol sym, string desc, + Symbol[] range) + : base (domain, name, new Term (sym), desc) { - if (r == null) - return true; - foreach (Symbol n in r) - if (name == n) - return true; - return false; - } - - public Sym (Symbol name, string description, Symbol value, Symbol[] range) - : base (name, new Term (value)) - { - if (! SubsetP (value, range)) - throw new Exception ("Invalid value: " + value); - desc = description; - default_val = val; this.range = range; + if (! ValueP (val)) + throw_exception ("Invalid symbol value for {0}: {1}", name, val); } public override bool ValueP (Term term) { - if (! (term.objval is Symbol)) + if (! term.IsSymbol) return false; - return SubsetP (term.Symval, range); + if (range == null) + return true; + Symbol name = term.Symval; + foreach (Symbol n in range) + if (name == n) + return true; + return false; } - public override object Range { - get { return range; } - set { - Symbol[] r = (Symbol[]) value; - if (! SubsetP (r, range) - || ! SubsetP (val.Symval, r) - || ! SubsetP (default_val.Symval, r)) - throw new Exception ("Invalid range"); - range = r; - } + public override Variable Clone (Domain domain) + { + return new Sym (domain, name, val.Symval, desc, range); } + + public Symbol[] Range { get { return range; } set { range = value; } } } } @@ -553,7 +635,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) @@ -568,7 +650,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; } @@ -581,49 +663,35 @@ namespace System.Xml.Expression } } -#if false - internal class ThrowException : Exception + private static void throw_exception (string fmt, params object[] args) { - Symbol tag; - public object value; - - public ThrowException (Symbol tag, object value) : base () - { - this.tag = tag; - this.value = value; - } + throw new Exception (String.Format (fmt, args)); } -#endif - internal class CatchTag : IEquatable + internal struct CatchTag { - private object val; + private Term tag; + + public CatchTag (Symbol sym) { tag = new Term (sym); } + public CatchTag (Symbol sym, string msg) { tag = new Term (sym, msg); } + public CatchTag (ErrorTerm e) { tag = new Term (e); } + private CatchTag (int i) { tag = new Term (i); } - public CatchTag (Symbol name) { val = name.name; } - private CatchTag (int i) { val = i; } + public Term Tag { get { return tag; } } public static CatchTag Return = new CatchTag (0); public static CatchTag Break = new CatchTag (1); - - public static bool operator== (CatchTag t1, CatchTag t2) - { return t1.val == t2.val; } - - public static bool operator!= (CatchTag t1, CatchTag t2) - { return t1.val != t2.val; } - - public bool Equals (CatchTag tag) { return this.val == tag.val; } - public override bool Equals (object val) { return this.val == val; } - - public override int GetHashCode () { return val.GetHashCode (); } } public class Domain { + public Symbol name; public object context; public int depth = 0; + private Stack call_stack = new Stack (); - internal Dictionary termtypes - = new Dictionary (); + internal Dictionary termtypes + = new Dictionary (); internal Dictionary functions = new Dictionary (); internal Dictionary variables @@ -632,18 +700,29 @@ namespace System.Xml.Expression private Stack catch_stack = new Stack (); 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 (parent.termtypes); + termtypes = new Dictionary (parent.termtypes); functions = new Dictionary (parent.functions); variables = new Dictionary (parent.variables); this.context = context; } + internal void PushTerm (Term term) + { + call_stack.Push (term); + } + + internal void PopTerm () + { + call_stack.Pop (); + } + internal void Bind (Variable vari, Term value) { bindings = Bindings.Bind (bindings, vari, value); @@ -668,46 +747,87 @@ namespace System.Xml.Expression catch_count--; } - public bool Thrown { - get { return catch_count < catch_stack.Count; } + public bool Thrown () { return catch_count < catch_stack.Count; } + + public bool Thrown (out bool caught) + { + if (catch_count < catch_stack.Count) + { + caught = catch_count == catch_stack.Count - 1; + return true; + } + caught = false; + return false; } internal void ThrowReturn () { - foreach (CatchTag tag in catch_stack) + foreach (CatchTag elt in catch_stack) { catch_count--; - if (tag == CatchTag.Return) + if (elt.Tag == CatchTag.Return.Tag) break; } } - internal void ThrowBreak () + internal bool ThrowBreak () { - if (catch_stack.Peek () != CatchTag.Break) - throw new Exception ("No outer loop to break"); + if (catch_stack.Peek ().Tag != CatchTag.Break.Tag) + return false; catch_count--; + return true; + } + + internal void ThrowSymbol (Term tag) + { + foreach (CatchTag elt in catch_stack) + { + catch_count--; + if (elt.Tag.Matches (tag)) + break; + } } - internal void ThrowTag (CatchTag tag) + internal Term ThrowError (Term tag) { + tag = tag.Clone (); + ErrorTerm e = tag.objval as ErrorTerm; + e.CallStack = call_stack.ToArray (); + foreach (CatchTag elt in catch_stack) { catch_count--; - if (elt == tag) + if (elt.Tag.Matches (tag)) break; } + return tag; } - public void DefTerm (Symbol name, TermParser parser) + public void DefType (Type type) { - termtypes[name] = new TermType (name, parser); + if (! type.IsSubclassOf (typeof (TermValue))) + throw new Exception ("Not a subclass of TermValue: " + type); + BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic; + FieldInfo finfo = type.GetField ("name", flags); + if (finfo == null || finfo.FieldType != typeof (Symbol)) + throw new Exception ("No \"name\" field of string type: " + type); + Symbol name = (Symbol) finfo.GetValue (null); + if (termtypes.ContainsKey (name) + || functions.ContainsKey (name)) + throw new Exception ("already defined: " + name); + Type[] types = new Type[] { typeof (Domain), typeof (XmlNode) }; + MethodInfo minfo = type.GetMethod ("Parser", types); + if (minfo == null || minfo.ReturnType != typeof (TermValue)) + throw new Exception ("No \"Parser\" method of correct type: " + type); + termtypes[name] = minfo; } public void DefSubr (Builtin builtin, string str, bool setvar, int min_arg, int max_arg, params string[] aliases) { Symbol name = str; + if (termtypes.ContainsKey (name)) + throw new Exception ("already defined as termtype: " + name); Function func = new Function.Subroutine (builtin, name, setvar, min_arg, max_arg); functions[name] = func; @@ -715,12 +835,14 @@ namespace System.Xml.Expression functions[(Symbol) a] = func; } - public void DefSpecial (Builtin builtin, string str, + public void DefSpecial (Builtin builtin, string str, bool setvar, int min_arg, int max_arg, params string[] aliases) { Symbol name = str; - Function func = new Function.SpecialForm (builtin, name, + if (termtypes.ContainsKey (name)) + throw new Exception ("already defined as termtype: " + name); + Function func = new Function.SpecialForm (builtin, name, setvar, min_arg, max_arg); functions[name] = func; foreach (string a in aliases) @@ -732,14 +854,16 @@ namespace System.Xml.Expression functions[(Symbol) alias] = functions[(Symbol) str]; } - public void Defun (Symbol name, bool args_evalled, - Symbol[] args, Term[] body, bool prototype) + public void Defun (Symbol name, Symbol[] args, Term[] body, + bool prototype) { Function func; + if (termtypes.ContainsKey (name)) + throw new Exception ("already defined as termtype: " + name); if (prototype || ! functions.TryGetValue (name, out func)) { - func = new Function.Lambda (this, name, args_evalled, args); + func = new Function.Lambda (this, name, args); functions[name] = func; } if (! prototype) @@ -749,6 +873,8 @@ namespace System.Xml.Expression public void Defun (XmlNode node, bool prototype) { Symbol name = node.Attributes[Qfname].Value; + if (termtypes.ContainsKey (name)) + throw new Exception ("already defined as termtype: " + name); Function func; if (prototype || ! functions.TryGetValue (name, out func)) @@ -765,6 +891,22 @@ namespace System.Xml.Expression functions[func.name] = func; } + public void Defmacro (XmlNode node, bool prototype) + { + Symbol name = node.Attributes[Qfname].Value; + if (termtypes.ContainsKey (name)) + throw new Exception ("already defined as termtype: " + name); + Function func; + + if (prototype || ! functions.TryGetValue (name, out func)) + { + func = new Function.Macro (this, node); + functions[name] = func; + } + if (! prototype) + ((Function.Macro) func).SetBody (this, node); + } + public Variable Defvar (XmlNode node) { Symbol name = node.Attributes[0].Value; @@ -795,43 +937,30 @@ namespace System.Xml.Expression if (type == Qinteger) { - int intval = parse_integer (val); + int n = parse_integer (val); int[] range = null; if (range_list != null) { range = new int[nranges * 2]; for (int i = 0; i < nranges; i++) { - XmlNode n = range_list[i]; - if (n.Name == Qrange) + XmlNode nd = range_list[i]; + if (nd.Name == Qrange) { range[i * 2] - = parse_integer (n.FirstChild.InnerText); + = parse_integer (nd.FirstChild.InnerText); range[i * 2 + 1] - = parse_integer (n.LastChild.InnerText); + = parse_integer (nd.LastChild.InnerText); } else { range[i * 2] = range[i * 2 + 1] - = parse_integer (n.FirstChild.InnerText); + = parse_integer (nd.FirstChild.InnerText); } } } - - if (variables.TryGetValue (name, out vari)) - { - if (! (vari is Variable.Int)) - throw new Exception ("Inalid value"); - vari = (Variable) vari.Clone (); - Term v = new Term (intval); - vari.Value = v; - vari.DefaultValue = v; - if (range != null) - vari.Range = range; - } - else - vari = new Variable.Int (name, desc, intval, range); + vari = DefvarInt (name, n, desc, range); } else if (type == Qstring) { @@ -842,20 +971,7 @@ namespace System.Xml.Expression for (int i = 0; i < nranges; i++) range[i] = range_list[i].FirstChild.InnerText; } - - if (variables.TryGetValue (name, out vari)) - { - if (! (vari is Variable.Str)) - throw new Exception ("Invalid value"); - vari = (Variable) vari.Clone (); - Term v = new Term (val); - vari.Value = v; - vari.DefaultValue = v; - if (range != null) - vari.Range = range; - } - else - vari = new Variable.Str (name, desc, val, range); + vari = DefvarStr (name, val, desc, range); } else if (type == Qsymbol) { @@ -866,20 +982,7 @@ namespace System.Xml.Expression for (int i = 0; i < nranges; i++) range[i] = range_list[i].FirstChild.InnerText; } - - if (variables.TryGetValue (name, out vari)) - { - if (! (vari is Variable.Sym)) - throw new Exception ("Invalid value"); - vari = (Variable) vari.Clone (); - Term v = new Term (val); - vari.Value = v; - vari.DefaultValue = v; - if (range != null) - vari.Range = range; - } - else - vari = new Variable.Sym (name, desc, val, range); + vari = DefvarSym (name, (Symbol) val, desc, range); } else throw new Exception ("Unknown type: " + type); @@ -887,27 +990,108 @@ namespace System.Xml.Expression else { if (variables.TryGetValue (name, out vari)) - vari = (Variable) vari.Clone (); + vari = vari.Clone (this); else - vari = new Variable (name, Zero); + vari = new Variable (this, name, Zero); + variables[name] = vari; } - variables[name] = vari; return vari; } 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; } + public Variable DefvarInt (Symbol name, int n, string desc, int[] range) + { + Variable vari; + + if (variables.TryGetValue (name, out vari)) + { + Variable.Int intvari = vari as Variable.Int; + if (intvari == null) + throw new Exception ("Variable type mismatch: " + name); + if (range != null) + { + if (! intvari.IsSubrange (range)) + throw new Exception ("Variable range mismatch: " + name); + intvari.Range = range;; + } + if (desc != null) + intvari.Description = desc; + } + else + { + vari = new Variable.Int (this, name, n, desc, range); + variables[name] = vari; + } + return vari; + } + + public Variable DefvarStr (Symbol name, string str, string desc, + string[] range) + { + Variable vari; + + if (variables.TryGetValue (name, out vari)) + { + Variable.Str strvari = vari as Variable.Str; + if (strvari == null) + throw new Exception ("Variable type mismatch: " + name); + if (range != null) + { + if (! strvari.IsSubrange (range)) + throw new Exception ("Variable range mismatch: " + name); + strvari.Range = range; + } + if (desc != null) + strvari.Description = desc; + } + else + { + vari = new Variable.Str (this, name, str, desc, range); + variables[name] = vari; + } + return vari; + } + + public Variable DefvarSym (Symbol name, Symbol sym, string desc, + Symbol[] range) + { + Variable vari; + + if (variables.TryGetValue (name, out vari)) + { + Variable.Sym symvari = vari as Variable.Sym; + if (symvari == null) + throw new Exception ("Variable type mismatch: " + name); + if (range != null) + { + if (! symvari.IsSubrange (range)) + throw new Exception ("Variable range mismatch: " + name); + symvari.Range = range; + } + if (desc != null) + symvari.Description = desc; + } + else + { + vari = new Variable.Sym (this, name, sym, desc, range); + variables[name] = vari; + } + return vari; + } + internal Function GetFunc (Symbol name) { Function func; @@ -939,7 +1123,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; } @@ -951,7 +1135,7 @@ namespace System.Xml.Expression str += " " + kv.Key; str += ") (variabls"; foreach (KeyValuePair kv in variables) - str += " " + kv.Key; + str += " " + kv.Value; str += ")"; if (bindings != null) str += " " + bindings; @@ -961,17 +1145,13 @@ namespace System.Xml.Expression return str; } - internal void DebugWrite (bool head, string fmt, params string[] arg) + internal void TraceWrite (string fmt, params string[] arg) { - if (debug_level > depth) + if (trace_depth > depth) { - if (head) - { - Console.WriteLine (); - for (int i = 0; i < depth; i++) - Console.Write (" "); - } - Console.Write (fmt, arg); + for (int i = 0; i < depth; i++) + Console.Write (" "); + Console.WriteLine (fmt, arg); } } @@ -980,7 +1160,7 @@ namespace System.Xml.Expression Dictionary values = new Dictionary (); foreach (KeyValuePair kv in variables) - values[kv.Value] = kv.Value.val.Clone (); + values[kv.Value] = kv.Value.Value.Clone (); return values; } @@ -988,17 +1168,19 @@ namespace System.Xml.Expression { foreach (KeyValuePair kv in (Dictionary) 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.DefType (typeof (Varref)); + basic.DefType (typeof (Funcall)); + basic.DefType (typeof (ErrorTerm)); basic.DefSubr (Fset, "set", true, 1, 1, "="); basic.DefSubr (Fnot, "not", false, 1, 1, "!"); @@ -1026,26 +1208,28 @@ namespace System.Xml.Expression basic.DefSubr (Feval, "eval", false, 1, 1); basic.DefSubr (Fbreak, "break", false, 0, 1); basic.DefSubr (Freturn, "return", false, 0, 1); - - basic.DefSpecial (Fand, "and", 1, -1, "&&"); - basic.DefSpecial (For, "or", 1, -1, "||"); - basic.DefSpecial (Fprogn, "progn", 0, -1, "expr"); - basic.DefSpecial (Fif, "if", 2, 3); - basic.DefSpecial (Fwhen, "when", 1, -1); - basic.DefSpecial (Floop, "loop", 1, -1); - basic.DefSpecial (Fwhile, "while", 1, -1); - basic.DefSpecial (Fcond, "cond", 1, -1); - basic.DefSpecial (Fforeach, "foreach", 2, -1); - basic.DefSpecial (Fquote, "quote", 1, 1); - basic.DefSpecial (Ftype, "type", 1, 1); - basic.DefSpecial (Fcatch, "catch", 2, 2); - basic.DefSpecial (Fthrow, "throw", 1, 2); + basic.DefSubr (Fthrow, "throw", false, 1, 2); + + basic.DefSpecial (Fand, "and", false, 1, -1, "&&"); + basic.DefSpecial (For, "or", false, 1, -1, "||"); + basic.DefSpecial (Fprogn, "progn", false, 0, -1, "expr"); + basic.DefSpecial (Fif, "if", false, 2, 3); + basic.DefSpecial (Fwhen, "when", false, 1, -1); + basic.DefSpecial (Floop, "loop", false, 1, -1); + basic.DefSpecial (Fwhile, "while", false, 1, -1); + basic.DefSpecial (Fcond, "cond", false, 1, -1); + basic.DefSpecial (Fforeach, "foreach", true, 2, -1); + basic.DefSpecial (Fquote, "quote", false, 1, 1); + basic.DefSpecial (Ftype, "type", false, 1, 1); + basic.DefSpecial (Fcatch, "catch", true, 2, -1); } private static Term Fset (Domain domain, Variable vari, Term[] args) { + if (vari == null) + return new Term (new ErrorTerm (Error.NoVariable, "")); vari.Value = args[0]; - return vari.val; + return args[0]; } private static Term Fnot (Domain domain, Variable vari, Term[] args) @@ -1055,25 +1239,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) @@ -1087,15 +1265,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) @@ -1109,34 +1284,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) @@ -1150,31 +1318,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) @@ -1261,7 +1422,7 @@ namespace System.Xml.Expression if (vari == null) list = new List (); else - list = vari.val.Listval; + list = vari.Value.Listval; foreach (Term arg in args) { @@ -1277,7 +1438,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) @@ -1287,7 +1448,7 @@ namespace System.Xml.Expression if (vari == null) str = ""; else - str = vari.val.Strval; + str = vari.Value.Strval; foreach (Term arg in args) { @@ -1299,15 +1460,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) @@ -1339,29 +1500,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) @@ -1421,7 +1588,8 @@ namespace System.Xml.Expression private static Term Fbreak (Domain domain, Variable vari, Term[] args) { - domain.ThrowBreak (); + if (! domain.ThrowBreak ()) + return domain.ThrowError (new Term (Error.NoOuterLoop, null)); return args.Length == 0 ? Zero : args[0]; } @@ -1430,11 +1598,11 @@ namespace System.Xml.Expression Term result = Zero; try { domain.Catch (CatchTag.Break); - while (! domain.Thrown) + while (! domain.Thrown ()) foreach (Term arg in args) { result = arg.Eval (domain); - if (domain.Thrown) + if (domain.Thrown ()) return result; } } finally { @@ -1448,11 +1616,11 @@ namespace System.Xml.Expression Term result = Zero; try { domain.Catch (CatchTag.Break); - while (! domain.Thrown && args[0].Eval (domain).IsTrue) + while (! domain.Thrown () && args[0].Eval (domain).IsTrue) for (int i = 1; i < args.Length; i++) { result = args[i].Eval (domain); - if (domain.Thrown) + if (domain.Thrown ()) return result; } } finally { @@ -1471,18 +1639,23 @@ namespace System.Xml.Expression if (result.IsTrue) { for (int i = 1; i < list.Count; i++) - result = list[i].Eval (domain); + { + domain.depth++; + result = list[i].Eval (domain); + domain.depth--; + if (domain.Thrown ()) + return result; + } return result; } } return Zero; } - private static Term Fforeach (Domain domain, Variable vari, - Term[] args) + private static Term Fforeach (Domain domain, Variable vari, Term[] args) { Term result = args[0].Eval (domain); - if (domain.Thrown) + if (domain.Thrown ()) return result; List list = result.Listval; Bindings current = domain.bindings; @@ -1496,7 +1669,7 @@ namespace System.Xml.Expression for (int i = 1; i < args.Length; i++) { result = args[i].Eval (domain); - if (domain.Thrown) + if (domain.Thrown ()) return result; } } finally { @@ -1511,7 +1684,7 @@ namespace System.Xml.Expression private static Term Fquote (Domain domain, Variable vari, Term[] args) { - return new Term (args[0]); + return args[0]; } private static Term Ftype (Domain domain, Variable vari, Term[] args) @@ -1530,111 +1703,145 @@ namespace System.Xml.Expression public static Term Fcatch (Domain domain, Variable vari, Term[] args) { Term result = Zero; - try { - domain.Catch (new CatchTag (args[0].Symval)); - result = args[1].Eval (domain); - } finally { - domain.Uncatch (); - } - return result; + bool caught; + + domain.Catch (new CatchTag (args[0].Symval)); + for (int i = 1; i < args.Length; i++) + { + result = args[i].Eval (domain); + if (domain.Thrown (out caught)) + { + domain.Uncatch (); + if (caught) + { + if (vari != null) + vari.Value = result; + return One; + } + return result; + } + } + domain.Uncatch (); + if (vari != null) + vari.Value = result; + return Zero; } public static Term Fthrow (Domain domain, Variable vari, Term[] args) { - domain.ThrowTag (new CatchTag (args[0].Symval)); - return (args.Length == 1 ? Zero : args[1]); + if (args[0].IsSymbol) + { + domain.ThrowSymbol (args[0]); + return (args[args.Length - 1]); + } + if (args[0].IsError) + return domain.ThrowError (args[0]); + return domain.ThrowError (new Term (Error.InvalidArgumentType, + args[0].ToString ())); } - public delegate TermValue TermParser (Domain domain, XmlNode node); + public abstract class TermValue + { + public virtual Term Eval (Domain domain) { return new Term (this); } + public virtual TermValue Clone () { return this; } + public virtual bool IsTrue { get { return true; } } + public virtual bool Matches (TermValue other) { return Equals (other); } + public override abstract bool Equals (object obj); + public override abstract int GetHashCode (); + public abstract string ToString (bool detail); + } - public class TermType + private class Varref : TermValue { - public readonly Symbol type; - internal readonly TermParser parser; + private static Symbol name = "varref"; + public static Symbol Name { get { return name; } } + + private Symbol vname; + private Variable vari; - public TermType (Symbol type, TermParser parser) + public Varref (Symbol vname) { this.vname = vname; } + + public override Term Eval (Domain domain) { - this.type = type; - this.parser = parser; + if (vari == null || vari.domain != domain) + vari = domain.GetVar (vname, true); + return vari.Value; } - } - public abstract class TermValue - { - public virtual Term Eval (Domain domain) { return new Term (this); } - public virtual TermValue Clone () { return this; } + public static TermValue Parser (Domain domain, XmlNode node) + { + return new Varref ((Symbol) node.Attributes[Qvname].Value); + } + + public override bool Equals (object obj) + { + Varref varref = obj as Varref; + return (varref != null && varref.vari.name == vari.name); + } + + public override int GetHashCode () + { + return vari.name.GetHashCode (); + } + + public override string ToString () { return ToString (true); } + + public override string ToString (bool detail) + { + return ""; + } } private class Funcall : TermValue { + private static Symbol name = "funcall"; + public static Symbol Name { get { return name; } } + internal Function func; internal Variable vari; internal Term[] args; - private Funcall (Function func, Variable vari, Term[] args) + public Funcall (Function func, Variable vari, Term[] args) { + int nargs = args.Length; + + if (nargs < func.min_arg + || (func.max_arg >= 0 && nargs > func.max_arg)) + throw_exception ("Invalid number of arguments to {0}: ", + func.name, nargs); + if (! func.setvar && vari != null) + throw_exception ("vname attribute not acceptable: ", func.name); this.func = func; this.vari = vari; this.args = args; } - 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); - 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 != Qnull) - vari = domain.GetVar (vname, true); - } + public static TermValue Parser (Domain domain, XmlNode node) + { + Symbol fname = node.Name; + XmlAttribute attr; - internal static TermValue parser (Domain domain, XmlNode node) - { - Symbol fname = node.Name; - Symbol vname = Qnull; - XmlAttribute attr; - - if (fname == Qfuncall) - fname = node.Attributes[Qfname].Value; - attr = node.Attributes[Qvname]; - if (attr != null) - vname = attr.Value; - - XmlNodeList nlist = node.ChildNodes; - int nargs = nlist.Count; - Term[] args = new Term[nargs]; - for (int i = 0; i < nargs; i++) - args[i] = new Term (domain, nlist[i]); - return new Funcall (domain, fname, vname, args); - } + if (fname == Qfuncall) + fname = node.Attributes[Qfname].Value; + Function func = domain.GetFunc (fname); + Variable vari; + attr = node.Attributes[Qvname]; + vari = attr == null ? null : domain.GetVar (attr.Value, true); + XmlNodeList nlist = node.ChildNodes; + int nargs = nlist.Count; + Term[] args = new Term[nargs]; + for (int i = 0; i < nargs; i++) + args[i] = new Term (domain, nlist[i]); + return new Funcall (func, vari, args); + } public override Term Eval (Domain domain) { - domain.DebugWrite (true, ToString ()); + domain.TraceWrite (ToString ()); domain.depth++; Term result = func.Call (domain, vari, args); domain.depth--; - domain.DebugWrite (true, " ==> {0})", result.ToString ()); + domain.TraceWrite ("=> {0}", result.ToString ()); return result; } @@ -1643,16 +1850,35 @@ namespace System.Xml.Expression return new Funcall (func, vari, args); } - public override string ToString () + public override bool Equals (object obj) + { + Funcall funcall = obj as Funcall; + return (obj != null + && funcall.func == func + && funcall.vari == vari + && funcall.args.Length == args.Length); + } + + public override int GetHashCode () + { + return func.GetHashCode () ^ args.Length; + } + + public override string ToString () { return ToString (true); } + + public override string ToString (bool detail) { string str = "<" + func.name; if (vari != null) str += " vname=\"" + vari.name + "\""; - if (args == null) + if (args.Length == 0 || ! detail) return str + "/>"; str += ">"; if (func is Function.SpecialForm) - str += "..."; + { + for (int i = 0; i < args.Length; i++) + str += "."; + } else foreach (Term e in args) str += e; @@ -1660,6 +1886,75 @@ namespace System.Xml.Expression } } + internal class ErrorTerm : TermValue + { + private static Symbol name = "error"; + public static Symbol Name { get { return name; } } + + private readonly Symbol ename; + private string message; + private Term[] stack; + + public ErrorTerm (Symbol ename, string message) + { + this.ename = ename; + this.message = message; + } + + public static TermValue Parser (Domain domain, XmlNode node) + { + XmlAttribute attr = node.Attributes[Qename]; + Symbol ename = attr == null ? Qnull : (Symbol) attr.Value; + string message = node.InnerText; + return new ErrorTerm (ename, message); + } + + public Term[] CallStack { get { return stack; } set { stack = value; } } + + public override TermValue Clone () + { + return new ErrorTerm (ename, message); + } + + public override bool Equals (object obj) + { + ErrorTerm e = obj as ErrorTerm; + if (e == null || e.ename != ename || e.message != message + || (e.stack == null ? stack != null + : (stack == null || e.stack.Length != stack.Length))) + return false; + if (stack != null) + for (int i = 0; i < stack.Length; i++) + if (! stack[i].Equals (e.stack[i])) + return false; + return true; + } + + public override int GetHashCode () + { + return ename.GetHashCode (); + } + + public override bool Matches (TermValue term) + { + ErrorTerm e = term as ErrorTerm; + return (e != null && (ename == Qnull || e.ename == ename)); + } + + public override string ToString () { return ToString (true); } + + public override string ToString (bool detail) + { + string str = ""; + if (message != null) + str += message; + if (stack != null) + for (int i = 0; i < stack.Length; i++) + str += stack[i].ToString (false); + return str + ""; + } + } + public struct Term { public int intval; @@ -1673,8 +1968,13 @@ namespace System.Xml.Expression public Term (string str) { intval = 0; objval = str; } // ... public Term (List list) { intval = 0; objval = list; } + // ERROR-MESSASGE + public Term (Symbol name, string message) + { + intval = 0; + objval = new ErrorTerm (name, message); + } - public Term (Term term) { intval = term.intval; objval = term.objval; } public Term (TermValue obj) { intval = 0; objval = obj; } public Term (Domain domain, XmlNode node) @@ -1693,8 +1993,6 @@ namespace System.Xml.Expression objval = (Symbol) node.InnerText; else if (name == Qstring) objval = node.InnerText.Clone (); - else if (name == Qvarref) - objval = domain.GetVar ((Symbol) node.Attributes[0].Value, true); else if (name == Qlist) { List list = new List (); @@ -1705,12 +2003,22 @@ namespace System.Xml.Expression } else { - TermType term_type; + MethodInfo minfo; - if (domain.termtypes.TryGetValue (name, out term_type)) - objval = term_type.parser (domain, node); + if (domain.termtypes.TryGetValue (name, out minfo)) + objval = (TermValue) minfo.Invoke (null, new Object[] { domain, node}); else - objval = Funcall.parser (domain, node); + { + Funcall funcall = (Funcall) Funcall.Parser (domain, node); + if (funcall.func is Function.Macro) + { + Term result = funcall.Eval (domain); + intval = result.intval; + objval = result.objval; + } + else + objval = funcall; + } } } } @@ -1719,21 +2027,29 @@ namespace System.Xml.Expression public Term (Domain domain, Symbol vname) { intval = 0; - objval = domain.GetVar (vname, true); + objval = new Varref (vname); } // ... public Term (Domain domain, Symbol fname, Term[] args) - { - intval = 0; - objval = new Funcall (domain, fname, args); - } + : this (domain, fname, Qnull, args) { } // ... public Term (Domain domain, Symbol fname, Symbol vname, Term[] args) { intval = 0; - objval = new Funcall (domain, fname, vname, args); + + Function func = domain.GetFunc (fname); + Variable vari = vname == Qnull ? null : domain.GetVar (vname, true); + Funcall funcall = new Funcall (func, vari, args); + if (func is Function.Macro) + { + Term result = funcall.Eval (domain); + intval = result.intval; + objval = result.objval; + } + else + objval = funcall; } public object Objval { @@ -1755,7 +2071,7 @@ namespace System.Xml.Expression public string Strval { get { if (! IsStr) - throw new Exception ("term is not string: " + this); + throw new Exception ("term is not a string: " + this); return (string) objval; } } @@ -1763,7 +2079,7 @@ namespace System.Xml.Expression public string Symval { get { if (! IsSymbol) - throw new Exception ("term is not symbol: " + this); + throw new Exception ("term is not a symbol: " + this); return (Symbol) objval; } } @@ -1771,7 +2087,7 @@ namespace System.Xml.Expression public List Listval { get { if (! IsList) - throw new Exception ("term is not list: " + this); + throw new Exception ("term is not a list: " + this); return (List) objval; } } @@ -1782,27 +2098,29 @@ namespace System.Xml.Expression ? (intval != 0) : objval is List ? (((List) objval).Count != 0) + : objval is TermValue + ? ((TermValue) objval).IsTrue : true); } } + public bool IsInt { get { return (objval == null); } } public bool IsStr { get { return (objval is string); } } public bool IsSymbol { get { return (objval is Symbol); } } public bool IsList { get { return (objval is List); } } - - public bool IsType (Type type) - { - return (objval == null ? type == typeof (int) - : type == objval.GetType ()); - } + public bool IsError { get { return (objval is ErrorTerm); } } public Term Eval (Domain domain) { - if (objval == null || objval is Symbol || objval is string) - return this; - if (objval is List) - return new Term ((List) objval); - return ((TermValue) objval).Eval (domain); + try { + domain.PushTerm (this); + if (objval == null || objval is Symbol || objval is string + || objval is List) + return this; + return ((TermValue) objval).Eval (domain); + } finally { + domain.PopTerm (); + } } public Term Clone () @@ -1818,7 +2136,60 @@ namespace System.Xml.Expression return new Term (((TermValue) objval).Clone ()); } - public override string ToString () + public static bool operator== (Term t1, Term t2) + { + return t1.Equals (t2); + } + + public static bool operator!= (Term t1, Term t2) { return ! (t1 == t2); } + + public override bool Equals (object obj) + { + if (! (obj is Term)) + return false; + Term term = (Term) obj; + if (IsInt) + return term.IsInt && term.Intval == Intval; + if (IsStr) + return term.IsStr && term.Strval == Strval; + if (IsSymbol) + return term.IsSymbol && term.Symval == Symval; + if (IsList) + { + if (! term.IsList) + return false; + List l1 = objval as List; + List l2 = term.objval as List; + + if (l1.Count != l2.Count) + return false; + for (int i = 0; i < l1.Count; i++) + if (! l1[i].Equals (l2[i])) + return false; + return true; + } + return ((TermValue) objval).Equals (obj); + } + + public override int GetHashCode () { return intval; } + + public bool Matches (Term term) + { + if (IsInt) + return term.IsInt && term.Intval == Intval; + if (IsStr) + return term.IsStr && term.Strval == Strval; + if (IsSymbol) + return term.IsSymbol && term.Symval == Symval; + if (IsList) + return (((List) objval).Count > 0 + && ((List) objval)[0].Matches (term)); + return ((TermValue) objval).Matches ((TermValue) term.objval); + } + + public override string ToString () { return ToString (true); } + + public string ToString (bool detail) { string str; @@ -1830,15 +2201,20 @@ namespace System.Xml.Expression str = "" + objval + ""; else if (objval is List) { - str = ""; - foreach (Term e in (List) objval) - str += e; - str += ""; + if (detail) + { + str = ""; + foreach (Term e in (List) objval) + str += e; + str += ""; + } + else + str = ""; } else if (objval is Term) str = "" + objval + ""; else if (objval is TermValue) - str = ((TermValue) objval).ToString (); + str = ((TermValue) objval).ToString (detail); else throw new Exception ("invalid Term object: " + objval); return str; @@ -1912,6 +2288,8 @@ namespace System.Xml.Expression { if (n.Name == Qdefun) domain.Defun (n, true); + else if (n.Name == Qdefmacro) + domain.Defmacro (n, true); else if (n.Name == Qdefvar) domain.Defvar (n); else @@ -1924,6 +2302,8 @@ namespace System.Xml.Expression { if (n.Name == Qdefun) domain.Defun (n, false); + else if (n.Name == Qdefmacro) + domain.Defmacro (n, false); else if (n.Name != Qdefvar) terms[i++]= new Term (domain, n); } @@ -1950,10 +2330,10 @@ namespace System.Xml.Expression public Xexpression (Domain domain, string url) { - XmlDocument doc = new XmlDocument (Symbol.Table); + XmlDocument doc = new XmlDocument (Symbol.NameTable); XmlNode node; - using (XmlTextReader reader = new XmlTextReader (url, Symbol.Table)) + using (XmlTextReader reader = new XmlTextReader (url, doc.NameTable)) { do { reader.Read (); @@ -1977,7 +2357,7 @@ namespace System.Xml.Expression foreach (Term term in terms) { result = term.Eval (domain); - if (domain.Thrown) + if (domain.Thrown ()) return result; } } finally {