1 // -* coding: utf-8; -*
5 Log: function (indent, arg)
10 for (var i = 0; i < indent; i++)
12 Xex.LogNode.value = str + arg + "\n" + Xex.LogNode.value;
17 UnknownError: "unknown-error",
18 WrongArgument: "wrong-argument",
20 InvalidInteger: "invalid-integer",
21 TermTypeInvalid: "term-type-invalid",
22 FunctionConflict: "function-conflict",
23 VariableTypeConflict: "variable-type-conflict",
24 VariableRangeConflict: "variable-range-conflict",
25 VariableWrongRange: "variable-wrong-range",
26 VariableWrongValue: "variable-wrong-value",
28 UnknownFunction: "unknown-function",
29 MacroExpansionError: "macro-expansion-error",
30 NoVariableName: "no-variable-name",
31 NoFunctionName: "no-funcion-name",
34 ArithmeticError: "arithmetic-error",
35 WrongType: "wrong-type",
36 IndexOutOfRange: "index-out-of-range",
37 ValueOutOfRange: "value-out-of-range",
38 NoLoopToBreak: "no-loop-to-break",
39 UncaughtThrow: "uncaught-throw"
42 Xex.Variable = function (domain, name, desc, val, range)
51 Xex.Variable.prototype.clone = function ()
53 return new Xex.Variable (this.domain, this.name, this.desc,
54 this.val, this.range);
57 Xex.Variable.prototype.Equals = function (obj)
59 return ((obj instanceof Xex.Variable)
60 && obj.name == this.name);
63 Xex.Variable.prototype.SetValue = function (term)
69 Xex.Function = function (name, with_var, min_args, max_args)
72 this.with_var = with_var;
73 this.min_args = min_args;
74 this.max_args = max_args;
77 Xex.Subrountine = function (builtin, name, with_var, min_args, max_args)
80 this.with_var = with_var;
81 this.min_args = min_args;
82 this.max_args = max_args;
83 this.builtin = builtin;
86 Xex.Subrountine.prototype.Call = function (domain, vari, args)
88 newargs = new Array ();
89 for (var i = 0; i < args.length; i++)
91 newargs[i] = args[i].Eval (domain);
95 return this.builtin (domain, vari, newargs)
98 Xex.SpecialForm = function (builtin, name, with_var, min_args, max_args)
101 this.with_var = with_var;
102 this.min_args = min_args;
103 this.max_args = max_args;
104 this.builtin = builtin;
107 Xex.SpecialForm.prototype.Call = function (domain, vari, args)
109 return this.builtin (domain, vari, args)
112 Xex.Lambda = function (name, min_args, max_args, args, body)
115 this.min_args = min_args;
116 this.max_args = max_args;
121 Xex.Lambda.prototype.Call = function (domain, vari, args)
123 var current = domain.bindings;
124 var result = Xex.Zero;
125 var limit = max_args >= 0 ? args.length : args.length - 1;
129 for (i = 0; i < limit; i++)
131 result = args[i].Eval (domain);
132 if (domain.Thrown ())
134 domain.Bind (this.args[i], result);
138 var list = new Array ();
139 for (i = 0; i < args[limit].length; i++)
141 result = args[limit].Eval (domain);
142 if (domain.Thrown ())
146 domain.Bind (this.args[limit], list);
149 domain.Catch (Xex.CatchTag.Return);
150 for (var term in this.body)
152 result = term.Eval (domain);
153 if (domain.Thrown ())
160 domain.UnboundTo (current);
165 Xex.Macro = function (name, min_args, max_args, args, body)
168 this.min_args = min_args;
169 this.max_args = max_args;
174 Xex.Macro.prototype.Call = function (domain, vari, args)
176 var current = domain.bindings;
177 var result = Xex.Zero;
181 for (i = 0; i < args.length; i++)
182 domain.Bind (this.args[i], args[i]);
184 domain.Catch (Xex.CatchTag.Return);
185 for (var term in body)
187 result = term.Eval (domain);
188 if (domain.Thrown ())
195 domain.UnboundTo (current);
200 Xex.Bindings = function (vari)
203 this.old_value = vari.val;
206 Xex.Bindings.prototype.UnboundTo = function (boundary)
208 for (var b = this; b != boundary; b = b.next)
209 b.vari.val = b.old_value;
213 Xex.Bind = function (bindings, vari, val)
215 var b = new Xex.Bindings (vari);
226 Xex.Domain = function (name, parent, context)
229 this.context = context;
232 if (name != 'basic' && ! parent)
233 parent = Xex.BasicDomain
234 this.parent = parent;
241 for (elt in parent.termtypes)
242 this.termtypes[elt] = parent.termtypes[elt];
243 for (elt in parent.functions)
244 this.functions[elt] = parent.functions[elt];
245 for (elt in parent.variables)
246 this.variables[elt] = parent.variables[elt];
249 this.call_stack = new Array ();
250 this.bindings = null;
251 this.catch_stack = new Array ();
252 this.catch_count = 0;
256 Xex.Domain.prototype = {
257 CallStackCount: function () { return this.call_stack.length; },
258 CallStackPush: function (term) { this.call_stack.push (term); },
259 CallStackPop: function () { this.call_stack.pop (); },
260 Bind: function (vari, val)
262 this.bindings = Xex.Bind (this.bindings, vari, val);
264 UnboundTo: function (boundary)
267 this.bindings = this.bindings.UnboundTo (boundary);
269 Catch: function (tag) { this.catch_stack.push (tag); this.catch_count++; },
272 this.catch_stack.pop ();
273 if (this.catch_count > this.catch_stack.length)
278 if (this.catch_count < this.catch_stack.length)
280 this.caught = (this.catch_count == this.catch_stack.length - 1);
286 ThrowReturn: function ()
288 for (var i = this.catch_stack.length - 1; i >= 0; i--)
291 if (this.catch_stack[i] == Xex.CatchTag.Return)
295 ThrowBreak: function ()
297 if (this.catch_stack[this.catch_stack.length - 1] != Xex.CatchTag.Break)
298 throw new Xex.ErrTerm (Xex.Error.NoLoopToBreak,
299 "No surrounding loop to break");
302 ThrowSymbol: function (tag)
304 var i = this.catch_count;
305 for (var j = this.catch_stack.length - 1; j >= 0; j--)
308 if (Xex.CatchTag.Matches (this.catch_stack[i], tag))
310 this.catch_count = i;
314 throw new Xex.ErrTerm (Xex.Error.UncaughtThrow,
315 "No corresponding catch: " + tag);
317 DefType: function (obj)
320 if (this.termtypes[type])
321 throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
322 "Already defined: " + type);
323 if (this.functions[type])
324 throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
325 "Already defined as a funciton or a macro: "
327 this.termtypes[type] = obj.Parser;
329 DefSubr: function (builtin, name, with_var, min_args, max_args)
331 this.functions[name] = new Xex.Subrountine (builtin, name, with_var,
334 DefSpecial: function (builtin, name, with_var, min_args, max_args)
336 this.functions[name] = new Xex.SpecialForm (builtin, name, with_var,
339 Defun: function (name, min_args, max_args, args, body)
341 this.functions[name] = new Xex.Lambda (name, min_args, max_args,
344 DefunByFunc: function (func) { this.functions[func.name] = func; },
345 Defmacro: function (name, min_args, max_args, args, body)
347 this.functions[name] = new Xex.Macro (name, min_args, max_args,
350 DefAlias: function (alias, fname)
352 var func = this.functions[fname];
355 throw new Xex.ErrTerm (Xex.Error.UnknownFunction, fname);
356 if (this.termtypes[alias])
357 throw new Xex.ErrTerm (Xex.Error.FunctionConflict,
358 "Already defined as a term type: " + alias);
359 if (this.functions[alias])
360 throw new Xex.ErrTerm (Xex.Error.FunctionConflict,
361 "Already defined as a function: " + alias);
362 this.functions[alias] = func;
364 Defvar: function (name, desc, val, range)
366 var vari = new Xex.Variable (this, name, desc, val, range);
367 this.variables[name] = vari;
370 GetFunc: function (name)
372 var func = this.functions[name];
374 throw new Xex.ErrTerm (Xex.Error.UnknownFunction,
375 "Unknown function: " + name);
378 CopyFunc: function (domain, name)
380 var func = this.functions[name];
381 domain.DefunByFunc (func);
384 CopyFuncAll: function (domain)
386 for (var elt in this.functions)
387 domain.DefunByFunc (this.functions[elt]);
389 GetVarCreate: function (name)
391 var vari = this.variables[name];
393 vari = this.variables[name] = new Xex.Variable (this, name, null,
397 GetVar: function (name) { return this.variables[name]; },
398 SaveValues: function ()
401 for (var elt in this.variables)
402 values[elt] = this.variables[elt].val.Clone ();
405 RestoreValues: function (values)
410 var vari = this.variables[name];
411 vari.val = values[name];
416 Xex.Term = function (type) { this.type = type; }
417 Xex.Term.prototype = {
418 IsTrue: function () { return true; },
419 Eval: function (domain) { return this.Clone (); },
420 Clone: function (domain) { return this; },
421 Equals: function (obj)
423 return (this.type == obj.type
425 && obj.val == this.val);
427 Matches: function (obj) { return this.Equals (obj); },
428 toString: function ()
430 if (this.val != undefined)
431 return '<' + this.type + '>' + this.val + '</' + this.type + '>';
432 return '<' + this.type + '/>';
434 Intval: function () { throw new Xex.ErrTerm (Xex.Error.WrongType,
435 "Not an integer"); },
436 Strval: function () { throw new Xex.ErrTerm (Xex.Error.WrongType,
440 Node.prototype.firstElement = function ()
442 for (var n = this.firstChild; n; n = n.nextSibling)
448 Node.prototype.nextElement = function ()
450 for (var n = this.nextSibling; n; n = n.nextSibling)
457 function parse_defvar (domain, node)
459 var name = node.attributes['vname'].nodeValue;
461 throw new Xex.ErrTerm (Xex.Error.NoVariableName, node, '');
462 var vari = domain.variables[name];
463 var desc, val, range;
466 desc = vari.description;
470 node = node.firstElement ();
471 if (node && node.nodeName == 'description')
473 desc = node.firstChild.nodeValue;
474 node = node.nextElement ();
478 val = Xex.Term.Parse (domain, node);
479 node = node.nextElement ();
480 if (node && node.nodeName == 'possible-values')
481 for (node = node.firstElement (); node; node = node.nextElement ())
484 if (node.nodeName == 'range')
487 throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
488 'Range not allowed for ' + name);
490 for (var n = node.firstElement (); n; n = n.nextElement ())
492 var v = Xex.Term.Parse (domain, n);
494 throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
495 'Invalid range value: ' + val);
501 pval = Xex.Term.Parse (domain, node);
502 if (val.type != pval.type)
503 throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
504 'Invalid possible value: ' + pval);
507 range = new Array ();
513 domain.Defvar (name, desc, val, range);
517 function parse_defun_head (domain, node)
519 var name = node.attributes['fname'].nodeValue;
521 throw new Xex.ErrTerm (Xex.Error.NoFunctionName, node, '');
522 var args = new Array ();
523 var nfixed = 0, noptional = 0, nrest = 0;
525 node = node.firstElement ();
526 if (node && node.nodeName == 'args')
529 for (n = n.firstElement (); n; n = n.nextElement ())
531 if (n.nodeName == 'fixed')
533 else if (n.nodeName == 'optional')
535 else if (n.nodeName == 'rest')
538 throw new Xex.ErrTerm (Xex.Error.WrongType, n, n.nodeName);
541 throw new Xex.ErrTerm (Xex.Error.WrongType, n, 'Too many <rest>');
542 for (n = node.firstElement (); n; n = n.nextElement ())
543 args.push (domain.DefVar (n.attributes['vname'].nodeValue));
545 args.min_args = nfixed;
546 args.max_args = nrest == 0 ? nfixed + noptional : -1;
548 if (node.nodeName == 'defun')
549 domain.Defun (name, args, null);
551 domain.Defmacro (name, args, null);
555 function parse_defun_body (domain, node)
557 var name = node.attributes['fname'].nodeValue;
558 var func = domain.GetFunc (name);
560 for (node = node.firstElement (); node; node = node.nextElement ())
561 if (node.nodeName != 'description' && node.nodeName != 'args')
563 body = Xex.Term.Parse (domain, node, null);
567 Xex.Term.Parse = function (domain, node, stop)
569 if (arguments.length == 2)
571 var name = node.nodeName;
572 var parser = domain.termtypes[name];
575 return parser (domain, node);
576 if (name == 'defun' || name == 'defmacro')
578 name = parse_defun_head (domain, node);
579 parse_defun_body (domain, node);
580 return new Xex.StrTerm (name);
582 if (name == 'defvar')
584 name = parse_defvar (domain, node);
585 return new Xex.StrTerm (name);
587 return new Xex.Funcall.prototype.Parser (domain, node);
589 for (var n = node; n && n != stop; n = n.nextElement ())
590 if (n.nodeName == 'defun' || n.nodeName == 'defmacro')
591 parse_defun_head (domain, n);
593 for (var n = node; n && n != stop; n = n.nextElement ())
595 if (n.nodeName == 'defun' || n.nodeName == 'defmacro')
596 parse_defun_body (domain, n);
597 else if (n.nodeName == 'defvar')
598 parse_defvar (domain, n);
602 terms = new Array ();
603 terms.push (Xex.Term.Parse (domain, n));
610 Xex.Varref = function (vname)
616 var proto = new Xex.Term ('varref');
618 proto.Clone = function () { return new Xex.Varref (this.val); }
619 proto.Eval = function (domain)
621 if (! this.vari || this.vari.domain != domain)
622 this.vari = domain.GetVarCreate (this.val);
623 Xex.Log (domain.depth, this.ToString () + '=>' + this.vari.val);
624 return this.vari.val;
627 proto.Parser = function (domain, node)
629 return new Xex.Varref (node.attributes['vname'].nodeValue);
632 proto.ToString = function ()
634 return '<varref vname="' + this.val + '"/>';
637 Xex.Varref.prototype = proto;
640 var null_args = new Array ();
642 Xex.Funcall = function (func, vari, args)
646 this.args = args || null_args;
650 var proto = new Xex.Term ('funcall');
652 proto.Parser = function (domain, node)
654 var fname = node.nodeName;
657 if (fname == 'funcall')
658 fname = node.attributes['fname'].nodeValue;
659 var func = domain.GetFunc (fname);
661 attr = node.attributes['vname'];
662 vari = attr != undefined ? domain.GetVarCreate (attr.nodeValue) : false;
663 var args = Xex.Term.Parse (domain, node.firstElement (), null);
664 return new Xex.Funcall (func, vari, args);
667 proto.New = function (domain, fname, vname, args)
669 var func = domain.GetFunc (fname);
670 var vari = vname ? domain.GetVarCreate (vname) : null;
671 var funcall = new Xex.Funcall (func, vari, args);
672 if (func instanceof Xex.Macro)
673 funcall = funcall.Eval (domain);
677 proto.Eval = function (domain)
679 Xex.Log (domain.depth++, this);
682 result = this.func.Call (domain, this.vari, this.args);
684 Xex.Log (--domain.depth, this + ' => ' + result);
689 proto.Clone = function ()
691 return new Xex.Funcall (this.func, this.vari, this.args);
694 proto.Equals = function (obj)
696 return (obj.type == 'funcall'
697 && obj.func == this.func
698 && obj.vari.Equals (this.vari)
699 && obj.args.length == this.func.length);
702 proto.toString = function ()
705 var len = this.args.length;
706 var str = '<' + this.func.name;
708 str += ' vname="' + this.vari.name + '"';
711 for (var i = 0; i < len; i++)
712 arglist += this.args[i].toString ();
713 return str + '>' + arglist + '</' + this.func.name + '>';
716 Xex.Funcall.prototype = proto;
719 Xex.ErrTerm = function (ename, message, stack)
722 this.message = message;
727 var proto = new Xex.Term ('error');
729 proto.IsError = true;
731 proto.Parser = function (domain, node)
733 return new Xex.ErrTerm (node.attributes['ename'].nodeValue,
734 node.innerText, false);
737 proto.CallStack = function () { return stack; }
739 proto.SetCallStack = function (value) { statck = value; }
741 proto.Clone = function ()
743 return new Xex.ErrTerm (ename, message, false);
746 proto.Equals = function (obj)
749 && obj.ename == ename && obj.message == message
750 && (obj.stack ? (stack && stack.length == obj.stack.length)
754 proto.Matches = function (obj)
756 return (obj.IsError && obj.ename == ename);
759 proto.toString = function ()
761 return '<error ename="' + this.ename + '">' + this.message + '</error>';
764 Xex.ErrTerm.prototype = proto;
767 Xex.IntTerm = function (num) { this.val = num; };
769 var proto = new Xex.Term ('integer');
771 proto.Intval = function () { return this.val; };
772 proto.IsTrue = function () { return this.val != 0; }
773 proto.Clone = function () { return new Xex.IntTerm (this.val); }
774 proto.Parser = function (domain, node)
776 var str = node.firstChild.nodeValue;
778 if (str.charAt (0) == '?' && str.length == 2)
779 return new Xex.IntTerm (str.charCodeAt (1));
780 return new Xex.IntTerm (parseInt (node.firstChild.nodeValue));
782 Xex.IntTerm.prototype = proto;
785 Xex.StrTerm = function (str) { this.val = str; };
787 var proto = new Xex.Term ('string');
789 proto.Strval = function () { return this.val; };
790 proto.IsTrue = function () { return this.val.length > 0; }
791 proto.Clone = function () { return new Xex.StrTerm (this.val); }
792 proto.Parser = function (domain, node)
794 return new Xex.StrTerm (node.firstChild.nodeValue);
796 Xex.StrTerm.prototype = proto;
799 Xex.SymTerm = function (str) { this.val = str; };
801 var proto = new Xex.Term ('symbol');
802 proto.IsSymbol = true;
803 proto.IsTrue = function () { return this.val != 'nil'; }
804 proto.Clone = function () { return new Xex.SymTerm (this.val); }
805 proto.Parser = function (domain, node)
807 return new Xex.SymTerm (node.firstChild.nodeValue);
809 Xex.SymTerm.prototype = proto;
812 Xex.LstTerm = function (list) { this.val = list; };
814 var proto = new Xex.Term ('list');
816 proto.IsTrue = function () { return this.val.length > 0; }
817 proto.Clone = function () { return new Xex.LstTerm (this.val.slice (0)); }
819 proto.Equals = function (obj)
821 if (obj.type != 'list' || obj.val.length != this.val.length)
823 var i, len = this.val.length;
824 for (i = 0; i < len; i++)
825 if (! this.val[i].Equals (obj.val[i]))
830 proto.Parser = function (domain, node)
832 var list = Xex.Term.Parse (domain, node.firstElement (), null);
833 return new Xex.LstTerm (list);
836 proto.toString = function ()
838 var len = this.val.length;
843 for (var i = 0; i < len; i++)
844 str += this.val[i].toString ();
845 return str + '</list>';
847 Xex.LstTerm.prototype = proto;
851 var basic = new Xex.Domain ('basic', null, null);
853 function Fset (domain, vari, args)
855 return vari.SetValue (args[0]);
858 function maybe_set_intvar (vari, n)
860 var term = new Xex.IntTerm (n);
862 vari.SetValue (term);
866 function Fset (domain, vari, args)
869 throw new Xex.ErrTerm (Xex.Error.NoVariableName,
870 'No variable name to set');
871 vari.SetValue (args[0]);
875 function maybe_set_intvar (vari, n)
877 var term = new IntTerm (n);
879 vari.SetValue (term);
883 function Fadd (domain, vari, args)
885 var n = vari ? vari.val.Intval () : 0;
886 var len = args.length;
888 for (var i = 0; i < len; i++)
889 n += args[i].Intval ();
890 return maybe_set_intvar (vari, n);
893 function Fmul (domain, vari, args)
895 var n = vari ? vari.val.Intval () : 1;
896 for (var i = 0; i < args.length; i++)
898 return maybe_set_intvar (vari, n);
901 function Fsub (domain, vari, args)
907 n = args[0].Intval ();
912 n = vari.val.Intval ();
915 while (i < args.length)
916 n -= args[i++].Intval ();
917 return maybe_set_intvar (vari, n);
920 function Fdiv (domain, vari, args)
926 n = args[0].Intval ();
931 n = vari.val.Intval ();
934 while (i < args.length)
935 n /= args[i++].Intval ();
936 return maybe_set_intvar (vari, n);
939 function Fmod (domain, vari, args)
941 return maybe_set_intvar (vari, args[0].Intval () % args[1].Intval ());
944 function Flogior (domain, vari, args)
946 var n = vari == null ? 0 : vari.val;
947 for (var i = 0; i < args.length; i++)
949 return maybe_set_intvar (vari, n);
952 function Fand (domain, vari, args)
954 var len = args.length;
955 for (var i = 0; i < len; i++)
957 var result = args[i].Eval (domain);
958 if (domain.Thrown ())
960 if (! result.IsTrue ())
966 function For (domain, vari, args)
968 var len = args.length;
969 for (var i = 0; i < len; i++)
971 var result = args[i].Eval (domain);
972 if (domain.Thrown ())
974 if (result.IsTrue ())
980 function Feq (domain, vari, args)
982 for (var i = 1; i < args.length; i++)
983 if (! args[i - 1].Equals (args[i]))
988 function Flt (domain, vari, args)
990 var n = args[0].Intval;
992 for (var i = 1; i < args.length; i++)
994 var n1 = args[i].Intval;
1002 function Fle (domain, vari, args)
1004 var n = args[0].Intval;
1005 for (var i = 1; i < args.length; i++)
1007 var n1 = args[i].Intval;
1015 function Fgt (domain, vari, args)
1017 var n = args[0].Intval;
1018 for (var i = 1; i < args.length; i++)
1020 var n1 = args[i].Intval;
1028 function Fge (domain, vari, args)
1030 var n = args[0].Intval;
1031 for (var i = 1; i < args.Length; i++)
1033 var n1 = args[i].Intval;
1041 function Fprogn (domain, vari, args)
1043 var result = Xex.One;
1044 var len = args.length;
1046 for (var i = 0; i < len; i++)
1048 result = args[i].Eval (domain);
1049 if (domain.Thrown ())
1055 function Fif (domain, vari, args)
1057 var result = args[0].Eval (domain);
1059 if (domain.Thrown ())
1061 if (result.IsTrue ())
1062 return args[1].Eval (domain);
1063 if (args.length == 2)
1065 return args[2].Eval (domain);
1068 function Fcond (domain, vari, args)
1070 for (var i = 0; i < args.length; i++)
1072 var list = args[i].val;
1073 var result = list.val[0].Eval (doamin);
1074 if (result.isTrue ())
1076 for (var j = 1; j < list.val.length; j++)
1079 result = list.val[j].Eval (domain);
1081 if (domain.Thrown ())
1090 function eval_terms (domain, terms, idx)
1092 var result = Xex.Zero;
1093 domain.caught = false;
1094 for (var i = idx; i < terms.length; i++)
1096 result = terms[i].Eval (domain);
1097 if (domain.Thrown ())
1103 function Fcatch (domain, vari, args)
1108 if (args[0].IsError)
1111 result = eval_terms (domain, args, 1);
1113 if (e instanceof Xex.ErrTerm)
1115 if (! args[0].Matches (e))
1123 else if (args[0].IsSymbol)
1126 domain.Catch (args[0].val);
1127 result = eval_terms (domain, args, 1);
1131 vari.SetValue (result);
1139 throw new Xex.ErrTerm (Xex.Error.WrongArgument,
1140 "Not a symbol nor an error: " + args[0]);
1143 function Fthrow (domain, vari, args)
1145 if (args[0].IsSymbl)
1147 domain.ThrowSymbol (args[0]);
1148 return (args[args.length - 1]);
1150 if (args[0].IsError)
1154 throw new Xex.ErrTerm (Xex.Error.WrongArgument,
1155 "Not a symbol nor an error:" + args[0]);
1158 Xex.BasicDomain = basic;
1160 basic.DefSubr (Fset, "set", true, 1, 1);
1161 basic.DefAlias ("=", "set");
1162 //basic.DefSubr (Fnot, "not", false, 1, 1);
1163 //basic.DefAlias ("!", "not");
1164 basic.DefSubr (Fadd, "add", true, 1, -1);
1165 basic.DefSubr (Fmul, "mul", true, 1, -1);
1166 basic.DefAlias ("*", "mul");
1167 basic.DefSubr (Fsub, "sub", true, 1, -1);
1168 basic.DefAlias ("-", "sub");
1169 basic.DefSubr (Fdiv, "div", true, 1, -1);
1170 basic.DefAlias ("/", "div");
1171 basic.DefSubr (Fmod, "mod", true, 1, 2);
1172 basic.DefAlias ("%", "mod");
1173 basic.DefSubr (Flogior, "logior", true, 1, -1);
1174 basic.DefAlias ('|', "logior");
1175 //basic.DefSubr (Flogand, "logand", true, 1, -1);
1176 //basic.DefAlias ("&", "logand");
1177 //basic.DefSubr (Flsh, "lsh", true, 1, 2);
1178 //basic.DefAlias ("<<", "lsh");
1179 //basic.DefSubr (Frsh, "rsh", true, 1, 2);
1180 //basic.DefAlias (">>", "rsh");
1181 basic.DefSubr (Feq, "eq", false, 2, -1);
1182 basic.DefAlias ("==", "eq");
1183 //basic.DefSubr (Fnoteq, "noteq", false, 2, 2);
1184 //basic.DefAlias ("!=", "noteq");
1185 basic.DefSubr (Flt, "lt", false, 2, -1);
1186 basic.DefAlias ("<", "lt");
1187 basic.DefSubr (Fle, "le", false, 2, -1);
1188 basic.DefAlias ("<=", "le");
1189 basic.DefSubr (Fgt, "gt", false, 2, -1);
1190 basic.DefAlias (">", "gt");
1191 basic.DefSubr (Fge, "ge", false, 2, -1);
1192 basic.DefAlias (">=", "ge");
1193 basic.DefSubr (Fthrow, "throw", false, 1, 2);
1195 //basic.DefSubr (Fappend, "append", true, 0, -1);
1196 //basic.DefSubr (Fconcat, "concat", true, 0, -1);
1197 //basic.DefSubr (Fnth, "nth", false, 2, 2);
1198 //basic.DefSubr (Fcopy, "copy", false, 1, 1);
1199 //basic.DefSubr (Fins, "ins", true, 2, 2);
1200 //basic.DefSubr (Fdel, "del", true, 2, 2);
1201 //basic.DefSubr (Feval, "eval", false, 1, 1);
1202 //basic.DefSubr (Fbreak, "break", false, 0, 1);
1203 //basic.DefSubr (Freturn, "return", false, 0, 1);
1204 //basic.DefSubr (Fthrow, "throw", false, 1, 2);
1206 basic.DefSpecial (Fand, "and", false, 1, -1);
1207 basic.DefAlias ("&&", "and");
1208 basic.DefSpecial (For, "or", false, 1, -1);
1209 basic.DefAlias ("||", "or");
1210 basic.DefSpecial (Fprogn, "progn", false, 1, -1);
1211 basic.DefAlias ("expr", "progn");
1212 basic.DefSpecial (Fif, "if", false, 2, 3);
1213 //basic.DefSpecial (Fwhen, "when", false, 1, -1);
1214 //basic.DefSpecial (Floop, "loop", false, 1, -1);
1215 //basic.DefSpecial (Fwhile, "while", false, 1, -1);
1216 basic.DefSpecial (Fcond, "cond", false, 1, -1);
1217 //basic.DefSpecial (Fforeach, "foreach", true, 2, -1);
1218 //basic.DefSpecial (Fquote, "quote", false, 1, 1);
1219 //basic.DefSpecial (Ftype, "type", false, 1, 1);
1220 basic.DefSpecial (Fcatch, "catch", true, 2, -1);
1222 basic.DefType (Xex.Funcall.prototype);
1223 basic.DefType (Xex.Varref.prototype);
1224 basic.DefType (Xex.ErrTerm.prototype);
1225 basic.DefType (Xex.IntTerm.prototype);
1226 basic.DefType (Xex.StrTerm.prototype);
1227 basic.DefType (Xex.SymTerm.prototype);
1228 basic.DefType (Xex.LstTerm.prototype);
1232 Xex.Zero = new Xex.IntTerm (0);
1233 Xex.One = new Xex.IntTerm (1);
1234 Xex.nil = new Xex.SymTerm ('nil');
1236 Xex.Load = function (server, file)
1238 var obj = new XMLHttpRequest ();
1239 var url = server ? server + '/' + file : file;
1240 obj.open ('GET', url, false);
1241 obj.overrideMimeType ('text/xml');
1243 return obj.responseXML.firstChild;
1247 // URL of the input method server.
1248 server: "http://www.m17n.org/common/mim-js",
1249 // Boolean flag to tell if MIM is active or not.
1251 // Boolean flag to tell if MIM is running in debug mode or not.
1253 // List of main input methods.
1255 // List of extra input methods;
1257 // Global input method data
1259 // Currently selected input method.
1263 LoadStatus: { NotLoaded:0, Loading:1, Loaded:2, Error:-1 },
1270 CandidateIndex:0x10,
1272 Preedit: 0x06, // PreeditText | CursorPos
1273 Candidate: 0x38 // CandidateList | CandidateIndex | CandidateShow
1295 ParseError: "parse-error"
1300 var keysyms = new Array ();
1301 keysyms["bs"] = "backspace";
1302 keysyms["lf"] = "linefeed";
1303 keysyms["cr"] = keysyms["enter"] = "return";
1304 keysyms["esc"] = "escape";
1305 keysyms["spc"] = "space";
1306 keysyms["del"] = "delete";
1308 function decode_keysym (str) {
1309 var parts = str.split ("-");
1310 var len = parts.length, i;
1311 var has_modifier = len > 1;
1313 for (i = 0; i < len - 1; i++)
1314 if (! MIM.KeyModifier.hasOwnProperty (parts[i]))
1316 var key = parts[len - 1];
1319 key = keysyms[key.toLowerCase ()];
1325 for (i = 1; i < len - 1; i++)
1326 str += '-' + parts[i];
1335 parts = new Array ();
1342 MIM.Key = function (val)
1345 this.has_modifier = false;
1346 if (typeof val == 'string' || val instanceof String)
1348 this.key = decode_keysym (val);
1350 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + val);
1351 if (this.key instanceof Array)
1353 this.key = this.key[0];
1354 this.has_modifier = true;
1357 else if (typeof val == 'number' || val instanceof Number)
1358 this.key = String.fromCharCode (val);
1360 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + val);
1363 MIM.Key.prototype.toString = function () { return this.key; };
1367 MIM.KeySeq = function (seq)
1369 this.val = new Array ();
1370 this.has_modifier = false;
1376 var len = seq.val.length;
1377 for (var i = 0; i < len; i++)
1380 if (v.type != 'string' && v.type != 'integer'
1381 && v.type != 'symbol')
1382 throw new Xex.ErrTerm (MIM.Error.ParseError,
1383 "Invalid key: " + v);
1384 var key = new MIM.Key (v.val);
1385 this.val.push (key);
1386 if (key.has_modifier)
1387 this.has_modifier = true;
1392 var len = seq.val.length;
1393 for (var i = 0; i < len; i++)
1394 this.val.push (new MIM.Key (seq.val.charCodeAt (i)));
1397 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + seq);
1401 var proto = new Xex.Term ('keyseq');
1402 proto.Clone = function () { return this; }
1403 proto.Parser = function (domain, node)
1405 var seq = new Array ();
1406 for (node = node.firstChild; node; node = node.nextSibling)
1407 if (node.nodeType == 1)
1409 var term = Xex.Term.Parse (domain, node);
1410 return new MIM.KeySeq (term);
1412 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid keyseq");
1414 proto.toString = function ()
1416 var len = this.val.length;
1420 var str = '<keyseq>';
1421 for (var i = 0; i < len; i++)
1425 else if (this.has_modifier)
1427 str += this.val[i].toString ();
1429 return str + '</keyseq>';
1432 MIM.KeySeq.prototype = proto;
1436 MIM.Marker = function () { }
1437 MIM.Marker.prototype = new Xex.Term ('marker');
1438 MIM.Marker.prototype.CharAt = function (ic)
1440 var p = this.Position (ic);
1441 if (p < 0 || p >= ic.preedit.length)
1443 return ic.preedit.charCodeAt (p);
1446 MIM.NamedMarker = function (name) { this.val = name; }
1447 MIM.NamedMarker.prototype = new MIM.Marker ();
1448 MIM.NamedMarker.prototype.Position = function (ic)
1450 var p = ic.marker_positions[this.val];
1451 return (p == undefined ? 0 : p);
1453 MIM.NamedMarker.prototype.Mark = function (ic)
1455 ic.marker_positions[this.val] = ic.cursor_pos;
1458 MIM.PredefinedMarker = function (name) { this.val = name; }
1459 MIM.PredefinedMarker.prototype = new MIM.Marker ();
1460 MIM.PredefinedMarker.prototype.Position = function (ic)
1462 if (typeof this.pos == 'number')
1464 return this.pos (ic);
1467 var predefined = { }
1469 function def_predefined (name, position)
1471 predefined[name] = new MIM.PredefinedMarker (name);
1472 predefined[name].pos = position;
1475 def_predefined ('@<', 0);
1476 def_predefined ('@>', function (ic) { return ic.preedit.length; });
1477 def_predefined ('@-', function (ic) { return ic.cursor_pos - 1; });
1478 def_predefined ('@+', function (ic) { return ic.cursor_pos + 1; });
1479 def_predefined ('@[', function (ic) {
1480 if (ic.cursor_pos > 0)
1482 var pos = ic.cursor_pos;
1483 return ic.preedit.FindProp ('candidates', pos - 1).from;
1487 def_predefined ('@]', function (ic) {
1488 if (ic.cursor_pos < ic.preedit.length - 1)
1490 var pos = ic.cursor_pos;
1491 return ic.preedit.FindProp ('candidates', pos).to;
1493 return ic.preedit.length;
1495 for (var i = 0; i < 10; i++)
1496 def_predefined ("@" + i, i);
1497 predefined['@first'] = predefined['@<'];
1498 predefined['@last'] = predefined['@>'];
1499 predefined['@previous'] = predefined['@-'];
1500 predefined['@next'] = predefined['@+'];
1501 predefined['@previous-candidate-change'] = predefined['@['];
1502 predefined['@next-candidate-change'] = predefined['@]'];
1504 MIM.SurroundMarker = function (name)
1507 this.distance = parseInt (name.slice (1));
1508 if (isNaN (this.distance))
1509 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid marker: " + name);
1511 MIM.SurroundMarker.prototype = new MIM.Marker ();
1512 MIM.SurroundMarker.prototype.Position = function (ic)
1514 return ic.cursor_pos + this.distance;
1516 MIM.SurroundMarker.prototype.CharAt = function (ic)
1518 if (this.val == '@-0')
1520 var p = this.Position (ic);
1522 return ic.GetSurroundingChar (p);
1523 else if (p >= ic.preedit.length)
1524 return ic.GetSurroundingChar (p - ic.preedit.length);
1525 return ic.preedit.charCodeAt (p);
1528 MIM.Marker.prototype.Parser = function (domain, node)
1530 var name = node.firstChild.nodeValue;
1531 if (name.charAt (0) == '@')
1533 var n = predefined[name];
1536 if (name.charAt (1) == '-')
1537 return new MIM.SurroundMarker (name);
1538 throw new Xex.ErrTerm (MIM.Error.ParseError,
1539 "Invalid marker: " + name);
1541 return new MIM.NamedMarker (name);
1545 MIM.Selector = function (name)
1549 MIM.Selector.prototype = new Xex.Term ('selector');
1553 selectors["@<"] = selectors["@first"] = new MIM.Selector ('@<');
1554 selectors["@="] = selectors["@current"] = new MIM.Selector ('@=');
1555 selectors["@>"] = selectors["@last"] = new MIM.Selector ('@>');
1556 selectors["@-"] = selectors["@previous"] = new MIM.Selector ('@-');
1557 selectors["@+"] = selectors["@next"] = new MIM.Selector ('@+');
1558 selectors["@["] = selectors["@previous-candidate-change"]
1559 = new MIM.Selector ('@[');
1560 selectors["@]"] = selectors["@next-candidate-change"]
1561 = new MIM.Selector ('@]');
1563 MIM.Selector.prototype.Parser = function (domain, node)
1565 var name = node.firstChild.nodeValue;
1566 var s = selectors[name];
1568 throw new Xex.ErrTerm (MIM.Error.ParseError,
1569 "Invalid selector: " + name);
1574 MIM.Rule = function (keyseq, actions)
1576 this.keyseq = keyseq;
1577 this.actions = actions;
1579 MIM.Rule.prototype = new Xex.Term ('rule');
1580 MIM.Rule.prototype.Parser = function (domain, node)
1583 for (n = node.firstChild; n && n.nodeType != 1; n = n.nextSibling);
1585 throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid rule:" + node);
1586 var keyseq = Xex.Term.Parse (domain, n);
1587 if (keyseq.type != 'keyseq')
1588 throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid rule:" + node);
1589 var actions = Xex.Term.Parse (domain, n.nextElement (), null);
1590 return new MIM.Rule (keyseq, actions);
1592 MIM.Rule.prototype.toString = function ()
1597 MIM.Map = function (name)
1600 this.rules = new Array ();
1604 var proto = new Xex.Term ('map');
1606 proto.Parser = function (domain, node)
1608 var name = node.attributes['mname'].nodeValue;
1610 throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid map");
1611 var map = new MIM.Map (name);
1612 for (var n = node.firstChild; n; n = n.nextSibling)
1613 if (n.nodeType == 1)
1614 map.rules.push (Xex.Term.Parse (domain, n));
1618 proto.toString = function ()
1620 var str = '<map mname="' + this.name + '">';
1621 var len = this.rules.length;
1622 for (i = 0; i < len; i++)
1623 str += this.rules[i];
1624 return str + '</map>';
1627 MIM.Map.prototype = proto;
1630 Xex.CatchTag._mimtag = new Xex.SymTerm ('@mimtag');
1632 MIM.Action = function (domain, terms)
1634 var args = new Array ();
1635 args.push (Xex.CatchTag_.mimtag);
1636 for (var i = 0; i < terms.length; i++)
1637 args.push (terms[i]);
1638 this.action = Xex.Funcall.prototype.New (domain, 'catch', null, args);
1641 MIM.Action.prototype.Run = function (domain)
1643 var result = this.action.Eval (domain);
1644 if (result.type == 'error')
1646 domain.context.Error = result.toString ();
1649 return (result != Xex.CatchTag._mimtag);
1652 MIM.Keymap = function ()
1655 this.submaps = null;
1656 this.actions = null;
1662 function add_rule (keymap, rule)
1664 var keyseq = rule.keyseq;
1665 var len = keyseq.val.length;
1668 for (var i = 0; i < len; i++)
1670 var key = keyseq.val[i];
1674 if (! keymap.submaps)
1675 keymap.submaps = {};
1677 sub = keymap.submaps[key.key];
1679 keymap.submaps[key.key] = sub = new MIM.Keymap ();
1683 keymap.actions = rule.actions;
1686 proto.Add = function (map)
1688 var rules = map.rules;
1689 var len = rules.length;
1691 for (var i = 0; i < len; i++)
1692 add_rule (this, rules[i]);
1694 proto.Lookup = function (keys, index)
1698 if (index < keys.val.length && this.submaps
1699 && (sub = this.submaps[keys.val[index].key]))
1702 return sub.Lookup (keys, index);
1704 return { map: this, index: index };
1707 MIM.Keymap.prototype = proto;
1710 MIM.State = function (name)
1713 this.keymap = new MIM.Keymap ();
1717 var proto = new Xex.Term ('state');
1719 proto.Parser = function (domain, node)
1721 var map_list = domain.map_list;
1722 var name = node.attributes['sname'].nodeValue;
1724 throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid map");
1725 var state = new MIM.State (name);
1726 for (node = node.firstElement (); node; node = node.nextElement ())
1728 if (node.nodeName == 'title')
1729 state.title = node.firstChild.nodeValue;
1732 var n = node.firstElement ();
1733 if (node.nodeName == 'branch')
1735 state.keymap.Add (map_list[node.attributes['mname'].nodeValue]);
1736 state.keymap.actions = Xex.Term.Parse (domain, n, null);
1738 else if (node.nodeName == 'state-hook')
1739 state.enter_actions = Xex.Term.Parse (domain, n, null);
1740 else if (node.nodeName == 'catch-all-branch')
1741 state.fallback_actions = Xex.Term.Parse (domain, n, null);
1747 proto.toString = function ()
1749 return '<state sname="' + this.name + '">' + this.keymap + '</state>';
1752 MIM.State.prototype = proto;
1756 function Block (index, term)
1760 this.Data = term.val;
1761 else if (term.IsList)
1763 this.Data = new Array ();
1764 for (var i = 0; i < term.val.length; i++)
1765 this.Data.push (term.val[i].val);
1769 Block.prototype.Count = function () { return this.Data.length; }
1770 Block.prototype.get = function (i)
1772 return (this.Data instanceof Array ? this.Data[i] : this.Data.charAt (i));
1775 MIM.Candidates = function (candidates, column)
1777 this.column = column;
1781 this.blocks = new Array ();
1783 for (var i = 0; i < candidates.length; i++)
1785 var block = new Block (this.total, candidates[i]);
1786 this.blocks.push (block);
1787 this.total += block.Count ();
1793 return (this.column > 0 ? this.index % this.column
1794 : this.index - this.blocks[this.row].Index);
1797 function prev_group ()
1799 var col = get_col.call (this);
1801 if (this.column > 0)
1803 this.index -= this.column;
1804 if (this.index >= 0)
1805 nitems = this.column;
1808 var lastcol = (this.total - 1) % this.column;
1809 this.index = (col < lastcol ? this.total - lastcol + col
1811 this.row = this.blocks.length - 1;
1812 nitems = lastcol + 1;
1814 while (this.blocks[this.row].Index > this.index)
1819 this.row = this.row > 0 ? this.row - 1 : this.blocks.length - 1;
1820 nitems = this.blocks[this.row].Count ();
1821 this.index = (this.blocks[this.row].Index
1822 + (col < nitems ? col : nitems - 1));
1827 function next_group ()
1829 var col = get_col.call (this);
1831 if (this.column > 0)
1833 this.index += this.column - col;
1834 if (this.index < this.total)
1836 if (this.index + col >= this.total)
1838 nitems = this.total - this.index;
1839 this.index = this.total - 1;
1843 nitems = this.column;
1852 while (this.blocks[this.row].Index > this.index)
1857 this.row = this.row < this.blocks.length - 1 ? this.row + 1 : 0;
1858 nitems = this.blocks[this.row].Count ();
1859 this.index = (this.blocks[this.row].Index
1860 + (col < nitems ? col : nitems - 1));
1867 if (this.index == 0)
1869 this.index = this.total - 1;
1870 this.row = this.blocks.length - 1;
1875 if (this.blocks[this.row].Index > this.index)
1883 if (this.index == this.total)
1890 var b = this.blocks[this.row];
1891 if (this.index == b.Index + b.Count ())
1898 this.index -= get_col.call (this);
1899 while (this.blocks[this.row].Index > this.index)
1905 var b = this.blocks[this.row];
1906 if (this.column > 0)
1908 if (this.index + 1 < this.total)
1910 this.index += this.column - get_col.call (this) + 1;
1911 while (b.Index + b.Count () <= this.index)
1912 b = this.blocks[++this.row];
1916 this.index = b.Index + b.Count () - 1;
1919 MIM.Candidates.prototype.Current = function ()
1921 var b = this.blocks[this.row];
1922 return b.get (this.index - b.Index);
1925 MIM.Candidates.prototype.Select = function (selector)
1927 if (selector.type == 'selector')
1929 switch (selector.val)
1931 case '@<': first.call (this); break;
1932 case '@>': last.call (this); break;
1933 case '@-': prev.call (this); break;
1934 case '@+': next.call (this); break;
1935 case '@[': prev_group.call (this); break;
1936 case '@]': next_group.cal (this); break;
1939 return this.Current ();
1942 if (this.column > 0)
1944 col = this.index % this.column;
1945 start = this.index - col;
1946 end = start + this.column;
1950 start = this.blocks[this.row].Index;
1951 col = this.index - start;
1952 end = start + this.blocks[this.row].Count;
1954 if (end > this.total)
1956 this.index += selector.val - col;
1957 if (this.index >= end)
1958 this.index = end - 1;
1959 if (this.column > 0)
1961 if (selector.val > col)
1962 while (this.blocks[this.row].Index + this.blocks[this.row].Count
1966 while (this.blocks[this.row].Index > this.index)
1969 return this.Current ();
1973 MIM.im_domain = new Xex.Domain ('input-method', null, null);
1974 MIM.im_domain.DefType (MIM.KeySeq.prototype);
1975 MIM.im_domain.DefType (MIM.Marker.prototype);
1976 MIM.im_domain.DefType (MIM.Selector.prototype);
1977 MIM.im_domain.DefType (MIM.Rule.prototype);
1978 MIM.im_domain.DefType (MIM.Map.prototype);
1979 MIM.im_domain.DefType (MIM.State.prototype);
1982 var im_domain = MIM.im_domain;
1984 function Finsert (domain, vari, args)
1987 if (args[0].type == 'integer')
1988 text = String.fromCharCode (args[0].val);
1991 domain.context.insert (text, null);
1994 function Finsert_candidates (domain, vari, args)
1996 var ic = domain.context;
1997 var gsize = domain.variables['candidates_group_size'];
1998 var candidates = new MIM.Candidates (args, gsize ? gsize.Intval : 0);
1999 ic.insert (candidates.Current (), candidates);
2003 function Fdelete (domain, vari, args)
2005 var ic = domain.context;
2006 var pos = args[0].IsInt ? args[0].Intval : args[0].Position (ic);
2008 return new Xex.Term (ic.del (pos));
2011 function Fselect (domain, vari, args)
2013 var ic = domain.context;
2014 var can = ic.candidates;
2018 var candidate = can.Current ();
2020 ic.del (ic.cursor_pos - candidate.length);
2021 candidate = can.Select (args[0]);
2022 ic.insert (candidate, can);
2027 function Fchar_at (domain, vari, args)
2029 return new Xex.IntTerm (args[0].CharAt (domain.context));
2032 function Fmove (domain, vari, args)
2034 var ic = domain.context;
2035 var pos = args[0].IsInt ? args[0].val : args[0].Position (ic);
2040 function Fmark (domain, vari, args)
2042 args[0].Mark (domain.context);
2046 function Fpushback (domain, vari, args)
2048 var arg = (args[0].IsInt ? args[0].Intval
2049 : args[0].IsStr ? new KeySeq (args[0])
2051 domain.context.pushback (arg)
2055 function Fundo (domain, vari, args)
2057 var ic = domain.context;
2058 var n = args.length == 0 ? -2 : args[0].val;
2060 ic.keys.val.splice (ic.keys.length + n, -n);
2062 ic.keys.val.splice (n, ic.keys.length);
2067 function Fcommit (domain, vari, args)
2069 domain.context.commit ();
2073 function Funhandle (domain, vari, args)
2075 domain.context.commit ();
2076 return Xex.Fthrow (domain, vari, Xex.CatchTag._mimtag);
2079 function Fshift (domain, vari, args)
2081 var ic = domain.context;
2082 var state_name = args[0].val;
2083 var state = ic.im.state_list[state_name];
2085 throw ("Unknown state: " + state_name);
2090 function Fsurrounding_flag (domain, vari, args)
2092 return new Xex.IntTerm (-1);
2095 im_domain.DefSubr (Finsert, "insert", false, 1, 1);
2096 im_domain.DefSubr (Finsert_candidates, "insert-candidates", false, 1, 1);
2097 im_domain.DefSubr (Fdelete, "delete", false, 1, 1);
2098 im_domain.DefSubr (Fselect, "select", false, 1, 1);
2099 //im_domain.DefSubr (Fshow, "show-candidates", false, 0, 0);
2100 //im_domain.DefSubr (Fhide, "hide-candidates", false, 0, 0);
2101 im_domain.DefSubr (Fmove, "move", false, 1, 1);
2102 im_domain.DefSubr (Fmark, "mark", false, 1, 1);
2103 im_domain.DefSubr (Fpushback, "pushback", false, 1, 1);
2104 //im_domain.DefSubr (Fpop, "pop", false, 0, 0);
2105 im_domain.DefSubr (Fundo, "undo", false, 0, 1);
2106 im_domain.DefSubr (Fcommit, "commit", false, 0, 0);
2107 im_domain.DefSubr (Funhandle, "unhandle", false, 0, 0);
2108 im_domain.DefSubr (Fshift, "shift", false, 1, 1);
2109 //im_domain.DefSubr (Fshiftback, "shiftback", false, 0, 0);
2110 im_domain.DefSubr (Fchar_at, "char-at", false, 1, 1);
2111 //im_domain.DefSubr (Fkey_count, "key-count", false, 0, 0);
2112 im_domain.DefSubr (Fsurrounding_flag, "surrounding-text-flag", false, 0, 0);
2117 function get_global_var (vname)
2119 if (MIM.im_global.load_status == MIM.LoadStatus.NotLoaded)
2120 MIM.im_global.Load ()
2121 return MIM.im_global.domain.variables[vname];
2124 function include (node)
2126 node = node.firstElement ();
2127 if (node.nodeName != 'tags')
2130 var lang = null, name = null, extra = null;
2131 for (node = node.firstElement (); node; node = node.nextElement ())
2133 if (node.nodeName == 'language')
2134 lang = node.firstChild.nodeValue;
2135 else if (node.nodeName == 'name')
2136 name = node.firstChild.nodeValue;
2137 else if (node.nodeName == 'extra-id')
2138 extra = node.firstChild.nodeValue;
2140 if (! lang || ! MIM.imlist[lang])
2144 if (! name || ! (im = MIM.imlist[lang][name]))
2149 if (! (im = MIM.imextra[lang][extra]))
2152 if (im.load_status != MIM.LoadStatus.Loaded
2153 && (im.load_status != MIM.LoadStatus.NotLoaded || ! im.Load ()))
2160 parsers['description'] = function (node)
2162 this.description = node.firstChild.nodeValue;
2164 parsers['variable-list'] = function (node)
2166 for (node = node.firstElement (); node; node = node.nextElement ())
2168 var vname = node.attributes['vname'].nodeValue;
2169 if (this != MIM.im_global)
2171 var vari = get_global_var (vname);
2173 this.domain.Defvar (vname);
2175 vname = Xex.Term.Parse (this.domain, node)
2178 parsers['command-list'] = function (node)
2181 parsers['macro-list'] = function (node)
2183 for (var n = node.firstElement (); n; n = n.nextElement ())
2184 if (n.nodeName == 'xi:include')
2186 var im = include (n);
2188 alert ('inclusion fail');
2190 for (var macro in im.domain.functions)
2192 var func = im.domain.functions[macro];
2193 if (func instanceof Xex.Macro)
2194 im.domain.CopyFunc (this.domain, macro);
2196 n = n.previousSibling;
2197 node.removeChild (n.nextSibling);
2199 Xex.Term.Parse (this.domain, node.firstElement (), null);
2201 parsers['title'] = function (node)
2203 this.title = node.firstChild.nodeValue;
2205 parsers['map-list'] = function (node)
2207 for (node = node.firstElement (); node; node = node.nextElement ())
2209 if (node.nodeName == 'xi:include')
2211 var im = include (node);
2214 alert ('inclusion fail');
2217 for (var mapname in im.map_list)
2218 this.map_list[mapname] = im.map_list[mapname];
2222 var map = Xex.Term.Parse (this.domain, node);
2223 this.map_list[map.name] = map;
2227 parsers['state-list'] = function (node)
2229 this.domain.map_list = this.map_list;
2230 for (node = node.firstElement (); node; node = node.nextElement ())
2232 if (node.nodeName == 'state')
2234 var state = Xex.Term.Parse (this.domain, node);
2236 state.title = this.title;
2237 if (! this.initial_state)
2238 this.initial_state = state;
2239 this.state_list[state.name] = state;
2242 delete this.domain.map_list;
2245 MIM.IM = function (lang, name, extra_id, file)
2249 this.extra_id = extra_id;
2251 this.load_status = MIM.LoadStatus.NotLoaded;
2252 this.domain = new Xex.Domain (this.lang + '-'
2253 + (this.name != 'nil'
2254 ? this.name : this.extra_id),
2255 MIM.im_domain, null);
2261 var node = Xex.Load (null, this.file);
2264 this.load_status = MIM.LoadStatus.Error;
2268 this.initial_state = null;
2269 this.state_list = {};
2270 for (node = node.firstElement (); node; node = node.nextElement ())
2272 var name = node.nodeName;
2273 var parser = parsers[name];
2275 parser.call (this, node);
2277 this.load_status = MIM.LoadStatus.Loaded;
2282 MIM.IM.prototype = proto;
2284 MIM.IC = function (im, target)
2286 if (im.load_status == MIM.LoadStatus.NotLoaded)
2288 if (im.load_status != MIM.LoadStatus.Loaded)
2289 alert ('im:' + im.name + ' error:' + im.load_status);
2291 this.target = target;
2292 this.domain = new Xex.Domain ('context', im.domain, this);
2298 MIM.CandidateTable = function ()
2300 this.table = new Array ();
2303 MIM.CandidateTable.prototype.get = function (from)
2305 for (var i = 0; i < this.table.length; i++)
2307 var elt = this.table[i];
2308 if (elt.from <= from && elt.to > from)
2313 MIM.CandidateTable.prototype.put = function (from, to, candidates)
2315 for (var i = 0; i < this.table.length; i++)
2317 var elt = this.table[i];
2318 if (elt.from >= from && elt.from < to
2319 || elt.to >= from && elt.to < to)
2323 elt.val = candidates;
2327 this.table.push ({ from: from, to: to, val: candidates });
2330 MIM.CandidateTable.prototype.adjust = function (from, to, inserted)
2332 var diff = inserted - (to - from);
2333 for (var i = 0; i < this.table.length; i++)
2335 var elt = this.table[i];
2344 MIM.CandidateTable.prototype.clear = function ()
2346 this.table.length = 0;
2349 function detach_candidates (ic)
2351 ic.candidate_table.clear ();
2352 ic.candidates = null;
2353 ic.changed |= (MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos
2354 | ChangedStatus.CandidateList
2355 | ChangedStatus.CandidateIndex
2356 | ChangedStatus.CandidateShow);
2359 function set_cursor (prefix, pos)
2361 this.cursor_pos = pos;
2363 this.candidates = this.candidate_table.get (pos - 1);
2365 this.candidates = null;
2368 function save_state ()
2370 this.state_var_values = this.domain.SaveValues ();
2371 this.state_preedit = this.preedit;
2372 this.state_key_head = this.key_head;
2373 this.state_pos = this.cursor_pos;
2376 function restore_state ()
2378 this.domain.RestoreValues (this.state_var_values);
2379 this.preedit = this.state_preedit;
2380 set_cursor.call (this, "restore", this.state_pos);
2383 function handle_key ()
2385 var out = this.keymap.Lookup (this.keys, this.key_head);
2387 var branch_actions = this.state.keymap.actions;
2389 Xex.Log ('handling ' + this.keys.val[this.key_head]
2390 + ' in ' + this.state.name + ':' + this.keymap.name + "\n");
2391 this.key_head = out.index;
2392 if (sub != this.keymap)
2395 restore_state.call (this);
2397 Xex.Log ('submap found\n');
2398 if (this.keymap.actions)
2400 Xex.Log ('taking map actions:\n');
2401 if (! this.take_actions (this.keymap.actions))
2404 else if (this.keymap.submaps)
2406 Xex.Log ('no map actions');
2407 for (var i = this.state_key_head; i < this.key_head; i++)
2409 Xex.Log ('inserting key:' + this.keys.val[i].key);
2410 this.insert (this.keys.val[i].key, null);
2413 if (! this.keymap.submaps)
2415 Xex.Log ('terminal:');
2416 if (this.keymap.branch_actions != null)
2418 Xex.Log ('branch actions:');
2419 if (! this.take_actions (branch_actions))
2422 if (this.keymap != this.state.keymap)
2423 this.shift (this.state);
2428 Xex.Log ('no submap');
2429 var current_state = this.state;
2430 var map = this.keymap;
2434 Xex.Log ('branch actions');
2435 if (! this.take_actions (this.keymap.branch_actions))
2439 if (map == this.keymap)
2441 Xex.Log ('no state change');
2442 if (map == this.initial_state.keymap
2443 && this.key_head < this.keys.val.length)
2445 Xex.Log ('unhandled');
2448 if (this.keymap != current_state.keymap)
2449 this.shift (current_state);
2450 else if (this.keymap.actions == null)
2451 this.shift (this.initial_state);
2460 this.produced = null;
2462 this.preedit_saved = '';
2463 this.cursor_pos = 0;
2464 this.marker_positions = {};
2465 this.candidates = null;
2466 this.candidate_show = false;
2468 this.prev_state = null;
2469 this.initial_state = this.im.initial_state;
2470 this.title = this.initial_state.title;
2471 this.state_preedit = '';
2472 this.state_key_head = 0;
2473 this.state_var_values = {};
2476 this.keys = new MIM.KeySeq ();
2478 this.key_unhandled = false;
2479 this.unhandled_key = null;
2480 this.changed = MIM.ChangedStatus.None;
2481 this.error_message = '';
2482 this.title = this.initial_state.title;
2485 this.preedit_saved = '';
2486 this.marker_positions = {};
2487 this.candidate_table = new MIM.CandidateTable ();
2488 this.candidates = null;
2489 this.candidate_show = false;
2490 this.shift (this.initial_state);
2493 catch_args: new Array (Xex.CatchTag._mimtag, null),
2495 take_actions: function (actions)
2497 var func_progn = this.domain.GetFunc ('progn');
2498 var func_catch = this.domain.GetFunc ('catch');
2499 this.catch_args[1] = new Xex.Funcall (func_progn, null, actions);
2500 var term = new Xex.Funcall (func_catch, null, this.catch_args);
2501 term = term.Eval (this.domain);
2502 return (! term.IsSymbol || term.val != '@mimtag');
2505 GetSurroundingChar: function (pos)
2508 Xex.Log (0, 'getting char at ' + pos);
2509 if (pos < 0 || pos >= this.target.value.length)
2511 return this.target.value.charCodeAt (pos);
2514 adjust_markers: function (from, to, inserted)
2516 var diff = inserted - (to - from);
2518 for (var m in this.marker_positions)
2519 if (this.marker_positions[m] > from)
2520 this.marker_positions[m] = (this.marker_positions[m] >= to
2521 ? pos + diff : from);
2522 if (this.cursor_pos >= to)
2523 set_cursor.call (this, 'adjust', this.cursor_pos + diff);
2524 else if (this.cursor_pos > from)
2525 set_cursor.call (this, 'adjust', from)
2528 preedit_replace: function (from, to, text, candidates)
2530 this.preedit = (this.preedit.substring (0, from)
2531 + text + this.preedit.substring (to));
2532 this.adjust_markers (from, to, text.length);
2533 this.candidate_table.adjust (from, to, text.length);
2535 this.candidate_table.put (from, from + text.length, candidates)
2538 insert: function (text, candidates)
2540 this.preedit_replace (this.cursor_pos, this.cursor_pos, text, candidates);
2541 this.changed = MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos;
2546 var deleted = pos - this.cursor_pos;
2549 this.DelSurroundText (pos);
2552 else if (pos > this.preedit.length)
2554 this.DelSurroundText (pos - this.preedit.length);
2555 pos = this.preedit.length;
2557 if (pos < this.cursor_pos)
2558 this.preedit = (this.predit.substring (0, pos)
2559 + this.preedit.substring (this.cursor_pos));
2561 this.preedit = (this.preedit.substring (0, this.cursor_pos)
2562 + this.predit.substring (pos));
2568 this.candidate_show = true;
2569 this.changed |= MIM.ChangedStatus.CandidateShow;
2574 this.candidate_show = false;
2575 this.changed |= MIM.ChangedStatus.CandidateShow;
2578 move: function (pos)
2582 else if (pos > this.preedit.length)
2583 pos = this.preedit.length;
2584 if (pos != this.cursor_pos)
2586 set_cursor.call (this, 'move', pos);
2587 this.changed |= MIM.ChangedStatus.Preedit;
2591 pushback: function (n)
2593 if (n instanceof MIM.KeySeq)
2595 if (this.key_head > 0)
2597 if (this.key_head < this.keys.val.length)
2598 this.keys.val.splice (this.key_head,
2599 this.keys.val.length - this.key_head);
2600 for (var i = 0; i < n.val.length; i++)
2601 this.keys.val.push (n.val[i]);
2607 if (this.key_head < 0)
2614 this.key_head = - n;
2615 if (this.key_head > this.keys.val.length)
2616 this.key_head = this.keys.val.length;
2622 if (this.key_head < this.keys.val.length)
2623 this.keys.val.splice (this.key_head, 1);
2628 if (this.preedit.length > 0)
2630 this.candidate_table.clear ();
2631 this.produced += this.preedit;
2632 this.preedit_replace.call (this, 0, this.preedit.length, '', null);
2636 shift: function (state)
2640 Xex.Log ("shifting back to previous");
2641 if (this.prev_state == null)
2643 state = this.prev_state;
2646 Xex.Log ("shifting to " + state.name);
2648 if (state == this.initial_state)
2653 this.keys.val.splice (0, this.key_head);
2655 this.prev_state = null;
2660 if (state != this.state)
2661 this.prev_state = this.state;
2663 if (state != this.state && state.enter_actions)
2664 this.take_actions (state.enter_actions);
2665 if (! this.state || this.state.title != state.title)
2666 this.changed |= MIM.ChangedStatus.StateTitle;
2668 this.keymap = state.keymap;
2669 this.state_key_head = this.key_head;
2670 save_state.call (this);
2673 Filter: function (key)
2677 this.key_unhandled = true;
2678 this.unhandled_key = key;
2681 if (key.key == '_reload')
2683 this.changed = MIM.ChangedStatus.None;
2685 this.key_unhandled = false;
2686 this.keys.val.push (key);
2688 while (this.key_head < this.keys.val.length)
2690 if (! handle_key.call (this))
2692 if (this.key_head < this.keys.val.length)
2694 this.unhandled_key = this.keys.val[this.key_head];
2695 this.keys.val.splice (this.key_head, this.key_head + 1);
2697 this.key_unhandled = true;
2703 this.key_unhandled = true;
2707 if (this.key_unhandled)
2709 this.keys.val.length = 0;
2710 this.key_head = this.state_key_head = this.commit_key_head = 0;
2712 return (! this.key_unhandled
2713 && this.produced.length == 0
2714 && this.preedit.length == 0);
2718 MIM.IC.prototype = proto;
2720 var node = Xex.Load (null, "imlist.xml");
2721 for (node = node.firstChild; node; node = node.nextSibling)
2722 if (node.nodeName == 'input-method')
2724 var lang = null, name = null, extra_id = null, file = null;
2726 for (var n = node.firstChild; n; n = n.nextSibling)
2728 if (n.nodeName == 'language')
2729 lang = n.firstChild.nodeValue;
2730 else if (n.nodeName == 'name')
2731 name = n.firstChild.nodeValue;
2732 else if (n.nodeName == 'extra-id')
2733 extra_id = n.firstChild.nodeValue;
2734 else if (n.nodeName == 'filename')
2735 file = n.firstChild.nodeValue;
2737 if (name && name != 'nil')
2739 if (! MIM.imlist[lang])
2740 MIM.imlist[lang] = {};
2741 MIM.imlist[lang][name] = new MIM.IM (lang, name, extra_id, file);
2743 else if (extra_id && extra_id != 'nil')
2745 if (! MIM.imextra[lang])
2746 MIM.imextra[lang] = {};
2747 MIM.imextra[lang][extra_id] = new MIM.IM (lang, name, extra_id, file);
2750 if (MIM.imextra.t && MIM.imextra.t.global)
2751 MIM.im_global = MIM.imextra.t.global;
2754 MIM.im_global = new MIM.IM ('t', 'nil', 'global', null);
2755 MIM.im_global.load_status = MIM.LoadStatus.Error;
2761 var keys = new Array ();
2763 keys[0x08] = 'backspace';
2764 keys[0x0D] = 'return';
2765 keys[0x1B] = 'escape';
2766 keys[0x20] = 'space';
2767 keys[0x21] = 'pageup';
2768 keys[0x22] = 'pagedown';
2770 keys[0x24] = 'home';
2771 keys[0x25] = 'left';
2773 keys[0x27] = 'right';
2774 keys[0x28] = 'down';
2775 keys[0x2D] = 'insert';
2776 keys[0x2E] = 'delete';
2777 for (var i = 1; i <= 12; i++)
2778 keys[111 + i] = "f" + i;
2779 keys[0x90] = "numlock";
2780 keys[0xF0] = "capslock";
2782 MIM.decode_key_event = function (event)
2784 var key = ((event.type == 'keydown' || event.keyCode) ? event.keyCode
2785 : event.charCode ? event.charCode
2789 if (event.type == 'keydown')
2794 if (event.shiftKey) key = "S-" + key ;
2797 key = String.fromCharCode (key);
2798 if (event.altKey) key = "A-" + key ;
2799 if (event.ctrlKey) key = "C-" + key ;
2800 return new MIM.Key (key);
2804 MIM.add_event_listener
2805 = (window.addEventListener
2806 ? function (target, type, listener) {
2807 target.addEventListener (type, listener, false);
2809 : window.attachEvent
2810 ? function (target, type, listener) {
2811 target.attachEvent ('on' + type,
2813 listener.call (target, window.event);
2816 : function (target, type, listener) {
2818 = function (e) { listener.call (target, e || window.event); };
2821 MIM.debug_print = function (event, ic)
2825 if (! MIM.debug_nodes)
2827 MIM.debug_nodes = new Array ();
2828 MIM.debug_nodes['keydown'] = document.getElementById ('keydown');
2829 MIM.debug_nodes['keypress'] = document.getElementById ('keypress');
2830 MIM.debug_nodes['status0'] = document.getElementById ('status0');
2831 MIM.debug_nodes['status1'] = document.getElementById ('status1');
2832 MIM.debug_nodes['keymap0'] = document.getElementById ('keymap0');
2833 MIM.debug_nodes['keymap1'] = document.getElementById ('keymap1');
2834 MIM.debug_nodes['preedit0'] = document.getElementById ('preedit0');
2835 MIM.debug_nodes['preedit1'] = document.getElementById ('preedit1');
2837 var target = event.target;
2838 var code = event.keyCode;
2839 var ch = event.type == 'keydown' ? 0 : event.charCode;
2840 var key = MIM.decode_key_event (event);
2843 MIM.debug_nodes[event.type].innerHTML = "" + code + "/" + ch + " : " + key;
2844 index = (event.type == 'keydown' ? '0' : '1');
2846 MIM.debug_nodes['status' + index].innerHTML = ic.im.load_status;
2848 MIM.debug_nodes['status' + index].innerHTML = 'no IM';
2849 MIM.debug_nodes['keymap' + index].innerHTML = ic.state.name;
2850 MIM.debug_nodes['preedit' + index].innerHTML = ic.preedit;
2853 MIM.get_range = function (target, range)
2855 if (target.selectionStart != null) // for Mozilla
2857 range[0] = target.selectionStart;
2858 range[1] = target.selectionEnd;
2862 var r = document.selection.createRange ();
2863 var rr = r.duplicate ();
2865 rr.moveToElementText (target);
2866 rr.setEndPoint ('EndToEnd', range);
2867 range[0] = rr.text.length - r.text.length;
2868 range[1] = rr.text.length;
2872 MIM.set_caret = function (target, ic)
2874 if (target.setSelectionRange) // Mozilla
2876 var scrollTop = target.scrollTop;
2877 target.setSelectionRange (ic.spot, ic.spot + ic.preedit.length);
2878 target.scrollTop = scrollTop;
2882 var range = target.createTextRange ();
2883 range.moveStart ('character', ic.spot);
2884 range.moveEnd ('character', ic.spot + ic.preedit.length);
2890 var range = new Array ();
2892 MIM.check_range = function (target, ic)
2894 MIM.get_range (target, range);
2895 if (range[0] != ic.spot || range[1] - range[0] != ic.preedit.length
2896 || target.value.substring (range[0], range[1]) != ic.preedit)
2898 Xex.Log ('reset:' + ic.spot + '-' + (ic.spot + ic.preedit.length)
2899 + '/' + range[0] + '-' + range[1]);
2902 target.value = (target.value.substring (0, range[0])
2903 + target.value.substring (range[1]));
2908 MIM.update = function (target, ic)
2910 var text = target.value;
2911 target.value = (text.substring (0, ic.spot)
2914 + text.substring (ic.spot));
2915 ic.spot += ic.produced.length;
2916 MIM.set_caret (target, ic);
2919 MIM.reset_ic = function (event)
2921 if (event.target.mim_ic)
2923 var ic = event.target.mim_ic;
2924 var pos = ic.spot + ic.preedit.length;
2927 event.target.setSelectionRange (pos, pos);
2931 MIM.keydown = function (event)
2933 var target = event.target;
2934 if (! (target.type == "text" || target.type == "textarea"))
2937 var ic = target.mim_ic;
2938 if (! ic || ic.im != MIM.current)
2940 Xex.Log ('creating IC');
2941 ic = new MIM.IC (MIM.current, target);
2943 MIM.add_event_listener (target, 'blur', MIM.reset_ic);
2945 if (ic.im.load_status != MIM.LoadStatus.Loaded)
2947 MIM.check_range (target, ic);
2948 MIM.debug_print (event, ic);
2949 ic.key = MIM.decode_key_event (event);
2952 MIM.keypress = function (event)
2954 if (! (event.target.type == "text" || event.target.type == "textarea"))
2957 var ic = event.target.mim_ic;
2961 if (ic.im.load_status != MIM.LoadStatus.Loaded)
2964 ic.key = MIM.decode_key_event (event);
2971 Xex.Log ("filtering " + ic.key);
2972 var result = ic.Filter (ic.key);
2973 MIM.update (event.target, ic);
2974 if (! ic.key_unhandled)
2975 event.preventDefault ();
2977 MIM.debug_print (event, ic);
2982 MIM.select_im = function (event)
2984 var target = event.target.parentNode;
2985 while (target.tagName != "SELECT")
2986 target = target.parentNode;
2989 for (var lang in MIM.imlist)
2990 for (var name in MIM.imlist[lang])
2991 if (idx++ == target.selectedIndex)
2993 im = MIM.imlist[lang][name];
2996 document.getElementsByTagName ('body')[0].removeChild (target);
2997 target.target.focus ();
2998 if (im && im != MIM.current)
3001 Xex.Log ('select IM: ' + im.name);
3005 MIM.destroy_menu = function (event)
3007 if (event.target.tagName == "SELECT")
3008 document.getElementsByTagName ('body')[0].removeChild (event.target);
3011 MIM.select_menu = function (event)
3013 var target = event.target;
3015 if (! ((target.type == "text" || target.type == "textarea")
3016 && event.which == 1 && event.ctrlKey))
3019 var sel = document.createElement ('select');
3020 sel.onclick = MIM.select_im;
3021 sel.onmouseout = MIM.destroy_menu;
3022 sel.style.position='absolute';
3023 sel.style.left = (event.clientX - 10) + "px";
3024 sel.style.top = (event.clientY - 10) + "px";
3025 sel.target = target;
3027 for (var lang in MIM.imlist)
3028 for (var name in MIM.imlist[lang])
3030 var option = document.createElement ('option');
3031 var imname = lang + "-" + name;
3032 option.appendChild (document.createTextNode (imname));
3033 option.value = imname;
3034 sel.appendChild (option);
3035 if (MIM.imlist[lang][name] == MIM.current)
3036 sel.selectedIndex = idx;
3040 document.getElementsByTagName ('body')[0].appendChild (sel);
3043 MIM.test = function ()
3045 var im = MIM.imlist['t']['latn-post'];
3046 var ic = new MIM.IC (im, null);
3048 ic.Filter (new MIM.Key ('a'));
3049 ic.Filter (new MIM.Key ("'"));
3052 document.getElementById ('text').value = ic.produced + ic.preedit;
3055 document.getElementById ('text').value
3056 = Xex.Term.Parse (domain, body).Eval (domain).toString ();
3058 if (e instanceof Xex.ErrTerm)
3066 MIM.init = function ()
3068 MIM.add_event_listener (window, 'keydown', MIM.keydown);
3069 MIM.add_event_listener (window, 'keypress', MIM.keypress);
3070 MIM.add_event_listener (window, 'mousedown', MIM.select_menu);
3071 if (window.location == 'http://localhost/mim/index.html')
3072 MIM.server = 'http://localhost/mim';
3073 MIM.current = MIM.imlist['vi']['telex'];
3076 MIM.init_debug = function ()
3079 Xex.LogNode = document.getElementById ('log');