+ 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<Term> rest = new List<Term> ();
+
+ 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;
+ }
+ }
+