X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=XmlExpr.cs;h=d21a6301ab3c71a25e7075b9ca1c2887822c602c;hb=f5543e0aaf8f077fd584cbbdeaa7be8936269aa0;hp=bfd48e7c64acf13ebf5e337b652986d22e939f14;hpb=c647f605517330db26cbabb4da77f152974feef8;p=m17n%2Fm17n-lib-cs.git diff --git a/XmlExpr.cs b/XmlExpr.cs index bfd48e7..d21a630 100644 --- a/XmlExpr.cs +++ b/XmlExpr.cs @@ -2,87 +2,73 @@ 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 Xex + public class Xexpression { - public struct Name + private static int debug_depth = 0; + + public static int DebugDepth { + get { return debug_depth; } + set { debug_depth = value; } + } + + public struct Symbol : IEquatable { private static NameTable nt = new NameTable (); private string name; - public Name (string str) - { - name = nt.Add (str); - } - - public Name (XmlAttribute attr) - { - name = nt.Add (attr.Value); - } - - public Name (XmlNode node) - { - name = node.Name; - } - - public static implicit operator Name (string str) - { - return new Name (str); - } - - public static implicit operator Name (XmlAttribute attr) - { - return new Name (attr); - } + public Symbol (string str) { name = nt.Add (str); } - public static implicit operator Name (XmlNode node) + public static implicit operator Symbol (string str) { - return new Name (node); + return new Symbol (str); } - public static implicit operator string (Name name) - { - return name.name; - } + public static implicit operator string (Symbol sym) { return sym.name; } - public static bool operator== (Name n1, Name n2) + public static bool operator== (Symbol n1, Symbol n2) { return (object) n1.name == (object) n2.name; } - public static bool operator== (Name n1, string n2) + public static bool operator!= (Symbol n1, Symbol n2) { - return (object) n1.name == (object) n2; + return (object) n1.name != (object) n2.name; } - public static bool operator== (string n1, Name n2) + public static bool operator== (Symbol n1, string n2) { - return (object) n1 == (object) n2.name; + return (object) n1.name == (object) n2; } - public static bool operator!= (Name n1, Name n2) + public static bool operator!= (Symbol n1, string n2) { - return (object) n1.name != (object) n2.name; + return (object) n1.name != (object) n2; } - public static bool operator!= (Name n1, string n2) + public static bool operator== (string n1, Symbol n2) { - return (object) n1.name != (object) n2; + return (object) n1 == (object) n2.name; } - public static bool operator!= (string n1, Name n2) + public static bool operator!= (string n1, Symbol n2) { return (object) n1 != (object) n2.name; } - public override bool Equals (object other) + public bool Equals (Symbol name) + { + return Object.ReferenceEquals (this.name, name.name); + } + + public override bool Equals (object obj) { - Console.WriteLine ("Equals (object)"); - return Object.ReferenceEquals (this, other); + return Object.ReferenceEquals (this.name, obj); } public override int GetHashCode () @@ -90,225 +76,539 @@ 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; } } - private static Name Ninteger = "integer"; - private static Name Nstring = "string"; - private static Name Nboolean = "boolean"; - private static Name Nsymbol = "symbol"; - private static Name Nlist = "list"; - private static Name Nobject = "object"; + 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"; + + public static Symbol Qdefun = "defun"; + public static Symbol Qdefmacro = "defmacro"; + private static Symbol Qfname = "fname"; + private static Symbol Qargs = "args"; + private static Symbol Qfixed = "fixed"; + private static Symbol Qoptional = "optional"; + private static Symbol Qrest = "rest"; + + public static Symbol Qdefvar = "defvar"; + private static Symbol Qvname = "vname"; + private static Symbol Qdescription = "description"; + private static Symbol Qrange = "range"; + + public abstract class Function + { + public Symbol name; + public int min_arg, max_arg; + + public Function () { } - private static Name Nconst = "const"; - private static Name Nvariable = "varialbe"; + public Function (Symbol name, int min_arg, int max_arg) + { + this.name = name; + this.min_arg = min_arg; + this.max_arg = max_arg; + } - private static Name Nfuncall = "funcall"; - private static Name Nmname = "mname"; - private static Name Nprogn = "progn"; + public abstract Term Call (Domain domain, Variable vari, Term[] args); - internal class Function - { - internal class Lambda + public override string ToString () { - internal Name[] args; - internal Xex[] body; + return name; + } - public Lambda (XmlNode node, Domain domain) - { - Set (node, domain); - } + internal class Subroutine : Function + { + public Builtin builtin; + public bool setvar; - public void Set (XmlNode node, Domain domain) - { - XmlNodeList body = node.ChildNodes; - int idx = 0; + public Subroutine (Builtin builtin, Symbol name, bool setvar, + int min_arg, int max_arg) + : base (name, min_arg, max_arg) + { + this.builtin = builtin; + this.setvar = setvar; + } - if (body[0].Name == "args") + public override Term Call (Domain domain, Variable vari, Term[] args) + { + if (args != null) { - XmlNodeList args = body[0].ChildNodes; - if (this.args == null) - this.args = new Name[args.Count]; - for (int i = 0; i < args.Count; i++) - this.args[i] = args[i].InnerText; - idx++; + args = (Term[]) args.Clone (); + for (int i = 0; i < args.Length; i++) + { + args[i] = args[i].Eval (domain); + if (domain.Thrown) + return args[i]; + } } - else if (this.args == null) - this.args = new Name[0]; - if (this.body == null) - this.body = new Xex[body.Count - idx]; - for (int i = 0; idx < body.Count; i++, idx++) - this.body[i] = new Xex (body[idx], domain); + return builtin (domain, vari, args); } } - public readonly Name name; - public Builtin builtin; - public int min_arg, max_arg; - internal Lambda lambda; - public bool specialp = false; + internal class SpecialForm : Function + { + public Builtin builtin; + + public SpecialForm (Builtin builtin, Symbol name, + int min_arg, int max_arg) + : base (name, min_arg, max_arg) + { + this.builtin = builtin; + } + + public override Term Call (Domain domain, Variable vari, Term[] args) + { + return builtin (domain, vari, args); + } + } - public Function (Name name, Builtin builtin, - int min_arg, int max_arg, bool specialp) + private static void parse_head (Domain domain, XmlNode node, + out Symbol name, + out int min_arg, out int max_arg, + out Variable[] args) { - this.name = name; - this.builtin = builtin; - this.min_arg = min_arg; - this.max_arg = max_arg; - this.specialp = specialp; + 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++; + 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; + args = null; + } } - internal Function (Name name, XmlNode node, Domain domain) + private static void parse_body (Domain domain, XmlNode node, + out Term[] body) { - this.name = name; - lambda = new Lambda (node, domain); - this.min_arg = this.max_arg = lambda.args.Length; + 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; } - private Function () + internal class Macro : Function { - name = "nil"; + 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); + } + + 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; + + try { + for (int i = 0; i < min_arg; i++) + domain.Bind (this.args[i], args[i]); + if (body != null) + { + try { + domain.Catch (CatchTag.Return); + foreach (Term term in body) + { + result = term.Eval (domain); + if (domain.Thrown) + return result; + } + } finally { + domain.Uncatch (); + } + } + } finally { + domain.UnboundTo (current); + } + return result; + } } - public object Call (Xex[] args, Domain domain) + internal class Lambda : Function { - Bindings current = domain.bindings; - object result = false; + internal Variable[] args; + internal Term[] body; + + public Lambda (Domain domain, XmlNode node) + { + parse_head (domain, node, out name, out min_arg, out max_arg, + out args); + } + + public Lambda (Domain domain, Symbol name, Symbol[] args) + { + int nfixed = 0; + int noptional = 0; + int nrest = 0; + + this.name = name; + if (args != null) + { + int i = 0; + for (i = 0; i < args.Length; i++, nfixed++) + if (args[i] == Qoptional || args[i] == Qrest) + break; + if (i < args.Length) + { + if (args[i] == Qoptional) + { + for (i++; i < args.Length; i++, noptional++) + if (args[i] == Qrest) + break; + if (i < args.Length) + nrest = 1; + } + } + min_arg = nfixed; + max_arg = nfixed + noptional + nrest; + this.args = new Variable[max_arg]; + int j; + for (i = j = 0; j < this.args.Length; i++) + if (args[i] != Qoptional || args[i] != Qrest) + this.args[j++] = domain.Defvar (args[i]); + } + else + { + min_arg = max_arg = 0; + } + } - try { - if (! specialp) - foreach (Xex e in args) - e.Eval (domain); - if (builtin != null) - return builtin (args, domain); - if (lambda == null) - return null; + public void SetBody (Domain domain, XmlNode node) + { + parse_body (domain, node, out body); + } - foreach (Xex e in lambda.body) - result = e.Eval (domain); - } finally { - domain.UnboundTo (current); + public void SetBody (Term[] body) + { + this.body = body; + } + + public override Term Call (Domain domain, Variable vari, Term[] args) + { + Bindings current = domain.bindings; + Term result = Zero; + + try { + int i; + if (args != null) + { + Term[] newargs = new Term[args.Length]; + for (i = 0; i < min_arg; i++) + newargs[i] = args[i].Eval (domain); + args = newargs; + } + for (i = 0; i < min_arg; i++) + domain.Bind (this.args[i], args[i]); + if (body != null) + { + try { + domain.Catch (CatchTag.Return); + foreach (Term term in body) + { + result = term.Eval (domain); + if (domain.Thrown) + return result; + } + } finally { + domain.Uncatch (); + } + } + } finally { + domain.UnboundTo (current); + } + return result; } - return result; } } - internal abstract class Variable + public class Variable { - public readonly Name name; - public readonly Name type; - internal object val; + public Domain domain; + public readonly Symbol name; + protected Term val; - public Variable (Name name, Name type, object value) + public Variable (Domain domain, Symbol name, Term val) { + this.domain = domain; this.name = name; - this.type = type; - val = value; + this.val = val; } - public object Value + public virtual bool ValueP (Term val) { return true; } + + public virtual Variable Clone (Domain domain) { - get { return val; } - set - { - if (! ValueP (value)) - throw new Exception ("Invalid value type: " + value); - val = value; - } + return new Variable (domain, name, val); } - public abstract bool ValueP (object value); + public virtual void Reset () { val = Zero; } - public override string ToString () { return name + "(" + type + ")"; } - } + public Term Value + { + get { return val; } + set { + if (! ValueP (value)) + throw new Exception ("Invalid value: " + value); + val = value; + } + } - internal class VarInt : Variable - { - public struct Range + public Term SetValue (int i) { - public int from, to; + val.intval = i; + val.objval = null; + return val; } - public Range[] ranges; + public Term SetValue (string s) + { + val.objval = s; + return val; + } - public VarInt (Name name, int value) : base (name, Ninteger, value) { } + public override string ToString () { return name + "(" + val + ")"; } - public override bool ValueP (object value) + public abstract class Typed : Variable { - int i; + protected string desc; + private Term default_val; - if (! (value is int)) - return false; - if (ranges == null) - return true; - i = (int) value; - foreach (Range r in ranges) - if (i >= r.from && i <= r.to) - return true; - return false; - } - } + protected Typed (Domain domain, Symbol name, Term val, string desc) + : base (domain, name, val) + { + this.desc = desc; + default_val = val; + } - internal class VarStr : Variable - { - public string[] ranges; + public override void Reset () { val = default_val; } - public VarStr (Name name, string value) : base (name, Nstring, value) { } + public string Description { + get { return desc; } + set { desc = value; } + } + } - public override bool ValueP (object value) + public class Int : Typed { - string str; + private int[] range; - if (! (value is string)) - return false; - if (ranges == null) - return true; - str = (string) value; - foreach (string s in ranges) - if (s == str) + public bool IsSubrange (int[] r) + { + if (range == null) + return true; + for (int i = 0; i < r.Length; i += 2) + { + int j; + for (j = 0; j < range.Length; j += 2) + if (range[j] <= r[i] && range[j + 1] >= r[i + 1]) + break; + if (j >= range.Length) + return false; + } return true; - return false; - } - } + } - internal class VarBool : Variable - { - public VarBool (Name name, bool value) : base (name, Nboolean, value) { } + public Int (Domain domain, Symbol name, int n, string desc, int[] range) + : base (domain, name, new Term (n), desc) + { + 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 (object value) - { - return value is bool; + public override bool ValueP (Term term) + { + if (! term.IsInt) + return false; + 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 Variable Clone (Domain domain) + { + return new Int (domain, name, val.Intval, desc, range); + } + + public int[] Range { get { return range; } set { range = value; } } } - } - internal class VarMisc : Variable - { - public VarMisc (Name name, object value) : base (name, Nobject, value) { } + public class Str : Typed + { + private string[] range; + + public bool IsSubrange (string[] r) + { + if (range == null) + return true; + 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; + } + + public Str (Domain domain, Symbol name, string str, string desc, + string[] range) + : base (domain, name, new Term (str), desc) + { + this.range = range; + if (! ValueP (val)) + throw_exception ("Invalid string value for {0}: {1}", name, val); + } + + public override bool ValueP (Term term) + { + if (! term.IsStr) + return false; + if (range == null) + return true; + string str = term.Strval; + foreach (string s in range) + if (str == s) + return true; + return false; + } - public override bool ValueP (object value) + 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 : Typed { - return true; + public Symbol[] range; + + public bool IsSubrange (Symbol[] r) + { + if (range == null) + return true; + 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; + } + + public Sym (Domain domain, Symbol name, Symbol sym, string desc, + Symbol[] range) + : base (domain, name, new Term (sym), desc) + { + this.range = range; + if (! ValueP (val)) + throw_exception ("Invalid symbol value for {0}: {1}", name, val); + } + + public override bool ValueP (Term term) + { + if (! term.IsSymbol) + return false; + if (range == null) + return true; + Symbol name = term.Symval; + foreach (Symbol n in range) + if (name == n) + return true; + return false; + } + + public override Variable Clone (Domain domain) + { + return new Sym (domain, name, val.Symval, desc, range); + } + + public Symbol[] Range { get { return range; } set { range = value; } } } } internal class Bindings { private Variable vari; - private object old_value; + private Term old_value; private Bindings next; - private Bindings (Variable vari, object value) + private Bindings (Variable vari) { this.vari = vari; - old_value = value; + old_value = vari.Value; } - public static Bindings Bind (Bindings bindings, - Variable vari, object value) + public static Bindings Bind (Bindings bindings, Variable vari, Term val) { - Bindings b = new Bindings (vari, vari.val); + Bindings b = new Bindings (vari); - b.vari.Value = value; + b.vari.Value = val; b.next = bindings; return b; } @@ -316,7 +616,7 @@ namespace System.Xml.Expression internal Bindings UnboundTo (Bindings boundary) { for (Bindings b = this; b != boundary; b = b.next) - vari.val = b.old_value; + b.vari.Value = b.old_value; return boundary; } @@ -324,653 +624,1399 @@ namespace System.Xml.Expression { string str = "(bindings"; for (Bindings b = this; b != null; b = b.next) - str += " " + vari; + str += " " + vari.name + "=" + b.old_value; return str + ")"; } } - internal class ThrowException : Exception + private static void throw_exception (string msg) + { + throw new Exception (msg); + } + + private static void throw_exception (string fmt, params object[] args) { - Name tag; - public object value; + throw new Exception (String.Format (fmt, args)); + } - public ThrowException (Name tag, object value) : base () - { - this.tag = tag; - this.value = value; - } + internal class CatchTag : IEquatable + { + private object val; + + public CatchTag (Symbol sym) { val = (string) sym; } + private CatchTag (int i) { val = i; } + + 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 { - private Domain parent; + public Symbol name; public object context; - - internal Dictionary functions - = new Dictionary (); - internal Dictionary variables - = new Dictionary (); + public int depth = 0; + + internal Dictionary termtypes + = new Dictionary (); + internal Dictionary functions + = new Dictionary (); + internal Dictionary variables + = new Dictionary (); internal Bindings bindings; + 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) { - this.parent = parent; + termtypes = new Dictionary (parent.termtypes); + functions = new Dictionary (parent.functions); + variables = new Dictionary (parent.variables); this.context = context; } - internal void Bind (Variable vari, object value) + internal void Bind (Variable vari, Term value) { bindings = Bindings.Bind (bindings, vari, value); } internal void UnboundTo (Bindings boundary) { - bindings = bindings.UnboundTo (boundary); + if (bindings != null) + bindings = bindings.UnboundTo (boundary); } - public void Defun (Name name, Builtin builtin, int min_arg, int max_arg) + internal void Catch (CatchTag tag) { - Defun (name, builtin, min_arg, max_arg, false); + catch_stack.Push (tag); + catch_count++; } - public void Defun (Name name, Builtin builtin, int min_arg, int max_arg, - bool specialp) + internal void Uncatch () { - Function func; + catch_stack.Pop (); + if (catch_count > catch_stack.Count) + catch_count--; + } + + public bool Thrown { + get { return catch_count < catch_stack.Count; } + } - if (functions.TryGetValue (name, out func)) + internal void ThrowReturn () + { + foreach (CatchTag tag in catch_stack) { - if (func.min_arg < min_arg || func.max_arg > max_arg) - throw new Exception ("Incompatible argument numbers to override: " - + name); - func.builtin = builtin; - func.lambda = null; - func.min_arg = min_arg; - func.max_arg = max_arg; - func.specialp = specialp; + catch_count--; + if (tag == CatchTag.Return) + break; } - else + } + + internal void ThrowBreak () + { + if (catch_stack.Peek () != CatchTag.Break) + throw_exception ("No outer loop to break"); + catch_count--; + } + + internal void ThrowTag (CatchTag tag) + { + foreach (CatchTag elt in catch_stack) { - functions[name] - = new Function (name, builtin, min_arg, max_arg, specialp); + catch_count--; + if (elt == tag) + break; } } - public void Defun (XmlNode node) + public void DefTerm (Symbol name, TermParser parser) + { + if (termtypes.ContainsKey (name) + || functions.ContainsKey (name)) + throw new Exception ("already defined: " + name); + termtypes[name] = new TermType (name, parser); + } + + public void DefType (Type type) + { + 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) + throw new Exception ("No \"name\" field: " + type); + Type[] types = new Type[] { typeof (Domain), typeof (XmlNode), + typeof (TermValue) }; + MethodInfo minfo = type.GetMethod ("Parser"); + if (minfo == null) + throw new Exception ("No \"Parser\" method: " + type); + } + + 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; + foreach (string a in aliases) + functions[(Symbol) a] = func; + } + + public void DefSpecial (Builtin builtin, string str, + 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.SpecialForm (builtin, name, + min_arg, max_arg); + functions[name] = func; + foreach (string a in aliases) + functions[(Symbol) a] = func; + } + + public void DefAlias (string alias, string str) + { + functions[(Symbol) alias] = functions[(Symbol) str]; + } + + public void Defun (Symbol name, Symbol[] args, Term[] body, + bool prototype) { - Name name = node.Attributes["id"]; Function func; - if (functions.TryGetValue (name, out func)) + if (termtypes.ContainsKey (name)) + throw new Exception ("already defined as termtype: " + name); + if (prototype || ! functions.TryGetValue (name, out func)) { - XmlNode args = node.FirstChild; - int nargs = args.Name == "args" ? args.ChildNodes.Count : 0; - - if (func.min_arg < nargs || func.max_arg > nargs) - throw new Exception ("Incompatible argument numbers to override: " - + name); - func.lambda.Set (node, this); - func.builtin = null; - } - else - { - func = new Function (name, node, this); + func = new Function.Lambda (this, name, args); functions[name] = func; - } + } + if (! prototype) + ((Function.Lambda) func).SetBody (body); } - internal Function GetFunc (Name name) + 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 (! functions.TryGetValue (name, out func)) + if (prototype || ! functions.TryGetValue (name, out func)) { - if (parent != null) - return parent.GetFunc (name); - throw new Exception ("Unknown function: " + name); + func = new Function.Lambda (this, node); + functions[name] = func; } - return func; + if (! prototype) + ((Function.Lambda) func).SetBody (this, node); } - public bool CopyFunc (Domain domain, Name name) + public void Defun (Function func) { - Function func = GetFunc (name); - - domain.functions[name] = func; - return true; + functions[func.name] = func; } - public void CopyFunc (Domain domain) + public void Defmacro (XmlNode node, bool prototype) { - foreach (KeyValuePair kv in functions) - domain.functions[kv.Key] = kv.Value; + 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); } - internal Variable GetVar (Name name) + public Variable Defvar (XmlNode node) { + Symbol name = node.Attributes[0].Value; + String desc; Variable vari; - if (! variables.TryGetValue (name, out vari)) - variables[name] = vari = new VarMisc (name, null); + node = node.FirstChild; + if (node != null && node.Name == Qdescription) + { + desc = node.InnerText; + node = node.NextSibling; + } + else + desc = null; + if (node != null) + { + Symbol type = node.Name; + XmlNodeList range_list = null; + int nranges = 0; + string val = node.InnerText; + + node = node.NextSibling; + if (node != null) + { + range_list = node.ChildNodes; + nranges = range_list.Count; + } + + if (type == Qinteger) + { + 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 nd = range_list[i]; + if (nd.Name == Qrange) + { + range[i * 2] + = parse_integer (nd.FirstChild.InnerText); + range[i * 2 + 1] + = parse_integer (nd.LastChild.InnerText); + } + else + { + range[i * 2] + = range[i * 2 + 1] + = parse_integer (nd.FirstChild.InnerText); + } + } + } + vari = DefvarInt (name, n, desc, range); + } + else if (type == Qstring) + { + string[] range = null; + if (range_list != null) + { + range = new string[nranges]; + for (int i = 0; i < nranges; i++) + range[i] = range_list[i].FirstChild.InnerText; + } + vari = DefvarStr (name, val, desc, range); + } + else if (type == Qsymbol) + { + Symbol[] range = null; + if (range_list != null) + { + range = new Symbol[nranges]; + for (int i = 0; i < nranges; i++) + range[i] = range_list[i].FirstChild.InnerText; + } + vari = DefvarSym (name, (Symbol) val, desc, range); + } + else + throw new Exception ("Unknown type: " + type); + } + else + { + if (variables.TryGetValue (name, out vari)) + vari = vari.Clone (this); + else + vari = new Variable (this, name, Zero); + variables[name] = vari; + } return vari; } - internal Variable GetVar (Xex e) + public Variable Defvar (Variable vari) { - if (! (e.val is Name)) - throw new Exception ("Not a symbol" + e.val); - return GetVar ((Name) e.val); + vari = vari.Clone (this); + variables[vari.name] = vari; + return vari; } - public override string ToString () + internal Variable Defvar (Symbol name) { - string str = "<(functions"; - foreach (KeyValuePair kv in functions) - str += " " + kv.Key; - str += ") (variabls"; - foreach (KeyValuePair kv in variables) - str += " " + kv.Key; - str += " " + bindings; - if (context != null) - str += " (" + context + ")"; - str += ">"; - return str; + Variable vari = new Variable (this, name, Zero); + variables[name] = vari; + return vari; } - } - - public delegate object Builtin (Xex[] args, Domain domain); - private static Domain basic = new Domain (); + 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; + } - internal static Function Fprogn; + public Variable DefvarSym (Symbol name, Symbol sym, string desc, + Symbol[] range) + { + Variable vari; - static Xex () + 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; + + if (! functions.TryGetValue (name, out func)) + throw new Exception ("Unknown function: " + name); + return func; + } + + public bool CopyFunc (Domain domain, Symbol name) + { + Function func = GetFunc (name); + + domain.functions[name] = func; + return true; + } + + public void CopyFunc (Domain domain) + { + foreach (KeyValuePair kv in functions) + domain.functions[kv.Key] = kv.Value; + } + + public Variable GetVar (Symbol name, bool create) + { + Variable vari; + + if (! variables.TryGetValue (name, out vari)) + { + if (! create) + return null; + variables[name] = vari = new Variable (this, name, Zero); + } + return vari; + } + + public override string ToString () + { + string str = "<(functions"; + foreach (KeyValuePair kv in functions) + str += " " + kv.Key; + str += ") (variabls"; + foreach (KeyValuePair kv in variables) + str += " " + kv.Value; + str += ")"; + if (bindings != null) + str += " " + bindings; + if (context != null) + str += " (" + context + ")"; + str += ">"; + return str; + } + + internal void DebugWrite (string fmt, params string[] arg) + { + if (debug_depth > depth) + { + for (int i = 0; i < depth; i++) + Console.Write (" "); + Console.WriteLine (fmt, arg); + } + } + + public object SaveValues () + { + Dictionary values = new Dictionary (); + + foreach (KeyValuePair kv in variables) + values[kv.Value] = kv.Value.Value.Clone (); + return values; + } + + public void RestoreValues (object values) + { + foreach (KeyValuePair kv + in (Dictionary) values) + kv.Key.Value = kv.Value; + } + } + + public delegate Term Builtin (Domain domain, Variable vari, Term[] args); + + private static Domain basic = new Domain ("basic"); + + static Xexpression () { - basic.Defun ("set", set_value, 2, 2, false); - basic.Defun ("=", set_value, 2, 2, false); - basic.Defun ("and", and, 1, -1, false); - basic.Defun ("&&", and, 1, -1, false); - basic.Defun ("or", or, 1, -1, false); - basic.Defun ("||", or, 1, -1, false); - basic.Defun ("not", not, 1, 1, false); - basic.Defun ("!", not, 1, 1, false); - basic.Defun ("+", add, 2, -1, false); - basic.Defun ("*", mul, 2, -1, false); - basic.Defun ("-", sub, 1, -1, false); - basic.Defun ("/", div, 2, -1, false); - basic.Defun ("%", mod, 2, 2, false); - basic.Defun ("|", logior, 2, -1, false); - basic.Defun ("&", logand, 2, -1, false); - basic.Defun ("+=", add_set, 2, -1, true); - basic.Defun ("*=", mul_set, 2, -1, true); - basic.Defun ("-=", sub_set, 2, -1, true); - basic.Defun ("/=", div_set, 2, -1, true); - basic.Defun ("%=", mod_set, 2, 2, true); - basic.Defun ("|=", logior_set, 2, -1, true); - basic.Defun ("&=", logand_set, 2, -1, true); - basic.Defun ("<<", lsh, 2, 2, false); - basic.Defun (">>", rsh, 2, 2, false); - basic.Defun ("<<=", lsh_set, 2, 2, true); - basic.Defun (">>=", rsh_set, 2, 2, true); - basic.Defun ("==", eq, 2, -1, false); - basic.Defun ("!=", noteq, 2, 2, false); - basic.Defun ("<", less_than, 2, -1, false); - basic.Defun ("<=", less_eq, 2, -1, false); - basic.Defun (">", greater_than, 2, -1, false); - basic.Defun (">=", greater_eq, 2, -1, false); - basic.Defun ("progn", progn_clause, 0, -1, true); - basic.Defun ("if", if_clause, 2, -1, true); - basic.Defun ("when", when_clause, 1, -1, true); - basic.Defun ("while", while_clause, 1, -1, true); - - Fprogn = basic.GetFunc (Nprogn); + basic.DefTerm ("funcall", Funcall.parser); + basic.DefTerm ("varref", Varref.parser); + basic.DefType (typeof (Funcall)); + + basic.DefSubr (Fset, "set", true, 1, 1, "="); + basic.DefSubr (Fnot, "not", false, 1, 1, "!"); + basic.DefSubr (Fadd, "add", true, 1, -1, "+"); + basic.DefSubr (Fmul, "mul", true, 1, -1, "*"); + basic.DefSubr (Fsub, "sub", true, 1, -1, "-"); + basic.DefSubr (Fdiv, "div", true, 1, -1, "/"); + basic.DefSubr (Fmod, "mod", true, 1, 2, "%"); + basic.DefSubr (Flogior, "logior", true, 1, -1, "|"); + basic.DefSubr (Flogand, "logand", true, 1, -1, "&"); + basic.DefSubr (Flsh, "lsh", true, 1, 2, "<<"); + basic.DefSubr (Frsh, "rsh", true, 1, 2, ">>"); + basic.DefSubr (Feq, "eq", false, 2, -1, "=="); + basic.DefSubr (Fnoteq, "noteq", false, 2, 2, "!="); + basic.DefSubr (Flt, "lt", false, 2, -1, "<"); + basic.DefSubr (Fle, "le", false, 2, -1, "<="); + basic.DefSubr (Fgt, "gt", false, 2, -1, ">"); + basic.DefSubr (Fge, "ge", false, 2, -1, ">="); + basic.DefSubr (Fappend, "append", true, 0, -1); + basic.DefSubr (Fconcat, "concat", true, 0, -1); + basic.DefSubr (Fnth, "nth", false, 2, 2); + basic.DefSubr (Fcopy, "copy", false, 1, 1); + basic.DefSubr (Fins, "ins", true, 2, 2); + basic.DefSubr (Fdel, "del", true, 2, 2); + 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); } - private static bool is_true (object val) + private static Term Fset (Domain domain, Variable vari, Term[] args) { - return (val is bool ? (bool) val - : val is int ? (int) val == 0 - : true); + vari.Value = args[0]; + return args[0]; } - private static object set_value (Xex[] args, Domain domain) + private static Term Fnot (Domain domain, Variable vari, Term[] args) { - Variable vari = domain.GetVar (args[0]); + return args[0].IsTrue ? Zero : One; + } - vari.Value = args[1].val; - return vari.val; + private static Term Fadd (Domain domain, Variable vari, Term[] args) + { + int n = vari == null ? 0 : vari.Value.Intval; + + foreach (Term arg in args) + n += arg.Intval; + return (vari == null ? new Term (n) : vari.SetValue (n)); } - private static object and (Xex[] args, Domain domain) + private static Term Fmul (Domain domain, Variable vari, Term[] args) { - foreach (Xex arg in args) - if (! is_true (arg.val)) - return false; - return true; + int n = vari == null ? 1 : vari.Value.Intval; + foreach (Term arg in args) + n *= arg.Intval; + return (vari == null ? new Term (n) : vari.SetValue (n)); } - private static object or (Xex[] args, Domain domain) + private static Term Fsub (Domain domain, Variable vari, Term[] args) { - foreach (Xex arg in args) - if (is_true (arg.val)) - return true; - return false; + int n, i; + + if (vari == null) + { + n = args[0].Intval; + i = 1; + } + else + { + n = vari.Value.Intval; + i = 0; + } + while (i < args.Length) + n -= args[i++].Intval; + return (vari == null ? new Term (n) : vari.SetValue (n)); } - private static object not (Xex[] args, Domain domain) + private static Term Fdiv (Domain domain, Variable vari, Term[] args) { - return ! is_true (args[0].val); + int n, i; + + if (vari == null) + { + n = args[0].Intval; + i = 1; + } + else + { + n = vari.Value.Intval; + i = 0; + } + while (i < args.Length) + n /= args[i++].Intval; + return (vari == null ? new Term (n) : vari.SetValue (n)); } - private static object add (Xex[] args, Domain domain) + private static Term Fmod (Domain domain, Variable vari, Term[] args) { - int n = 0; - foreach (Xex e in args) - n += (int) e.val; - return n; + int n = args[0].Intval % args[1].Intval; + + return (vari == null ? new Term (n) : vari.SetValue (n)); } - private static object mul (Xex[] args, Domain domain) - { - int n = 1; - foreach (Xex e in args) - n *= (int) e.val; - return n; - } + private static Term Flogior (Domain domain, Variable vari, Term[] args) + { + int n = vari == null ? 0 : vari.Value.Intval; + foreach (Term arg in args) + n |= arg.Intval; + return (vari == null ? new Term (n) : vari.SetValue (n)); + } - private static object sub (Xex[] args, Domain domain) - { - int n = (int) args[0].val; - if (args.Length == 1) - return - n; - for (int i = 1; i < args.Length; i++) - n -= (int) args[i].val; - return n; - } + private static Term Flogand (Domain domain, Variable vari, Term[] args) + { + int n, i; - private static object div (Xex[] args, Domain domain) - { - int n = (int) args[0].val; - for (int i = 1; i < args.Length; i++) - n /= (int) args[i].val; - return n; - } + if (vari == null) + { + n = args[0].Intval; + i = 1; + } + else + { + n = vari.Value.Intval; + i = 0; + } + while (i < args.Length) + n &= args[i++].Intval; + return (vari == null ? new Term (n) : vari.SetValue (n)); + } - private static object mod (Xex[] args, Domain domain) - { - return ((int) args[0].val % (int) args[1].val); - } + private static Term Flsh (Domain domain, Variable vari, Term[] args) + { + int n = args[0].Intval << args[1].Intval; + return (vari == null ? new Term (n) : vari.SetValue (n)); + } - private static object logior (Xex[] args, Domain domain) - { - int n = 0; - foreach (Xex e in args) - n |= (int) e.val; - return n; - } + private static Term Frsh (Domain domain, Variable vari, Term[] args) + { + int n = args[0].Intval >> args[1].Intval; + return (vari == null ? new Term (n) : vari.SetValue (n)); + } - private static object logand (Xex[] args, Domain domain) - { - int n = (int) args[0].val; - for (int i = 1; i < args.Length; i++) - n &= (int) args[i].val; - return n; - } + private static Term Feq (Domain domain, Variable vari, Term[] args) + { + Term o = args[0]; - private static object add_set (Xex[] args, Domain domain) - { - Variable vari = domain.GetVar (args[0]); - int n = (int) vari.val; + if (o.objval == null) + { + for (int i = 1; i < args.Length; i++) + if (args[i].objval != null || args[i].intval != o.intval) + return Zero; + } + else + { + for (int i = 1; i < args.Length; i++) + if (o.objval.Equals (args[i].objval)) + return Zero; + } + return One; + } - for (int i = 1; i < args.Length; i++) - n += (int) args[i].val; - vari.val = n; - return n; - } + private static Term Fnoteq (Domain domain, Variable vari, Term[] args) + { + return Feq (domain, vari, args); + } - private static object mul_set (Xex[] args, Domain domain) - { - Variable vari = domain.GetVar (args[0]); - int n = (int) vari.val; + private static Term Flt (Domain domain, Variable vari, Term[] args) + { + int n = args[0].Intval; - for (int i = 1; i < args.Length; i++) - n *= (int) args[i].val; - vari.val = n; - return n; - } + for (int i = 1; i < args.Length; i++) + { + int n1 = args[i].Intval; + if (n >= n1) + return Zero; + n = n1; + } + return One; + } - private static object sub_set (Xex[] args, Domain domain) - { - Variable vari = domain.GetVar (args[0]); - int n = (int) vari.val; + private static Term Fle (Domain domain, Variable vari, Term[] args) + { + int n = args[0].Intval; + for (int i = 1; i < args.Length; i++) + { + int n1 = args[i].Intval; + if (n > n1) + return Zero; + n = n1; + } + return One; + } - for (int i = 1; i < args.Length; i++) - n -= (int) args[i].val; - vari.val = n; - return n; - } + private static Term Fgt (Domain domain, Variable vari, Term[] args) + { + int n = args[0].Intval; + for (int i = 1; i < args.Length; i++) + { + int n1 = args[i].Intval; + if (n <= n1) + return Zero; + n = n1; + } + return One; + } - private static object div_set (Xex[] args, Domain domain) - { - Variable vari = domain.GetVar (args[0]); - int n = (int) vari.val; + private static Term Fge (Domain domain, Variable vari, Term[] args) + { + int n = args[0].Intval; + for (int i = 1; i < args.Length; i++) + { + int n1 = args[i].Intval; + if (n < n1) + return Zero; + n = n1; + } + return One; + } - for (int i = 1; i < args.Length; i++) - n /= (int) args[i].val; - vari.val = n; - return n; - } + private static Term Fappend (Domain domain, Variable vari, Term[] args) + { + List list; - private static object mod_set (Xex[] args, Domain domain) - { - Variable vari = domain.GetVar (args[0]); - int n = (int) vari.val; + if (vari == null) + list = new List (); + else + list = vari.Value.Listval; - for (int i = 1; i < args.Length; i++) - n %= (int) args[i].val; - vari.val = n; - return n; - } + foreach (Term arg in args) + { + if (arg.IsList) + list.AddRange ((List) arg.objval); + else + list.Add (arg); + } + if (vari == null) + { + Term result; + result.intval = 0; + result.objval = list; + return result; + } + return vari.Value; + } - private static object logior_set (Xex[] args, Domain domain) - { - Variable vari = domain.GetVar (args[0]); - int n = (int) vari.val; + private static Term Fconcat (Domain domain, Variable vari, Term[] args) + { + string str; - for (int i = 1; i < args.Length; i++) - n |= (int) args[i].val; - vari.val = n; - return n; - } + if (vari == null) + str = ""; + else + str = vari.Value.Strval; - private static object logand_set (Xex[] args, Domain domain) - { - Variable vari = domain.GetVar (args[0]); - int n = (int) vari.val; + foreach (Term arg in args) + { + if (arg.IsStr) + str += (string) arg.objval; + else if (arg.IsList) + foreach (Term term in (List) arg.objval) + str += (char) term.Intval; + else + str += (char) arg.Intval; + } - for (int i = 1; i < args.Length; i++) - n &= (int) args[i].val; - vari.val = n; - return n; - } + if (vari == null) + { + Term term; + term.intval = 0; + term.objval = str; + return term; + } + return vari.SetValue (str); + } - private static object lsh (Xex[] args, Domain domain) - { - return (int) args[0].val << (int) args[1].val; - } + private static Term Fnth (Domain domain, Variable vari, Term[] args) + { + Term result; - private static object lsh_set (Xex[] args, Domain domain) - { - Variable vari = domain.GetVar (args[0]); - int n = (int) vari.val; + if (args[1].IsStr) + { + result.intval = ((string) args[1].objval)[args[0].Intval]; + result.objval = null; + } + else if (args[1].IsList) + { + result = ((List) args[1].objval)[args[0].Intval]; + } + else + throw new Exception ("Term is not enumelable: " + args[1]); + return result; + } - n <<= (int) args[1].val; - vari.val = n; - return n; - } + private static Term Fcopy (Domain domain, Variable vari, Term[] args) + { + Term result; - private static object rsh (Xex[] args, Domain domain) - { - return (int) args[0].val >> (int) args[1].val; - } + result.intval = 0; + result.objval = new List (args[0].Listval); + return result; + } - private static object rsh_set (Xex[] args, Domain domain) - { - Variable vari = domain.GetVar (args[0]); - int n = (int) vari.val; + private static Term Fins (Domain domain, Variable vari, Term[] args) + { + Term term = vari.Value; - n >>= (int) args[1].val; - vari.val = n; - return n; - } + 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.Value); + return vari.Value; + } - private static object eq (Xex[] args, Domain domain) - { - int n = (int) args[0].val; + private static Term Fdel (Domain domain, Variable vari, Term[] args) + { + 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.Value); + return vari.Value; + } - for (int i = 1; i < args.Length; i++) - if (n != (int) args[i].val) - return false; - return true; - } + private static Term Fand (Domain domain, Variable vari, Term[] args) + { + foreach (Term arg in args) + if (! arg.Eval (domain).IsTrue) + return Zero; + return One; + } - private static object noteq (Xex[] args, Domain domain) - { - return ((int) args[0].val != (int) args[1].val); - } + private static Term For (Domain domain, Variable vari, Term[] args) + { + foreach (Term arg in args) + if (arg.Eval (domain).IsTrue) + return One; + return Zero; + } - private static object less_than (Xex[] args, Domain domain) - { - int n = (int) args[0].val; + private static Term Feval (Domain domain, Variable vari, Term[] args) + { + return (args[0].Eval (domain)); + } - for (int i = 1; i < args.Length; i++) - { - int n1 = (int) args[i].val; - if (n >= n1) - return false; - n = n1; - } - return true; - } + private static Term Fprogn (Domain domain, Variable vari, Term[] args) + { + Term result = One; - private static object less_eq (Xex[] args, Domain domain) - { - int n = (int) args[0].val; - for (int i = 1; i < args.Length; i++) - { - int n1 = (int) args[i].val; - if (n > n1) - return false; - n = n1; - } - return true; - } + foreach (Term arg in args) + result = arg.Eval (domain); + return result; + } - private static object greater_than (Xex[] args, Domain domain) - { - int n = (int) args[0].val; - for (int i = 1; i < args.Length; i++) - { - int n1 = (int) args[i].val; - if (n <= n1) - return false; - n = n1; - } - return true; + private static Term Fif (Domain domain, Variable vari, Term[] args) + { + if (args[0].Eval (domain).IsTrue) + return args[1].Eval (domain); + if (args.Length == 2) + return Zero; + return args[2].Eval (domain); + } + + private static Term Fwhen (Domain domain, Variable vari, Term[] args) + { + if (! args[0].Eval (domain).IsTrue) + return Zero; + Term result = One; + for (int i = 1; i < args.Length; i++) + result = args[i].Eval (domain); + return result; + } + + private static Term Freturn (Domain domain, Variable vari, Term[] args) + { + domain.ThrowReturn (); + return args.Length == 0 ? Zero : args[0]; + } + + private static Term Fbreak (Domain domain, Variable vari, Term[] args) + { + domain.ThrowBreak (); + return args.Length == 0 ? Zero : args[0]; + } + + private static Term Floop (Domain domain, Variable vari, Term[] args) + { + Term result = Zero; + try { + domain.Catch (CatchTag.Break); + while (! domain.Thrown) + foreach (Term arg in args) + { + result = arg.Eval (domain); + if (domain.Thrown) + return result; + } + } finally { + domain.Uncatch (); } + return result; + } - private static object greater_eq (Xex[] args, Domain domain) - { - int n = (int) args[0].val; - for (int i = 1; i < args.Length; i++) - { - int n1 = (int) args[i].val; - if (n < n1) - return false; - n = n1; - } - return true; + private static Term Fwhile (Domain domain, Variable vari, Term[] args) + { + Term result = Zero; + try { + domain.Catch (CatchTag.Break); + while (! domain.Thrown && args[0].Eval (domain).IsTrue) + for (int i = 1; i < args.Length; i++) + { + result = args[i].Eval (domain); + if (domain.Thrown) + return result; + } + } finally { + domain.Uncatch (); } + return result; + } - private static object progn_clause (Xex[] args, Domain domain) - { - object result = true; + private static Term Fcond (Domain domain, Variable vari, Term[] args) + { + foreach (Term arg in args) + { + List list = arg.Listval; + Term result = list[0].Eval (domain); - foreach (Xex e in args) - result = e.Eval (domain); - return result; - } + if (result.IsTrue) + { + for (int i = 1; i < list.Count; i++) + { + domain.depth++; + result = list[i].Eval (domain); + domain.depth--; + if (domain.Thrown) + return result; + } + return result; + } + } + return Zero; + } - private static object if_clause (Xex[] args, Domain domain) - { - object result; + private static Term Fforeach (Domain domain, Variable vari, + Term[] args) + { + Term result = args[0].Eval (domain); + if (domain.Thrown) + return result; + List list = result.Listval; + Bindings current = domain.bindings; - if (is_true (args[0].Eval (domain))) - result = args[1].Eval (domain); - else + try { + domain.Catch (CatchTag.Break); + foreach (Term term in list) { - result = false; - for (int i = 2; i < args.Length; i++) - result = args[i].Eval (domain); + domain.Bind (vari, term); + try { + for (int i = 1; i < args.Length; i++) + { + result = args[i].Eval (domain); + if (domain.Thrown) + return result; + } + } finally { + domain.UnboundTo (current); + } } - return result; + } finally { + domain.Uncatch (); } + return result; + } - private static object when_clause (Xex[] args, Domain domain) - { - if (! is_true (args[0].Eval (domain))) - return false; + private static Term Fquote (Domain domain, Variable vari, Term[] args) + { + return new Term (args[0]); + } - object result = true; - for (int i = 1; i < args.Length; i++) - result = args[i].Eval (domain); - return result; + private static Term Ftype (Domain domain, Variable vari, Term[] args) + { + if (args[0].IsInt) + return TermInt; + if (args[0].IsStr) + return TermStr; + if (args[0].IsSymbol) + return TermSymbol; + if (args[0].IsList) + return TermList; + return TermTerm; + } + + 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; + } + + public static Term Fthrow (Domain domain, Variable vari, Term[] args) + { + domain.ThrowTag (new CatchTag (args[0].Symval)); + return (args.Length == 1 ? Zero : args[1]); + } + + public delegate TermValue TermParser (Domain domain, XmlNode node); + + public class TermType + { + private readonly Symbol name; + private readonly TermParser parser; - private static object while_clause (Xex[] args, Domain domain) + public TermType (Symbol name, TermParser parser) { - while (is_true (args[0].Eval (domain))) - for (int i = 1; i < args.Length; i++) - args[i].Eval (domain); - return false; + this.name = name; + this.parser = parser; } - // FUNCALL: function != null - // VARREF: function == null, args[0] = DIRECT-SYMBOL - // DIRECT: function == null, args == null + public Symbol Name { get { return name; } } + internal TermParser Parser { get { return parser; } } + } + + public abstract class TermValue + { + public virtual Term Eval (Domain domain) { return new Term (this); } + public virtual TermValue Clone () { return this; } + } + + private class Varref : TermValue + { + private Symbol vname; + private Variable vari; - private Function function; - private Xex[] args; - private object val; + public Varref (Symbol vname) { this.vname = vname; } - public Xex[] Args { get { return args; } } - public object Val { get { return val; } } + public override Term Eval (Domain domain) + { + if (vari == null || vari.domain != domain) + vari = domain.GetVar (vname, true); + return vari.Value; + } - private Xex () { } + internal static TermValue parser (Domain domain, XmlNode node) + { + return new Varref ((Symbol) node.Attributes[Qvname].Value); + } - private Xex (object val) - { - this.val = val; + public override string ToString () + { + return ""; + } } - private static Xex macro_expand (Xex[] bindings, Name[] args, Xex e) + private class Funcall : TermValue { - Xex xex; + private static Symbol name = "funcall"; - if (e.function != null) - { - xex = new Xex (); - xex.function = e.function; - xex.args = new Xex[e.args.Length]; - for (int i = e.args.Length - 1; i >= 0; i--) - xex.args[i] = macro_expand (bindings, args, e.args[i]); - } - else if (e.args != null) + public static Symbol Name { get { return name; } } + + internal Function func; + internal Variable vari; + internal Term[] args; + + public Funcall (Function func, Variable vari, Term[] args) { - xex = new Xex (); - Name name = (Name) e.args[0].val; - for (int i = args.Length - 1; i >= 0; i--) - if (args[i] == name) - return bindings[i]; - xex.function = null; - xex.args = new Xex[1]; - xex.args[0] = e.args[0]; + if (args != null) + { + 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); + } + this.func = func; + this.vari = vari; + this.args = args; } - else + + public static TermValue Parser (Domain domain, XmlNode node) + { + return null; + } + + internal static TermValue parser (Domain domain, XmlNode node) { - xex = e; + Symbol fname = node.Name; + XmlAttribute attr; + + 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); } - return xex; + + public override Term Eval (Domain domain) + { + domain.DebugWrite (ToString ()); + domain.depth++; + Term result = func.Call (domain, vari, args); + domain.depth--; + domain.DebugWrite ("=> {0}", result.ToString ()); + return result; + } + + public override TermValue Clone () + { + return new Funcall (func, vari, args); + } + + public override string ToString () + { + string str = "<" + func.name; + if (vari != null) + str += " vname=\"" + vari.name + "\""; + if (args == null) + return str + "/>"; + str += ">"; + if (func is Function.SpecialForm) + { + for (int i = 0; i < args.Length; i++) + str += "."; + } + else + foreach (Term e in args) + str += e; + return (str + ""); + } } - // EXPR = SYMBOL | MTEXT | INTEGER | FUNCALL | PROGN - // FUNCALL = '(' SYMBOL EXPR* ')' - // PROGN = '(' EXPR * ')' - public Xex (XmlNode node, Domain domain) + public struct Term { - Name name = node.Name; - - if (name == Nconst) + public int intval; + public object objval; + + // ... + public Term (int i) { intval = i; objval = null; } + // ... + public Term (Symbol name) { intval = 0; objval = name; } + // ... + public Term (string str) { intval = 0; objval = str; } + // ... + public Term (List list) { intval = 0; objval = list; } + + public Term (Term term) { intval = term.intval; objval = term.objval; } + public Term (TermValue obj) { intval = 0; objval = obj; } + + public Term (Domain domain, XmlNode node) { - Name type = node.Attributes["type"].Value; - - if (type == Ninteger) - val = parse_integer (node.InnerText); - else if (type == Nstring) - val = node.InnerText; - else if (type == Nsymbol) - val = (Name) node.InnerText; - else if (type == Nboolean) - val = node.InnerText == "true"; - else if (type == Nlist) + Symbol name = node.Name; + + if (name == Qinteger) { - List list = new List (); - for (XmlNode n = node.FirstChild; n != null; n = n.NextSibling) - list.Add (new Xex (n, domain)); - val = list; + intval = parse_integer (node.InnerText); + objval = null; } else - throw new Exception ("Unknown type: " + type); + { + intval = 0; + if (name == Qsymbol) + objval = (Symbol) node.InnerText; + else if (name == Qstring) + objval = node.InnerText.Clone (); + else if (name == Qlist) + { + List list = new List (); + for (node = node.FirstChild; node != null; + node = node.NextSibling) + list.Add (new Term (domain, node)); + objval = list; + } + else + { + TermType term_type; + + if (domain.termtypes.TryGetValue (name, out term_type)) + objval = term_type.Parser (domain, node); + else + { + 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; + } + } + } } - else if (name == Nvariable) + + // + public Term (Domain domain, Symbol vname) { - args = new Xex[1]; - args[0] = new Xex (node.Attributes[0]); + intval = 0; + objval = new Varref (vname); } - else + + // ... + public Term (Domain domain, Symbol fname, Term[] args) + : this (domain, fname, Qnull, args) { } + + // ... + public Term (Domain domain, Symbol fname, Symbol vname, Term[] args) { - bool is_macro = false; + intval = 0; - if (name == Nfuncall) + 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) { - name = node.Attributes[0].Value; - if (Nmname == node.Attributes[0].Name) - is_macro = true; + Term result = funcall.Eval (domain); + intval = result.intval; + objval = result.objval; } - function = domain.GetFunc (name); + else + objval = funcall; + } - XmlNodeList nlist = node.ChildNodes; - int nargs = nlist.Count; + public object Objval { + get { + if (objval == null) + throw new Exception ("term is an integer: " + this); + return objval; + } + } - if (nargs < function.min_arg - || (function.max_arg >= 0 && nargs > function.max_arg)) - throw new Exception ("Invalid number of arguments to: " - + name + " " + nargs); - args = new Xex[nargs]; - for (int i = 0; i < nargs; i++) - args[i] = new Xex (nlist[i]); + public int Intval { + get { + if (objval != null) + throw new Exception ("term is not integer: " + this); + return intval; + } + } - if (is_macro) - { - Function.Lambda lambda = function.lambda; - Xex[] body = lambda.body; - int len = body.Length; - Xex[] newargs = new Xex[len]; - - for (int i = 0; i < len; i++) - newargs[i] = macro_expand (args, lambda.args, body[i]); - function = Fprogn; - args = newargs; - } + public string Strval { + get { + if (! IsStr) + throw new Exception ("term is not string: " + this); + return (string) objval; } + } + + public string Symval { + get { + if (! IsSymbol) + throw new Exception ("term is not symbol: " + this); + return (Symbol) objval; + } + } + + public List Listval { + get { + if (! IsList) + throw new Exception ("term is not list: " + this); + return (List) objval; + } + } + + public bool IsTrue { + get { + return (objval == null + ? (intval != 0) + : objval is List + ? (((List) objval).Count != 0) + : 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 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); + } + + public Term Clone () + { + if (objval == null || objval is Symbol || objval is string) + return this; + if (objval is List) + { + List list = new List (); + list.InsertRange (0, ((List) objval)); + return new Term (list); + } + return new Term (((TermValue) objval).Clone ()); + } + + public override string ToString () + { + string str; + + if (objval == null) + str = "" + intval + ""; + else if (objval is Symbol) + str = "" + objval + ""; + else if (objval is string) + str = "" + objval + ""; + else if (objval is List) + { + str = ""; + foreach (Term e in (List) objval) + str += e; + str += ""; + } + else if (objval is Term) + str = "" + objval + ""; + else if (objval is TermValue) + str = ((TermValue) objval).ToString (); + else + throw new Exception ("invalid Term object: " + objval); + return str; + } } - private int parse_integer (string str) + static private Term Zero = new Term (0); + static private Term One = new Term (1); + 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) { int len = str.Length; bool negative = false; if (len <= 1) - return (len == 0 ? 0 : str[0]); + return (len == 0 ? 0 : str[0] - '0'); int c = str[0]; int i; - if (c == '0' && str[1] == 'x') + if (c == '?') + return str[1]; + if ((c == '0' || c == '#') && str[1] == 'x') { i = 0; for (int idx = 2; idx < len; idx++) @@ -979,7 +2025,7 @@ namespace System.Xml.Expression if (c < '0') break; else if (c <= '9') - i = i * 16 + c; + i = i * 16 + (c - '0'); else if (c < 'A') break; else if (c <= 'F') @@ -995,7 +2041,7 @@ namespace System.Xml.Expression } if (c == '-') negative = true; - i = c; + i = c - '0'; for (int idx = 1; idx < len; idx++) { c = str[idx]; @@ -1006,47 +2052,99 @@ namespace System.Xml.Expression return negative ? - i : i; } - public object Eval (Domain domain) + private Term[] terms; + + public static Term[] ParseTerms (Domain domain, XmlNode node) { - if (function == null) + int nterms = 0; + for (XmlNode n = node; n != null; n = n.NextSibling) + if (n.NodeType == XmlNodeType.Element) + { + 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 + 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 == 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); + } + return terms; + } + + public static Term Eval (Domain domain, Term[] terms) + { + Term result = new Term (0); + foreach (Term term in terms) { - if (args != null) - { - Variable vari = domain.GetVar ((Name) args[0].val); - val = vari.val; - } - return val; + result = term; + if (result.Objval is Funcall) + while ((result = result.Eval (domain)).Objval is Funcall); } - else - val = function.Call (args, domain); - return val; + return result; } - public override string ToString () + + public Xexpression (Domain domain, XmlNode node) { - string str; + terms = ParseTerms (domain, node); + } - if (function != null) - { - str = "(" + function.name; - if (args != null) - foreach (Xex e in args) - str += " " + e.ToString (); - str += ")"; - } - else if (args != null) + public Xexpression (Domain domain, string url) + { + XmlDocument doc = new XmlDocument (Symbol.NameTable); + XmlNode node; + + using (XmlTextReader reader = new XmlTextReader (url, doc.NameTable)) { - str = (string) args[0].val; + do { + reader.Read (); + } while (reader.NodeType != XmlNodeType.None + && (reader.NodeType != XmlNodeType.Element + || reader.Name != Qexpr)); + if (reader.NodeType == XmlNodeType.None) + throw new Exception ("Node not found"); + node = doc.ReadNode (reader); } - else if (val != null) - { - if (val is string) - str = "\"" + ((string) val) + "\""; - else - str = val.ToString (); - } - else - str = "()"; + terms = ParseTerms (domain, node.FirstChild); + } + + public Term Eval (Domain domain) + { + Term result = Zero; + + domain.depth = 0; + try { + domain.Catch (CatchTag.Return); + foreach (Term term in terms) + { + result = term.Eval (domain); + if (domain.Thrown) + return result; + } + } finally { + domain.Uncatch (); + } + return result; + } + + public override string ToString () + { + string str = ""; + for (int i = 0; i < terms.Length; i++) + str += terms[i]; return str; } }