namespace System.Xml
{
+ /// <summary>
+ /// Static class to provide XmlExpression loader and evaluator.
+ /// </summary>
public static class Xexpression
{
- private static int trace_depth = 0;
-
- public static int TraceDepth {
- get { return trace_depth; }
- set { trace_depth = value; }
- }
-
+ /// <summary>
+ /// Exception thrown while loading and evaluating XmlExpression.
+ /// </summary>
public class Error : Exception
{
private readonly Symbol name;
string str = (InnerException != null ? InnerException.ToString ()
: base.ToString ()) + "\n" + "Xexpression:" + name + "\n";
if (node != null)
- str += " at " + node.ParentNode.OuterXml + "\n";
+ str += " at " + node.OuterXml + "\n";
if (stack != null)
{
str += "Call stack: ";
public static Symbol VariableRangeConflict = "variable-range-conflict";
public static Symbol VariableWrongRange = "variable-wrong-range";
public static Symbol VariableWrongValue = "variable-wrong-value";
+
public static Symbol UnknownFunction = "unknown-function";
public static Symbol MacroExpansionError = "macro-expansion-error";
public static Symbol NoVariableName = "no-variable-anme";
internal void ThrowSymbol (Term tag)
{
+ int i = catch_count;
foreach (CatchTag elt in catch_stack)
{
- catch_count--;
+ i--;
if (elt.Tag.Matches (tag))
- return;
+ {
+ catch_count = i;
+ return;
+ }
}
throw new Error (Error.UncaughtThrow,
"No corresponding catch: {0}", tag);
internal Variable Defvar (Symbol name)
{
- Variable vari = new Variable (this, name, Zero);
- variables[name] = vari;
+ Variable vari;
+
+ if (variables.TryGetValue (name, out vari))
+ {
+ Variable.Typed typed = vari as Variable.Typed;
+ if (typed != null)
+ throw new Error (Error.VariableTypeConflict,
+ "Not a non-typed variable: {0}", name);
+ }
+ else
+ {
+ vari = new Variable (this, name, Zero);
+ variables[name] = vari;
+ }
return vari;
}
domain.functions[kv.Key] = kv.Value;
}
- public Variable GetVar (Symbol name)
+ public Variable GetVarCreate (Symbol name)
{
Variable vari;
return vari;
}
+ public Variable GetVar (Symbol name)
+ {
+ Variable vari;
+
+ if (! variables.TryGetValue (name, out vari))
+ return null;
+ return vari;
+ }
+
public override string ToString ()
{
string str = "<(functions";
private static Term Fand (Domain domain, Variable vari, Term[] args)
{
foreach (Term arg in args)
- if (! arg.Eval (domain).IsTrue)
- return Zero;
+ {
+ Term result = arg.Eval (domain);
+ if (domain.Thrown ())
+ result;
+ if (! result.IsTrue)
+ return Zero;
+ }
return One;
}
private static Term For (Domain domain, Variable vari, Term[] args)
{
foreach (Term arg in args)
- if (arg.Eval (domain).IsTrue)
- return One;
+ {
+ Term result = arg.Eval (domain);
+ if (domain.Thrown ())
+ return result;
+ if (result.IsTrue)
+ return One;
+ }
return Zero;
}
Term result = One;
foreach (Term arg in args)
- result = arg.Eval (domain);
+ {
+ result = arg.Eval (domain);
+ if (domain.Thrown ())
+ return result;
+ }
return result;
}
private static Term Fif (Domain domain, Variable vari, Term[] args)
{
- if (args[0].Eval (domain).IsTrue)
+ Term result = args[0].Eval (domain);
+
+ if (domain.Thrown)
+ return result;
+ if (result.IsTrue)
return args[1].Eval (domain);
if (args.Length == 2)
return Zero;
private static Term Fwhen (Domain domain, Variable vari, Term[] args)
{
- if (! args[0].Eval (domain).IsTrue)
+ Term result = args[0].Eval (domain);
+
+ if (domain.Thrown)
+ return result;
+ if (! result.IsTrue)
return Zero;
- Term result = One;
+ result = One;
for (int i = 1; i < args.Length; i++)
- result = args[i].Eval (domain);
+ {
+ result = args[i].Eval (domain);
+ if (domain.Thrown)
+ return result;
+ }
return result;
}
{
result = terms[i].Eval (domain);
if (domain.Thrown (out caught))
- break;
+ return result;
}
return result;
}
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 virtual string ToString (bool detail) { return ToString (); }
}
private class Varref : TermValue
public override Term Eval (Domain domain)
{
if (vari == null || vari.domain != domain)
- vari = domain.GetVar (vname);
+ vari = domain.GetVarCreate (vname);
return vari.Value;
}
{
private static Symbol name = "funcall";
public static Symbol Name { get { return name; } }
+ private static Term[] null_args = new Term[0];
internal Function func;
internal Variable vari;
public Funcall (Function func, Variable vari, Term[] args)
{
+ if (args == null)
+ args = null_args;
int nargs = args.Length;
-
if (nargs < func.min_args
|| (func.max_args >= 0 && nargs > func.max_args))
throw new Error (Error.WrongArgument,
Function func = domain.GetFunc (fname);
Variable vari;
attr = node.Attributes[Qvname];
- vari = attr == null ? null : domain.GetVar (attr.Value);
+ vari = attr == null ? null : domain.GetVarCreate (attr.Value);
XmlNodeList nlist = node.ChildNodes;
int nargs = nlist.Count;
Term[] args = new Term[nargs];
public override string ToString () { return str; }
}
+ /// <summary> Structure of term object.</summary>
public struct Term
{
- public int intval;
- public object objval;
+ internal int intval;
+ internal object objval;
- // <integer>...</integer>
+ /// <summary>Create an integer term.</summary>
+ /// <param name='i'>Integer value of the term.</param>
+ /// <returns>An integer term.</returns>
+ /// <remarks>Create an integer term that has the integer value
+ /// specified by <paramref name="i"/>. This is an constant
+ /// term; i.e. the integer value never changes.</remarks>
public Term (int i) { intval = i; objval = null; }
- // <symbol>...</symbol>
+
+ /// <summary>Create a symbol term.</summary>
+ /// <param name='name'>Symbol value of the term.</param>
+ /// <returns>A symbol term.</returns>
+ /// <remarks>Create a symbol term that has the symbol value
+ /// specified by <paramref name="name"/>. This is an constant
+ /// term; i.e. the symbol value never changes. It is evaluated
+ /// to itself.</remarks>
public Term (Symbol name) { intval = 0; objval = name; }
- // <string>...</string>
+
+ /// <summary>Create a string term.</summary>
+ /// <param name='str'>String value of the term.</param>
+ /// <returns>A string term.</returns>
+ /// <remarks>Create a string term that has the string value
+ /// specified by <paramref name="str"/>. It is evaluated to
+ /// itself. The string value can be modified by "ins", "del",
+ /// and "concat" functions.</remarks>
public Term (string str) { intval = 0; objval = new Str (str); }
// <list>...</list>
+
+ /// <summary>Create a list term.</summary>
+ /// <param name='list'>List value of the term.</param>
+ /// <returns>A list term.</returns>
+ /// <remarks>Create a list term that has the list value
+ /// specified by <paramref name="list"/>. It is evaluated to
+ /// itself. The list value can be modified by "ins", "del", and
+ /// "append" functions.</remarks>
public Term (List<Term> list) { intval = 0; objval = list; }
// <error ename="ERROR-NAME">ERROR-MESSASGE</error>
+
+ /// <summary>Create an error term.</summary>
+ /// <param name='name'>Name of the error.</param>
+ /// <param name='message'>Error message.</param>
+ /// <returns>An error term.</returns>
+ /// <remarks>Create an error term whose error name is <paramref
+ /// name="name"/> and error message is <paramref
+ /// name="message"/>. It is evaluated to itself.</remarks>
public Term (Symbol name, string message)
{
intval = 0;
objval = new ErrorTerm (name, message);
}
- public Term (Str str) { intval = 0; objval = str; }
- public Term (TermValue obj) { intval = 0; objval = obj; }
+ /// <summary>Create a term of a specific value</summary>
+ /// <param name='val'>Value of the term.</param>
+ /// <returns>A term.</returns>
+ /// <remarks>Create a term whose value is <paramref name="val">.
+ /// It is evaluated to a term that is returned by "Eval" method
+ /// of <paramref name="val">.</remarks>
+ public Term (TermValue val) { intval = 0; objval = val; }
+
+ internal Term (Str str) { intval = 0; objval = str; }
- // <varref vname="VNAME"/>
+ /// <summary>Create a varref term.</summary>
+ /// <param name='domain'>Domain to create the term in.</param>
+ /// <param name='vname'>Name of the referred variable.</param>
+ /// <returns>A varref term.</returns>
+ /// <remarks>Create a varref term that is evaluated to the value
+ /// of the referring variable.</remarks>
public Term (Domain domain, Symbol vname)
{
intval = 0;
objval = new Varref (vname);
}
- // <funcall fname="FNAME">...</funcall>
+ /// <summary>Create a funcall term.</summary>
+ /// <param name='domain'>Domain to create the term in.</param>
+ /// <param name='fname'>Name of the calling function.</param>
+ /// <param name='args'>Array of terms that are given to the
+ /// function as arguments.</param>
+ /// <returns>A funcall term.</returns>
+ /// <remarks>Create a funcall term that is evaluated to a term
+ /// returned by the function <paramref name="fname"> when called
+ /// with <paramref name="args">.<remarks>
public Term (Domain domain, Symbol fname, Term[] args)
: this (domain, fname, Qnull, args) { }
intval = 0;
Function func = domain.GetFunc (fname);
- Variable vari = vname == Qnull ? null : domain.GetVar (vname);
+ Variable vari = vname == Qnull ? null : domain.GetVarCreate(vname);
Funcall funcall = new Funcall (func, vari, args);
if (func is Function.Macro)
{
return args;
}
- public static Symbol parse_defun_head (Domain domain, XmlNode node)
+ private static Symbol parse_defun_head (Domain domain, XmlNode node)
{
Symbol name = node.Attributes[Qfname].Value;
int min_args, max_args;
return name;
}
- public static void parse_defun_body (Domain domain, XmlNode node)
+ private static void parse_defun_body (Domain domain, XmlNode node)
{
bool is_defun = node.Name == Qdefun;
Symbol name = node.Attributes[Qfname].Value;
Function func = domain.GetFunc (name);
for (node = node.FirstChild; node != null; node = node.NextSibling)
- if (node.Name != Qdescription
- && node.Name != Qargs)
+ if (node.Name != Qdescription && node.Name != Qargs)
break;
+ Console.WriteLine ("found body " + node.Name);
+
Term[] body = Parse (domain, node, null);
if (is_defun)
((Function.Lambda) func).SetBody (body);
}
}
- private static bool default_stop (XmlNode n) { return n == null; }
-
- public delegate bool ParseStop (XmlNode node);
+ /// <summary>Parse a node and the following siblings as "term"s in a
+ /// specific domain.</summary>
+ /// <param name='domain'></param>
+ /// <param name='start'></param>
+ /// <param name='stop'></param>
+ /// <returns>Array of terms.</returns>
- public static Term[] Parse (Domain domain, XmlNode node, ParseStop stop)
+ public static Term[] Parse (Domain domain, XmlNode start, XmlNode stop)
{
- if (stop == null)
- stop = default_stop;
-
XmlNode n;
- for (n = node; ! stop (n); n = n.NextSibling)
+ for (n = start; n != stop && n != null; n = n.NextSibling)
if (n.NodeType == XmlNodeType.Element
&& (n.Name == Qdefun || n.Name == Qdefmacro))
{
parse_defun_head (domain, n);
} catch (Error e) {
if (e.Node == null)
- e.Node = node;
+ e.Node = n;
throw e;
} catch (Exception e) {
- throw new Error (Error.UnknownError, node, e, "Parsing error");
+ throw new Error (Error.UnknownError, n, e, "Parsing error");
}
}
List<Term> terms = new List<Term> ();
- for (; node != n; node = node.NextSibling)
- if (node.NodeType == XmlNodeType.Element)
+ for (; start != n; start = start.NextSibling)
+ if (start.NodeType == XmlNodeType.Element)
{
try {
- if (node.Name == Qdefun || node.Name == Qdefmacro)
- parse_defun_body (domain, node);
- else if (node.Name == Qdefvar)
- parse_defvar (domain, node);
+ if (start.Name == Qdefun || start.Name == Qdefmacro)
+ parse_defun_body (domain, start);
+ else if (start.Name == Qdefvar)
+ parse_defvar (domain, start);
else
- terms.Add (Parse (domain, node));
+ terms.Add (Parse (domain, start));
} catch (Error e) {
if (e.Node == null)
- e.Node = node;
+ e.Node = start;
throw e;
} catch (Exception e) {
- throw new Error (Error.UnknownError, node, e, "Parsing error");
+ throw new Error (Error.UnknownError, start, e, "Parsing error");
}
}
return terms.ToArray ();
XmlDocument doc = new XmlDocument (Symbol.NameTable);
XmlNode node;
- using (XmlTextReader reader = new XmlTextReader (url, doc.NameTable))
+ using (XmlTextReader reader = new XmlTextReader (url, Symbol.NameTable))
{
+ reader.WhitespaceHandling = WhitespaceHandling.None;
do {
reader.Read ();
} while (reader.NodeType != XmlNodeType.None
return Parse (domain, node.FirstChild, null);
}
+ /// <summary>Evaluate a term in a specific domain.</summary>
+ /// <param name='domain'>Domain to evaluate the term in.</param>
+ /// <param name='term'>The term to evaluate.</param>
+ /// <returns>The result of evaluating the <paramref
+ /// name="term"/>.</returns>
+ public static Term Eval (Domain domain, Term term)
+ {
+ return Eval (domain, new Term[] { term });
+ }
+
+ /// <summary>Evaluate terms in a specific domain.</summary>
+ /// <param name='domain'>Domain to evaluate terms in.</param>
+ /// <param name='terms'>Array of terms to evaluate.</param>
+ /// <returns>The result of evaluating the last term of <paramref
+ /// name="terms"/>.</returns>
public static Term Eval (Domain domain, Term[] terms)
{
Term result = Zero;
throw new Error (Error.UnknownError, null, e, "Runtime error");
}
}
+
+ // TRACING
+
+ private static int trace_depth = 0;
+
+ /// <value> TraceDepth specifies the minimum depth of call stack
+ /// to suppress tracing. 0 means no tracing. </value>
+ public static int TraceDepth {
+ get { return trace_depth; }
+ set { trace_depth = value; }
+ }
}
}