-// -* coding: utf-8; -*
+// xex.js -- Xex (XML Expression) interpreter
+// Copyright (C) 2010
+// National Institute of Advanced Industrial Science and Technology (AIST)
+// Registration Number H15PRO112
-var XEX = {};
+// This file is part of the m17n database; a sub-part of the m17n
+// library.
-XEX.Variable = function (domain, name, val)
+// The m17n library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public License
+// as published by the Free Software Foundation; either version 2.1 of
+// the License, or (at your option) any later version.
+
+// The m17n library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+
+// You should have received a copy of the GNU Lesser General Public
+// License along with the m17n library; if not, write to the Free
+// Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+// Please note that the code is not yet matured.
+
+var Xex = {};
+
+(function () { // Logging
+ // The logging node containing tracing information.
+ var log = null;
+ // Number of lines.
+ var lines;
+ // Style properties of the logging node.
+ var styles = { border: '1px solid black',
+ font: 'normal normal normal small monospace',
+ width: '600px',
+ minHeight: '300px',
+ maxHeight: '300px',
+ overflow: 'auto' };
+
+ // Toggle logging on and off. PARENT if non-null specifies the
+ // parent of the log node. The log node is appended to PARENT.
+ // If PARENT is null, 'body' node is assumed.
+ Xex.LogToggle = function (parent)
+ {
+ if (log)
+ {
+ log.parentNode.removeChild (log);
+ log = null;
+ return;
+ }
+ if (! parent)
+ parent = document.getElementsByTagName ('body')[0];
+ log = document.createElement ('ol');
+ for (var prop in styles)
+ log.style[prop] = styles[prop];
+ parent.appendChild (log);
+ lines = 0;
+ return log;
+ }
+
+ // Log ARG (string). INDENT if specified is a number of columns to
+ // indent. If INDENT is -1, ARG is appended to the last log.
+ Xex.Log = function (arg, indent)
+ {
+ if (! log)
+ return;
+ if (! arg)
+ {
+ while (log.childNodes.length > 0)
+ log.removeChild (log.firstChild);
+ lines = 0;
+ }
+ else
+ {
+ var node;
+ if (indent == -1)
+ log.lastChild.innerText += arg;
+ else
+ {
+ lines++;
+ if (lines >= 256)
+ {
+ node = log.firstElement ();
+ log.start = lines - 254;
+ }
+ else
+ node = document.createElement ('li');
+ if (indent != undefined)
+ node.style.textIndent = (indent + 1) + 'em';
+ else
+ node.style.textIndent = '0px';
+ node.innerText = arg;
+ log.appendChild (node);
+ log.scrollTop = log.scrollHeight;
+ }
+ }
+ }
+}) ();
+
+Xex.Error = {
+ UnknownError: "unknown-error",
+ WrongArgument: "wrong-argument",
+ // Load time errors.
+ InvalidInteger: "invalid-integer",
+ TermTypeInvalid: "term-type-invalid",
+ FunctionConflict: "function-conflict",
+ VariableTypeConflict: "variable-type-conflict",
+ VariableRangeConflict: "variable-range-conflict",
+ VariableWrongRange: "variable-wrong-range",
+ VariableWrongValue: "variable-wrong-value",
+
+ UnknownFunction: "unknown-function",
+ MacroExpansionError: "macro-expansion-error",
+ NoVariableName: "no-variable-name",
+ NoFunctionName: "no-funcion-name",
+
+ // Run time errors.
+ ArithmeticError: "arithmetic-error",
+ WrongType: "wrong-type",
+ IndexOutOfRange: "index-out-of-range",
+ ValueOutOfRange: "value-out-of-range",
+ NoLoopToBreak: "no-loop-to-break",
+ UncaughtThrow: "uncaught-throw"
+};
+
+Xex.Variable = function (name, desc, val, range)
{
- this.domain = domain;
- this.name = name;
+ if (name)
+ this.name = name;
+ if (desc)
+ this.desc = desc;
this.val = val;
+ if (range)
+ this.range = range;
}
-XEX.Variable.prototype = {
- value: function () { return this.val; },
- set_value: function (val) {
- this.val = val;
- return val;
+Xex.Variable.prototype = {
+ clone: function ()
+ {
+ return new Xex.Variable (this.name, this.desc, this.val, this.range);
},
- clone: function () {
- {
- return new XEX.Variable (this.domain, this.name, this.value);
- }
+ equals: function (obj)
+ {
+ return ((obj instanceof Xex.Variable)
+ && obj.name == this.name);
+ },
+ SetValue: function (term)
+ {
+ this.val = term;
+ return term;
}
-}
-
-XEX.Function = function (name, with_var, min_args, max_args) {
+}
+
+
+Xex.Function = function (name, with_var, min_args, max_args)
+{
this.name = name;
this.with_var = with_var;
this.min_args = min_args;
this.max_args = max_args;
};
-XEX.Subrountine = function (builtin, name, with_var, min_args, max_args) {
- this.prototype = new XEX.Function (name, with_var, min_args, max_args);
+Xex.Subrountine = function (builtin, name, with_var, min_args, max_args)
+{
+ Xex.Function.apply (this, [name, with_var, min_args, max_args]);
this.builtin = builtin;
-};
+}
-XEX.Subrountine.prototype.Call = function (domain, vari, args)
+Xex.Subrountine.prototype.Call = function (domain, vari, args)
{
- newargs = new Array ();
+ var newargs = new Array ();
for (var i = 0; i < args.length; i++)
{
newargs[i] = args[i].Eval (domain);
return this.builtin (domain, vari, newargs)
}
-XEX.SpecialForm = function (builtin, name, with_var, min_args, max_args)
+Xex.SpecialForm = function (builtin, name, with_var, min_args, max_args)
{
- this.prototype = new XEX.Function (name, with_var, min_args, max_args);
+ Xex.Function.apply (this, [name, with_var, min_args, max_args]);
this.builtin = builtin;
}
-XEX.SpecialForm.prototype.Call = function (domain, vari, args)
+Xex.SpecialForm.prototype.Call = function (domain, vari, args)
{
return this.builtin (domain, vari, args)
}
-XEX.Lambda = function (name, min_args, max_args, args, body)
+Xex.Lambda = function (name, min_args, max_args, args, body)
{
- this.prototype = new XEX.Function (name, false, min_args, max_args);
+ Xex.Function.apply (this, [name, false, min_args, max_args]);
this.args = args;
this.body = body;
}
-XEX.Lambda.prototype.Call = function (domain, vari, args)
+Xex.Lambda.prototype.Call = function (domain, vari, args)
{
var current = domain.bindings;
- var result = XEX.Term.zero;
+ var result = Xex.Zero;
var limit = max_args >= 0 ? args.length : args.length - 1;
var i;
domain.Bind (this.args[limit], list);
}
try {
- domain.Catch (XEX.CatchTag.Return);
+ domain.Catch (Xex.CatchTag.Return);
for (var term in this.body)
{
result = term.Eval (domain);
return result;
}
-XEX.Macro = function (name, min_args, max_args, args, body)
+Xex.Macro = function (name, min_args, max_args, args, body)
{
- this.prototype = new XEX.Function (name, false, min_args, max_args);
+ Xex.Function.apply (this, [name, false, min_args, max_args]);
this.args = args;
this.body = body;
}
-XEX.Macro.prototype.Call = function (domain, vari, args)
+Xex.Macro.prototype.Call = function (domain, vari, args)
{
var current = domain.bindings;
- var result = XEX.Term.Zero;
+ var result = Xex.Zero;
var i;
try {
for (i = 0; i < args.length; i++)
domain.Bind (this.args[i], args[i]);
try {
- domain.Catch (XEX.CatchTag.Return);
- for (var term in body)
+ domain.Catch (Xex.CatchTag.Return);
+ for (var i in this.body)
{
- result = term.Eval (domain);
+ result = this.body[i].Eval (domain);
if (domain.Thrown ())
break;
}
return result;
}
-XEX.EvalConstant = function (domain)
+Xex.Bindings = function (vari)
{
- if (this.nodeName == 'integer')
- alert ("integer:" + this.attributes[0].nodeValue);
- else if (this.nodeName == 'string')
- alert ("string:" + this.firstChild.nodeValue);
- return this;
-};
+ this.vari = vari;
+ this.old_value = vari.val;
+}
-XEX.EvalFuncall = function (domain)
+Xex.Bindings.prototype.UnboundTo = function (boundary)
{
- try {
- domain.CallStackPush (this);
- } catch (e) {
- alert (e);
+ for (var b = this; b != boundary; b = b.next)
+ b.vari.val = b.old_value;
+ return boundary;
+}
+
+Xex.Bind = function (bindings, vari, val)
+{
+ var b = new Xex.Bindings (vari);
+ b.vari.val = val;
+ b.next = bindings;
+ return b;
+}
+
+Xex.CatchTag = {
+ Return: 0,
+ Break: 1
+}
+
+Xex.Domain = function (name, parent, context)
+{
+ this.name = name;
+ this.context = context;
+ this.depth = 0;
+
+ if (name != 'basic' && ! parent)
+ parent = Xex.BasicDomain
+ this.parent = parent;
+ this.termtypes = {};
+ this.functions = {};
+ this.variables = {};
+ if (parent)
+ {
+ var elt;
+ for (elt in parent.termtypes)
+ this.termtypes[elt] = parent.termtypes[elt];
+ for (elt in parent.functions)
+ this.functions[elt] = parent.functions[elt];
+ for (elt in parent.variables)
+ {
+ var vari = parent.variables[elt];
+ this.variables[elt] = new Xex.Variable (vari.name, vari.desc,
+ vari.val, vari.range);
+ }
+ }
+
+ this.call_stack = new Array ();
+ this.bindings = null;
+ this.catch_stack = new Array ();
+ this.catch_count = 0;
+ this.caught = false;
+};
+
+Xex.Domain.prototype = {
+ CallStackCount: function () { return this.call_stack.length; },
+ CallStackPush: function (term) { this.call_stack.push (term); },
+ CallStackPop: function () { this.call_stack.pop (); },
+ Bind: function (vari, val)
+ {
+ this.bindings = Xex.Bind (this.bindings, vari, val);
+ },
+ UnboundTo: function (boundary)
+ {
+ if (this.bindings)
+ this.bindings = this.bindings.UnboundTo (boundary);
+ },
+ Catch: function (tag) { this.catch_stack.push (tag); this.catch_count++; },
+ Uncatch: function ()
+ {
+ this.catch_stack.pop ();
+ if (this.catch_count > this.catch_stack.length)
+ this.catch_count--;
+ },
+ Thrown: function ()
+ {
+ if (this.catch_count < this.catch_stack.length)
+ {
+ this.caught = (this.catch_count == this.catch_stack.length - 1);
+ return true;
+ }
+ this.caught = false;
+ return false;
+ },
+ ThrowReturn: function ()
+ {
+ for (var i = this.catch_stack.length - 1; i >= 0; i--)
+ {
+ this.catch_count--;
+ if (this.catch_stack[i] == Xex.CatchTag.Return)
+ break;
+ }
+ },
+ ThrowBreak: function ()
+ {
+ if (this.catch_stack[this.catch_stack.length - 1] != Xex.CatchTag.Break)
+ throw new Xex.ErrTerm (Xex.Error.NoLoopToBreak,
+ "No surrounding loop to break");
+ this.catch_count--;
+ },
+ ThrowSymbol: function (tag)
+ {
+ var i = this.catch_count;
+ for (var j = this.catch_stack.length - 1; j >= 0; j--)
+ {
+ i--;
+ if (Xex.CatchTag.Matches (this.catch_stack[i], tag))
+ {
+ this.catch_count = i;
+ return;
+ }
+ }
+ throw new Xex.ErrTerm (Xex.Error.UncaughtThrow,
+ "No corresponding catch: " + tag);
+ },
+ DefType: function (obj)
+ {
+ var type = obj.type;
+ if (this.termtypes[type])
+ throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
+ "Already defined: " + type);
+ if (this.functions[type])
+ throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
+ "Already defined as a funciton or a macro: "
+ + type);
+ this.termtypes[type] = obj.Parser;
+ },
+ DefSubr: function (builtin, name, with_var, min_args, max_args)
+ {
+ this.functions[name] = new Xex.Subrountine (builtin, name, with_var,
+ min_args, max_args);
+ },
+ DefSpecial: function (builtin, name, with_var, min_args, max_args)
+ {
+ this.functions[name] = new Xex.SpecialForm (builtin, name, with_var,
+ min_args, max_args);
+ },
+ Defun: function (name, min_args, max_args, args, body)
+ {
+ this.functions[name] = new Xex.Lambda (name, min_args, max_args,
+ args, body);
+ },
+ DefunByFunc: function (func) { this.functions[func.name] = func; },
+ Defmacro: function (name, min_args, max_args, args, body)
+ {
+ this.functions[name] = new Xex.Macro (name, min_args, max_args,
+ args, body);
+ },
+ DefAlias: function (alias, fname)
+ {
+ var func = this.functions[fname];
+
+ if (! func)
+ throw new Xex.ErrTerm (Xex.Error.UnknownFunction, fname);
+ if (this.termtypes[alias])
+ throw new Xex.ErrTerm (Xex.Error.FunctionConflict,
+ "Already defined as a term type: " + alias);
+ if (this.functions[alias])
+ throw new Xex.ErrTerm (Xex.Error.FunctionConflict,
+ "Already defined as a function: " + alias);
+ this.functions[alias] = func;
+ },
+ Defvar: function (name, desc, val, range)
+ {
+ var vari = new Xex.Variable (name, desc, val, range);
+ this.variables[name] = vari;
+ return vari;
+ },
+ GetFunc: function (name)
+ {
+ var func = this.functions[name];
+ if (! func)
+ throw new Xex.ErrTerm (Xex.Error.UnknownFunction,
+ "Unknown function: " + name);
+ return func;
+ },
+ CopyFunc: function (domain, name)
+ {
+ var func = this.functions[name];
+ domain.DefunByFunc (func);
+ return true;
+ },
+ CopyFuncAll: function (domain)
+ {
+ for (var elt in this.functions)
+ domain.DefunByFunc (this.functions[elt]);
+ },
+ GetVarCreate: function (name)
+ {
+ var vari = this.variables[name];
+ if (! vari)
+ vari = this.variables[name] = new Xex.Variable (name, null,
+ Xex.Zero, null);
+ return vari;
+ },
+ GetVar: function (name) { return this.variables[name]; },
+ SaveValues: function ()
+ {
+ values = {};
+ for (var elt in this.variables)
+ values[elt] = this.variables[elt].val.Clone ();
+ return values;
+ },
+ RestoreValues: function (values)
+ {
+ var name;
+ for (name in values)
+ {
+ var vari = this.variables[name];
+ vari.val = values[name];
+ }
}
+};
+
+Xex.Term = function (type) { this.type = type; }
+Xex.Term.prototype = {
+ IsTrue: function () { return true; },
+ Eval: function (domain) { return this.Clone (); },
+ Clone: function (domain) { return this; },
+ equals: function (obj)
+ {
+ return (this.type == obj.type
+ && this.val != undefined
+ && obj.val == this.val);
+ },
+ Matches: function (obj) { return this.equals (obj); },
+ toString: function ()
+ {
+ if (this.val != undefined)
+ return '<' + this.type + '>' + this.val + '</' + this.type + '>';
+ return '<' + this.type + '/>';
+ },
+ Intval: function () { throw new Xex.ErrTerm (Xex.Error.WrongType,
+ "Not an integer"); },
+ Strval: function () { throw new Xex.ErrTerm (Xex.Error.WrongType,
+ "Not a string"); }
+};
+
+Node.prototype.firstElement = function ()
+{
+ for (var n = this.firstChild; n; n = n.nextSibling)
+ if (n.nodeType == 1)
+ return n;
+ return null;
}
-var obj = new XMLHttpRequest ();
-obj.open ('GET', 'xex.xml', false);
-obj.send ('');
-var body = obj.responseXML.firstChild;
-for (var i = body.childNodes.length - 1; i >= 0 ; i--)
+Node.prototype.nextElement = function ()
+{
+ for (var n = this.nextSibling; n; n = n.nextSibling)
+ if (n.nodeType == 1)
+ return n;
+ return null;
+};
+
+(function () {
+ function parse_defvar (domain, node)
+ {
+ var name = node.attributes['vname'].nodeValue;
+ if (! name)
+ throw new Xex.ErrTerm (Xex.Error.NoVariableName, node, '');
+ var vari = domain.variables[name];
+ var desc, val = null, range;
+ if (vari)
+ {
+ desc = vari.description;
+ val = vari.val;
+ range = vari.range;
+ }
+ node = node.firstElement ();
+ if (node && node.nodeName == 'description')
+ {
+ desc = node.firstChild.nodeValue;
+ node = node.nextElement ();
+ }
+ if (node)
+ {
+ val = Xex.Term.Parse (domain, node);
+ node = node.nextElement ();
+ if (node && node.nodeName == 'possible-values')
+ for (node = node.firstElement (); node; node = node.nextElement ())
+ {
+ var pval;
+ if (node.nodeName == 'range')
+ {
+ if (! val.IsInt)
+ throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
+ 'Range not allowed for ' + name);
+ pval = new Array ();
+ for (var n = node.firstElement (); n; n = n.nextElement ())
+ {
+ var v = Xex.Term.Parse (domain, n);
+ if (! v.IsInt)
+ throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
+ 'Invalid range value: ' + val);
+ pval.push (v);
+ }
+ }
+ else
+ {
+ pval = Xex.Term.Parse (domain, node);
+ if (val.type != pval.type)
+ throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
+ 'Invalid possible value: ' + pval);
+ }
+ if (! range)
+ range = new Array ();
+ range.push (pval);
+ }
+ }
+ if (val == null)
+ val = Xex.Zero;
+ domain.Defvar (name, desc, val, range);
+ return name;
+ }
+
+ function parse_defun_head (domain, node)
{
- var node = body.childNodes[i];
- if (node.nodeType == 1)
- node.Eval = XEX.EvalConstant;
+ var name = node.attributes['fname'].nodeValue;
+ if (! name)
+ throw new Xex.ErrTerm (Xex.Error.NoFunctionName, node, '');
+ var args = new Array ();
+ var nfixed = 0, noptional = 0, nrest = 0;
+
+ node = node.firstElement ();
+ if (node && node.nodeName == 'args')
+ {
+ var n;
+ for (n = n.firstElement (); n; n = n.nextElement ())
+ {
+ if (n.nodeName == 'fixed')
+ nfixed++;
+ else if (n.nodeName == 'optional')
+ noptional++;
+ else if (n.nodeName == 'rest')
+ nrest++;
+ else
+ throw new Xex.ErrTerm (Xex.Error.WrongType, n, n.nodeName);
+ }
+ if (nrest > 1)
+ throw new Xex.ErrTerm (Xex.Error.WrongType, n, 'Too many <rest>');
+ for (n = node.firstElement (); n; n = n.nextElement ())
+ args.push (domain.DefVar (n.attributes['vname'].nodeValue));
+ }
+ args.min_args = nfixed;
+ args.max_args = nrest == 0 ? nfixed + noptional : -1;
+
+ if (node.nodeName == 'defun')
+ domain.Defun (name, args, null);
else
- body.removeChild (node);
+ domain.Defmacro (name, args, null);
+ return name;
}
-for (var i = 0; i < body.childNodes.length; i++)
+
+ function parse_defun_body (domain, node)
{
- var node = body.childNodes[i];
- node.Eval ();
+ var name = node.attributes['fname'].nodeValue;
+ var func = domain.GetFunc (name);
+ var body;
+ for (node = node.firstElement (); node; node = node.nextElement ())
+ if (node.nodeName != 'description' && node.nodeName != 'args')
+ break;
+ body = Xex.Term.Parse (domain, node, null);
+ func.body = body;
}
+ Xex.Term.Parse = function (domain, node, stop)
+ {
+ if (arguments.length == 2)
+ {
+ var name = node.nodeName;
+ var parser = domain.termtypes[name];
+
+ if (parser)
+ return parser (domain, node);
+ if (name == 'defun' || name == 'defmacro')
+ {
+ name = parse_defun_head (domain, node);
+ parse_defun_body (domain, node);
+ return new Xex.StrTerm (name);
+ }
+ if (name == 'defvar')
+ {
+ name = parse_defvar (domain, node);
+ return new Xex.StrTerm (name);
+ }
+ return new Xex.Funcall.prototype.Parser (domain, node);
+ }
+ for (var n = node; n && n != stop; n = n.nextElement ())
+ if (n.nodeName == 'defun' || n.nodeName == 'defmacro')
+ parse_defun_head (domain, n);
+ var terms = null;
+ for (var n = node; n && n != stop; n = n.nextElement ())
+ {
+ if (n.nodeName == 'defun' || n.nodeName == 'defmacro')
+ parse_defun_body (domain, n);
+ else if (n.nodeName == 'defvar')
+ parse_defvar (domain, n);
+ else
+ {
+ if (! terms)
+ terms = new Array ();
+ terms.push (Xex.Term.Parse (domain, n));
+ }
+ }
+ return terms;
+ }
+}) ();
+Xex.Varref = function (vname)
+{
+ this.val = vname;
+};
+
+(function () {
+ var proto = new Xex.Term ('varref');
+
+ proto.Clone = function () { return new Xex.Varref (this.val); }
+ proto.Eval = function (domain)
+ {
+ var vari = domain.GetVarCreate (this.val);
+ Xex.Log (this.ToString () + '=>' + vari.val, domain.depth);
+ return vari.val;
+ }
+
+ proto.Parser = function (domain, node)
+ {
+ return new Xex.Varref (node.attributes['vname'].nodeValue);
+ }
+
+ proto.ToString = function ()
+ {
+ return '<varref vname="' + this.val + '"/>';
+ }
+
+ Xex.Varref.prototype = proto;
+}) ();
+
+var null_args = new Array ();
+
+Xex.Funcall = function (func, vname, args)
+{
+ this.func = func;
+ this.vname = vname;
+ this.args = args || null_args;
+};
+
+(function () {
+ var proto = new Xex.Term ('funcall');
+
+ proto.Parser = function (domain, node)
+ {
+ var fname = node.nodeName;
+ var attr;
+
+ if (fname == 'funcall')
+ fname = node.attributes['fname'].nodeValue;
+ var func = domain.GetFunc (fname);
+ var vname;
+ attr = node.attributes['vname'];
+ vname = attr != undefined ? attr.nodeValue : null;
+ var args = Xex.Term.Parse (domain, node.firstElement (), null);
+ return new Xex.Funcall (func, vname, args);
+ }
+
+ proto.New = function (domain, fname, vname, args)
+ {
+ var func = domain.GetFunc (fname);
+ var funcall = new Xex.Funcall (func, vname, args);
+ if (func instanceof Xex.Macro)
+ funcall = funcall.Eval (domain);
+ return funcall;
+ }
+
+ proto.Eval = function (domain)
+ {
+ Xex.Log (this, domain.depth);
+ var vari;
+ if (this.vname)
+ vari = domain.GetVarCreate (this.vname);
+ domain.depth++;
+ var result;
+ try {
+ result = this.func.Call (domain, vari, this.args);
+ } finally {
+ Xex.Log (' => ' + result, --domain.depth,
+ this.func instanceof Xex.Subrountine);
+ }
+ return result;
+ }
+
+ proto.Clone = function ()
+ {
+ return new Xex.Funcall (this.func, this.vari, this.args);
+ }
+
+ proto.equals = function (obj)
+ {
+ return (obj.type == 'funcall'
+ && obj.func == this.func
+ && obj.vari.equals (this.vari)
+ && obj.args.length == this.func.length);
+ }
+
+ proto.toString = function ()
+ {
+ var arglist = ''
+ var len = this.args.length;
+ var str = '<' + this.func.name;
+ if (this.vname)
+ str += ' vname="' + this.vname + '"';
+ if (len == 0)
+ return str + '/>';
+ if (this.func instanceof Xex.Subrountine)
+ for (var i = 0; i < len; i++)
+ arglist += this.args[i].toString ();
+ else
+ for (var i = 0; i < len; i++)
+ arglist += '.';
+ return str + '>' + arglist + '</' + this.func.name + '>';
+ }
+
+ Xex.Funcall.prototype = proto;
+}) ();
+
+Xex.ErrTerm = function (ename, message, stack)
+{
+ this.ename = ename;
+ this.message = message;
+ this.stack = stack;
+};
+
+(function () {
+ var proto = new Xex.Term ('error');
+
+ proto.IsError = true;
+
+ proto.Parser = function (domain, node)
+ {
+ return new Xex.ErrTerm (node.attributes['ename'].nodeValue,
+ node.innerText, false);
+ }
+
+ proto.CallStack = function () { return stack; }
+
+ proto.SetCallStack = function (value) { statck = value; }
+
+ proto.Clone = function ()
+ {
+ return new Xex.ErrTerm (ename, message, false);
+ }
+
+ proto.equals = function (obj)
+ {
+ return (obj.IsError
+ && obj.ename == ename && obj.message == message
+ && (obj.stack ? (stack && stack.length == obj.stack.length)
+ : ! stack));
+ }
+
+ proto.Matches = function (obj)
+ {
+ return (obj.IsError && obj.ename == ename);
+ }
+
+ proto.toString = function ()
+ {
+ return '<error ename="' + this.ename + '">' + this.message + '</error>';
+ }
+
+ Xex.ErrTerm.prototype = proto;
+}) ();
+
+Xex.IntTerm = function (num) { this.val = num; };
+(function () {
+ var proto = new Xex.Term ('integer');
+ proto.IsInt = true;
+ proto.Intval = function () { return this.val; };
+ proto.IsTrue = function () { return this.val != 0; }
+ proto.Clone = function () { return new Xex.IntTerm (this.val); }
+ proto.Parser = function (domain, node)
+ {
+ var str = node.firstChild.nodeValue;
+
+ if (str.charAt (0) == '?' && str.length == 2)
+ return new Xex.IntTerm (str.charCodeAt (1));
+ return new Xex.IntTerm (parseInt (node.firstChild.nodeValue));
+ }
+ Xex.IntTerm.prototype = proto;
+}) ();
+
+Xex.StrTerm = function (str) { this.val = str; };
+(function () {
+ var proto = new Xex.Term ('string');
+ proto.IsStr = true;
+ proto.Strval = function () { return this.val; };
+ proto.IsTrue = function () { return this.val.length > 0; }
+ proto.Clone = function () { return new Xex.StrTerm (this.val); }
+ proto.Parser = function (domain, node)
+ {
+ return new Xex.StrTerm (node.firstChild ? node.firstChild.nodeValue : '');
+ }
+ Xex.StrTerm.prototype = proto;
+}) ();
+
+Xex.SymTerm = function (str) { this.val = str; };
+(function () {
+ var proto = new Xex.Term ('symbol');
+ proto.IsSymbol = true;
+ proto.IsTrue = function () { return this.val != 'nil'; }
+ proto.Clone = function () { return new Xex.SymTerm (this.val); }
+ proto.Parser = function (domain, node)
+ {
+ return new Xex.SymTerm (node.firstChild.nodeValue);
+ }
+ Xex.SymTerm.prototype = proto;
+}) ();
+
+Xex.LstTerm = function (list) { this.val = list; };
+(function () {
+ var proto = new Xex.Term ('list');
+ proto.IsList = true;
+ proto.IsTrue = function () { return this.val.length > 0; }
+ proto.Clone = function () { return new Xex.LstTerm (this.val.slice (0)); }
+
+ proto.equals = function (obj)
+ {
+ if (obj.type != 'list' || obj.val.length != this.val.length)
+ return false;
+ var i, len = this.val.length;
+ for (i = 0; i < len; i++)
+ if (! this.val[i].equals (obj.val[i]))
+ return false;
+ return true;
+ }
+
+ proto.Parser = function (domain, node)
+ {
+ var list = Xex.Term.Parse (domain, node.firstElement (), null);
+ return new Xex.LstTerm (list);
+ }
+
+ proto.toString = function ()
+ {
+ var len = this.val.length;
+
+ if (len == 0)
+ return '<list/>';
+ var str = '<list>';
+ for (var i = 0; i < len; i++)
+ str += this.val[i].toString ();
+ return str + '</list>';
+ }
+ Xex.LstTerm.prototype = proto;
+}) ();
+
+(function () {
+ var basic = new Xex.Domain ('basic', null, null);
+
+ function Fset (domain, vari, args)
+ {
+ if (! vari)
+ throw new Xex.ErrTerm (Xex.Error.NoVariableName,
+ 'No variable name to set');
+ vari.SetValue (args[0]);
+ return args[0];
+ }
+
+ function Fnot (domain, vari, args)
+ {
+ return (args[0].IsTrue () ? Xex.Zero : Xex.One);
+ }
+
+ function maybe_set_intvar (vari, n)
+ {
+ var term = new Xex.IntTerm (n);
+ if (vari)
+ vari.SetValue (term);
+ return term;
+ }
+
+ function Fadd (domain, vari, args)
+ {
+ var n = vari ? vari.val.Intval () : 0;
+ var len = args.length;
+
+ for (var i = 0; i < len; i++)
+ n += args[i].Intval ();
+ return maybe_set_intvar (vari, n);
+ }
+
+ function Fmul (domain, vari, args)
+ {
+ var n = vari ? vari.val.Intval () : 1;
+ for (var i = 0; i < args.length; i++)
+ n *= args[i].Intval ();
+ return maybe_set_intvar (vari, n);
+ }
+
+ function Fsub (domain, vari, args)
+ {
+ var n, i;
+
+ if (! vari)
+ {
+ n = args[0].Intval ();
+ i = 1;
+ }
+ else
+ {
+ n = vari.val.Intval ();
+ i = 0;
+ }
+ while (i < args.length)
+ n -= args[i++].Intval ();
+ return maybe_set_intvar (vari, n);
+ }
+
+ function Fdiv (domain, vari, args)
+ {
+ var n, i;
+
+ if (! vari == null)
+ {
+ n = args[0].Intval ();
+ i = 1;
+ }
+ else
+ {
+ n = vari.val.Intval ();
+ i = 0;
+ }
+ while (i < args.length)
+ n /= args[i++].Intval ();
+ return maybe_set_intvar (vari, n);
+ }
+
+ function Fmod (domain, vari, args)
+ {
+ return maybe_set_intvar (vari, args[0].Intval () % args[1].Intval ());
+ }
+
+ function Flogior (domain, vari, args)
+ {
+ var n = vari == null ? 0 : vari.val;
+ for (var i = 0; i < args.length; i++)
+ n |= args[i].val;
+ return maybe_set_intvar (vari, n);
+ }
+
+ function Flogand (domain, vari, args)
+ {
+ var n, i;
+ if (vari == null)
+ {
+ Xex.Log ("logand arg args[0]" + args[0]);
+ n = args[0].Intval ()
+ i = 1;
+ }
+ else
+ {
+ Xex.Log ("logand arg var " + vari);
+ n = vari.val.Intval ();
+ i = 0;
+ }
+ while (n > 0 && i < args.length)
+ {
+ Xex.Log ("logand arg " + args[i]);
+ n &= args[i++].val;
+ }
+ return maybe_set_intvar (vari, n);
+ }
+
+ function Flsh (domain, vari, args)
+ {
+ return maybe_set_intvar (vari, args[0].Intval () << args[1].Intval ());
+ }
+
+ function Frsh (domain, vari, args)
+ {
+ return maybe_set_intvar (vari, args[0].Intval () >> args[1].Intval ());
+ }
+
+ function Fand (domain, vari, args)
+ {
+ var len = args.length;
+ for (var i = 0; i < len; i++)
+ {
+ var result = args[i].Eval (domain);
+ if (domain.Thrown ())
+ return result;
+ if (! result.IsTrue ())
+ return Xex.Zero;
+ }
+ return Xex.One;
+ }
+
+ function For (domain, vari, args)
+ {
+ var len = args.length;
+ for (var i = 0; i < len; i++)
+ {
+ var result = args[i].Eval (domain);
+ if (domain.Thrown ())
+ return result;
+ if (result.IsTrue ())
+ return Xex.One;
+ }
+ return Xex.Zero;
+ }
+
+ function Feq (domain, vari, args)
+ {
+ for (var i = 1; i < args.length; i++)
+ if (! args[i - 1].equals (args[i]))
+ return Xex.Zero;
+ return Xex.One;
+ }
+
+ function Fnoteq (domain, vari, args)
+ {
+ return (Feq (domain, vari, args) == Xex.One ? Xex.Zero : Xex.One);
+ }
+
+ function Flt (domain, vari, args)
+ {
+ var n = args[0].Intval ();
+
+ for (var i = 1; i < args.length; i++)
+ {
+ var n1 = args[i].Intval ();
+ if (n >= n1)
+ return Xex.Zero;
+ n = n1;
+ }
+ return Xex.One;
+ }
+
+ function Fle (domain, vari, args)
+ {
+ var n = args[0].Intval ();
+ for (var i = 1; i < args.length; i++)
+ {
+ var n1 = args[i].Intval ();
+ if (n > n1)
+ return Xex.Zero;
+ n = n1;
+ }
+ return Xex.One;
+ }
+
+ function Fgt (domain, vari, args)
+ {
+ var n = args[0].Intval ();
+ for (var i = 1; i < args.length; i++)
+ {
+ var n1 = args[i].Intval ();
+ if (n <= n1)
+ return Xex.Zero;
+ n = n1;
+ }
+ return Xex.One;
+ }
+
+ function Fge (domain, vari, args)
+ {
+ var n = args[0].Intval ();
+ for (var i = 1; i < args.length; i++)
+ {
+ var n1 = args[i].Intval ();
+ if (n < n1)
+ return Xex.Zero;
+ n = n1;
+ }
+ return Xex.One;
+ }
+
+ function Fprogn (domain, vari, args)
+ {
+ var result = Xex.One;
+ var len = args.length;
+
+ for (var i = 0; i < len; i++)
+ {
+ result = args[i].Eval (domain);
+ if (domain.Thrown ())
+ return result;
+ }
+ return result;
+ }
+
+ function Fif (domain, vari, args)
+ {
+ var result = args[0].Eval (domain);
+
+ if (domain.Thrown ())
+ return result;
+ if (result.IsTrue ())
+ return args[1].Eval (domain);
+ if (args.length == 2)
+ return Xex.Zero;
+ return args[2].Eval (domain);
+ }
+
+ function Fcond (domain, vari, args)
+ {
+ for (var i = 0; i < args.length; i++)
+ {
+ var list = args[i];
+ var result = list.val[0].Eval (domain);
+ if (result.IsTrue ())
+ {
+ for (var j = 1; j < list.val.length; j++)
+ {
+ domain.depth++;
+ result = list.val[j].Eval (domain);
+ domain.depth--;
+ if (domain.Thrown ())
+ return result;
+ }
+ return result;
+ }
+ }
+ return Xex.Zero;
+ }
+
+ function eval_terms (domain, terms, idx)
+ {
+ var result = Xex.Zero;
+ domain.caught = false;
+ for (var i = idx; i < terms.length; i++)
+ {
+ result = terms[i].Eval (domain);
+ if (domain.Thrown ())
+ return result;
+ }
+ return result;
+ }
+
+ function Fcatch (domain, vari, args)
+ {
+ var caught = false;
+ var result;
+
+ if (args[0].IsError)
+ {
+ try {
+ result = eval_terms (domain, args, 1);
+ } catch (e) {
+ if (e instanceof Xex.ErrTerm)
+ {
+ if (! args[0].Matches (e))
+ throw e;
+ if (vari)
+ vari.SetValue (e);
+ return Xex.One;
+ }
+ }
+ }
+ else if (args[0].IsSymbol)
+ {
+ try {
+ domain.Catch (args[0].val);
+ result = eval_terms (domain, args, 1);
+ if (domain.caught)
+ {
+ if (vari != null)
+ vari.SetValue (result);
+ return Xex.One;
+ }
+ return Xex.Zero;
+ } finally {
+ domain.Uncatch ();
+ }
+ }
+ throw new Xex.ErrTerm (Xex.Error.WrongArgument,
+ "Not a symbol nor an error: " + args[0]);
+ }
+
+ function Fthrow (domain, vari, args)
+ {
+ if (args[0].IsSymbl)
+ {
+ domain.ThrowSymbol (args[0]);
+ return (args[args.length - 1]);
+ }
+ if (args[0].IsError)
+ {
+ throw args[0];
+ }
+ throw new Xex.ErrTerm (Xex.Error.WrongArgument,
+ "Not a symbol nor an error:" + args[0]);
+ }
+
+ Xex.BasicDomain = basic;
+
+ basic.DefSubr (Fset, "set", true, 1, 1);
+ basic.DefAlias ("=", "set");
+ basic.DefSubr (Fnot, "not", false, 1, 1);
+ basic.DefAlias ("!", "not");
+ basic.DefSubr (Fadd, "add", true, 1, -1);
+ basic.DefSubr (Fmul, "mul", true, 1, -1);
+ basic.DefAlias ("*", "mul");
+ basic.DefSubr (Fsub, "sub", true, 1, -1);
+ basic.DefAlias ("-", "sub");
+ basic.DefSubr (Fdiv, "div", true, 1, -1);
+ basic.DefAlias ("/", "div");
+ basic.DefSubr (Fmod, "mod", true, 1, 2);
+ basic.DefAlias ("%", "mod");
+ basic.DefSubr (Flogior, "logior", true, 1, -1);
+ basic.DefAlias ('|', "logior");
+ basic.DefSubr (Flogand, "logand", true, 1, -1);
+ basic.DefAlias ("&", "logand");
+ basic.DefSubr (Flsh, "lsh", true, 1, 2);
+ basic.DefAlias ("<<", "lsh");
+ basic.DefSubr (Frsh, "rsh", true, 1, 2);
+ basic.DefAlias (">>", "rsh");
+ basic.DefSubr (Feq, "eq", false, 2, -1);
+ basic.DefAlias ("==", "eq");
+ basic.DefSubr (Fnoteq, "noteq", false, 2, 2);
+ basic.DefAlias ("!=", "noteq");
+ basic.DefSubr (Flt, "lt", false, 2, -1);
+ basic.DefAlias ("<", "lt");
+ basic.DefSubr (Fle, "le", false, 2, -1);
+ basic.DefAlias ("<=", "le");
+ basic.DefSubr (Fgt, "gt", false, 2, -1);
+ basic.DefAlias (">", "gt");
+ basic.DefSubr (Fge, "ge", false, 2, -1);
+ basic.DefAlias (">=", "ge");
+ basic.DefSubr (Fthrow, "throw", false, 1, 2);
+
+ //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.DefSubr (Fthrow, "throw", false, 1, 2);
+
+ basic.DefSpecial (Fand, "and", false, 1, -1);
+ basic.DefAlias ("&&", "and");
+ basic.DefSpecial (For, "or", false, 1, -1);
+ basic.DefAlias ("||", "or");
+ basic.DefSpecial (Fprogn, "progn", false, 1, -1);
+ basic.DefAlias ("expr", "progn");
+ 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);
+
+ basic.DefType (Xex.Funcall.prototype);
+ basic.DefType (Xex.Varref.prototype);
+ basic.DefType (Xex.ErrTerm.prototype);
+ basic.DefType (Xex.IntTerm.prototype);
+ basic.DefType (Xex.StrTerm.prototype);
+ basic.DefType (Xex.SymTerm.prototype);
+ basic.DefType (Xex.LstTerm.prototype);
+
+}) ();
+
+Xex.Zero = new Xex.IntTerm (0);
+Xex.One = new Xex.IntTerm (1);
+Xex.nil = new Xex.SymTerm ('nil');
+
+(function () {
+ var queue = new Array ();
+ var iframe = null;
+
+ function receiver (event)
+ {
+ var request = queue.shift ();
+ //alert ('received: ' + request[0]);
+ var parser = new DOMParser ();
+ var xml = parser.parseFromString (event.data, 'text/xml');
+ if (queue.length > 0)
+ {
+ document.getElementsByTagName ('body')[0].removeChild (iframe);
+ iframe.src = queue[0][0];
+ document.getElementsByTagName ('body')[0].appendChild (iframe);
+ }
+ else
+ {
+ window.removeEventListener ('message', receiver, false);
+ document.getElementsByTagName ('body')[0].removeChild (iframe);
+ }
+ request[1] (xml.firstElement (), request[2]);
+ event.preventDefault ();
+ };
+
+ Xex.Load = function (server, file, callback, arg)
+ {
+ var url = server + '/loadxml.html#' + file;
+ //alert ('loading file:' + file);
+ queue.push ([url, callback, arg]);
+ if (queue.length == 1)
+ {
+ window.addEventListener ('message', receiver, false);
+ iframe = document.createElement ('iframe');
+ iframe.style.display = 'none';
+ iframe.src = url;
+ //alert ('iframe created');
+ document.getElementsByTagName ('body')[0].appendChild (iframe);
+ }
+ }
+}) ();