1 // -* coding: utf-8; -*
5 Xex.Variable = function (domain, name, val)
12 Xex.Variable.prototype.clone = function () {
13 return new Xex.Variable (this.domain, this.name, this.value);
16 Xex.Variable.prototype.Equals = function (obj) {
17 return ((obj instanceof Xex.Variable)
18 && obj.name == this.name);
21 Xex.Variable.prototype.SetValue = function (term) {
26 Xex.Function = function (name, with_var, min_args, max_args) {
28 this.with_var = with_var;
29 this.min_args = min_args;
30 this.max_args = max_args;
33 Xex.Subrountine = function (builtin, name, with_var, min_args, max_args) {
35 this.with_var = with_var;
36 this.min_args = min_args;
37 this.max_args = max_args;
38 this.builtin = builtin;
41 Xex.Subrountine.prototype.Call = function (domain, vari, args)
43 newargs = new Array ();
44 for (var i = 0; i < args.length; i++)
46 newargs[i] = args[i].Eval (domain);
50 return this.builtin (domain, vari, newargs)
53 Xex.SpecialForm = function (builtin, name, with_var, min_args, max_args)
56 this.with_var = with_var;
57 this.min_args = min_args;
58 this.max_args = max_args;
59 this.builtin = builtin;
62 Xex.SpecialForm.prototype.Call = function (domain, vari, args)
64 return this.builtin (domain, vari, args)
67 Xex.Lambda = function (name, min_args, max_args, args, body)
70 this.with_var = with_var;
71 this.min_args = min_args;
72 this.max_args = max_args;
77 Xex.Lambda.prototype.Call = function (domain, vari, args)
79 var current = domain.bindings;
80 var result = Xex.Zero;
81 var limit = max_args >= 0 ? args.length : args.length - 1;
85 for (i = 0; i < limit; i++)
87 result = args[i].Eval (domain);
90 domain.Bind (this.args[i], result);
94 var list = new Array ();
95 for (i = 0; i < args[limit].length; i++)
97 result = args[limit].Eval (domain);
102 domain.Bind (this.args[limit], list);
105 domain.Catch (Xex.CatchTag.Return);
106 for (var term in this.body)
108 result = term.Eval (domain);
109 if (domain.Thrown ())
116 domain.UnboundTo (current);
121 Xex.Macro = function (name, min_args, max_args, args, body)
124 this.with_var = with_var;
125 this.min_args = min_args;
126 this.max_args = max_args;
131 Xex.Macro.prototype.Call = function (domain, vari, args)
133 var current = domain.bindings;
134 var result = Xex.Zero;
138 for (i = 0; i < args.length; i++)
139 domain.Bind (this.args[i], args[i]);
141 domain.Catch (Xex.CatchTag.Return);
142 for (var term in body)
144 result = term.Eval (domain);
145 if (domain.Thrown ())
152 domain.UnboundTo (current);
157 Xex.Bindings = function (vari)
160 this.old_value = vari.val;
163 Xex.Bindings.prototype.UnboundTo = function (boundary)
165 for (var b = this; b != boundary; b = b.next)
166 b.vari.val = b.old_value;
170 Xex.Bind = function (bindings, vari, val)
172 var b = new Xex.Bindings (vari);
183 Xex.Domain = function (name, parent, context)
186 this.context = context;
188 this.termtypes = parent ? parent.termtypes.slice () : new Array ();
189 this.functions = parent ? parent.functions.slice () : new Array ();
190 this.variables = parent ? parent.variable.slice () : new Array ();
192 var call_stack = new Array ();
194 var catch_stack = new Array ();
197 if (this.CallStackCount)
200 var proto = Xex.Domain.prototype;
202 proto.CallStackCount = function () { return call_stack.length; }
203 proto.CallStackPush = function (term) { call_stack.push (term); }
204 proto.CallStackPop = function () { call_stack.pop (); }
205 proto.Bind = function (vari, val)
207 bindings = Xex.Bind (bindings, vari, val);
209 proto.UnboundTo = function (boundary)
212 bindings = bindings.UnboundTo (boundary);
214 proto.Catch = function (tag) { catch_stack.push (tag); catch_count++; }
215 proto.Uncatch = function ()
218 if (catch_count > catch_stack.length)
221 proto.Thrown = function ()
223 var i = catch_stack.length - catch_count;
224 return (i > 0 ? i - 1 : false);
226 proto.ThrowReturn = function ()
228 for (var i = catch_stack.length - 1; i >= 0; i--)
231 if (catch_stack[i] == Xex.CatchTag.Return)
235 proto.ThrowBreak = function ()
237 if (catch_stack[catch_stack.length - 1] != Xex.CatchTag.Break)
238 throw new Xex.Error (Xex.Error.NoLoopToBreak,
239 "No surrounding loop to break");
242 proto.ThrowSymbol = function (tag)
245 for (var j = catch_stack.length - 1; j >= 0; j--)
248 if (Xex.CatchTag.Matches (catch_stack[i], tag))
254 throw new Xex.Error (Xex.Error.UncaughtThrow,
255 "No corresponding catch: " + tag);
257 proto.DefType = function (obj)
260 if (this.termtypes[type])
261 throw new Xex.Error (Xex.Error.TermTypeInvalid,
262 "Already defined: " + type);
263 if (this.functions[type])
264 throw new Xex.Error (Xex.Error.TermTypeInvalid,
265 "Already defined as a funciton or a macro: "
267 this.termtypes[type] = obj.Parser;
270 proto.DefSubr = function (builtin, name, with_var, min_args, max_args)
272 this.functions[name] = new Xex.Subrountine (builtin, name, with_var,
275 proto.DefSpecial = function (builtin, name, with_var, min_args, max_args)
277 this.functions[name] = new Xex.SpecialForm (builtin, name, with_var,
280 proto.Defun = function (name, min_args, max_args, args, body)
282 this.functions[name] = new Xex.Lambda (name, min_args, max_args,
285 proto.DefunByFunc = function (func) { this.functions[func.Name] = func; }
286 proto.Defmacro = function (name, min_args, max_args, args, body)
288 this.functions[name] = new Xex.Macro (name, min_args, max_args, args, body);
290 proto.DefAlias = function (alias, fname)
292 var func = this.functions[fname];
294 if (this.termtypes[alias])
295 throw new Xex.Error (Xex.Error.FunctionConflict,
296 "Already defined as a term type: " + alias);
297 if (this.functions[alias])
298 throw new Xex.Error (Xex.Error.FunctionConflict,
299 "Already defined as a function: " + alias);
301 throw new Xex.Error (Xex.Error.UnknownFunction, fname);
302 this.functions[alias] = func;
304 proto.Defvar = function (name)
306 var vari = this.variables[name];
310 throw new Xex.Error (Xex.Error.VariableTypeConflict,
311 "Not a non-typed variable: " + name);
315 vari = new Xex.Variable (this, name, Xex.Zero);
316 this.variables[name] = vari;
320 proto.GetFunc = function (name) { return this.functions[name]; }
321 proto.CopyFunc = function (domain, name)
323 var func = this.functions[name];
324 domain.DefunByFunc (func);
327 proto.CopyFuncAll = function (domain)
329 for (var i = this.functions.length - 1; i >= 0; i--)
330 domain.DefunByFunc (this.functions[i]);
332 proto.GetVarCreate = function (name)
334 var vari = this.variables[name];
336 this.variables[name] = vari
337 = new Xex.Variable (this, name, Xex.Zero);
340 proto.GetVar = function (name) { return this.variables[name]; }
341 proto.SaveValues = function ()
343 values = new Array ()
344 for (var i = this.variables.length - 1; i >= 0; i--)
346 var vari = this.variables[i];
347 values[vari.Name] = vari.val.Clone ();
351 proto.RestoreValues = function (values)
356 var vari = this.variables[name];
357 vari.val = values[name];
362 Xex.Term = function () { }
363 Xex.Term.prototype = {
365 Eval: function (domain) { return this.Clone (); },
366 Equals: function (obj)
368 return (this.type == obj.type
370 && obj.val == this.val);
372 Matches: function (obj) { return this.Equals (obj); },
373 toString: function ()
375 if (this.val != undefined)
376 return '<' + this.type + '>' + this.val + '</' + this.type + '>';
377 return '<' + this.type + '/>';
381 Xex.ParseTerm = function (domain, node)
383 var name = node.nodeName;
384 var parser = domain.termtypes[name];
387 return parser (domain, node);
388 if (name == 'defun' || name == 'defmacro')
390 name = parse_defun_head (domain, node);
391 parse_defun_body (domain, node);
392 return new Xex.StrTerm (name);
394 if (name == 'defvar')
396 name = parse_defvar (doamin, node);
397 return new Xex.StrTerm (nanme);
400 return new Xex.Funcall.prototype.Parser (domain, node);
403 Xex.Varref = function (vname)
410 var proto = Xex.Varref.prototype;
412 proto.type = 'varref';
414 proto.Clone = function () { return new Xex.Varref (this.val); }
415 proto.Eval = function (domain)
417 if (! vari || vari.domain != domain)
418 vari = domain.GetVarCreate (this.val);
422 proto.Parser = function (domain, node)
424 return new Xex.Varref (node.attributes['vname'].nodeValue);
428 Xex.Varref.prototype = new Xex.Term ();
430 var null_args = new Array ();
432 Xex.Funcall = function (func, vari, args)
442 var proto = Xex.Funcall.prototype;
444 proto.type = 'funcall';
446 proto.Parser = function (domain, node)
448 var fname = node.nodeName;
451 if (fname == 'funcall')
452 fname = node.attributes['fname']
453 var func = domain.GetFunc (fname);
455 attr = node.attributes['vname'];
456 vari = attr != undefined ? domain.GetVarCreate (attr.nodeValue) : false;
457 var args = new Array ();
458 for (node = node.firstChild; node; node = node.nextSibling)
459 if (node.nodeType == 1)
460 args.push (Xex.ParseTerm (domain, node));
461 return new Xex.Funcall (func, vari, args);
464 proto.Eval = function (domain)
466 return this.func.Call (domain, this.vari, this.args);
469 proto.Clone = function ()
471 return new Xex.Funcall (this.func, this.vari, this.args);
474 proto.Equals = function (obj)
476 return (obj.type == 'funcall'
477 && obj.func == this.func
478 && obj.vari.Equals (this.vari)
479 && obj.args.length == this.func.length);
482 proto.toString = function ()
485 var len = this.args.length;
487 return '<' + this.func.name + '/>';
488 for (var i = 0; i < len; i++)
489 arglist += this.args[i].toString ();
490 return '<' + this.func.name + '>' + arglist + '</' + this.func.name + '>';
494 Xex.Funcall.prototype = new Xex.Term ();
496 Xex.ErrTerm = function (ename, message, stack)
501 var proto = Xex.ErrTerm.prototype;
503 proto.type = 'error';
505 proto.Parser = function (domain, node)
507 return new Xex.ErrTerm (node.attributes['ename'].nodeValue,
508 node.innerText, false);
511 proto.CallStack = function () { return stack; }
513 proto.SetCallStack = function (value) { statck = value; }
515 proto.Clone = function ()
517 return new Xex.ErrTerm (ename, message, false);
520 proto.Equals = function (obj)
522 return (obj.type == 'error'
523 && obj.ename == ename && obj.message == message
524 && (obj.stack ? (stack && stack.length == obj.stack.length)
528 proto.Matches = function (obj)
530 return (obj.type == 'error' && obj.ename == ename);
534 Xex.ErrTerm.prototype = new Xex.Term ();
536 Xex.IntTerm = function (num)
539 this.IsTrue = num != 0;
542 var proto = Xex.IntTerm.prototype;
543 proto.type = 'integer';
544 proto.Clone = function () { return new Xex.IntTerm (this.val); }
545 proto.Parser = function (domain, node)
547 return new Xex.IntTerm (parseInt (node.firstChild.nodeValue));
551 Xex.IntTerm.prototype = new Xex.Term ();
553 Xex.StrTerm = function (str)
556 this.IsTrue = str && str.length > 0;
559 var proto = Xex.StrTerm.prototype;
560 proto.type = 'string';
561 proto.Clone = function () { return new Xex.StrTerm (this.val); }
562 proto.Parser = function (domain, node)
564 return new Xex.StrTerm (node.firstChild.nodeValue);
568 Xex.StrTerm.prototype = new Xex.Term ();
570 Xex.LstTerm = function (list)
573 this.IsTrue = list && list.length > 0;
577 var proto = Xex.LstTerm.prototype;
581 proto.Clone = function () { return new Xex.LstTerm (this.val.slice ()); }
583 proto.Equals = function (obj)
585 if (obj.type != 'list' || obj.val.length != this.val.length)
587 var i, len = this.val.length;
588 for (i = 0; i < len; i++)
589 if (! this.val[i].Equals (obj.val[i]))
594 proto.Parser = function (domain, node)
596 var list = new Array ();
598 for (node = node.firstChild; node; node = node.nextSibling)
599 if (node.nodeType == 1)
600 list.push (Xex.ParseTerm (domain, node));
601 return new Xex.LstTerm (list);
604 proto.toString = function ()
606 var len = this.val.length;
611 for (i = 0; i < len; i++)
612 str += this.val[i].toString ();
613 return str + '</list>';
617 Xex.LstTerm.prototype = new Xex.Term ();
620 var basic = new Xex.Domain ('basic');
622 function Fset (domain, vari, args)
624 return vari.SetValue (args[0]);
627 function maybe_set_intvar (vari, n)
629 var term = new Xex.IntTerm (n);
631 vari.SetValue (term);
635 function Fadd (domain, vari, args)
637 var n = vari ? vari.val.val : 0;
638 var len = args.length;
640 for (var i = 0; i < len; i++)
642 return maybe_set_intvar (vari, n);
645 function Fand (domain, vari, args)
647 var len = args.length;
648 for (var i = 0; i < len; i++)
650 var result = args[i].Eval (domain);
651 if (domain.Thrown ())
659 function For (domain, vari, args)
661 var len = args.length;
662 for (var i = 0; i < len; i++)
664 var result = args[i].Eval (domain);
665 if (domain.Thrown ())
673 function Fprogn (domain, vari, args)
675 var result = Xex.One;
676 var len = args.length;
678 for (var i = 0; i < len; i++)
680 result = args[i].Eval (domain);
681 if (domain.Thrown ())
687 function Fif (domain, vari, args)
689 var result = args[0].Eval (domain);
691 if (domain.Thrown ())
694 return args[1].Eval (domain);
695 if (args.Length == 2)
697 return args[2].Eval (domain);
700 basic.DefSubr (Fset, "set", true, 1, 1);
701 basic.DefSubr (Fadd, "add", true, 1, -1);
702 basic.DefSpecial (Fand, "and", false, 1, -1);
703 basic.DefSpecial (For, "or", false, 1, -1);
704 basic.DefAlias ("=", "set");
705 basic.DefSpecial (Fprogn, "progn", false, 1, -1);
706 basic.DefSpecial (Fif, "if", false, 2, 3);
707 basic.DefType (new Xex.Funcall ());
708 basic.DefType (new Xex.Varref ());
709 basic.DefType (new Xex.ErrTerm ());
710 basic.DefType (new Xex.IntTerm ());
711 basic.DefType (new Xex.StrTerm ());
712 basic.DefType (new Xex.LstTerm ());
714 Xex.Domain.basic = basic;
717 Xex.Zero = new Xex.IntTerm (0);
718 Xex.One = new Xex.IntTerm (1);
720 var obj = new XMLHttpRequest ();
721 obj.open ('GET', 'xex.xml', false);
723 var body = obj.responseXML.firstChild;
724 var domain = Xex.Domain.basic;
725 document.ATTR = body;
726 alert (Xex.ParseTerm (domain, body).Eval (domain));