X-Git-Url: http://git.chise.org/gitweb/?p=m17n%2Fm17n-lib-js.git;a=blobdiff_plain;f=xex-old.js;fp=xex-old.js;h=f4fabee55dacc30ca7cf595b86feec4faf477b8a;hp=0000000000000000000000000000000000000000;hb=7fd3557aaf324859cda73dd7b0fce908e720951a;hpb=0eb9adf6e42434704f52f04a5d79ea5219da118e diff --git a/xex-old.js b/xex-old.js new file mode 100644 index 0000000..f4fabee --- /dev/null +++ b/xex-old.js @@ -0,0 +1,1388 @@ +// xex.js -- Xex (XML Expression) interpreter +// Copyright (C) 2010 +// National Institute of Advanced Industrial Science and Technology (AIST) +// Registration Number H15PRO112 + +// This file is part of the m17n database; a sub-part of the m17n +// library. + +// 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: '100%', + 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) +{ + if (name) + this.name = name; + if (desc) + this.desc = desc; + this.val = val; + if (range) + this.range = range; +} + +Xex.Variable.prototype = { + clone: function () + { + return new Xex.Variable (this.name, this.desc, this.val, this.range); + }, + 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) +{ + 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) +{ + Xex.Function.apply (this, [name, with_var, min_args, max_args]); + this.builtin = builtin; +} + +Xex.Subrountine.prototype.Call = function (domain, vari, args) +{ + var newargs = new Array (); + for (var i = 0; i < args.length; i++) + { + newargs[i] = args[i].Eval (domain); + if (domain.Thrown ()) + return newargs[i]; + } + return this.builtin (domain, vari, newargs) +} + +Xex.SpecialForm = function (builtin, 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) +{ + return this.builtin (domain, vari, args) +} + +Xex.Lambda = function (name, min_args, max_args, args, body) +{ + Xex.Function.apply (this, [name, false, min_args, max_args]); + this.args = args; + this.body = body; +} + +Xex.Lambda.prototype.Call = function (domain, vari, args) +{ + var current = domain.bindings; + var result = Xex.Zero; + var limit = max_args >= 0 ? args.length : args.length - 1; + var i; + + try { + for (i = 0; i < limit; i++) + { + result = args[i].Eval (domain); + if (domain.Thrown ()) + return result; + domain.Bind (this.args[i], result); + } + if (max_args < 0) + { + var list = new Array (); + for (i = 0; i < args[limit].length; i++) + { + result = args[limit].Eval (domain); + if (domain.Thrown ()) + return result; + list[i] = result; + } + domain.Bind (this.args[limit], list); + } + try { + domain.Catch (Xex.CatchTag.Return); + for (var term in this.body) + { + result = term.Eval (domain); + if (domain.Thrown ()) + return result; + } + } finally { + domain.Uncatch (); + } + } finally { + domain.UnboundTo (current); + } + return result; +} + +Xex.Macro = function (name, min_args, max_args, args, body) +{ + Xex.Function.apply (this, [name, false, min_args, max_args]); + this.args = args; + this.body = body; +} + +Xex.Macro.prototype.Call = function (domain, vari, args) +{ + var current = domain.bindings; + 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 i in this.body) + { + result = this.body[i].Eval (domain); + if (domain.Thrown ()) + break; + } + } finally { + domain.Uncatch (); + } + } finally { + domain.UnboundTo (current); + } + return result; +} + +Xex.Bindings = function (vari) +{ + this.vari = vari; + this.old_value = vari.val; +} + +Xex.Bindings.prototype.UnboundTo = function (boundary) +{ + 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 + ''; + 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; +} + +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 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 '); + 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 + domain.Defmacro (name, args, null); + return name; + } + + function parse_defun_body (domain, node) + { + 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 ''; + } + + 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 + ''; + } + + 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 '' + this.message + ''; + } + + 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 ''; + var str = ''; + for (var i = 0; i < len; i++) + str += this.val[i].toString (); + return str + ''; + } + 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'); + +Xex.Load = function (server, file) +{ + var obj = new XMLHttpRequest (); + var url = server ? server + '/' + file : file; + obj.open ('GET', url, false); + obj.overrideMimeType ('text/xml'); + obj.send (''); + return (obj.responseXML && obj.responseXML.firstElement ()); +}; + +(function () { + function getxml (event) + { + var parser = new DOMParser (); + Xex.xml = parser.parseFromString (event.data, 'text/xml'); + }; + + Xex.LoadTesting = function (server, file) + { + var body = document.getElementsByTagName ('body')[0]; + Xex.xml = undefined; + window.addEventListener ('message', getxml, false); + var iframe = document.createElement ('iframe'); + iframe.src = server + '/loadxml.html#' + file; + alert ('iframe created'); + body.appendChild (iframe); +/* + while (! Xex.xml) + alert ('wait loading ' + file); + window.removeEventListener ('message', getxml, false); + body.removeChild (iframe); + return (Xex.xml.firstChild); +*/ + } +}) ();