1 // -* coding: utf-8; -*
5 Log: function (arg, indent, cont)
10 Xex.LogNode.value = '';
16 Xex.LogNode.value += "\n";
17 if (indent != undefined)
18 for (var i = 0; i <= indent; i++)
21 Xex.LogNode.value += str + arg;
22 Xex.LogNode.scrollTop = Xex.LogNode.scrollHeight;
28 UnknownError: "unknown-error",
29 WrongArgument: "wrong-argument",
31 InvalidInteger: "invalid-integer",
32 TermTypeInvalid: "term-type-invalid",
33 FunctionConflict: "function-conflict",
34 VariableTypeConflict: "variable-type-conflict",
35 VariableRangeConflict: "variable-range-conflict",
36 VariableWrongRange: "variable-wrong-range",
37 VariableWrongValue: "variable-wrong-value",
39 UnknownFunction: "unknown-function",
40 MacroExpansionError: "macro-expansion-error",
41 NoVariableName: "no-variable-name",
42 NoFunctionName: "no-funcion-name",
45 ArithmeticError: "arithmetic-error",
46 WrongType: "wrong-type",
47 IndexOutOfRange: "index-out-of-range",
48 ValueOutOfRange: "value-out-of-range",
49 NoLoopToBreak: "no-loop-to-break",
50 UncaughtThrow: "uncaught-throw"
53 Xex.Variable = function (domain, name, desc, val, range)
62 Xex.Variable.prototype.clone = function ()
64 return new Xex.Variable (this.domain, this.name, this.desc,
65 this.val, this.range);
68 Xex.Variable.prototype.Equals = function (obj)
70 return ((obj instanceof Xex.Variable)
71 && obj.name == this.name);
74 Xex.Variable.prototype.SetValue = function (term)
80 Xex.Function = function (name, with_var, min_args, max_args)
83 this.with_var = with_var;
84 this.min_args = min_args;
85 this.max_args = max_args;
88 Xex.Subrountine = function (builtin, name, with_var, min_args, max_args)
91 this.with_var = with_var;
92 this.min_args = min_args;
93 this.max_args = max_args;
94 this.builtin = builtin;
97 Xex.Subrountine.prototype.Call = function (domain, vari, args)
99 var newargs = new Array ();
100 for (var i = 0; i < args.length; i++)
102 newargs[i] = args[i].Eval (domain);
103 if (domain.Thrown ())
106 return this.builtin (domain, vari, newargs)
109 Xex.SpecialForm = function (builtin, name, with_var, min_args, max_args)
112 this.with_var = with_var;
113 this.min_args = min_args;
114 this.max_args = max_args;
115 this.builtin = builtin;
118 Xex.SpecialForm.prototype.Call = function (domain, vari, args)
120 return this.builtin (domain, vari, args)
123 Xex.Lambda = function (name, min_args, max_args, args, body)
126 this.min_args = min_args;
127 this.max_args = max_args;
132 Xex.Lambda.prototype.Call = function (domain, vari, args)
134 var current = domain.bindings;
135 var result = Xex.Zero;
136 var limit = max_args >= 0 ? args.length : args.length - 1;
140 for (i = 0; i < limit; i++)
142 result = args[i].Eval (domain);
143 if (domain.Thrown ())
145 domain.Bind (this.args[i], result);
149 var list = new Array ();
150 for (i = 0; i < args[limit].length; i++)
152 result = args[limit].Eval (domain);
153 if (domain.Thrown ())
157 domain.Bind (this.args[limit], list);
160 domain.Catch (Xex.CatchTag.Return);
161 for (var term in this.body)
163 result = term.Eval (domain);
164 if (domain.Thrown ())
171 domain.UnboundTo (current);
176 Xex.Macro = function (name, min_args, max_args, args, body)
179 this.min_args = min_args;
180 this.max_args = max_args;
185 Xex.Macro.prototype.Call = function (domain, vari, args)
187 var current = domain.bindings;
188 var result = Xex.Zero;
192 for (i = 0; i < args.length; i++)
193 domain.Bind (this.args[i], args[i]);
195 domain.Catch (Xex.CatchTag.Return);
196 for (var i in this.body)
198 result = this.body[i].Eval (domain);
199 if (domain.Thrown ())
206 domain.UnboundTo (current);
211 Xex.Bindings = function (vari)
214 this.old_value = vari.val;
217 Xex.Bindings.prototype.UnboundTo = function (boundary)
219 for (var b = this; b != boundary; b = b.next)
220 b.vari.val = b.old_value;
224 Xex.Bind = function (bindings, vari, val)
226 var b = new Xex.Bindings (vari);
237 Xex.Domain = function (name, parent, context)
240 this.context = context;
243 if (name != 'basic' && ! parent)
244 parent = Xex.BasicDomain
245 this.parent = parent;
252 for (elt in parent.termtypes)
253 this.termtypes[elt] = parent.termtypes[elt];
254 for (elt in parent.functions)
255 this.functions[elt] = parent.functions[elt];
256 for (elt in parent.variables)
258 var vari = parent.variables[elt];
259 this.variables[elt] = new Xex.Variable (this, vari.name, vari.desc,
260 vari.val, vari.range);
264 this.call_stack = new Array ();
265 this.bindings = null;
266 this.catch_stack = new Array ();
267 this.catch_count = 0;
271 Xex.Domain.prototype = {
272 CallStackCount: function () { return this.call_stack.length; },
273 CallStackPush: function (term) { this.call_stack.push (term); },
274 CallStackPop: function () { this.call_stack.pop (); },
275 Bind: function (vari, val)
277 this.bindings = Xex.Bind (this.bindings, vari, val);
279 UnboundTo: function (boundary)
282 this.bindings = this.bindings.UnboundTo (boundary);
284 Catch: function (tag) { this.catch_stack.push (tag); this.catch_count++; },
287 this.catch_stack.pop ();
288 if (this.catch_count > this.catch_stack.length)
293 if (this.catch_count < this.catch_stack.length)
295 this.caught = (this.catch_count == this.catch_stack.length - 1);
301 ThrowReturn: function ()
303 for (var i = this.catch_stack.length - 1; i >= 0; i--)
306 if (this.catch_stack[i] == Xex.CatchTag.Return)
310 ThrowBreak: function ()
312 if (this.catch_stack[this.catch_stack.length - 1] != Xex.CatchTag.Break)
313 throw new Xex.ErrTerm (Xex.Error.NoLoopToBreak,
314 "No surrounding loop to break");
317 ThrowSymbol: function (tag)
319 var i = this.catch_count;
320 for (var j = this.catch_stack.length - 1; j >= 0; j--)
323 if (Xex.CatchTag.Matches (this.catch_stack[i], tag))
325 this.catch_count = i;
329 throw new Xex.ErrTerm (Xex.Error.UncaughtThrow,
330 "No corresponding catch: " + tag);
332 DefType: function (obj)
335 if (this.termtypes[type])
336 throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
337 "Already defined: " + type);
338 if (this.functions[type])
339 throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
340 "Already defined as a funciton or a macro: "
342 this.termtypes[type] = obj.Parser;
344 DefSubr: function (builtin, name, with_var, min_args, max_args)
346 this.functions[name] = new Xex.Subrountine (builtin, name, with_var,
349 DefSpecial: function (builtin, name, with_var, min_args, max_args)
351 this.functions[name] = new Xex.SpecialForm (builtin, name, with_var,
354 Defun: function (name, min_args, max_args, args, body)
356 this.functions[name] = new Xex.Lambda (name, min_args, max_args,
359 DefunByFunc: function (func) { this.functions[func.name] = func; },
360 Defmacro: function (name, min_args, max_args, args, body)
362 this.functions[name] = new Xex.Macro (name, min_args, max_args,
365 DefAlias: function (alias, fname)
367 var func = this.functions[fname];
370 throw new Xex.ErrTerm (Xex.Error.UnknownFunction, fname);
371 if (this.termtypes[alias])
372 throw new Xex.ErrTerm (Xex.Error.FunctionConflict,
373 "Already defined as a term type: " + alias);
374 if (this.functions[alias])
375 throw new Xex.ErrTerm (Xex.Error.FunctionConflict,
376 "Already defined as a function: " + alias);
377 this.functions[alias] = func;
379 Defvar: function (name, desc, val, range)
381 var vari = new Xex.Variable (this, name, desc, val, range);
382 this.variables[name] = vari;
385 GetFunc: function (name)
387 var func = this.functions[name];
389 throw new Xex.ErrTerm (Xex.Error.UnknownFunction,
390 "Unknown function: " + name);
393 CopyFunc: function (domain, name)
395 var func = this.functions[name];
396 domain.DefunByFunc (func);
399 CopyFuncAll: function (domain)
401 for (var elt in this.functions)
402 domain.DefunByFunc (this.functions[elt]);
404 GetVarCreate: function (name)
406 var vari = this.variables[name];
408 vari = this.variables[name] = new Xex.Variable (this, name, null,
412 GetVar: function (name) { return this.variables[name]; },
413 SaveValues: function ()
416 for (var elt in this.variables)
417 values[elt] = this.variables[elt].val.Clone ();
420 RestoreValues: function (values)
425 var vari = this.variables[name];
426 vari.val = values[name];
431 Xex.Term = function (type) { this.type = type; }
432 Xex.Term.prototype = {
433 IsTrue: function () { return true; },
434 Eval: function (domain) { return this.Clone (); },
435 Clone: function (domain) { return this; },
436 Equals: function (obj)
438 return (this.type == obj.type
440 && obj.val == this.val);
442 Matches: function (obj) { return this.Equals (obj); },
443 toString: function ()
445 if (this.val != undefined)
446 return '<' + this.type + '>' + this.val + '</' + this.type + '>';
447 return '<' + this.type + '/>';
449 Intval: function () { throw new Xex.ErrTerm (Xex.Error.WrongType,
450 "Not an integer"); },
451 Strval: function () { throw new Xex.ErrTerm (Xex.Error.WrongType,
455 Node.prototype.firstElement = function ()
457 for (var n = this.firstChild; n; n = n.nextSibling)
463 Node.prototype.nextElement = function ()
465 for (var n = this.nextSibling; n; n = n.nextSibling)
472 function parse_defvar (domain, node)
474 var name = node.attributes['vname'].nodeValue;
476 throw new Xex.ErrTerm (Xex.Error.NoVariableName, node, '');
477 var vari = domain.variables[name];
478 var desc, val = null, range;
481 desc = vari.description;
485 node = node.firstElement ();
486 if (node && node.nodeName == 'description')
488 desc = node.firstChild.nodeValue;
489 node = node.nextElement ();
493 val = Xex.Term.Parse (domain, node);
494 node = node.nextElement ();
495 if (node && node.nodeName == 'possible-values')
496 for (node = node.firstElement (); node; node = node.nextElement ())
499 if (node.nodeName == 'range')
502 throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
503 'Range not allowed for ' + name);
505 for (var n = node.firstElement (); n; n = n.nextElement ())
507 var v = Xex.Term.Parse (domain, n);
509 throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
510 'Invalid range value: ' + val);
516 pval = Xex.Term.Parse (domain, node);
517 if (val.type != pval.type)
518 throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
519 'Invalid possible value: ' + pval);
522 range = new Array ();
528 domain.Defvar (name, desc, val, range);
532 function parse_defun_head (domain, node)
534 var name = node.attributes['fname'].nodeValue;
536 throw new Xex.ErrTerm (Xex.Error.NoFunctionName, node, '');
537 var args = new Array ();
538 var nfixed = 0, noptional = 0, nrest = 0;
540 node = node.firstElement ();
541 if (node && node.nodeName == 'args')
544 for (n = n.firstElement (); n; n = n.nextElement ())
546 if (n.nodeName == 'fixed')
548 else if (n.nodeName == 'optional')
550 else if (n.nodeName == 'rest')
553 throw new Xex.ErrTerm (Xex.Error.WrongType, n, n.nodeName);
556 throw new Xex.ErrTerm (Xex.Error.WrongType, n, 'Too many <rest>');
557 for (n = node.firstElement (); n; n = n.nextElement ())
558 args.push (domain.DefVar (n.attributes['vname'].nodeValue));
560 args.min_args = nfixed;
561 args.max_args = nrest == 0 ? nfixed + noptional : -1;
563 if (node.nodeName == 'defun')
564 domain.Defun (name, args, null);
566 domain.Defmacro (name, args, null);
570 function parse_defun_body (domain, node)
572 var name = node.attributes['fname'].nodeValue;
573 var func = domain.GetFunc (name);
575 for (node = node.firstElement (); node; node = node.nextElement ())
576 if (node.nodeName != 'description' && node.nodeName != 'args')
578 body = Xex.Term.Parse (domain, node, null);
582 Xex.Term.Parse = function (domain, node, stop)
584 if (arguments.length == 2)
586 var name = node.nodeName;
587 var parser = domain.termtypes[name];
590 return parser (domain, node);
591 if (name == 'defun' || name == 'defmacro')
593 name = parse_defun_head (domain, node);
594 parse_defun_body (domain, node);
595 return new Xex.StrTerm (name);
597 if (name == 'defvar')
599 name = parse_defvar (domain, node);
600 return new Xex.StrTerm (name);
602 return new Xex.Funcall.prototype.Parser (domain, node);
604 for (var n = node; n && n != stop; n = n.nextElement ())
605 if (n.nodeName == 'defun' || n.nodeName == 'defmacro')
606 parse_defun_head (domain, n);
608 for (var n = node; n && n != stop; n = n.nextElement ())
610 if (n.nodeName == 'defun' || n.nodeName == 'defmacro')
611 parse_defun_body (domain, n);
612 else if (n.nodeName == 'defvar')
613 parse_defvar (domain, n);
617 terms = new Array ();
618 terms.push (Xex.Term.Parse (domain, n));
625 Xex.Varref = function (vname)
631 var proto = new Xex.Term ('varref');
633 proto.Clone = function () { return new Xex.Varref (this.val); }
634 proto.Eval = function (domain)
636 var vari = domain.GetVarCreate (this.val);
637 Xex.Log (this.ToString () + '=>' + vari.val, domain.depth);
641 proto.Parser = function (domain, node)
643 return new Xex.Varref (node.attributes['vname'].nodeValue);
646 proto.ToString = function ()
648 return '<varref vname="' + this.val + '"/>';
651 Xex.Varref.prototype = proto;
654 var null_args = new Array ();
656 Xex.Funcall = function (func, vname, args)
660 this.args = args || null_args;
664 var proto = new Xex.Term ('funcall');
666 proto.Parser = function (domain, node)
668 var fname = node.nodeName;
671 if (fname == 'funcall')
672 fname = node.attributes['fname'].nodeValue;
673 var func = domain.GetFunc (fname);
675 attr = node.attributes['vname'];
676 vname = attr != undefined ? attr.nodeValue : null;
677 var args = Xex.Term.Parse (domain, node.firstElement (), null);
678 return new Xex.Funcall (func, vname, args);
681 proto.New = function (domain, fname, vname, args)
683 var func = domain.GetFunc (fname);
684 var funcall = new Xex.Funcall (func, vname, args);
685 if (func instanceof Xex.Macro)
686 funcall = funcall.Eval (domain);
690 proto.Eval = function (domain)
692 Xex.Log (this, domain.depth);
695 vari = domain.GetVarCreate (this.vname);
699 result = this.func.Call (domain, vari, this.args);
701 Xex.Log (' => ' + result, --domain.depth,
702 this.func instanceof Xex.Subrountine);
707 proto.Clone = function ()
709 return new Xex.Funcall (this.func, this.vari, this.args);
712 proto.Equals = function (obj)
714 return (obj.type == 'funcall'
715 && obj.func == this.func
716 && obj.vari.Equals (this.vari)
717 && obj.args.length == this.func.length);
720 proto.toString = function ()
723 var len = this.args.length;
724 var str = '<' + this.func.name;
726 str += ' vname="' + this.vari.name + '"';
729 if (this.func instanceof Xex.Subrountine)
730 for (var i = 0; i < len; i++)
731 arglist += this.args[i].toString ();
733 for (var i = 0; i < len; i++)
735 return str + '>' + arglist + '</' + this.func.name + '>';
738 Xex.Funcall.prototype = proto;
741 Xex.ErrTerm = function (ename, message, stack)
744 this.message = message;
749 var proto = new Xex.Term ('error');
751 proto.IsError = true;
753 proto.Parser = function (domain, node)
755 return new Xex.ErrTerm (node.attributes['ename'].nodeValue,
756 node.innerText, false);
759 proto.CallStack = function () { return stack; }
761 proto.SetCallStack = function (value) { statck = value; }
763 proto.Clone = function ()
765 return new Xex.ErrTerm (ename, message, false);
768 proto.Equals = function (obj)
771 && obj.ename == ename && obj.message == message
772 && (obj.stack ? (stack && stack.length == obj.stack.length)
776 proto.Matches = function (obj)
778 return (obj.IsError && obj.ename == ename);
781 proto.toString = function ()
783 return '<error ename="' + this.ename + '">' + this.message + '</error>';
786 Xex.ErrTerm.prototype = proto;
789 Xex.IntTerm = function (num) { this.val = num; };
791 var proto = new Xex.Term ('integer');
793 proto.Intval = function () { return this.val; };
794 proto.IsTrue = function () { return this.val != 0; }
795 proto.Clone = function () { return new Xex.IntTerm (this.val); }
796 proto.Parser = function (domain, node)
798 var str = node.firstChild.nodeValue;
800 if (str.charAt (0) == '?' && str.length == 2)
801 return new Xex.IntTerm (str.charCodeAt (1));
802 return new Xex.IntTerm (parseInt (node.firstChild.nodeValue));
804 Xex.IntTerm.prototype = proto;
807 Xex.StrTerm = function (str) { this.val = str; };
809 var proto = new Xex.Term ('string');
811 proto.Strval = function () { return this.val; };
812 proto.IsTrue = function () { return this.val.length > 0; }
813 proto.Clone = function () { return new Xex.StrTerm (this.val); }
814 proto.Parser = function (domain, node)
816 return new Xex.StrTerm (node.firstChild ? node.firstChild.nodeValue : '');
818 Xex.StrTerm.prototype = proto;
821 Xex.SymTerm = function (str) { this.val = str; };
823 var proto = new Xex.Term ('symbol');
824 proto.IsSymbol = true;
825 proto.IsTrue = function () { return this.val != 'nil'; }
826 proto.Clone = function () { return new Xex.SymTerm (this.val); }
827 proto.Parser = function (domain, node)
829 return new Xex.SymTerm (node.firstChild.nodeValue);
831 Xex.SymTerm.prototype = proto;
834 Xex.LstTerm = function (list) { this.val = list; };
836 var proto = new Xex.Term ('list');
838 proto.IsTrue = function () { return this.val.length > 0; }
839 proto.Clone = function () { return new Xex.LstTerm (this.val.slice (0)); }
841 proto.Equals = function (obj)
843 if (obj.type != 'list' || obj.val.length != this.val.length)
845 var i, len = this.val.length;
846 for (i = 0; i < len; i++)
847 if (! this.val[i].Equals (obj.val[i]))
852 proto.Parser = function (domain, node)
854 var list = Xex.Term.Parse (domain, node.firstElement (), null);
855 return new Xex.LstTerm (list);
858 proto.toString = function ()
860 var len = this.val.length;
865 for (var i = 0; i < len; i++)
866 str += this.val[i].toString ();
867 return str + '</list>';
869 Xex.LstTerm.prototype = proto;
873 var basic = new Xex.Domain ('basic', null, null);
875 function Fset (domain, vari, args)
878 throw new Xex.ErrTerm (Xex.Error.NoVariableName,
879 'No variable name to set');
880 vari.SetValue (args[0]);
884 function Fnot (domain, vari, args)
886 return (args[0].IsTrue () ? Xex.Zero : Xex.One);
889 function maybe_set_intvar (vari, n)
891 var term = new Xex.IntTerm (n);
893 vari.SetValue (term);
897 function Fadd (domain, vari, args)
899 var n = vari ? vari.val.Intval () : 0;
900 var len = args.length;
902 for (var i = 0; i < len; i++)
903 n += args[i].Intval ();
904 return maybe_set_intvar (vari, n);
907 function Fmul (domain, vari, args)
909 var n = vari ? vari.val.Intval () : 1;
910 for (var i = 0; i < args.length; i++)
912 return maybe_set_intvar (vari, n);
915 function Fsub (domain, vari, args)
921 n = args[0].Intval ();
926 n = vari.val.Intval ();
929 while (i < args.length)
930 n -= args[i++].Intval ();
931 return maybe_set_intvar (vari, n);
934 function Fdiv (domain, vari, args)
940 n = args[0].Intval ();
945 n = vari.val.Intval ();
948 while (i < args.length)
949 n /= args[i++].Intval ();
950 return maybe_set_intvar (vari, n);
953 function Fmod (domain, vari, args)
955 return maybe_set_intvar (vari, args[0].Intval () % args[1].Intval ());
958 function Flogior (domain, vari, args)
960 var n = vari == null ? 0 : vari.val;
961 for (var i = 0; i < args.length; i++)
963 return maybe_set_intvar (vari, n);
966 function Flogand (domain, vari, args)
971 Xex.Log ("logand arg args[0]" + args[0]);
972 n = args[0].Intval ()
977 Xex.Log ("logand arg var " + vari);
978 n = vari.val.Intval ();
981 while (n > 0 && i < args.length)
983 Xex.Log ("logand arg " + args[i]);
986 return maybe_set_intvar (vari, n);
989 function Flsh (domain, vari, args)
991 return maybe_set_intvar (vari, args[0].Intval () << args[1].Intval ());
994 function Frsh (domain, vari, args)
996 return maybe_set_intvar (vari, args[0].Intval () >> args[1].Intval ());
999 function Fand (domain, vari, args)
1001 var len = args.length;
1002 for (var i = 0; i < len; i++)
1004 var result = args[i].Eval (domain);
1005 if (domain.Thrown ())
1007 if (! result.IsTrue ())
1013 function For (domain, vari, args)
1015 var len = args.length;
1016 for (var i = 0; i < len; i++)
1018 var result = args[i].Eval (domain);
1019 if (domain.Thrown ())
1021 if (result.IsTrue ())
1027 function Feq (domain, vari, args)
1029 for (var i = 1; i < args.length; i++)
1030 if (! args[i - 1].Equals (args[i]))
1035 function Fnoteq (domain, vari, args)
1037 return (Feq (domain, vari, args) == Xex.One ? Xex.Zero : Xex.One);
1040 function Flt (domain, vari, args)
1042 var n = args[0].Intval ();
1044 for (var i = 1; i < args.length; i++)
1046 var n1 = args[i].Intval ();
1054 function Fle (domain, vari, args)
1056 var n = args[0].Intval ();
1057 for (var i = 1; i < args.length; i++)
1059 var n1 = args[i].Intval ();
1067 function Fgt (domain, vari, args)
1069 var n = args[0].Intval ();
1070 for (var i = 1; i < args.length; i++)
1072 var n1 = args[i].Intval ();
1080 function Fge (domain, vari, args)
1082 var n = args[0].Intval ();
1083 for (var i = 1; i < args.Length; i++)
1085 var n1 = args[i].Intval ();
1093 function Fprogn (domain, vari, args)
1095 var result = Xex.One;
1096 var len = args.length;
1098 for (var i = 0; i < len; i++)
1100 result = args[i].Eval (domain);
1101 if (domain.Thrown ())
1107 function Fif (domain, vari, args)
1109 var result = args[0].Eval (domain);
1111 if (domain.Thrown ())
1113 if (result.IsTrue ())
1114 return args[1].Eval (domain);
1115 if (args.length == 2)
1117 return args[2].Eval (domain);
1120 function Fcond (domain, vari, args)
1122 for (var i = 0; i < args.length; i++)
1125 var result = list.val[0].Eval (domain);
1126 if (result.IsTrue ())
1128 for (var j = 1; j < list.val.length; j++)
1131 result = list.val[j].Eval (domain);
1133 if (domain.Thrown ())
1142 function eval_terms (domain, terms, idx)
1144 var result = Xex.Zero;
1145 domain.caught = false;
1146 for (var i = idx; i < terms.length; i++)
1148 result = terms[i].Eval (domain);
1149 if (domain.Thrown ())
1155 function Fcatch (domain, vari, args)
1160 if (args[0].IsError)
1163 result = eval_terms (domain, args, 1);
1165 if (e instanceof Xex.ErrTerm)
1167 if (! args[0].Matches (e))
1175 else if (args[0].IsSymbol)
1178 domain.Catch (args[0].val);
1179 result = eval_terms (domain, args, 1);
1183 vari.SetValue (result);
1191 throw new Xex.ErrTerm (Xex.Error.WrongArgument,
1192 "Not a symbol nor an error: " + args[0]);
1195 function Fthrow (domain, vari, args)
1197 if (args[0].IsSymbl)
1199 domain.ThrowSymbol (args[0]);
1200 return (args[args.length - 1]);
1202 if (args[0].IsError)
1206 throw new Xex.ErrTerm (Xex.Error.WrongArgument,
1207 "Not a symbol nor an error:" + args[0]);
1210 Xex.BasicDomain = basic;
1212 basic.DefSubr (Fset, "set", true, 1, 1);
1213 basic.DefAlias ("=", "set");
1214 basic.DefSubr (Fnot, "not", false, 1, 1);
1215 basic.DefAlias ("!", "not");
1216 basic.DefSubr (Fadd, "add", true, 1, -1);
1217 basic.DefSubr (Fmul, "mul", true, 1, -1);
1218 basic.DefAlias ("*", "mul");
1219 basic.DefSubr (Fsub, "sub", true, 1, -1);
1220 basic.DefAlias ("-", "sub");
1221 basic.DefSubr (Fdiv, "div", true, 1, -1);
1222 basic.DefAlias ("/", "div");
1223 basic.DefSubr (Fmod, "mod", true, 1, 2);
1224 basic.DefAlias ("%", "mod");
1225 basic.DefSubr (Flogior, "logior", true, 1, -1);
1226 basic.DefAlias ('|', "logior");
1227 basic.DefSubr (Flogand, "logand", true, 1, -1);
1228 basic.DefAlias ("&", "logand");
1229 basic.DefSubr (Flsh, "lsh", true, 1, 2);
1230 basic.DefAlias ("<<", "lsh");
1231 basic.DefSubr (Frsh, "rsh", true, 1, 2);
1232 basic.DefAlias (">>", "rsh");
1233 basic.DefSubr (Feq, "eq", false, 2, -1);
1234 basic.DefAlias ("==", "eq");
1235 basic.DefSubr (Fnoteq, "noteq", false, 2, 2);
1236 basic.DefAlias ("!=", "noteq");
1237 basic.DefSubr (Flt, "lt", false, 2, -1);
1238 basic.DefAlias ("<", "lt");
1239 basic.DefSubr (Fle, "le", false, 2, -1);
1240 basic.DefAlias ("<=", "le");
1241 basic.DefSubr (Fgt, "gt", false, 2, -1);
1242 basic.DefAlias (">", "gt");
1243 basic.DefSubr (Fge, "ge", false, 2, -1);
1244 basic.DefAlias (">=", "ge");
1245 basic.DefSubr (Fthrow, "throw", false, 1, 2);
1247 //basic.DefSubr (Fappend, "append", true, 0, -1);
1248 //basic.DefSubr (Fconcat, "concat", true, 0, -1);
1249 //basic.DefSubr (Fnth, "nth", false, 2, 2);
1250 //basic.DefSubr (Fcopy, "copy", false, 1, 1);
1251 //basic.DefSubr (Fins, "ins", true, 2, 2);
1252 //basic.DefSubr (Fdel, "del", true, 2, 2);
1253 //basic.DefSubr (Feval, "eval", false, 1, 1);
1254 //basic.DefSubr (Fbreak, "break", false, 0, 1);
1255 //basic.DefSubr (Freturn, "return", false, 0, 1);
1256 //basic.DefSubr (Fthrow, "throw", false, 1, 2);
1258 basic.DefSpecial (Fand, "and", false, 1, -1);
1259 basic.DefAlias ("&&", "and");
1260 basic.DefSpecial (For, "or", false, 1, -1);
1261 basic.DefAlias ("||", "or");
1262 basic.DefSpecial (Fprogn, "progn", false, 1, -1);
1263 basic.DefAlias ("expr", "progn");
1264 basic.DefSpecial (Fif, "if", false, 2, 3);
1265 //basic.DefSpecial (Fwhen, "when", false, 1, -1);
1266 //basic.DefSpecial (Floop, "loop", false, 1, -1);
1267 //basic.DefSpecial (Fwhile, "while", false, 1, -1);
1268 basic.DefSpecial (Fcond, "cond", false, 1, -1);
1269 //basic.DefSpecial (Fforeach, "foreach", true, 2, -1);
1270 //basic.DefSpecial (Fquote, "quote", false, 1, 1);
1271 //basic.DefSpecial (Ftype, "type", false, 1, 1);
1272 basic.DefSpecial (Fcatch, "catch", true, 2, -1);
1274 basic.DefType (Xex.Funcall.prototype);
1275 basic.DefType (Xex.Varref.prototype);
1276 basic.DefType (Xex.ErrTerm.prototype);
1277 basic.DefType (Xex.IntTerm.prototype);
1278 basic.DefType (Xex.StrTerm.prototype);
1279 basic.DefType (Xex.SymTerm.prototype);
1280 basic.DefType (Xex.LstTerm.prototype);
1284 Xex.Zero = new Xex.IntTerm (0);
1285 Xex.One = new Xex.IntTerm (1);
1286 Xex.nil = new Xex.SymTerm ('nil');
1288 Xex.Load = function (server, file)
1290 var obj = new XMLHttpRequest ();
1291 var url = server ? server + '/' + file : file;
1292 obj.open ('GET', url, false);
1293 obj.overrideMimeType ('text/xml');
1295 return obj.responseXML.firstChild;
1299 // URL of the input method server.
1300 server: "http://www.m17n.org/common/mim-js",
1301 // Boolean flag to tell if MIM is active or not.
1303 // Boolean flag to tell if MIM is running in debug mode or not.
1305 // List of main input methods.
1307 // List of extra input methods;
1309 // Global input method data
1311 // Currently selected input method.
1315 LoadStatus: { NotLoaded:0, Loading:1, Loaded:2, Error:-1 },
1322 CandidateIndex:0x10,
1324 Preedit: 0x06, // PreeditText | CursorPos
1325 Candidate: 0x38 // CandidateList | CandidateIndex | CandidateShow
1347 ParseError: "parse-error"
1352 var keysyms = new Array ();
1353 keysyms["bs"] = "backspace";
1354 keysyms["lf"] = "linefeed";
1355 keysyms["cr"] = keysyms["enter"] = "return";
1356 keysyms["esc"] = "escape";
1357 keysyms["spc"] = "space";
1358 keysyms["del"] = "delete";
1360 function decode_keysym (str) {
1361 if (str.length == 1)
1363 var parts = str.split ("-");
1364 var len = parts.length, i;
1365 var has_modifier = len > 1;
1367 for (i = 0; i < len - 1; i++)
1368 if (! MIM.KeyModifier.hasOwnProperty (parts[i]))
1370 var key = parts[len - 1];
1373 key = keysyms[key.toLowerCase ()];
1379 for (i = 1; i < len - 1; i++)
1380 str += '-' + parts[i];
1389 parts = new Array ();
1396 MIM.Key = function (val)
1399 if (val instanceof Xex.Term)
1401 else if (typeof val == 'string' || val instanceof String)
1403 this.key = decode_keysym (val);
1405 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + val);
1406 if (this.key instanceof Array)
1408 this.key = this.key[0];
1409 this.has_modifier = true;
1412 else if (typeof val == 'number' || val instanceof Number)
1413 this.key = String.fromCharCode (val);
1415 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + val);
1418 MIM.Key.prototype.toString = function () { return this.key; };
1420 MIM.Key.FocusIn = new MIM.Key (new Xex.StrTerm ('input-focus-in'));
1421 MIM.Key.FocusOut = new MIM.Key (new Xex.StrTerm ('input-focus-out'));
1422 MIM.Key.FocusMove = new MIM.Key (new Xex.StrTerm ('input-focus-move'));
1426 MIM.KeySeq = function (seq)
1428 this.val = new Array ();
1434 var len = seq.val.length;
1435 for (var i = 0; i < len; i++)
1437 var v = seq.val[i], key;
1438 if (v.type == 'symbol' || v.type == 'string')
1439 key = new MIM.Key (v);
1440 else if (v.type == 'integer')
1441 key = new MIM.Key (v.val);
1443 throw new Xex.ErrTerm (MIM.Error.ParseError,
1444 "Invalid key: " + v);
1445 this.val.push (key);
1446 if (key.has_modifier)
1447 this.has_modifier = true;
1452 var len = seq.val.length;
1453 for (var i = 0; i < len; i++)
1454 this.val.push (new MIM.Key (seq.val.charCodeAt (i)));
1457 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + seq);
1461 var proto = new Xex.Term ('keyseq');
1462 proto.Clone = function () { return this; }
1463 proto.Parser = function (domain, node)
1465 var seq = new Array ();
1466 for (node = node.firstChild; node; node = node.nextSibling)
1467 if (node.nodeType == 1)
1469 var term = Xex.Term.Parse (domain, node);
1470 return new MIM.KeySeq (term);
1472 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid keyseq");
1474 proto.toString = function ()
1476 var len = this.val.length;
1480 var str = '<keyseq>';
1481 for (var i = 0; i < len; i++)
1485 else if (this.has_modifier)
1487 str += this.val[i].toString ();
1489 return str + '</keyseq>';
1492 MIM.KeySeq.prototype = proto;
1496 MIM.Marker = function () { }
1497 MIM.Marker.prototype = new Xex.Term ('marker');
1498 MIM.Marker.prototype.CharAt = function (ic)
1500 var p = this.Position (ic);
1501 if (p < 0 || p >= ic.preedit.length)
1503 return ic.preedit.charCodeAt (p);
1506 MIM.FloatingMarker = function (name) { this.val = name; };
1507 var proto = new MIM.Marker ();
1508 MIM.FloatingMarker.prototype = proto;
1509 proto.Position = function (ic) { return ic.marker_positions[this.val]; };
1510 proto.Mark = function (ic) { ic.marker_positions[this.val] = ic.cursor_pos; };
1512 MIM.PredefinedMarker = function (name) { this.val = name; }
1513 MIM.PredefinedMarker.prototype = new MIM.Marker ();
1514 MIM.PredefinedMarker.prototype.Position = function (ic)
1516 if (typeof this.pos == 'number')
1518 return this.pos (ic);
1521 var predefined = { }
1523 function def_predefined (name, position)
1525 predefined[name] = new MIM.PredefinedMarker (name);
1526 predefined[name].pos = position;
1529 def_predefined ('@<', 0);
1530 def_predefined ('@>', function (ic) { return ic.preedit.length; });
1531 def_predefined ('@-', function (ic) { return ic.cursor_pos - 1; });
1532 def_predefined ('@+', function (ic) { return ic.cursor_pos + 1; });
1533 def_predefined ('@[', function (ic) {
1534 if (ic.cursor_pos > 0)
1536 var pos = ic.cursor_pos;
1537 return ic.preedit.FindProp ('candidates', pos - 1).from;
1541 def_predefined ('@]', function (ic) {
1542 if (ic.cursor_pos < ic.preedit.length - 1)
1544 var pos = ic.cursor_pos;
1545 return ic.preedit.FindProp ('candidates', pos).to;
1547 return ic.preedit.length;
1549 for (var i = 0; i < 10; i++)
1550 def_predefined ("@" + i, i);
1551 predefined['@first'] = predefined['@<'];
1552 predefined['@last'] = predefined['@>'];
1553 predefined['@previous'] = predefined['@-'];
1554 predefined['@next'] = predefined['@+'];
1555 predefined['@previous-candidate-change'] = predefined['@['];
1556 predefined['@next-candidate-change'] = predefined['@]'];
1558 MIM.SurroundMarker = function (name)
1561 this.distance = parseInt (name.slice (1));
1562 if (isNaN (this.distance))
1563 throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid marker: " + name);
1565 MIM.SurroundMarker.prototype = new MIM.Marker ();
1566 MIM.SurroundMarker.prototype.Position = function (ic)
1568 return ic.cursor_pos + this.distance;
1570 MIM.SurroundMarker.prototype.CharAt = function (ic)
1572 if (this.val == '@-0')
1574 var p = this.Position (ic);
1576 return ic.GetSurroundingChar (p);
1577 else if (p >= ic.preedit.length)
1578 return ic.GetSurroundingChar (p - ic.preedit.length);
1579 return ic.preedit.charCodeAt (p);
1582 MIM.Marker.prototype.Parser = function (domain, node)
1584 var name = node.firstChild.nodeValue;
1585 if (name.charAt (0) == '@')
1587 var n = predefined[name];
1590 if (name.charAt (1) == '-' || name.charAt (1) == '+')
1591 return new MIM.SurroundMarker (name);
1592 throw new Xex.ErrTerm (MIM.Error.ParseError,
1593 "Invalid marker: " + name);
1595 return new MIM.FloatingMarker (name);;
1599 MIM.Selector = function (name)
1603 MIM.Selector.prototype = new Xex.Term ('selector');
1607 selectors["@<"] = selectors["@first"] = new MIM.Selector ('@<');
1608 selectors["@="] = selectors["@current"] = new MIM.Selector ('@=');
1609 selectors["@>"] = selectors["@last"] = new MIM.Selector ('@>');
1610 selectors["@-"] = selectors["@previous"] = new MIM.Selector ('@-');
1611 selectors["@+"] = selectors["@next"] = new MIM.Selector ('@+');
1612 selectors["@["] = selectors["@previous-group"] = new MIM.Selector ('@[');
1613 selectors["@]"] = selectors["@next-group"] = new MIM.Selector ('@]');
1615 MIM.Selector.prototype.Parser = function (domain, node)
1617 var name = node.firstChild.nodeValue;
1618 var s = selectors[name];
1620 throw new Xex.ErrTerm (MIM.Error.ParseError,
1621 "Invalid selector: " + name);
1626 MIM.Rule = function (keyseq, actions)
1628 this.keyseq = keyseq;
1630 this.actions = actions;
1632 MIM.Rule.prototype = new Xex.Term ('rule');
1633 MIM.Rule.prototype.Parser = function (domain, node)
1636 for (n = node.firstChild; n && n.nodeType != 1; n = n.nextSibling);
1638 throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid rule:" + node);
1639 var keyseq = Xex.Term.Parse (domain, n);
1640 if (keyseq.type != 'keyseq')
1641 throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid rule:" + node);
1643 n = n.nextElement ();
1645 actions = Xex.Term.Parse (domain, n, null);
1646 return new MIM.Rule (keyseq, actions);
1648 MIM.Rule.prototype.toString = function ()
1653 MIM.Map = function (name)
1656 this.rules = new Array ();
1660 var proto = new Xex.Term ('map');
1662 proto.Parser = function (domain, node)
1664 var name = node.attributes['mname'].nodeValue;
1666 throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid map");
1667 var map = new MIM.Map (name);
1668 for (var n = node.firstChild; n; n = n.nextSibling)
1669 if (n.nodeType == 1)
1670 map.rules.push (Xex.Term.Parse (domain, n));
1674 proto.toString = function ()
1676 var str = '<map mname="' + this.name + '">';
1677 var len = this.rules.length;
1678 for (i = 0; i < len; i++)
1679 str += this.rules[i];
1680 return str + '</map>';
1683 MIM.Map.prototype = proto;
1686 Xex.CatchTag._mimtag = new Xex.SymTerm ('@mimtag');
1688 MIM.Action = function (domain, terms)
1690 var args = new Array ();
1691 args.push (Xex.CatchTag_.mimtag);
1692 for (var i = 0; i < terms.length; i++)
1693 args.push (terms[i]);
1694 this.action = Xex.Funcall.prototype.New (domain, 'catch', null, args);
1697 MIM.Action.prototype.Run = function (domain)
1699 var result = this.action.Eval (domain);
1700 if (result.type == 'error')
1702 domain.context.Error = result.toString ();
1705 return (result != Xex.CatchTag._mimtag);
1708 MIM.Keymap = function ()
1711 this.submaps = null;
1717 function add_rule (keymap, rule, branch_actions)
1719 var keyseq = rule.keyseq;
1720 var len = keyseq.val.length;
1723 for (var i = 0; i < len; i++)
1725 var key = keyseq.val[i];
1729 if (! keymap.submaps)
1730 keymap.submaps = {};
1732 sub = keymap.submaps[key.key];
1734 keymap.submaps[key.key] = sub = new MIM.Keymap ();
1738 keymap.map_actions = rule.actions;
1740 keymap.branch_actions = branch_actions;
1743 proto.Add = function (map, branch_actions)
1745 var rules = map.rules;
1746 var len = rules.length;
1748 for (var i = 0; i < len; i++)
1749 add_rule (this, rules[i], branch_actions);
1751 proto.Lookup = function (keys, index)
1755 if (index < keys.val.length && this.submaps
1756 && ! keys.val[index])
1758 Xex.Log ('invalid key at ' + index);
1759 throw 'invalid key';
1762 if (index < keys.val.length && this.submaps
1763 && (sub = this.submaps[keys.val[index].key]))
1766 return sub.Lookup (keys, index);
1768 return { map: this, index: index };
1771 MIM.Keymap.prototype = proto;
1774 MIM.State = function (name)
1777 this.keymap = new MIM.Keymap ();
1781 var proto = new Xex.Term ('state');
1783 proto.Parser = function (domain, node)
1785 var map_list = domain.map_list;
1786 var name = node.attributes['sname'].nodeValue;
1788 throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid map");
1789 var state = new MIM.State (name);
1790 for (node = node.firstElement (); node; node = node.nextElement ())
1792 if (node.nodeName == 'title')
1793 state.title = node.firstChild.nodeValue;
1796 var n = node.firstElement ();
1797 var branch_actions = n ? Xex.Term.Parse (domain, n, null) : null;
1798 if (node.nodeName == 'branch')
1799 state.keymap.Add (map_list[node.attributes['mname'].nodeValue],
1801 else if (node.nodeName == 'state-hook')
1802 state.enter_actions = branch_actions;
1803 else if (node.nodeName == 'catch-all-branch')
1804 state.fallback_actions = branch_actions;
1810 proto.toString = function ()
1812 return '<state sname="' + this.name + '">' + this.keymap + '</state>';
1815 MIM.State.prototype = proto;
1819 function Block (index, term)
1823 this.Data = term.val;
1824 else if (term.IsList)
1826 this.Data = new Array ();
1827 for (var i = 0; i < term.val.length; i++)
1828 this.Data.push (term.val[i].val);
1832 Block.prototype.Count = function () { return this.Data.length; }
1833 Block.prototype.get = function (i)
1835 return (this.Data instanceof Array ? this.Data[i] : this.Data.charAt (i));
1838 MIM.Candidates = function (ic, candidates, column)
1841 this.column = column;
1845 this.blocks = new Array ();
1847 for (var i = 0; i < candidates.length; i++)
1849 var block = new Block (this.total, candidates[i]);
1850 this.blocks.push (block);
1851 this.total += block.Count ();
1857 return (this.column > 0 ? this.index % this.column
1858 : this.index - this.blocks[this.row].Index);
1861 function prev_group ()
1863 var col = get_col.call (this);
1865 if (this.column > 0)
1867 this.index -= this.column;
1868 if (this.index >= 0)
1869 nitems = this.column;
1872 var lastcol = (this.total - 1) % this.column;
1873 this.index = (col < lastcol ? this.total - lastcol + col
1875 this.row = this.blocks.length - 1;
1876 nitems = lastcol + 1;
1878 while (this.blocks[this.row].Index > this.index)
1883 this.row = this.row > 0 ? this.row - 1 : this.blocks.length - 1;
1884 nitems = this.blocks[this.row].Count ();
1885 this.index = (this.blocks[this.row].Index
1886 + (col < nitems ? col : nitems - 1));
1891 function next_group ()
1893 var col = get_col.call (this);
1895 if (this.column > 0)
1897 this.index += this.column - col;
1898 if (this.index < this.total)
1900 if (this.index + col >= this.total)
1902 nitems = this.total - this.index;
1903 this.index = this.total - 1;
1907 nitems = this.column;
1916 while (this.blocks[this.row].Index + this.blocks[this.row].Count ()
1922 this.row = this.row < this.blocks.length - 1 ? this.row + 1 : 0;
1923 nitems = this.blocks[this.row].Count ();
1924 this.index = (this.blocks[this.row].Index
1925 + (col < nitems ? col : nitems - 1));
1932 if (this.index == 0)
1934 this.index = this.total - 1;
1935 this.row = this.blocks.length - 1;
1940 if (this.blocks[this.row].Index > this.index)
1948 if (this.index == this.total)
1955 var b = this.blocks[this.row];
1956 if (this.index == b.Index + b.Count ())
1963 this.index -= get_col.call (this);
1964 while (this.blocks[this.row].Index > this.index)
1970 var b = this.blocks[this.row];
1971 if (this.column > 0)
1973 if (this.index + 1 < this.total)
1975 this.index += this.column - get_col.call (this) + 1;
1976 while (b.Index + b.Count () <= this.index)
1977 b = this.blocks[++this.row];
1981 this.index = b.Index + b.Count () - 1;
1984 MIM.Candidates.prototype.Current = function ()
1986 var b = this.blocks[this.row];
1987 return b.get (this.index - b.Index);
1990 MIM.Candidates.prototype.Select = function (selector)
1992 var idx = this.index;
1993 var gidx = this.column > 0 ? idx / this.column : this.row;
1994 if (selector.type == 'selector')
1996 switch (selector.val)
1998 case '@<': first.call (this); break;
1999 case '@>': last.call (this); break;
2000 case '@-': prev.call (this); break;
2001 case '@+': next.call (this); break;
2002 case '@[': prev_group.call (this); break;
2003 case '@]': next_group.call (this); break;
2010 if (this.column > 0)
2012 col = this.index % this.column;
2013 start = this.index - col;
2014 end = start + this.column;
2018 start = this.blocks[this.row].Index;
2019 col = this.index - start;
2020 end = start + this.blocks[this.row].Count;
2022 if (end > this.total)
2024 this.index += selector.val - col;
2025 if (this.index >= end)
2026 this.index = end - 1;
2027 if (this.column > 0)
2029 if (selector.val > col)
2030 while (this.blocks[this.row].Index + this.blocks[this.row].Count
2034 while (this.blocks[this.row].Index > this.index)
2038 var newgidx = this.column > 0 ? this.index / this.column : this.row;
2039 if (this.index != idx)
2040 this.ic.changed |= (gidx == newgidx
2041 ? MIM.ChangedStatus.CandidateIndex
2042 : MIM.ChangedStatus.CandidateList);
2043 return this.Current ();
2046 MIM.Candidates.prototype.CurrentCol = function ()
2048 return get_col.call (this);
2051 MIM.Candidates.prototype.CurrentGroup = function ()
2053 var col, start, end, gnum, gidx;
2054 if (this.column > 0)
2056 gnum = Math.floor ((this.total - 1) / this.column) + 1;
2057 col = this.index % this.column;
2058 start = this.index - col;
2059 gidx = start / this.column + 1;
2060 end = start + this.column;
2061 if (end > this.total)
2066 gnum = this.blocks.length;
2067 gidx = this.row + 1;
2068 start = this.blocks[this.row].Index;
2069 col = this.index - start;
2070 end = start + this.blocks[this.row].Count ();
2072 var group = new Array ();
2073 var indices = new Array (gnum, gidx, col);
2074 group.push (indices);
2076 var block = this.blocks[row++];
2079 var c = block.get (start - block.Index);
2082 if (start == block.Index + block.Count ())
2083 block = this.blocks[row++];
2089 MIM.im_domain = new Xex.Domain ('input-method', null, null);
2090 MIM.im_domain.DefType (MIM.KeySeq.prototype);
2091 MIM.im_domain.DefType (MIM.Marker.prototype);
2092 MIM.im_domain.DefType (MIM.Selector.prototype);
2093 MIM.im_domain.DefType (MIM.Rule.prototype);
2094 MIM.im_domain.DefType (MIM.Map.prototype);
2095 MIM.im_domain.DefType (MIM.State.prototype);
2098 var im_domain = MIM.im_domain;
2100 function Finsert (domain, vari, args)
2103 if (args[0].type == 'integer')
2104 text = String.fromCharCode (args[0].val);
2107 domain.context.ins (text, null);
2111 function Finsert_candidates (domain, vari, args)
2113 var ic = domain.context;
2114 var gsize = domain.variables['candidates-group-size'];
2115 var candidates = new MIM.Candidates (ic, args,
2116 gsize ? gsize.val.Intval () : 0);
2117 ic.ins (candidates.Current (), candidates);
2121 function Fdelete (domain, vari, args)
2123 var ic = domain.context;
2124 var pos = args[0].IsInt ? args[0].Intval () : args[0].Position (ic);
2125 return new Xex.IntTerm (ic.del (pos));
2128 function Fselect (domain, vari, args)
2130 var ic = domain.context;
2131 var can = ic.candidates;
2135 var old_text = can.Current ();
2136 var new_text = can.Select (args[0]);
2137 ic.rep (old_text, new_text, can);
2140 Xex.Log ('no candidates at ' + ic.cursor_pos + ' of ' + ic.candidate_table.table.length);
2144 function Fshow (domain, vari, args)
2146 domain.context.candidate_show = true;
2147 domain.context.changed |= MIM.ChangedStatus.CandidateShow;
2151 function Fhide (domain, vari, args)
2153 domain.context.candidate_show = false;
2154 domain.context.changed |= MIM.ChangedStatus.CandidateShow;
2158 function Fchar_at (domain, vari, args)
2160 return new Xex.IntTerm (args[0].CharAt (domain.context));
2163 function Fmove (domain, vari, args)
2165 var ic = domain.context;
2166 var pos = args[0].IsInt ? args[0].val : args[0].Position (ic);
2168 return new Xex.IntTerm (pos);
2171 function Fmark (domain, vari, args)
2173 args[0].Mark (domain.context);
2177 function Fpushback (domain, vari, args)
2179 var a = (args[0].IsInt ? args[0].Intval ()
2180 : args[0].IsStr ? new KeySeq (args[0])
2182 domain.context.pushback (a);
2186 function Fpop (domain, vari, args)
2188 var ic = domain.context;
2189 if (ic.key_head < ic.keys.val.length)
2190 ic.keys.val.splice (ic.keys_head, 1);
2194 function Fundo (domain, vari, args)
2196 var ic = domain.context;
2197 var n = args.length == 0 ? -2 : args[0].val;
2198 Xex.Log ('undo with arg ' + args[0]);
2200 ic.keys.val.splice (ic.keys.val.length + n, -n);
2202 ic.keys.val.splice (n, ic.keys.val.length);
2207 function Fcommit (domain, vari, args)
2209 domain.context.commit ();
2213 function Funhandle (domain, vari, args)
2215 domain.context.commit ();
2216 return Xex.Fthrow (domain, vari, Xex.CatchTag._mimtag);
2219 function Fshift (domain, vari, args)
2221 var ic = domain.context;
2222 var state_name = args[0].val;
2223 var state = ic.im.state_list[state_name];
2225 throw ("Unknown state: " + state_name);
2230 function Fshiftback (domain, vari, args)
2232 domain.context.shift (null);
2236 function Fkey_count (domain, vari, args)
2238 return new Xex.IntTerm (domain.context.key_head);
2241 function Fsurrounding_flag (domain, vari, args)
2243 return new Xex.IntTerm (-1);
2246 im_domain.DefSubr (Finsert, "insert", false, 1, 1);
2247 im_domain.DefSubr (Finsert_candidates, "insert-candidates", false, 1, 1);
2248 im_domain.DefSubr (Fdelete, "delete", false, 1, 1);
2249 im_domain.DefSubr (Fselect, "select", false, 1, 1);
2250 im_domain.DefSubr (Fshow, "show-candidates", false, 0, 0);
2251 im_domain.DefSubr (Fhide, "hide-candidates", false, 0, 0);
2252 im_domain.DefSubr (Fmove, "move", false, 1, 1);
2253 im_domain.DefSubr (Fmark, "mark", false, 1, 1);
2254 im_domain.DefSubr (Fpushback, "pushback", false, 1, 1);
2255 im_domain.DefSubr (Fpop, "pop", false, 0, 0);
2256 im_domain.DefSubr (Fundo, "undo", false, 0, 1);
2257 im_domain.DefSubr (Fcommit, "commit", false, 0, 0);
2258 im_domain.DefSubr (Funhandle, "unhandle", false, 0, 0);
2259 im_domain.DefSubr (Fshift, "shift", false, 1, 1);
2260 im_domain.DefSubr (Fshiftback, "shiftback", false, 0, 0);
2261 im_domain.DefSubr (Fchar_at, "char-at", false, 1, 1);
2262 im_domain.DefSubr (Fkey_count, "key-count", false, 0, 0);
2263 im_domain.DefSubr (Fsurrounding_flag, "surrounding-text-flag", false, 0, 0);
2268 function get_global_var (vname)
2270 if (MIM.im_global.load_status == MIM.LoadStatus.NotLoaded)
2271 MIM.im_global.Load ()
2272 return MIM.im_global.domain.variables[vname];
2275 function include (node)
2277 node = node.firstElement ();
2278 if (node.nodeName != 'tags')
2281 var lang = null, name = null, extra = null;
2282 for (node = node.firstElement (); node; node = node.nextElement ())
2284 if (node.nodeName == 'language')
2285 lang = node.firstChild.nodeValue;
2286 else if (node.nodeName == 'name')
2287 name = node.firstChild.nodeValue;
2288 else if (node.nodeName == 'extra-id')
2289 extra = node.firstChild.nodeValue;
2291 if (! lang || ! MIM.imlist[lang])
2295 if (! name || ! (im = MIM.imlist[lang][name]))
2300 if (! (im = MIM.imextra[lang][extra]))
2303 if (im.load_status != MIM.LoadStatus.Loaded
2304 && (im.load_status != MIM.LoadStatus.NotLoaded || ! im.Load ()))
2311 parsers['description'] = function (node)
2313 this.description = node.firstChild.nodeValue;
2315 parsers['variable-list'] = function (node)
2317 for (node = node.firstElement (); node; node = node.nextElement ())
2319 var vname = node.attributes['vname'].nodeValue;
2320 if (this != MIM.im_global)
2322 var vari = get_global_var (vname);
2324 this.domain.Defvar (vname, vari.desc, vari.val, vari.range);
2326 vname = Xex.Term.Parse (this.domain, node)
2329 parsers['command-list'] = function (node)
2332 parsers['macro-list'] = function (node)
2334 for (var n = node.firstElement (); n; n = n.nextElement ())
2335 if (n.nodeName == 'xi:include')
2337 var im = include (n);
2339 alert ('inclusion fail');
2341 for (var macro in im.domain.functions)
2343 var func = im.domain.functions[macro];
2344 if (func instanceof Xex.Macro)
2345 im.domain.CopyFunc (this.domain, macro);
2347 n = n.previousSibling;
2348 node.removeChild (n.nextSibling);
2350 Xex.Term.Parse (this.domain, node.firstElement (), null);
2352 parsers['title'] = function (node)
2354 this.title = node.firstChild.nodeValue;
2356 parsers['map-list'] = function (node)
2358 for (node = node.firstElement (); node; node = node.nextElement ())
2360 if (node.nodeName == 'xi:include')
2362 var im = include (node);
2365 alert ('inclusion fail');
2368 for (var mname in im.map_list)
2369 this.map_list[mname] = im.map_list[mname];
2373 var map = Xex.Term.Parse (this.domain, node);
2374 this.map_list[map.name] = map;
2378 parsers['state-list'] = function (node)
2380 this.domain.map_list = this.map_list;
2381 for (node = node.firstElement (); node; node = node.nextElement ())
2383 if (node.nodeName == 'xi:include')
2385 var im = include (node);
2387 alert ('inclusion fail');
2388 for (var sname in im.state_list)
2390 state = im.state_list[sname];
2391 if (! this.initial_state)
2392 this.initial_state = state;
2393 this.state_list[sname] = state;
2396 else if (node.nodeName == 'state')
2398 var state = Xex.Term.Parse (this.domain, node);
2400 state.title = this.title;
2401 if (! this.initial_state)
2402 this.initial_state = state;
2403 this.state_list[state.name] = state;
2406 delete this.domain.map_list;
2409 MIM.IM = function (lang, name, extra_id, file)
2413 this.extra_id = extra_id;
2415 this.load_status = MIM.LoadStatus.NotLoaded;
2416 this.domain = new Xex.Domain (this.lang + '-'
2417 + (this.name != 'nil'
2418 ? this.name : this.extra_id),
2419 MIM.im_domain, null);
2425 var node = Xex.Load (null, this.file);
2428 this.load_status = MIM.LoadStatus.Error;
2432 this.initial_state = null;
2433 this.state_list = {};
2434 for (node = node.firstElement (); node; node = node.nextElement ())
2436 var name = node.nodeName;
2437 var parser = parsers[name];
2439 parser.call (this, node);
2441 this.load_status = MIM.LoadStatus.Loaded;
2446 MIM.IM.prototype = proto;
2448 MIM.IC = function (im, target)
2450 if (im.load_status == MIM.LoadStatus.NotLoaded)
2452 if (im.load_status != MIM.LoadStatus.Loaded)
2453 alert ('im:' + im.name + ' error:' + im.load_status);
2455 this.target = target;
2456 this.domain = new Xex.Domain ('context', im.domain, this);
2458 this.range = new Array ();
2459 this.range[0] = this.range[1] = 0;
2461 this.initial_state = this.im.initial_state;
2462 this.keys = new MIM.KeySeq ();
2463 this.marker_positions = new Array ();
2464 this.candidate_table = new MIM.CandidateTable ();
2468 MIM.CandidateTable = function ()
2470 this.table = new Array ();
2473 MIM.CandidateTable.prototype.get = function (pos)
2475 for (var i = 0; i < this.table.length; i++)
2477 var elt = this.table[i];
2478 if (elt.from < pos && pos <= elt.to)
2483 MIM.CandidateTable.prototype.put = function (from, to, candidates)
2485 for (var i = 0; i < this.table.length; i++)
2487 var elt = this.table[i];
2488 if (elt.from < to && elt.to > from)
2492 elt.val = candidates;
2496 this.table.push ({ from: from, to: to, val: candidates });
2499 MIM.CandidateTable.prototype.adjust = function (from, to, inserted)
2501 var diff = inserted - (to - from);
2504 for (var i = 0; i < this.table.length; i++)
2506 var elt = this.table[i];
2515 MIM.CandidateTable.prototype.clear = function ()
2517 this.table.length = 0;
2520 function set_cursor (prefix, pos)
2522 this.cursor_pos = pos;
2523 var candidates = this.candidate_table.get (pos);
2524 if (this.candidates != candidates)
2526 this.candidates = candidates;
2527 this.changed |= MIM.ChangedStatus.CandidateList;
2531 function save_state ()
2533 this.state_var_values = this.domain.SaveValues ();
2534 this.state_preedit = this.preedit;
2535 this.state_key_head = this.key_head;
2536 this.state_pos = this.cursor_pos;
2539 function restore_state ()
2541 this.domain.RestoreValues (this.state_var_values);
2542 this.preedit = this.state_preedit;
2543 set_cursor.call (this, "restore", this.state_pos);
2546 function handle_key ()
2548 Xex.Log ('Key(' + this.key_head + ') "' + this.keys.val[this.key_head]
2549 + '" in ' + this.state.name + ':' + this.keymap.name
2550 + " key/state/commit-head/len:"
2551 + this.key_head + '/' + this.state_key_head + '/' + this.commit_key_head + '/' + this.keys.val.length);
2552 var out = this.state.keymap.Lookup (this.keys, this.state_key_head);
2555 if (out.index > this.key_head)
2557 this.key_head = out.index;
2558 Xex.Log (' with submap', false, true);
2559 restore_state.call (this);
2561 if (sub.map_actions)
2563 Xex.Log ('taking map actions:');
2564 if (! this.take_actions (sub.map_actions))
2567 else if (sub.submaps)
2569 Xex.Log ('no map actions');
2570 for (var i = this.state_key_head; i < this.key_head; i++)
2572 Xex.Log ('inserting key:' + this.keys.val[i].key);
2573 this.ins (this.keys.val[i].key, null);
2578 Xex.Log ('terminal:');
2579 if (this.keymap.branch_actions)
2581 Xex.Log ('branch actions:');
2582 if (! this.take_actions (this.keymap.branch_actions))
2585 if (sub != this.state.keymap)
2586 this.shift (this.state);
2591 Xex.Log (' without submap', false, true);
2593 var current_state = this.state;
2594 var map = this.keymap;
2596 if (map.branch_actions)
2598 Xex.Log ('branch actions:');
2599 if (! this.take_actions (map.branch_actions))
2603 if (map == this.keymap)
2605 Xex.Log ('no state change');
2606 if (map == this.initial_state.keymap
2607 && this.key_head < this.keys.val.length)
2609 Xex.Log ('unhandled');
2612 if (this.keymap != current_state.keymap)
2613 this.shift (current_state);
2614 else if (this.keymap.actions == null)
2615 this.shift (this.initial_state);
2624 this.cursor_pos = 0;
2625 this.candidate_show = false;
2626 this.prev_state = null;
2627 this.title = this.initial_state.title;
2628 this.state_preedit = '';
2629 this.state_key_head = 0;
2630 this.state_var_values = {};
2633 this.commit_key_head = 0;
2634 this.key_unhandled = false;
2635 this.unhandled_key = null;
2636 this.changed = MIM.ChangedStatus.None;
2637 this.error_message = '';
2638 this.title = this.initial_state.title;
2641 this.preedit_saved = '';
2642 this.candidate_table.clear ();
2643 this.candidates = null;
2644 this.candidate_show = false;
2645 for (var elt in this.marker_positions)
2646 this.marker_positions[elt] = 0;
2647 this.shift (this.initial_state);
2650 catch_args: new Array (Xex.CatchTag._mimtag, null),
2652 take_actions: function (actions)
2654 if (actions.length == 0)
2656 var func_progn = this.domain.GetFunc ('progn');
2657 var func_catch = this.domain.GetFunc ('catch');
2658 this.catch_args[1] = new Xex.Funcall (func_progn, null, actions);
2659 var term = new Xex.Funcall (func_catch, null, this.catch_args);
2660 term = term.Eval (this.domain);
2661 return (! term.IsSymbol || term.val != '@mimtag');
2664 GetSurroundingChar: function (pos)
2668 pos += this.range[0];
2674 pos += this.range[1];
2675 if (pos >= this.target.value.length)
2678 return this.target.value.charCodeAt (pos);
2681 DelSurroundText: function (pos)
2686 pos += this.range[0];
2692 text = this.target.value.substring (0, pos);
2693 if (this.range[0] < this.target.value.length)
2694 text += this.target.value.substring (this.range[0]);
2695 this.target.value = text;
2696 this.range[1] -= this.range[0] - pos;
2697 this.range[0] = pos;
2701 pos += this.range[1];
2702 text = this.target.value.substring (0, this.range[1]);
2703 if (pos >= this.target.value.length)
2704 pos = this.target.value.length;
2706 text += this.target.value.substring (pos);
2707 this.target.value = text;
2711 adjust_markers: function (from, to, inserted)
2713 var diff = inserted - (to - from);
2715 for (var name in this.marker_positions)
2717 var pos = this.marker_positions[name];
2721 this.marker_positions[name] += diff;
2722 else if (pos > from)
2723 this.marker_positions[name] = from;
2728 preedit_replace: function (from, to, text, candidates)
2730 var newlen = text.length;
2731 this.preedit = (this.preedit.substring (0, from)
2732 + text + this.preedit.substring (to));
2733 this.changed |= MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos;
2734 this.adjust_markers (from, to, newlen);
2735 this.candidate_table.adjust (from, to, newlen);
2737 this.candidate_table.put (from, from + newlen, candidates)
2738 if (this.cursor_pos >= to)
2739 set_cursor.call (this, 'adjust', this.cursor_pos + text.length - (to - from));
2740 else if (this.cursor_pos > from)
2741 set_cursor.call (this, 'adjust', from)
2744 ins: function (text, candidates)
2746 this.preedit_replace (this.cursor_pos, this.cursor_pos, text, candidates);
2749 rep: function (old_text, new_text, candidates)
2751 this.preedit_replace (this.cursor_pos - old_text.length,
2752 this.cursor_pos, new_text, candidates);
2757 var deleted = pos - this.cursor_pos;
2758 if (pos < this.cursor_pos)
2762 this.DelSurroundText (pos);
2763 deleted = - this.cursor_pos;
2766 if (pos < this.cursor_pos)
2767 this.preedit_replace (pos, this.cursor_pos, '', null);
2771 if (pos > this.preedit.length)
2773 this.DelSurroundText (pos - this.preedit.length);
2774 deleted = this.preedit.length - this.cursor_pos;
2775 pos = this.preedit.length;
2777 if (pos > this.cursor_pos)
2778 this.preedit_replace (this.cursor_pos, pos, '', null);
2785 this.candidate_show = true;
2786 this.changed |= MIM.ChangedStatus.CandidateShow;
2791 this.candidate_show = false;
2792 this.changed |= MIM.ChangedStatus.CandidateShow;
2795 move: function (pos)
2799 else if (pos > this.preedit.length)
2800 pos = this.preedit.length;
2801 if (pos != this.cursor_pos)
2803 set_cursor.call (this, 'move', pos);
2804 this.changed |= MIM.ChangedStatus.Preedit;
2808 pushback: function (n)
2810 if (n instanceof MIM.KeySeq)
2812 if (this.key_head > 0)
2814 if (this.key_head < this.keys.val.length)
2815 this.keys.val.splice (this.key_head,
2816 this.keys.val.length - this.key_head);
2817 for (var i = 0; i < n.val.length; i++)
2818 this.keys.val.push (n.val[i]);
2824 if (this.key_head < 0)
2831 this.key_head = - n;
2832 if (this.key_head > this.keys.val.length)
2833 this.key_head = this.keys.val.length;
2839 if (this.key_head < this.keys.val.length)
2840 this.keys.val.splice (this.key_head, 1);
2845 if (this.preedit.length > 0)
2847 this.candidate_table.clear ();
2848 this.produced += this.preedit;
2849 this.preedit_replace.call (this, 0, this.preedit.length, '', null);
2850 this.preedit_saved = '';
2852 this.commit_key_head = this.key_head;
2856 shift: function (state)
2860 if (this.prev_state == null)
2862 state = this.prev_state;
2865 if (state == this.initial_state)
2870 this.keys.val.splice (0, this.key_head);
2871 this.key_head = this.state_key_head = this.commit_key_head = 0;
2872 this.prev_state = null;
2877 if (state != this.state)
2878 this.prev_state = this.state;
2880 if (state != this.state && state.enter_actions)
2881 this.take_actions (state.enter_actions);
2882 if (! this.state || this.state.title != state.title)
2883 this.changed |= MIM.ChangedStatus.StateTitle;
2885 this.keymap = state.keymap;
2886 save_state.call (this);
2889 Filter: function (key)
2893 Xex.Log ("active = false");
2894 this.key_unhandled = true;
2895 this.unhandled_key = key;
2898 if (key.key == '_reload')
2900 this.changed = MIM.ChangedStatus.None;
2902 this.key_unhandled = false;
2903 this.keys.val.push (key);
2905 while (this.key_head < this.keys.val.length)
2907 if (! handle_key.call (this))
2909 if (this.key_head < this.keys.val.length)
2911 this.unhandled_key = this.keys.val[this.key_head];
2912 this.keys.val.splice (this.key_head, this.key_head + 1);
2914 if (this.state_key_head > 0)
2915 this.state_key_head--;
2916 if (this.commit_key_head > 0)
2917 this.commit_key_head--;
2918 this.key_unhandled = true;
2924 this.key_unhandled = true;
2928 if (this.keymap == this.initial_state.keymap)
2931 if (this.commit_key_head > 0)
2933 this.keys.val.splice (0, this.commit_key_head);
2934 this.key_head -= this.commit_key_head;
2935 this.state_key_head -= this.commit_key_head;
2936 this.commit_key_head = 0;
2938 if (this.key_unhandled)
2940 this.keys.val.length = 0;
2941 //this.keys.val.splice (0, this.keys.val.length);
2942 this.key_head = this.state_key_head = this.commit_key_head = 0;
2944 if (this.changed & MIM.ChangedStatus.Candidate)
2946 if (this.candidate_show && this.candidates)
2951 return (! this.key_unhandled
2952 && this.produced.length == 0);
2956 MIM.IC.prototype = proto;
2958 var node = Xex.Load (null, "imlist.xml");
2959 for (node = node.firstChild; node; node = node.nextSibling)
2960 if (node.nodeName == 'input-method')
2962 var lang = null, name = null, extra_id = null, file = null;
2964 for (var n = node.firstChild; n; n = n.nextSibling)
2966 if (n.nodeName == 'language')
2967 lang = n.firstChild.nodeValue;
2968 else if (n.nodeName == 'name')
2969 name = n.firstChild.nodeValue;
2970 else if (n.nodeName == 'extra-id')
2971 extra_id = n.firstChild.nodeValue;
2972 else if (n.nodeName == 'filename')
2973 file = n.firstChild.nodeValue;
2975 if (name && name != 'nil')
2977 if (! MIM.imlist[lang])
2978 MIM.imlist[lang] = {};
2979 MIM.imlist[lang][name] = new MIM.IM (lang, name, extra_id, file);
2981 else if (extra_id && extra_id != 'nil')
2983 if (! MIM.imextra[lang])
2984 MIM.imextra[lang] = {};
2985 MIM.imextra[lang][extra_id] = new MIM.IM (lang, name, extra_id, file);
2988 if (MIM.imextra.t && MIM.imextra.t.global)
2989 MIM.im_global = MIM.imextra.t.global;
2992 MIM.im_global = new MIM.IM ('t', 'nil', 'global', null);
2993 MIM.im_global.load_status = MIM.LoadStatus.Error;
2999 var keys = new Array ();
3001 keys[0x08] = 'backspace';
3002 keys[0x0D] = 'return';
3003 keys[0x1B] = 'escape';
3004 keys[0x20] = 'space';
3005 keys[0x21] = 'pageup';
3006 keys[0x22] = 'pagedown';
3008 keys[0x24] = 'home';
3009 keys[0x25] = 'left';
3011 keys[0x27] = 'right';
3012 keys[0x28] = 'down';
3013 keys[0x2D] = 'insert';
3014 keys[0x2E] = 'delete';
3015 for (var i = 1; i <= 12; i++)
3016 keys[111 + i] = "f" + i;
3017 keys[0x90] = "numlock";
3018 keys[0xF0] = "capslock";
3021 keyids['U+0008'] = 'Backspace';
3022 keyids['U+0009'] = 'Tab';
3023 keyids['U+0018'] = 'Cancel';
3024 keyids['U+001B'] = 'Escape';
3025 keyids['U+0020'] = 'Space';
3026 keyids['U+007F'] = 'Delete';
3029 modifiers.Shift = 1;
3030 modifiers.Control = 1;
3032 modifiers.AltGraph = 1;
3035 MIM.decode_key_event = function (event)
3037 var key = event.keyIdentifier;
3039 if (key) // keydown event of Chrome
3044 if (event.ctrlKey) mod += 'C-';
3045 if (event.metaKey) mod += 'M-';
3046 if (event.altKey) mod += 'A-';
3047 var keysym = keyids[key];
3050 else if (key.match(/^U\+([0-9A-Z]+)$/))
3052 if (mod.length == 0)
3054 key = String.fromCharCode (parseInt (RegExp.$1, 16));
3057 //key = key.toLowerCase ();
3058 if (event.shiftKey) mod += 'S-';
3059 return new MIM.Key (mod + key);
3063 key = ((event.type == 'keydown' || event.keyCode) ? event.keyCode
3064 : event.charCode ? event.charCode
3068 if (event.type == 'keydown')
3073 if (event.shiftKey) key = "S-" + key ;
3076 key = String.fromCharCode (key);
3078 if (event.altKey) key = "A-" + key ;
3079 if (event.ctrlKey) key = "C-" + key ;
3080 return new MIM.Key (key);
3084 MIM.add_event_listener
3085 = (window.addEventListener
3086 ? function (target, type, listener) {
3087 target.addEventListener (type, listener, false);
3089 : window.attachEvent
3090 ? function (target, type, listener) {
3091 target.attachEvent ('on' + type,
3093 listener.call (target, window.event);
3096 : function (target, type, listener) {
3098 = function (e) { listener.call (target, e || window.event); };
3101 MIM.debug_print = function (event, ic)
3105 if (! MIM.debug_nodes)
3107 MIM.debug_nodes = new Array ();
3108 MIM.debug_nodes['status0'] = document.getElementById ('status0');
3109 MIM.debug_nodes['status1'] = document.getElementById ('status1');
3110 MIM.debug_nodes['keydown'] = document.getElementById ('keydown');
3111 MIM.debug_nodes['keypress'] = document.getElementById ('keypress');
3112 MIM.debug_nodes['keymap0'] = document.getElementById ('keymap0');
3113 MIM.debug_nodes['keymap1'] = document.getElementById ('keymap1');
3114 MIM.debug_nodes['preedit0'] = document.getElementById ('preedit0');
3115 MIM.debug_nodes['preedit1'] = document.getElementById ('preedit1');
3117 var target = event.target;
3118 var code = event.keyCode;
3119 var ch = event.type == 'keypress' ? event.charCode : 0;
3120 var key = MIM.decode_key_event (event);
3123 MIM.debug_nodes[event.type].innerHTML = "" + code + "/" + ch + ":" + key + '/' + event.keyIdentifier;
3124 index = (event.type == 'keydown' ? '0' : '1');
3126 MIM.debug_nodes['status' + index].innerHTML = ic.im.load_status;
3128 MIM.debug_nodes['status' + index].innerHTML = 'no IM';
3129 MIM.debug_nodes['keymap' + index].innerHTML = ic.state.name;
3130 MIM.debug_nodes['preedit' + index].innerHTML = ic.preedit;
3133 MIM.debug_nodes.keypress.innerHTML = '';
3134 MIM.debug_nodes.status1.innerHTML = '';
3135 MIM.debug_nodes.keymap1.innerHTML = '';
3136 MIM.debug_nodes.preedit1.innerHTML = ''
3140 MIM.get_range = function (target, ic)
3143 if (target.selectionStart != null) // for Mozilla
3145 from = target.selectionStart;
3146 to = target.selectionEnd;
3150 var r = document.selection.createRange ();
3151 var rr = r.duplicate ();
3153 rr.moveToElementText (target);
3154 rr.setEndPoint ('EndToEnd', range);
3155 from = rr.text.length - r.text.length;
3156 to = rr.text.length;
3158 if (ic.range[0] == from && ic.range[1] == to
3159 && (to == from || target.value.substring (from, to) == ic.preedit))
3166 MIM.set_caret = function (target, ic)
3168 if (target.setSelectionRange) // Mozilla
3170 var scrollTop = target.scrollTop;
3171 target.setSelectionRange (ic.range[0], ic.range[1]);
3172 target.scrollTop = scrollTop;
3176 var range = target.createTextRange ();
3177 range.moveStart ('character', ic.range[0]);
3178 range.moveEnd ('character', ic.range[1]);
3183 MIM.update = function (target, ic)
3185 var text = target.value;
3186 target.value = (text.substring (0, ic.range[0])
3189 + text.substring (ic.range[1]));
3190 ic.range[0] += ic.produced.length;
3191 ic.range[1] = ic.range[0] + ic.preedit.length;
3192 MIM.set_caret (target, ic);
3199 padingLeft: 'padding-left',
3200 paddingRight: 'padding-right',
3201 paddingTop: 'padding-top',
3202 paddintBottom: 'padding-bottom',
3203 borderLeftStyle: 'border-left-style',
3204 borderRightStyle: 'border-right-style',
3205 borderTopStyle: 'border-top-style',
3206 borderBottomStyle: 'border-bottom-style',
3207 borderLeftWidth: 'border-left-width',
3208 borderRightWidth: 'border-right-width',
3209 borderTopWidth: 'border-top-width',
3210 borderBottomWidth: 'border-bottom-width',
3211 fontFamily: 'font-family',
3212 fontSize: 'font-size',
3213 lineHeight: 'line-height',
3214 letterSpacing: 'letter-spacing',
3215 wordSpacing: 'word-spacing' };
3217 function copy_style (from, to)
3219 var from_style = getComputedStyle(from,'');
3220 for(var name in style_props)
3221 to.style[name] = from_style.getPropertyValue (style_props[name]);
3222 to.style.left = from.offsetLeft + 'px';
3223 to.style.top = from.offsetTop + 'px';
3224 to.style.width = from.offsetWidth;
3225 to.style.height = from.offsetHeight;
3228 MIM.show = function (ic)
3230 if (! ic.candidates)
3232 var target = ic.target;
3237 for (var elm = ic.target.offsetParent; elm; elm = elm.offsetParent)
3239 ic.target_top += elm.offsetTop;
3240 ic.target_left += elm.offsetLeft;
3242 ic.div_node = document.createElement ('div');
3243 copy_style (target, ic.div_node);
3244 ic.div_node.style.visibility="hidden";
3245 ic.div_node.style.position = "absolute";
3246 document.getElementsByTagName ('body')[0].appendChild (ic.div_node);
3247 ic.div_node_first = document.createElement ('span');
3248 ic.div_node_last = document.createElement('span');
3249 ic.div_node_last.innerHTML = '.';
3250 ic.div_node.appendChild (ic.div_node_first);
3251 ic.div_node.appendChild (ic.div_node_last);
3252 ic.can_node = document.createElement ('table');
3253 ic.can_node.style.position = 'absolute';
3254 ic.can_node.style.display = 'none';
3255 ic.can_node.style.backgroundColor = "white";
3256 ic.can_node.style.border = "1px solid black";
3257 document.getElementsByTagName ('body')[0].appendChild (ic.can_node);
3260 if (ic.changed & MIM.ChangedStatus.CandidateList)
3262 while (ic.can_node.childNodes.length > 0)
3263 ic.can_node.removeChild (ic.can_node.firstChild);
3264 var tr = document.createElement ('tr');
3265 var group = ic.candidates.CurrentGroup ();
3266 var td = document.createElement ('td');
3267 td.innerHTML = group[0][1] + '/' + group[0][0];
3268 td.style.color = 'white';
3269 td.style.backgroundColor = 'black';
3270 tr.appendChild (td);
3271 for (var i = 1; i < group.length; i++)
3273 var td = document.createElement ('td');
3275 td.innerHTML = (i < 10 ? i : i == 10 ? '0' : String.fromCharCode (0x60 + (i - 10))) + '.' + group[i];
3276 if (i == group[0][2] + 1)
3277 td.style.backgroundColor = 'lightblue';
3278 tr.appendChild (td);
3280 ic.can_node.appendChild (tr);
3281 ic.div_node_first.innerHTML = target.value.substr (0, ic.range[0]);
3282 var x = ic.target_left + ic.div_node.lastChild.offsetLeft;
3283 var y = (ic.target_top + ic.div_node.lastChild.offsetTop
3284 + ic.div_node.lastChild.offsetHeight - target.scrollTop + 10);
3285 ic.can_node.style.left = x + 'px';
3286 ic.can_node.style.top = y + 'px';
3290 var td = ic.can_node.firstElement ().firstElement ().nextElement ();
3291 var col = ic.candidates.CurrentCol ();
3292 for (var i = 0; td; td = td.nextElement ())
3293 td.style.backgroundColor = (i++ == col ? 'lightblue' : 'white');
3295 ic.can_node.style.display = 'block';
3298 MIM.hide = function (ic)
3301 ic.can_node.style.display = 'none';
3305 MIM.focus_in = function (event)
3307 var target = event.target;
3308 var ic = target.mim_ic;
3309 if (ic.wait_update == true)
3311 Xex.Log ("Focus in " + target.tagName + ' IGNORED');
3312 event.preventDefault ();
3315 Xex.Log ("Focus in " + target.tagName);
3316 ic.Filter (MIM.Key.FocusIn);
3317 MIM.update (target, ic);
3320 MIM.focus_out = function (event)
3322 var target = event.target;
3323 var ic = target.mim_ic;
3324 function reset_update () { ic.wait_update = false; };
3325 if (ic.wait_update == true)
3327 Xex.Log ("Focus out " + target.tagName + ' IGNORED');
3328 event.preventDefault ();
3331 Xex.Log ("Focus out " + target.tagName);
3332 ic.Filter (MIM.Key.FocusOut);
3333 ic.wait_update = true;
3334 MIM.update (target, ic, true);
3335 setTimeout (reset_update, 1000);
3338 MIM.keydown = function (event)
3340 var target = event.target;
3341 if (target.id == 'log')
3343 if (! (target.type == "text" || target.type == "textarea"))
3346 var ic = target.mim_ic;
3347 if (! ic || ic.im != MIM.current)
3349 target.mim_ic = null;
3350 Xex.Log ('creating IC');
3351 ic = new MIM.IC (MIM.current, target);
3352 if (ic.im.load_status != MIM.LoadStatus.Loaded)
3355 MIM.add_event_listener (target, 'focus', MIM.focus_in);
3356 MIM.add_event_listener (target, 'blur', MIM.focus_out);
3357 MIM.get_range (target, ic)
3361 if (! MIM.get_range (target, ic))
3364 MIM.debug_print (event, ic);
3365 ic.key = MIM.decode_key_event (event);
3369 var result = ic.Filter (ic.key);
3371 Xex.Log ('Error' + e);
3374 MIM.update (target, ic);
3375 if (! ic.key_unhandled)
3376 event.preventDefault ();
3380 MIM.keypress = function (event)
3382 var target = event.target;
3383 if (target.id == 'log')
3385 if (! (target.type == "text" || target.type == "textarea"))
3388 var ic = target.mim_ic;
3392 if (ic.im.load_status != MIM.LoadStatus.Loaded)
3395 ic.key = MIM.decode_key_event (event);
3403 var result = ic.Filter (ic.key);
3405 Xex.Log ('Error:' + e);
3408 MIM.update (target, ic);
3409 if (! ic.key_unhandled)
3410 event.preventDefault ();
3412 Xex.Log ("error:" + e);
3413 event.preventDefault ();
3415 MIM.debug_print (event, ic);
3422 var lang_category = {
3424 cs: { name: 'Czech' },
3425 da: { name: 'Danish' },
3426 el: { name: 'Greek' },
3427 en: { name: 'English' },
3428 eo: { name: 'Esperanto' },
3429 fr: { name: 'French' },
3430 grc: { name: 'ClassicGreek' },
3431 hr: { name: 'Croatian' },
3432 hy: { name: 'Armenian' },
3433 ka: { name: 'Georgian' },
3434 kk: { name: 'Kazakh' },
3435 ru: { name: 'Russian' },
3436 sk: { name: 'Slovak' },
3437 sr: { name: 'Serbian' },
3438 sv: { name: 'Swedish' },
3439 yi: { name: 'Yiddish' } },
3441 ar: { name: 'Arabic' },
3442 dv: { name: 'Divehi' },
3443 fa: { name: 'Persian' },
3444 he: { name: 'Hebrew' },
3445 kk: { name: 'Kazakh' },
3446 ps: { name: 'Pushto' },
3447 ug: { name: 'Uighur' },
3448 yi: { name: 'Yiddish' } },
3450 as: { name: 'Assamese' },
3451 bn: { name: 'Bengali' },
3452 bo: { name: 'Tibetan' },
3453 gu: { name: 'Gujarati' },
3454 hi: { name: 'Hindi' },
3455 kn: { name: 'Kannada' },
3456 ks: { name: 'Kashmiri' },
3457 ml: { name: 'Malayalam' },
3458 mr: { name: 'Marathi' },
3459 ne: { name: 'Nepali' },
3460 or: { name: 'Oriya' },
3461 pa: { name: 'Panjabi' },
3462 sa: { name: 'Sanskirit' },
3463 sd: { name: 'Sindhi' },
3464 si: { name: 'Sinhalese' },
3465 ta: { name: 'Tamil' },
3466 te: { name: 'Telugu' },
3467 ur: { name: 'Urdu' } },
3469 cmc: { name: 'Cham' },
3470 km: { name: 'Khmer'},
3471 lo: { name: 'Lao' },
3472 my: { name: 'Burmese' },
3473 tai: { name: 'Tai Viet' },
3474 th: { name: 'Thai' },
3475 vi: { name: 'Vietanamese' } },
3477 ii: { name: 'Yii' },
3478 ja: { name: 'Japanese' },
3479 ko: { name: 'Korean' },
3480 zh: { name: 'Chinese' } },
3482 am: { name: 'Amharic' },
3483 ath: { name: 'Carrier' },
3484 bla: { name: 'Blackfoot' },
3485 cr: { name: 'Cree' },
3486 eo: { name: 'Esperanto' },
3487 iu: { name: 'Inuktitut' },
3488 nsk: { name: 'Naskapi' },
3489 oj: { name: 'Ojibwe' },
3490 t: { name: 'Generic' } }
3493 function categorize_im ()
3495 var cat, lang, list, name;
3496 for (lang in MIM.imlist)
3499 for (cat in lang_category)
3500 if (lang_category[cat][lang])
3502 list = lang_category[cat][lang].list;
3504 list = lang_category[cat][lang].list = {};
3505 for (name in MIM.imlist[lang])
3506 list[name] = MIM.imlist[lang][name];
3509 for (name in MIM.imlist[lang])
3510 Xex.Log ('no category ' + lang + '-' + name);
3519 clearTimeout (destroy_timer);
3520 destroy_timer = null;
3521 var target = document.getElementById ('mim-menu');
3524 for (; last_target && last_target.menu_level;
3525 last_target = last_target.parentLi)
3526 last_target.style.backgroundColor = 'white';
3527 var nodes = target.getElementsByTagName ('ul');
3528 for (var i = 0; i < nodes.length; i++)
3529 nodes[i].style.visibility = 'hidden';
3530 document.getElementsByTagName ('body')[0].removeChild (target);
3534 function destroy_menu () {
3535 if (! destroy_timer)
3536 destroy_timer = setTimeout (destroy, 1000);
3539 function show_submenu (event)
3543 clearTimeout (destroy_timer);
3544 destroy_timer = null;
3546 var target = event.target;
3547 if (! target.menu_level)
3549 if (last_target && target.parentLi != last_target)
3551 last_target.style.backgroundColor = 'white';
3552 if (target.menu_level < last_target.menu_level)
3554 last_target = last_target.parentLi;
3555 last_target.style.backgroundColor = 'white';
3557 var uls = last_target.getElementsByTagName ('ul');
3558 for (var i = 0; i < uls.length; i++)
3559 uls[i].style.visibility = 'hidden';
3561 last_target = target;
3562 target.style.backgroundColor = 'yellow';
3563 if (target.menu_level < 3)
3565 target.lastChild.style.visibility = 'visible';
3566 target.lastChild.style.left = target.clientWidth + 'px';
3568 event.preventDefault ();
3571 function select_im (event)
3573 var target = event.target;
3576 MIM.current = target.im;
3579 event.preventDefault ();
3582 function create_ul (visibility)
3584 var ul = document.createElement ('ul');
3585 ul.style.position = 'absolute';
3586 ul.style.margin = '0px';
3587 ul.style.padding = '0px';
3588 ul.style.border = '1px solid gray';
3589 ul.style.borderBottom = 'none';
3590 ul.style.top = '-1px';
3591 ul.style.backgroundColor = 'white';
3592 ul.style.visibility = visibility;
3596 function create_li (level, text)
3598 var li = document.createElement ('li');
3599 li.style.position = 'relative';
3600 li.style.margin = '0px';
3601 li.style.padding = '1px';
3602 li.style.borderBottom = '1px solid gray';
3603 li.style.top = '0px';
3604 li.style.listStyle = 'none';
3605 li.menu_level = level;
3606 var nobr = document.createElement ('nobr');
3607 nobr.innerHTML = text;
3608 li.appendChild (nobr);
3614 function create_menu (event)
3616 var target = event.target;
3618 if (! ((target.type == "text" || target.type == "textarea")
3619 && event.which == 1 && event.ctrlKey))
3624 menu = create_ul ('visible');
3625 menu.style.fontFamily = 'sans-serif';
3626 menu.style.fontWeight = 'bold';
3627 menu.id = 'mim-menu';
3628 menu.onclick = select_im;
3629 menu.onmouseover = show_submenu;
3630 menu.onmouseout = destroy_menu;
3631 for (var catname in lang_category)
3633 var cat = lang_category[catname];
3634 var li = create_li (1, catname);
3635 var sub = create_ul ('hidden');
3636 for (var langname in cat)
3638 var lang = cat[langname];
3641 var sub_li = create_li (2, lang.name);
3642 sub_li.parentLi = li;
3643 var subsub = create_ul ('hidden');
3644 for (var name in lang.list)
3646 var im = lang.list[name];
3647 var subsub_li = create_li (3, im.name);
3648 subsub_li.parentLi = sub_li;
3650 subsub.appendChild (subsub_li);
3652 sub_li.appendChild (subsub);
3653 sub.appendChild (sub_li);
3655 li.appendChild (sub);
3656 menu.appendChild (li);
3658 lang_category = null;
3660 menu.style.left = (event.clientX - 10) + "px";
3661 menu.style.top = (event.clientY - 10) + "px";
3662 document.getElementsByTagName ('body')[0].appendChild (menu);
3665 MIM.init = function ()
3667 MIM.add_event_listener (window, 'keydown', MIM.keydown);
3668 MIM.add_event_listener (window, 'keypress', MIM.keypress);
3669 MIM.add_event_listener (window, 'mousedown', create_menu);
3670 if (window.location == 'http://localhost/mim/index.html')
3671 MIM.server = 'http://localhost/mim';
3672 MIM.current = MIM.imlist['zh']['py-gb'];
3676 MIM.test = function ()
3678 var im = MIM.imlist['t']['latn-post'];
3679 var ic = new MIM.IC (im, null);
3681 ic.Filter (new MIM.Key ('a'));
3682 ic.Filter (new MIM.Key ("'"));
3685 document.getElementById ('text').value = ic.produced + ic.preedit;
3688 document.getElementById ('text').value
3689 = Xex.Term.Parse (domain, body).Eval (domain).toString ();
3691 if (e instanceof Xex.ErrTerm)
3699 MIM.init_debug = function ()
3702 Xex.LogNode = document.getElementById ('log');