*** empty log message ***
[m17n/m17n-lib-js.git] / xex.js
1 // -* coding: utf-8; -*
2
3 var Xex = {};
4
5 Xex.Error = {
6   UnknownError: "unknown-error",
7   WrongArgument: "wrong-argument",
8   // Load time errors.
9   InvalidInteger: "invalid-integer",
10   TermTypeInvalid: "term-type-invalid",
11   FunctionConflict: "function-conflict",
12   VariableTypeConflict: "variable-type-conflict",
13   VariableRangeConflict: "variable-range-conflict",
14   VariableWrongRange: "variable-wrong-range",
15   VariableWrongValue: "variable-wrong-value",
16
17   UnknownFunction: "unknown-function",
18   MacroExpansionError: "macro-expansion-error",
19   NoVariableName: "no-variable-name",
20   NoFunctionName: "no-funcion-name",
21
22   // Run time errors.
23   ArithmeticError: "arithmetic-error",
24   WrongType: "wrong-type",
25   IndexOutOfRange: "index-out-of-range",
26   ValueOutOfRange: "value-out-of-range",
27   NoLoopToBreak: "no-loop-to-break",
28   UncaughtThrow: "uncaught-throw"
29 };
30
31 Xex.Variable = function (domain, name, desc, val, range)
32 {
33   this.domain = domain;
34   this.name = name;
35   this.desc = desc;
36   this.val = val;
37   this.range = range;
38 }
39
40 Xex.Variable.prototype.clone = function ()
41 {
42   return new Xex.Variable (this.domain, this.name, this.desc,
43                            this.val, this.range);
44 }
45     
46 Xex.Variable.prototype.Equals = function (obj)
47 {
48   return ((obj instanceof Xex.Variable)
49           && obj.name == this.name);
50 }
51
52 Xex.Variable.prototype.SetValue = function (term)
53 {
54   this.val = term;
55   return term;
56 }
57
58 Xex.Function = function (name, with_var, min_args, max_args)
59 {
60   this.name = name;
61   this.with_var = with_var;
62   this.min_args = min_args;
63   this.max_args = max_args;
64 };  
65
66 Xex.Subrountine = function (builtin, name, with_var, min_args, max_args)
67 {
68   this.name = name;
69   this.with_var = with_var;
70   this.min_args = min_args;
71   this.max_args = max_args;
72   this.builtin = builtin;
73 }
74
75 Xex.Subrountine.prototype.Call = function (domain, vari, args)
76 {
77   newargs = new Array ();
78   for (var i = 0; i < args.length; i++)
79     {
80       newargs[i] = args[i].Eval (domain);
81       if (domain.Thrown ())
82         return newargs[i];
83     }
84   return this.builtin (domain, vari, newargs)
85 }
86
87 Xex.SpecialForm = function (builtin, name, with_var, min_args, max_args)
88 {
89   this.name = name;
90   this.with_var = with_var;
91   this.min_args = min_args;
92   this.max_args = max_args;
93   this.builtin = builtin;
94 }
95
96 Xex.SpecialForm.prototype.Call = function (domain, vari, args)
97 {
98   return this.builtin (domain, vari, args)
99 }
100
101 Xex.Lambda = function (name, min_args, max_args, args, body)
102 {
103   this.name = name;
104   this.min_args = min_args;
105   this.max_args = max_args;
106   this.args = args;
107   this.body = body;
108 }
109
110 Xex.Lambda.prototype.Call = function (domain, vari, args)
111 {
112   var current = domain.bindings;
113   var result = Xex.Zero;
114   var limit = max_args >= 0 ? args.length : args.length - 1;
115   var i;
116   
117   try {
118     for (i = 0; i < limit; i++)
119       {
120         result = args[i].Eval (domain);
121         if (domain.Thrown ())
122           return result;
123         domain.Bind (this.args[i], result);
124       }
125     if (max_args < 0)
126       {
127         var list = new Array ();
128         for (i = 0; i < args[limit].length; i++)
129           {
130             result = args[limit].Eval (domain);
131             if (domain.Thrown ())
132               return result;
133             list[i] = result;
134           }
135         domain.Bind (this.args[limit], list);
136       }
137     try {
138       domain.Catch (Xex.CatchTag.Return);
139       for (var term in this.body)
140         {
141           result = term.Eval (domain);
142           if (domain.Thrown ())
143             return result;
144         }
145     } finally {
146       domain.Uncatch ();
147     }
148   } finally {
149     domain.UnboundTo (current);
150   }
151   return result;
152 }
153
154 Xex.Macro = function (name, min_args, max_args, args, body)
155 {
156   this.name = name;
157   this.min_args = min_args;
158   this.max_args = max_args;
159   this.args = args;
160   this.body = body;
161 }
162
163 Xex.Macro.prototype.Call = function (domain, vari, args)
164 {
165   var current = domain.bindings;
166   var result = Xex.Zero;
167   var i;
168
169   try {
170     for (i = 0; i < args.length; i++)
171       domain.Bind (this.args[i], args[i]);
172     try {
173       domain.Catch (Xex.CatchTag.Return);
174       for (var term in body)
175         {
176           result = term.Eval (domain);
177           if (domain.Thrown ())
178             break;
179         }
180     } finally {
181       domain.Uncatch ();
182     }
183   } finally {
184     domain.UnboundTo (current);
185   }
186   return result;
187 }
188
189 Xex.Bindings = function (vari)
190 {
191   this.vari = vari;
192   this.old_value = vari.val;
193 }
194
195 Xex.Bindings.prototype.UnboundTo = function (boundary)
196 {
197   for (var b = this; b != boundary; b = b.next)
198     b.vari.val = b.old_value;
199   return boundary;
200 }
201
202 Xex.Bind = function (bindings, vari, val)
203 {
204   var b = new Xex.Bindings (vari);
205   b.vari.val = val;
206   b.next = bindings;
207   return b;
208 }
209
210 Xex.CatchTag = {
211   Return: 0,
212   Break: 1
213 }
214
215 Xex.Domain = function (name, parent, context)
216 {
217   this.name = name;
218   this.context = context;
219   this.depth = 0;
220
221   if (name != 'basic' && ! parent)
222     parent = Xex.BasicDomain
223   this.parent = parent;
224   this.termtypes = {};
225   this.functions = {};
226   this.variables = {};
227   if (parent)
228     {
229       var elt;
230       for (elt in parent.termtypes)
231         this.termtypes[elt] = parent.termtypes[elt];
232       for (elt in parent.functions)
233         this.functions[elt] = parent.functions[elt];
234       for (elt in parent.variables)
235         this.variables[elt] = parent.variables[elt];
236     }
237
238   this.call_stack = new Array ();
239   this.bindings = null;
240   this.catch_stack = new Array ();
241   this.catch_count = 0;
242   this.caught = false;
243 };
244
245 Xex.Domain.prototype = {
246   CallStackCount: function () { return this.call_stack.length; },
247   CallStackPush: function (term) { this.call_stack.push (term); },
248   CallStackPop: function () { this.call_stack.pop (); },
249   Bind: function (vari, val)
250   {
251     this.bindings = Xex.Bind (this.bindings, vari, val);
252   },
253   UnboundTo: function (boundary)
254   {
255     if (this.bindings)
256       this.bindings = this.bindings.UnboundTo (boundary);
257   },
258   Catch: function (tag) { this.catch_stack.push (tag); this.catch_count++; },
259   Uncatch: function ()
260   {
261     this.catch_stack.pop ();
262     if (this.catch_count > this.catch_stack.length)
263       this.catch_count--;
264   },
265   Thrown: function ()
266   {
267     if (this.catch_count < this.catch_stack.length)
268       {
269         this.caught = (this.catch_count == this.catch_stack.length - 1);
270         return true;
271       }
272     this.caught = false;
273     return false;
274   },
275   ThrowReturn: function ()
276   {
277     for (var i = this.catch_stack.length - 1; i >= 0; i--)
278       {
279         this.catch_count--;
280         if (this.catch_stack[i] == Xex.CatchTag.Return)
281           break;
282       }
283   },
284   ThrowBreak: function ()
285   {
286     if (this.catch_stack[this.catch_stack.length - 1] != Xex.CatchTag.Break)
287       throw new Xex.ErrTerm (Xex.Error.NoLoopToBreak,
288                            "No surrounding loop to break");
289     this.catch_count--;
290   },
291   ThrowSymbol: function (tag)
292   {
293     var i = this.catch_count;
294     for (var j = this.catch_stack.length - 1; j >= 0; j--)
295       {
296         i--;
297         if (Xex.CatchTag.Matches (this.catch_stack[i], tag))
298           {
299             this.catch_count = i;
300             return;
301           }
302       }
303     throw new Xex.ErrTerm (Xex.Error.UncaughtThrow,
304                          "No corresponding catch: " + tag);
305   },
306   DefType: function (obj)
307   {
308     var type = obj.type;
309     if (this.termtypes[type])
310       throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
311                            "Already defined: " + type);
312     if (this.functions[type])
313       throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
314                            "Already defined as a funciton or a macro: "
315                            + type);
316     this.termtypes[type] = obj.Parser;
317   },
318   DefSubr: function (builtin, name, with_var, min_args, max_args)
319   {
320     this.functions[name] = new Xex.Subrountine (builtin, name, with_var,
321                                                 min_args, max_args);
322   },
323   DefSpecial: function (builtin, name, with_var, min_args, max_args)
324   {
325     this.functions[name] = new Xex.SpecialForm (builtin, name, with_var,
326                                                 min_args, max_args);
327   },
328   Defun: function (name, min_args, max_args, args, body)
329   {
330     this.functions[name] =  new Xex.Lambda (name, min_args, max_args,
331                                             args, body);
332   },
333   DefunByFunc: function (func) { this.functions[func.name] = func; },
334   Defmacro: function (name, min_args, max_args, args, body)
335   {
336     this.functions[name] = new Xex.Macro (name, min_args, max_args,
337                                           args, body);
338   },
339   DefAlias: function (alias, fname)
340   {
341     var func = this.functions[fname];
342
343     if (! func)
344       throw new Xex.ErrTerm (Xex.Error.UnknownFunction, fname);
345     if (this.termtypes[alias])
346       throw new Xex.ErrTerm (Xex.Error.FunctionConflict,
347                            "Already defined as a term type: " + alias);
348     if (this.functions[alias])
349       throw new Xex.ErrTerm (Xex.Error.FunctionConflict,
350                            "Already defined as a function: " + alias);
351     this.functions[alias] = func;
352   },
353   Defvar: function (name, desc, val, range)
354   {
355     var vari = new Xex.Variable (name, desc, val, range);
356     this.variables[name] = vari;
357     return vari;
358   },
359   GetFunc: function (name)
360   {
361     var func = this.functions[name];
362     if (! func)
363       throw new Xex.ErrTerm (Xex.Error.UnknownFunction,
364                              "Unknown function: " + name);
365     return func;
366   },
367   CopyFunc: function (domain, name)
368   {
369     var func = this.functions[name];
370     domain.DefunByFunc (func);
371     return true;
372   },
373   CopyFuncAll: function (domain)
374   {
375     for (var elt in this.functions)
376       domain.DefunByFunc (this.functions[elt]);
377   },
378   GetVarCreate: function (name)
379   {
380     var vari = this.variables[name];
381     if (! vari)
382       vari = this.variables[name] = new Xex.Variable (this, name, null,
383                                                       Xex.Zero, null);
384     return vari;
385   },
386   GetVar: function (name) { return this.variables[name]; },
387   SaveValues: function ()
388   {
389     values = {};
390     for (var elt in this.variables)
391       {
392         if (! this.variables[elt].val)
393           alert ('unknown value of ' + elt);
394         else
395           values[elt] = this.variables[elt].val.Clone ();
396       }
397     return values;
398   },
399   RestoreValues: function (values)
400   {
401     var name;
402     for (name in values)
403       {
404         var vari = this.variables[name];
405         vari.val = values[name];
406       }
407   }
408 };
409
410 Xex.Term = function (type) { this.type = type; }
411 Xex.Term.prototype = {
412   IsTrue: function () { return true; },
413   Eval: function (domain) { return this.Clone (); },
414   Clone: function (domain) { return this; },
415   Equals: function (obj)
416   {
417     return (this.type == obj.type
418             && this.val
419             && obj.val == this.val);
420   },
421   Matches: function (obj) { return this.Equals (obj); },
422   toString: function ()
423   {
424     if (this.val != undefined)
425       return '<' + this.type + '>' + this.val + '</' + this.type + '>';
426     return '<' + this.type + '/>';
427   },
428   Intval: function () { throw new Xex.ErrTerm (Xex.Error.WrongType,
429                                                "Not an integer"); },
430   Strval: function () { throw new Xex.ErrTerm (Xex.Error.WrongType,
431                                                "Not a string"); }
432 };
433
434 Node.prototype.firstElement = function ()
435 {
436   for (var n = this.firstChild; n; n = n.nextSibling)
437     if (n.nodeType == 1)
438       return n;
439   return null;
440 }
441
442 Node.prototype.nextElement = function ()
443 {
444   for (var n = this.nextSibling; n; n = n.nextSibling)
445     if (n.nodeType == 1)
446       return n;
447   return null;
448 };
449
450 (function () {
451   function parse_defvar (domain, node)
452   {
453     var name = node.attributes['vname'].nodeValue;
454     if (! name)
455       throw new Xex.ErrTerm (Xex.Error.NoVariableName, node, '');
456     var vari = domain.variables['name'];
457     var desc, val, range;
458     if (vari)
459       {
460         desc = vari.description;
461         val = vari.val;
462         range = vari.range;
463       }
464     node = node.firstElement ();
465     if (node && node.nodeName == 'description')
466       {
467         desc = node.firstChild.nodeValue;
468         node = node.nextElement ();
469       }
470     if (node)
471       {
472         val = Xex.Term.Parse (domain, node);
473         node = node.nextElement ();
474         if (node && node.nodeName == 'possible-values')
475           for (node = node.firstElement (); node; node = node.nextElement ())
476             {
477               var pval;
478               if (node.nodeName == 'range')
479                 {
480                   if (! val.IsInt)
481                     throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
482                                            'Range not allowed for ' + name);
483                   pval = new Array ();
484                   for (var n = node.firstElement (); n; n = n.nextElement ())
485                     {
486                       var v = Xex.Term.Parse (domain, n);
487                       if (! v.IsInt)
488                         throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
489                                                'Invalid range value: ' + val);
490                       pval.push (v);
491                     }
492                   }
493               else
494                 {
495                   pval = Xex.Term.Parse (domain, node);
496                   if (val.type != pval.type)
497                     throw new Xex.ErrTerm (Xex.Error.TermTypeInvalid,
498                                            'Invalid possible value: ' + pval);
499                 }
500               if (! range)
501                 range = new Array ();
502               range.push (pval);
503           }
504       }
505     if (! val)
506       val = Xex.Zero;
507     domain.Defvar (name, desc, val, range);
508     return name;
509   }
510
511   function parse_defun_head (domain, node)
512   {
513     var name = node.attributes['fname'].nodeValue;
514     if (! name)
515       throw new Xex.ErrTerm (Xex.Error.NoFunctionName, node, '');
516     var args = new Array ();
517     var nfixed = 0, noptional = 0, nrest = 0;
518
519     node = node.firstElement ();
520     if (node && node.nodeName == 'args')
521       {
522         var n;
523         for (n = n.firstElement (); n; n = n.nextElement ())
524           {
525             if (n.nodeName == 'fixed')
526               nfixed++;
527             else if (n.nodeName == 'optional')
528               noptional++;
529             else if (n.nodeName == 'rest')
530               nrest++;
531             else
532               throw new Xex.ErrTerm (Xex.Error.WrongType, n, n.nodeName);
533           }
534         if (nrest > 1)
535           throw new Xex.ErrTerm (Xex.Error.WrongType, n, 'Too many <rest>');
536         for (n = node.firstElement (); n; n = n.nextElement ())
537           args.push (domain.DefVar (n.attributes['vname'].nodeValue));
538       }
539     args.min_args = nfixed;
540     args.max_args = nrest == 0 ? nfixed + noptional : -1;
541
542     if (node.nodeName == 'defun')
543       domain.Defun (name, args, null);
544     else
545       domain.Defmacro (name, args, null);
546     return name;
547   }
548
549   function parse_defun_body (domain, node)
550   {
551     var name = node.attributes['fname'].nodeValue;
552     var func = domain.GetFunc (name);
553     var body;
554     for (node = node.firstElement (); node; node = node.nextElement ())
555       if (node.nodeName != 'description' && node.nodeName != 'args')
556         break;
557     body = Xex.Term.Parse (domain, node, null);
558     func.body = body;
559   }
560
561   Xex.Term.Parse = function (domain, node, stop)
562   {
563     if (arguments.length == 2)
564       {
565         var name = node.nodeName;
566         var parser = domain.termtypes[name];
567
568         if (parser)
569           return parser (domain, node);
570         if (name == 'defun' || name == 'defmacro')
571           {
572             name = parse_defun_head (domain, node);
573             MIM.log ('defmacro:' + name);
574             parse_defun_body (domain, node);
575             return new Xex.StrTerm (name);
576           }
577         if (name == 'defvar')
578           {
579             name = parse_defvar (domain, node);
580             MIM.log ('defvar:' + name);
581             return new Xex.StrTerm (name);
582           }
583         return new Xex.Funcall.prototype.Parser (domain, node);
584       }
585     for (var n = node; n && n != stop; n = n.nextElement ())
586       {
587         if (n.nodeName == 'defun' || n.nodeName == 'defmacro')
588           {
589             var name = parse_defun_head (domain, n);
590             MIM.log ('defmacro:' + name);
591           }
592       }
593     var terms = null;
594     for (var n = node; n && n != stop; n = n.nextElement ())
595       {
596         if (n.nodeName == 'defun' || n.nodeName == 'defmacro')
597           parse_defun_body (domain, n);
598         else if (n.nodeName == 'defvar')
599           parse_defvar (domain, n);
600         else
601           {
602             if (! terms)
603               terms = new Array ();
604             terms.push (Xex.Term.Parse (domain, n));
605           }
606       }
607     return terms;
608   }
609 }) ();
610
611 Xex.Varref = function (vname)
612 {
613   this.val = vname;
614 };
615
616 (function () {
617   var proto = new Xex.Term ('varref');
618
619   proto.Clone = function () { return new Xex.Varref (this.val); }
620   proto.Eval = function (domain)
621   {
622     if (! this.vari || this.vari.domain != domain)
623       this.vari = domain.GetVarCreate (this.val);
624     return this.vari.val;
625   }
626
627   proto.Parser = function (domain, node)
628   {
629     return new Xex.Varref (node.attributes['vname'].nodeValue);
630   }
631
632   Xex.Varref.prototype = proto;
633 }) ();
634
635 var null_args = new Array ();
636   
637 Xex.Funcall = function (func, vari, args)
638 {
639   this.func = func;
640   this.vari = vari;
641   this.args = args || null_args;
642 };
643
644 (function () {
645   var proto = new Xex.Term ('funcall');
646
647   proto.Parser = function (domain, node)
648   {
649     var fname = node.nodeName;
650     var attr;
651
652     if (fname == 'funcall')
653       fname = node.attributes['fname'].nodeValue;
654     var func = domain.GetFunc (fname);
655     var vari;
656     attr = node.attributes['vname'];
657     vari = attr != undefined ? domain.GetVarCreate (attr.nodeValue) : false;
658     var args = Xex.Term.Parse (domain, node.firstElement (), null);
659     return new Xex.Funcall (func, vari, args);
660   }
661
662   proto.New = function (domain, fname, vname, args)
663   {
664     var func = domain.GetFunc (fname);
665     var vari = vname ? domain.GetVarCreate (vname) : null;
666     var funcall = new Xex.Funcall (func, vari, args);
667     if (func instanceof Xex.Macro)
668       funcall = funcall.Eval (domain);
669     return funcall;
670   }
671
672   proto.Eval = function (domain)
673   {
674     return this.func.Call (domain, this.vari, this.args);
675   }
676
677   proto.Clone = function ()
678   {
679     return new Xex.Funcall (this.func, this.vari, this.args);
680   }
681
682   proto.Equals = function (obj)
683   {
684     return (obj.type == 'funcall'
685             && obj.func == this.func
686             && obj.vari.Equals (this.vari)
687             && obj.args.length == this.func.length);
688   }
689
690   proto.toString = function ()
691   {
692     var arglist = ''
693     var len = this.args.length;
694     if (len == 0)
695       return '<' + this.func.name + '/>';
696     for (var i = 0; i < len; i++)
697       arglist += this.args[i].toString ();
698     return '<' + this.func.name + '>' + arglist + '</' + this.func.name + '>';
699   }
700
701   Xex.Funcall.prototype = proto;
702 }) ();
703
704 Xex.ErrTerm = function (ename, message, stack)
705 {
706   this.ename = ename;
707   this.message = message;
708   this.stack = stack;
709 };
710
711 (function () {
712   var proto = new Xex.Term ('error');
713
714   proto.IsError = true;
715
716   proto.Parser = function (domain, node)
717   {
718     return new Xex.ErrTerm (node.attributes['ename'].nodeValue,
719                             node.innerText, false);
720   }
721
722   proto.CallStack = function () { return stack; }
723
724   proto.SetCallStack = function (value) { statck = value; }
725
726   proto.Clone = function ()
727   {
728     return new Xex.ErrTerm (ename, message, false);
729   }
730
731   proto.Equals = function (obj)
732   {
733     return (obj.IsError
734             && obj.ename == ename && obj.message == message
735             && (obj.stack ? (stack && stack.length == obj.stack.length)
736                 : ! stack));
737   }
738
739   proto.Matches = function (obj)
740   {
741     return (obj.IsError && obj.ename == ename);
742   }
743
744   proto.toString = function ()
745   {
746     return '<error ename="' + this.ename + '">' + this.message + '</error>';
747   }
748
749   Xex.ErrTerm.prototype = proto;
750 }) ();
751
752 Xex.IntTerm = function (num) { this.val = num; };
753 (function () {
754   var proto = new Xex.Term ('integer');
755   proto.IsInt = true;
756   proto.Intval = function () { return this.val; };
757   proto.IsTrue = function () { return this.val != 0; }
758   proto.Clone = function () { return new Xex.IntTerm (this.val); }
759   proto.Parser = function (domain, node)
760   {
761     var str = node.firstChild.nodeValue;
762
763     if (str.charAt (0) == '?' && str.length == 2)
764       return new Xex.IntTerm (str.charCodeAt (1));
765     return new Xex.IntTerm (parseInt (node.firstChild.nodeValue));
766   }
767   Xex.IntTerm.prototype = proto;
768 }) ();
769
770 Xex.StrTerm = function (str) { this.val = str; };
771 (function () {
772   var proto = new Xex.Term ('string');
773   proto.IsStr = true;
774   proto.Strval = function () { return this.val; };
775   proto.IsTrue = function () { return this.val.length > 0; }
776   proto.Clone = function () { return new Xex.StrTerm (this.val); }
777   proto.Parser = function (domain, node)
778   {
779     return new Xex.StrTerm (node.firstChild.nodeValue);
780   }
781   Xex.StrTerm.prototype = proto;
782 }) ();
783
784 Xex.SymTerm = function (str) { this.val = str; };
785 (function () {
786   var proto = new Xex.Term ('symbol');
787   proto.IsSymbol = true;
788   proto.IsTrue = function () { return this.val != 'nil'; }
789   proto.Clone = function () { return new Xex.SymTerm (this.val); }
790   proto.Parser = function (domain, node)
791   {
792     return new Xex.SymTerm (node.firstChild.nodeValue);
793   }
794   Xex.SymTerm.prototype = proto;
795 }) ();
796
797 Xex.LstTerm = function (list) { this.val = list; };
798 (function () {
799   var proto = new Xex.Term ('list');
800   proto.IsList = true;
801   proto.IsTrue = function () { return this.val.length > 0; }
802   proto.Clone = function () { return new Xex.LstTerm (this.val.slice (0)); }
803
804   proto.Equals = function (obj)
805   {
806     if (obj.type != 'list' || obj.val.length != this.val.length)
807       return false;
808     var i, len = this.val.length;
809     for (i = 0; i < len; i++)
810       if (! this.val[i].Equals (obj.val[i]))
811         return false;
812     return true;
813   }
814
815   proto.Parser = function (domain, node)
816   {
817     var list = Xex.Term.Parse (domain, node.firstElement (), null);
818     return new Xex.LstTerm (list);
819   }
820
821   proto.toString = function ()
822   {
823     var len = this.val.length;
824
825     if (len == 0)
826       return '<list/>';
827     var str = '<list>';
828     for (var i = 0; i < len; i++)
829       str += this.val[i].toString ();
830     return str + '</list>';
831   }
832   Xex.LstTerm.prototype = proto;
833 }) ();
834
835 (function () {
836   var basic = new Xex.Domain ('basic', null, null);
837
838   function Fset (domain, vari, args)
839   {
840     return vari.SetValue (args[0]);
841   }
842
843   function maybe_set_intvar (vari, n)
844   {
845     var term = new Xex.IntTerm (n);
846     if (vari != null)
847       vari.SetValue (term);
848     return term;
849   }
850
851   function Fset (domain, vari, args)
852   {
853     if (! vari)
854       throw new Xex.ErrTerm (Xex.Error.NoVariableName,
855                              'No variable name to set');
856     vari.SetValue (args[0]);
857     return args[0];
858   }
859
860   function maybe_set_intvar (vari, n)
861   {
862     var term = new IntTerm (n);
863     if (vari)
864       vari.SetValue (term);
865     return term;
866   }
867
868   function Fadd (domain, vari, args)
869   {
870     var n = vari ? vari.val.Intval () : 0;
871     var len = args.length;
872
873     for (var i = 0; i < len; i++)
874       n += args[i].Intval ();
875     return maybe_set_intvar (vari, n);
876   }
877
878   function Fmul (domain, vari, args)
879   {
880     var n = vari ? vari.val.Intval () : 1;
881     for (var i = 0; i < args.length; i++)
882       n *= arg.Intval ();
883     return maybe_set_intvar (vari, n);
884   }
885
886   function Fsub (domain, vari, args)
887   {
888     var n, i;
889
890     if (! vari)
891       {
892         n = args[0].Intval ();
893         i = 1;
894       }
895     else
896       {
897         n = vari.val.Intval ();
898         i = 0;
899       }
900     while (i < args.length)
901       n -= args[i++].Intval ();
902     return maybe_set_intvar (vari, n);
903   }
904
905   function Fdiv (domain, vari, args)
906   {
907     var n, i;
908
909     if (! vari == null)
910       {
911         n = args[0].Intval ();
912         i = 1;
913       }
914     else
915       {
916         n = vari.val.Intval ();
917         i = 0;
918       }
919     while (i < args.length)
920       n /= args[i++].Intval ();
921     return maybe_set_intvar (vari, n);
922   }
923
924   function Fmod (domain, vari, args)
925   {
926     return maybe_set_intvar (vari, args[0].Intval () % args[1].Intval ());
927   }
928
929   function Flogior (domain, vari, args)
930   {
931     var n = vari == null ? 0 : vari.val;
932     for (var i = 0; i < args.length; i++)
933       n |= args[i].val;
934     return maybe_set_intvar (vari, n);
935   }
936
937   function Fand (domain, vari, args)
938   {
939     var len = args.length;
940     for (var i = 0; i < len; i++)
941     {
942       var result = args[i].Eval (domain);
943       if (domain.Thrown ())
944         return result;
945       if (! result.IsTrue ())
946         return Xex.Zero;
947     }
948     return Xex.One;
949   }
950
951   function For (domain, vari, args)
952   {
953     var len = args.length;
954     for (var i = 0; i < len; i++)
955     {
956       var result = args[i].Eval (domain);
957       if (domain.Thrown ())
958         return result;
959       if (result.IsTrue ())
960         return Xex.One;
961     }
962     return Xex.Zero;
963   }
964
965   function Feq (domain, vari, args)
966   {
967     for (var i = 1; i < args.length; i++)
968       if (! args[i - 1].Equals (args[i]))
969         return Xex.Zero;
970     return Xex.One;
971   }
972
973   function Flt (domain, vari, args)
974   {
975     var n = args[0].Intval;
976
977     for (var i = 1; i < args.length; i++)
978       {
979         var n1 = args[i].Intval;
980         if (n >= n1)
981           return Xex.Zero;
982         n = n1;
983       }
984     return Xex.One;
985   }
986
987   function Fle (domain, vari, args)
988   {
989     var n = args[0].Intval;
990     for (var i = 1; i < args.length; i++)
991       {
992         var n1 = args[i].Intval;
993         if (n > n1)
994           return Xex.Zero;
995         n = n1;
996       }
997     return Xex.One;
998   }
999
1000   function Fgt (domain, vari, args)
1001   {
1002     var n = args[0].Intval;
1003     for (var i = 1; i < args.length; i++)
1004       {
1005         var n1 = args[i].Intval;
1006         if (n <= n1)
1007           return Xex.Zero;
1008         n = n1;
1009       }
1010     return Xex.One;
1011   }
1012
1013   function Fge (domain, vari, args)
1014   {
1015     var n = args[0].Intval;
1016     for (var i = 1; i < args.Length; i++)
1017       {
1018         var n1 = args[i].Intval;
1019         if (n < n1)
1020           return Xex.Zero;
1021         n = n1;
1022       }
1023     return Xex.One;
1024   }
1025
1026   function Fprogn (domain, vari, args)
1027   {
1028     var result = Xex.One;
1029     var len = args.length;
1030
1031     for (var i = 0; i < len; i++)
1032       {
1033         result = args[i].Eval (domain);
1034         if (domain.Thrown ())
1035           return result;
1036       }
1037     return result;
1038   }
1039
1040   function Fif (domain, vari, args)
1041   {
1042     var result = args[0].Eval (domain);
1043
1044     if (domain.Thrown ())
1045       return result;
1046     if (result.IsTrue ())
1047       return args[1].Eval (domain);
1048     if (args.length == 2)
1049       return Zero;
1050     return args[2].Eval (domain);
1051   }
1052
1053   function Fcond (domain, vari, args)
1054   {
1055     for (var i = 0; i < args.length; i++)
1056       {
1057         var list = args[i].val;
1058         var result = list.val[0].Eval (doamin);
1059         if (result.isTrue ())
1060           {
1061             for (var j = 1; j < list.val.length; j++)
1062               {
1063                 domain.depth++;
1064                 result = list.val[j].Eval (domain);
1065                 domain.depth--;
1066                 if (domain.Thrown ())
1067                   return result;
1068                 }
1069             return result;
1070           }
1071       }
1072     return Xex.Zero;
1073   }
1074
1075   function eval_terms (domain, terms, idx)
1076   {
1077     var result = Xex.Zero;
1078     domain.caught = false;
1079     for (var i = idx; i < terms.length; i++)
1080       {
1081         result = terms[i].Eval (domain);
1082         if (domain.Thrown ())
1083           return result;
1084       }
1085     return result;
1086   }
1087
1088   function Fcatch (domain, vari, args)
1089   {
1090     var caught = false;
1091     var result;
1092
1093     if (args[0].IsError)
1094       {
1095         try {
1096           result = eval_terms (domain, args, 1);
1097         } catch (e) {
1098           if (e instanceof Xex.ErrTerm)
1099             {
1100               if (! args[0].Matches (e))
1101                 throw e;
1102               if (vari)
1103                 vari.SetValue (e);
1104               return Xex.One;
1105             }
1106         }
1107       }
1108     else if (args[0].IsSymbol)
1109       {
1110         try {
1111           domain.Catch (args[0].val);
1112           result = eval_terms (domain, args, 1);
1113           if (domain.caught)
1114             {
1115               if (vari != null)
1116                 vari.SetValue (result);
1117               return Xex.One;
1118             }
1119           return Xex.Zero;
1120         } finally {
1121           domain.Uncatch ();
1122         }
1123       }
1124     throw new Xex.ErrTerm (Xex.Error.WrongArgument,
1125                            "Not a symbol nor an error: " + args[0]);
1126   }
1127
1128   function Fthrow (domain, vari, args)
1129   {
1130     if (args[0].IsSymbl)
1131       {
1132         domain.ThrowSymbol (args[0]);
1133         return (args[args.length - 1]);
1134       }
1135     if (args[0].IsError)
1136       {
1137         throw args[0];
1138       }
1139     throw new Xex.ErrTerm (Xex.Error.WrongArgument,
1140                            "Not a symbol nor an error:" + args[0]);
1141   }
1142
1143   Xex.BasicDomain = basic;
1144
1145   basic.DefSubr (Fset, "set", true, 1, 1);
1146   if (basic.functions['='])
1147     alert (basic.functions['=']);
1148   basic.DefAlias ("=", "set");
1149   //basic.DefSubr (Fnot, "not", false, 1, 1);
1150   //basic.DefAlias ("!", "not");
1151   basic.DefSubr (Fadd, "add", true, 1, -1);
1152   basic.DefSubr (Fmul, "mul", true, 1, -1);
1153   basic.DefAlias ("*", "mul");
1154   basic.DefSubr (Fsub, "sub", true, 1, -1);
1155   basic.DefAlias ("-", "sub");
1156   basic.DefSubr (Fdiv, "div", true, 1, -1);
1157   basic.DefAlias ("/", "div");
1158   basic.DefSubr (Fmod, "mod", true, 1, 2);
1159   basic.DefAlias ("%", "mod");
1160   basic.DefSubr (Flogior, "logior", true, 1, -1);
1161   basic.DefAlias ('|', "logior");
1162   //basic.DefSubr (Flogand, "logand", true, 1, -1);
1163   //basic.DefAlias ("&", "logand");
1164   //basic.DefSubr (Flsh, "lsh", true, 1, 2);
1165   //basic.DefAlias ("<<", "lsh");
1166   //basic.DefSubr (Frsh, "rsh", true, 1, 2);
1167   //basic.DefAlias (">>", "rsh");
1168   basic.DefSubr (Feq, "eq", false, 2, -1);
1169   basic.DefAlias ("==", "eq");
1170   //basic.DefSubr (Fnoteq, "noteq", false, 2, 2);
1171   //basic.DefAlias ("!=", "noteq");
1172   basic.DefSubr (Flt, "lt", false, 2, -1);
1173   basic.DefAlias ("<", "lt");
1174   basic.DefSubr (Fle, "le", false, 2, -1);
1175   basic.DefAlias ("<=", "le");
1176   basic.DefSubr (Fgt, "gt", false, 2, -1);
1177   basic.DefAlias (">", "gt");
1178   basic.DefSubr (Fge, "ge", false, 2, -1);
1179   basic.DefAlias (">=", "ge");
1180   basic.DefSubr (Fthrow, "throw", false, 1, 2);
1181
1182   //basic.DefSubr (Fappend, "append", true, 0, -1);
1183   //basic.DefSubr (Fconcat, "concat", true, 0, -1);
1184   //basic.DefSubr (Fnth, "nth", false, 2, 2);
1185   //basic.DefSubr (Fcopy, "copy", false, 1, 1);
1186   //basic.DefSubr (Fins, "ins", true, 2, 2);
1187   //basic.DefSubr (Fdel, "del", true, 2, 2);
1188   //basic.DefSubr (Feval, "eval", false, 1, 1);
1189   //basic.DefSubr (Fbreak, "break", false, 0, 1);
1190   //basic.DefSubr (Freturn, "return", false, 0, 1);
1191   //basic.DefSubr (Fthrow, "throw", false, 1, 2);
1192
1193   basic.DefSpecial (Fand, "and", false, 1, -1);
1194   basic.DefAlias ("&&", "and");
1195   basic.DefSpecial (For, "or", false, 1, -1);
1196   basic.DefAlias ("||", "or");
1197   basic.DefSpecial (Fprogn, "progn", false, 1, -1);
1198   basic.DefAlias ("expr", "progn");
1199   basic.DefSpecial (Fif, "if", false, 2, 3);
1200   //basic.DefSpecial (Fwhen, "when", false, 1, -1);
1201   //basic.DefSpecial (Floop, "loop", false, 1, -1);
1202   //basic.DefSpecial (Fwhile, "while", false, 1, -1);
1203   basic.DefSpecial (Fcond, "cond", false, 1, -1);
1204   //basic.DefSpecial (Fforeach, "foreach", true, 2, -1);
1205   //basic.DefSpecial (Fquote, "quote", false, 1, 1);
1206   //basic.DefSpecial (Ftype, "type", false, 1, 1);
1207   basic.DefSpecial (Fcatch, "catch", true, 2, -1);
1208
1209   basic.DefType (Xex.Funcall.prototype);
1210   basic.DefType (Xex.Varref.prototype);
1211   basic.DefType (Xex.ErrTerm.prototype);
1212   basic.DefType (Xex.IntTerm.prototype);
1213   basic.DefType (Xex.StrTerm.prototype);
1214   basic.DefType (Xex.SymTerm.prototype);
1215   basic.DefType (Xex.LstTerm.prototype);
1216
1217 }) ();
1218
1219 Xex.Zero = new Xex.IntTerm (0);
1220 Xex.One = new Xex.IntTerm (1);
1221 Xex.nil = new Xex.SymTerm ('nil');
1222
1223 Xex.Load = function (server, file)
1224 {
1225   var obj = new XMLHttpRequest ();
1226   var url = server ? server + '/' + file : file;
1227   obj.open ('GET', url, false);
1228   obj.overrideMimeType ('text/xml');
1229   obj.send ('');
1230   return obj.responseXML.firstChild;
1231 }
1232
1233 var MIM = {
1234   // URL of the input method server.
1235   server: "http://www.m17n.org/common/mim-js",
1236   // Boolean flag to tell if MIM is active or not.
1237   enabled: true,
1238   // Boolean flag to tell if MIM is running in debug mode or not.
1239   debug: false,
1240   // List of main input methods.
1241   imlist: {},
1242   // List of extra input methods;
1243   imextra: {},
1244   // Global input method data
1245   im_global: null,
1246   // Currently selected input method.
1247   current: false,
1248
1249   // enum
1250   LoadStatus: { NotLoaded:0, Loading:1, Loaded:2, Error:-1 },
1251   ChangedStatus: {
1252     None:       0x00,
1253     StateTitle: 0x01,
1254     PreeditText:0x02,
1255     CursorPos:  0x04,
1256     CandidateList:0x08,
1257     CandidateIndex:0x10,
1258     CandidateShow:0x20,
1259     Preedit:    0x06,           // PreeditText | CursorPos
1260     Candidate:  0x38 // CandidateList | CandidateIndex | CandidateShow
1261   },
1262   KeyModifier: {
1263     SL: 0x00400000,
1264     SR: 0x00800000,
1265     S:  0x00C00000,
1266     CL: 0x01000000,
1267     CR: 0x02000000,
1268     C:  0x03000000,
1269     AL: 0x04000000,
1270     AR: 0x08000000,
1271     A:  0x0C000000,
1272     ML: 0x04000000,
1273     MR: 0x08000000,
1274     M:  0x0C000000,
1275     G:  0x10000000,
1276     s:  0x20000000,
1277     H:  0x40000000,
1278     High:       0x70000000,
1279     All:        0x7FC00000
1280   },
1281   Error: {
1282     ParseError: "parse-error"
1283   }
1284 };
1285   
1286 (function () {
1287   var keysyms = new Array ();
1288   keysyms["bs"] = "backspace";
1289   keysyms["lf"] = "linefeed";
1290   keysyms["cr"] = keysyms["enter"] = "return";
1291   keysyms["esc"] = "escape";
1292   keysyms["spc"] = "space";
1293   keysyms["del"] = "delete";
1294
1295   function decode_keysym (str) {
1296     var parts = str.split ("-");
1297     var len = parts.length, i;
1298     var has_modifier = len > 1;
1299
1300     for (i = 0; i < len - 1; i++)
1301       if (! MIM.KeyModifier.hasOwnProperty (parts[i]))
1302         return false;
1303     var key = parts[len - 1];
1304     if (key.length > 1)
1305       {
1306         key = keysyms[key.toLowerCase ()];
1307         if (key)
1308           {
1309             if (len > 1)
1310               {
1311                 str = parts[0];
1312                 for (i = 1; i < len - 1; i++)
1313                   str += '-' + parts[i];
1314                 str += '-' + key;
1315               }
1316             else
1317               str = key;
1318           }
1319       }
1320     if (has_modifier)
1321       {
1322         parts = new Array ();
1323         parts.push (str);
1324         return parts;
1325       }
1326     return str;
1327   }
1328
1329   MIM.Key = function (val)
1330   {
1331     this.key;
1332     this.has_modifier = false;
1333     if (typeof val == 'string' || val instanceof String)
1334       {
1335         this.key = decode_keysym (val);
1336         if (! this.key)
1337           throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + val);
1338         if (this.key instanceof Array)
1339           {
1340             this.key = this.key[0];
1341             this.has_modifier = true;
1342           }
1343       }
1344     else if (typeof val == 'number' || val instanceof Number)
1345       this.key = String.fromCharCode (val);
1346     else
1347       throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + val);
1348   }
1349
1350   MIM.Key.prototype.toString = function () { return this.key; };
1351 }) ();
1352
1353 (function () {
1354   MIM.KeySeq = function (seq)
1355   {
1356     this.val = new Array ();
1357     this.has_modifier = false;
1358
1359     if (seq)
1360       {
1361         if (seq.IsList)
1362           {
1363             var len = seq.val.length;
1364             for (var i = 0; i < len; i++)
1365               {
1366                 var v = seq.val[i];
1367                 if (v.type != 'string' && v.type != 'integer'
1368                     && v.type != 'symbol')
1369                   throw new Xex.ErrTerm (MIM.Error.ParseError,
1370                                          "Invalid key: " + v);
1371                 var key = new MIM.Key (v.val);
1372                 this.val.push (key);
1373                 if (key.has_modifier)
1374                   this.has_modifier = true;
1375               }
1376           }
1377         else if (seq.IsStr)
1378           {
1379             var len = seq.val.length;
1380             for (var i = 0; i < len; i++)
1381               this.val.push (new MIM.Key (seq.val.charCodeAt (i)));
1382           }
1383         else
1384           throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid key: " + seq);
1385       }
1386   }
1387
1388   var proto = new Xex.Term ('keyseq');
1389   proto.Clone = function () { return this; }
1390   proto.Parser = function (domain, node)
1391   {
1392     var seq = new Array ();
1393     for (node = node.firstChild; node; node = node.nextSibling)
1394       if (node.nodeType == 1)
1395         {
1396           var term = Xex.Term.Parse (domain, node);
1397           return new MIM.KeySeq (term);
1398         }
1399     throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid keyseq");
1400   }
1401   proto.toString = function ()
1402   {
1403     var len = this.val.length;
1404     if (len == 0)
1405       return '<keyseq/>';
1406     var first = true;
1407     var str = '<keyseq>';
1408     for (var i = 0; i < len; i++)
1409       {
1410         if (first)
1411           first = false;
1412         else if (this.has_modifier)
1413           str += ' ';
1414         str += this.val[i].toString ();
1415       }
1416     return str + '</keyseq>';
1417   }
1418
1419   MIM.KeySeq.prototype = proto;
1420 }) ();
1421
1422 (function () {
1423   MIM.Marker = function () { }
1424   MIM.Marker.prototype = new Xex.Term ('marker');
1425   MIM.Marker.prototype.CharAt = function (ic)
1426   {
1427     var p = this.Position (ic);
1428     if (p < 0)
1429       return ic.GetSurroundingChar (p);
1430     else if (p >= ic.preedit.length)
1431       return ic.GetSurroundingChar (p - ic.preedit.length);
1432     return ic.preedit.charCodeAt (p);
1433   }
1434
1435   MIM.NamedMarker = function (name) { this.val = name; }
1436   MIM.NamedMarker.prototype = new MIM.Marker ();
1437   MIM.NamedMarker.prototype.Position = function (ic)
1438   {
1439     var p = ic.marker_positions[this.val];
1440     return (p == undefined ? 0 : p);
1441   }
1442   MIM.NamedMarker.prototype.Mark = function (ic)
1443   {
1444     ic.marker_positions[this.val] = ic.cursor_pos;
1445   }
1446
1447   MIM.PredefinedMarker = function (name) { this.val = name; }
1448   MIM.PredefinedMarker.prototype = new MIM.Marker ();
1449   MIM.PredefinedMarker.prototype.Position = function (ic)
1450   {
1451     if (typeof this.pos == 'number')
1452       return this.pos;
1453     return this.pos (ic);
1454   }
1455
1456   var predefined = { }
1457
1458   function def_predefined (name, position)
1459   {
1460     predefined[name] = new MIM.PredefinedMarker (name);
1461     predefined[name].pos = position;
1462   }
1463
1464   def_predefined ('@<', 0);
1465   def_predefined ('@>', function (ic) { return ic.preedit.length; });
1466   def_predefined ('@-', function (ic) { return ic.cursor_pos - 1; });
1467   def_predefined ('@+', function (ic) { return ic.cursor_pos + 1; });
1468   def_predefined ('@[', function (ic) {
1469     if (ic.cursor_pos > 0)
1470       {
1471         var pos = ic.cursor_pos;
1472         return ic.preedit.FindProp ('candidates', pos - 1).from;
1473       }
1474     return 0;
1475   });
1476   def_predefined ('@]', function (ic) {
1477     if (ic.cursor_pos < ic.preedit.length - 1)
1478       {
1479         var pos = ic.cursor_pos;
1480         return ic.preedit.FindProp ('candidates', pos).to;
1481       }
1482     return ic.preedit.length;
1483   });
1484   for (var i = 0; i < 10; i++)
1485     def_predefined ("@" + i, i);
1486   predefined['@first'] = predefined['@<'];
1487   predefined['@last'] = predefined['@>'];
1488   predefined['@previous'] = predefined['@-'];
1489   predefined['@next'] = predefined['@+'];
1490   predefined['@previous-candidate-change'] = predefined['@['];
1491   predefined['@next-candidate-change'] = predefined['@]'];
1492
1493   MIM.SurroundMarker = function (name)
1494   {
1495     this.val = name;
1496     this.distance = parseInt (name.slice (2));
1497     if (isNaN (this.distance))
1498       throw new Xex.ErrTerm (MIM.Error.ParseError, "Invalid marker: " + name);
1499   }
1500   MIM.SurroundMarker.prototype = new MIM.Marker ();
1501   MIM.SurroundMarker.prototype.Position = function (ic)
1502   {
1503     return ic.cursor_pos + this.distance;
1504   }
1505
1506   MIM.Marker.prototype.Parser = function (domain, node)
1507   {
1508     var name = node.firstChild.nodeValue;
1509     if (name.charAt (0) == '@')
1510       {
1511         var n = predefined[name];
1512         if (n)
1513           return n;
1514         if (name.charAt (1) == '-')
1515           return new MIM.SurroundMarker (name);
1516         throw new Xex.ErrTerm (MIM.Error.ParseError,
1517                                "Invalid marker: " + name);
1518       }
1519     return new MIM.NamedMarker (name);
1520   }
1521 }) ();
1522
1523 MIM.Selector = function (name)
1524 {
1525   this.val = name;
1526 }
1527 MIM.Selector.prototype = new Xex.Term ('selector');
1528
1529 (function () {
1530   var selectors = {};
1531   selectors["@<"] = selectors["@first"] = new MIM.Selector ('@<');
1532   selectors["@="] = selectors["@current"] = new MIM.Selector ('@=');
1533   selectors["@>"] = selectors["@last"] = new MIM.Selector ('@>');
1534   selectors["@-"] = selectors["@previous"] = new MIM.Selector ('@-');
1535   selectors["@+"] = selectors["@next"] = new MIM.Selector ('@+');
1536   selectors["@["] = selectors["@previous-candidate-change"]
1537     = new MIM.Selector ('@[');
1538   selectors["@]"] = selectors["@next-candidate-change"]
1539     = new MIM.Selector ('@]');
1540
1541   MIM.Selector.prototype.Parser = function (domain, node)
1542   {
1543     var name = node.firstChild.nodeValue;
1544     var s = selectors[name];
1545     if (! s)
1546       throw new Xex.ErrTerm (MIM.Error.ParseError,
1547                              "Invalid selector: " + name);
1548     return s;
1549   }
1550 }) ();
1551
1552 MIM.Rule = function (keyseq, actions)
1553 {
1554   this.keyseq = keyseq;
1555   this.actions = actions;
1556 }
1557 MIM.Rule.prototype = new Xex.Term ('rule');
1558 MIM.Rule.prototype.Parser = function (domain, node)
1559 {
1560   var n;
1561   for (n = node.firstChild; n && n.nodeType != 1; n = n.nextSibling);
1562   if (! n)
1563     throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid rule:" + node);
1564   var keyseq = Xex.Term.Parse (domain, n);
1565   if (keyseq.type != 'keyseq')
1566     throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid rule:" + node);
1567   var actions = Xex.Term.Parse (domain, n.nextElement (), null);
1568   return new MIM.Rule (keyseq, actions);
1569 }
1570 MIM.Rule.prototype.toString = function ()
1571 {
1572   return '<rule/>';
1573 }
1574
1575 MIM.Map = function (name)
1576 {
1577   this.name = name;
1578   this.rules = new Array ();
1579 };
1580
1581 (function () {
1582   var proto = new Xex.Term ('map');
1583
1584   proto.Parser = function (domain, node)
1585   {
1586     var name = node.attributes['mname'].nodeValue;
1587     if (! name)
1588       throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid map");
1589     var map = new MIM.Map (name);
1590     for (var n = node.firstChild; n; n = n.nextSibling)
1591       if (n.nodeType == 1)
1592         map.rules.push (Xex.Term.Parse (domain, n));
1593     return map;
1594   }
1595
1596   proto.toString = function ()
1597   {
1598     var str = '<map mname="' + this.name + '">';
1599     var len = this.rules.length;
1600     for (i = 0; i < len; i++)
1601       str += this.rules[i];
1602     return str + '</map>';
1603   }
1604
1605   MIM.Map.prototype = proto;
1606 }) ();
1607
1608 Xex.CatchTag._mimtag = new Xex.SymTerm ('@mimtag');
1609
1610 MIM.Action = function (domain, terms)
1611 {
1612   var args = new Array ();
1613   args.push (Xex.CatchTag_.mimtag);
1614   for (var i = 0; i < terms.length; i++)
1615     args.push (terms[i]);
1616   this.action = Xex.Funcall.prototype.New (domain, 'catch', null, args);
1617 }
1618
1619 MIM.Action.prototype.Run = function (domain)
1620 {
1621   var result = this.action.Eval (domain);
1622   if (result.type == 'error')
1623     {
1624       domain.context.Error = result.toString ();
1625       return false;
1626     }
1627   return (result != Xex.CatchTag._mimtag);
1628 }
1629
1630 MIM.Keymap = function ()
1631 {
1632   this.name = 'TOP';
1633   this.submaps = null;
1634   this.actions = null;
1635 };
1636
1637 (function () {
1638   var proto = {};
1639
1640   function add_rule (keymap, rule)
1641   {
1642     var keyseq = rule.keyseq;
1643     var len = keyseq.val.length;
1644     var name = '';
1645
1646     for (var i = 0; i < len; i++)
1647       {
1648         var key = keyseq.val[i];
1649         var sub = false;
1650
1651         name += key.key;
1652         if (! keymap.submaps)
1653           keymap.submaps = {};
1654         else
1655           sub = keymap.submaps[key.key];
1656         if (! sub)
1657           keymap.submaps[key.key] = sub = new MIM.Keymap ();
1658         keymap = sub;
1659         keymap.name = name;
1660       }
1661     keymap.actions = rule.actions;
1662   }
1663
1664   proto.Add = function (map)
1665   {
1666     var rules = map.rules;
1667     var len = rules.length;
1668
1669     for (var i = 0; i < len; i++)
1670       add_rule (this, rules[i]);
1671   }
1672   proto.Lookup = function (keys, index)
1673   {
1674     var sub;
1675
1676     if (index < keys.val.length && this.submaps
1677         && (sub = this.submaps[keys.val[index].key]))
1678       {
1679         index++;
1680         return sub.Lookup (keys, index);
1681       }
1682     return { map: this, index: index };
1683   }
1684
1685   MIM.Keymap.prototype = proto;
1686 }) ();
1687
1688 MIM.State = function (name)
1689 {
1690   this.name = name;
1691   this.keymap = new MIM.Keymap ();
1692 };
1693
1694 (function () {
1695   var proto = new Xex.Term ('state');
1696
1697   proto.Parser = function (domain, node)
1698   {
1699     var map_list = domain.map_list;
1700     var name = node.attributes['sname'].nodeValue;
1701     if (! name)
1702       throw new Xex.ErrTerm (MIM.Error.ParseError, "invalid map");
1703     var state = new MIM.State (name);
1704     for (node = node.firstElement (); node; node = node.nextElement ())
1705       {
1706         if (node.nodeName == 'title')
1707           state.title = node.firstChild.nodeValue;
1708         else
1709           {
1710             var n = node.firstElement ();
1711             if (node.nodeName == 'branch')
1712               {
1713                 state.keymap.Add (map_list[node.attributes['mname'].nodeValue]);
1714                 state.keymap.actions = Xex.Term.Parse (domain, n, null);
1715               }
1716             else if (node.nodeName == 'state-hook')
1717               state.enter_actions = Xex.Term.Parse (domain, n, null);
1718             else if (node.nodeName == 'catch-all-branch')
1719               state.fallback_actions = Xex.Term.Parse (domain, n, null);
1720           }
1721       }
1722     return state;
1723   }
1724
1725   proto.toString = function ()
1726   {
1727     return '<state sname="' + this.name + '">' + this.keymap + '</state>';
1728   }
1729
1730   MIM.State.prototype = proto;
1731 }) ();
1732
1733 MIM.im_domain = new Xex.Domain ('input-method', null, null);
1734 MIM.im_domain.DefType (MIM.KeySeq.prototype);
1735 MIM.im_domain.DefType (MIM.Marker.prototype);
1736 MIM.im_domain.DefType (MIM.Selector.prototype);
1737 MIM.im_domain.DefType (MIM.Rule.prototype);
1738 MIM.im_domain.DefType (MIM.Map.prototype);
1739 MIM.im_domain.DefType (MIM.State.prototype);
1740
1741 (function () {
1742   var im_domain = MIM.im_domain;
1743
1744   function Finsert (domain, vari, args)
1745   {
1746     var text;
1747     if (args[0].type == 'integer')
1748       text = String.fromCharCode (args[0].val);
1749     else
1750       text = args[0].val;
1751     domain.context.insert (text, null);
1752   }
1753
1754   function Finsert_candidates (domain, vari, args)
1755   {
1756     var ic = domain.context;
1757     var candidates = new Candidates (args, column);
1758     ic.insert (candidates.Current (), candidates);
1759     return args[0];
1760   }
1761
1762   function Fdelete (domain, vari, args)
1763   {
1764     var ic = domain.context;
1765     var pos = args[0].IsInt ? args[0].Intval : args[0].Position (ic);
1766     ic.del (pos);
1767     return new Xex.Term (ic.del (pos));
1768   }
1769
1770   function Fselect (domain, vari, args)
1771   {
1772     var ic = domain.context;
1773     var can = ic.candidates;
1774
1775     if (can)
1776       {
1777         var candidate = can.Current ();
1778
1779         ic.del (ic.cursor_pos - candidate.length);
1780         candidate = can.Select (args[0]);
1781         ic.insert (candidate, can);
1782       }
1783     return args[0];
1784   }
1785
1786   function Fchar_at (domain, vari, args)
1787   {
1788     return new Xex.Term (args[0].CharAt (domain.context));
1789   }
1790
1791   function Fmove (domain, vari, args)
1792   {
1793     var ic = domain.context;
1794     var pos = args[0].IsInt ? args[0].val : args[0].Position (ic);
1795     ic.move (pos);
1796     return args[0];
1797   }
1798
1799   function Fmark (domain, vari, args)
1800   {
1801     args[0].Mark (domain.context);
1802     return args[0];
1803   }
1804
1805   function Fpushback (domain, vari, args)
1806   {
1807     var arg = (args[0].IsInt ? args[0].Intval
1808                : args[0].IsStr ? new KeySeq (args[0])
1809                : args[0]);
1810     domain.context.pushback (arg)
1811     return args[0];
1812   }
1813
1814   function Fundo  (domain, vari, args)
1815   {
1816     var ic = domain.context;
1817     var n = args.length == 0 ? -2 : args[0].val;
1818     if (n < 0)
1819       ic.keys.val.splice (ic.keys.length + n, -n);
1820     else
1821       ic.keys.val.splice (n, ic.keys.length);
1822     ic.reset ();
1823     return Xex.nil;
1824   }
1825
1826   function Fcommit (domain, vari, args)
1827   {
1828     domain.context.commit ();
1829     return Xex.nil;
1830   }
1831
1832   function Funhandle (domain, vari, args)
1833     {
1834       domain.context.commit ();
1835       return Xex.Fthrow (domain, vari, Xex.CatchTag._mimtag);
1836     }
1837
1838   function Fshift (domain, vari, args)
1839   {
1840     var ic = domain.context;
1841     var state_name = args[0].val;
1842     var state = ic.im.state_list[state_name];
1843     if (! state)
1844       throw ("Unknown state: " + state_name);
1845       ic.shift (state);
1846     return args[0];
1847   }
1848
1849   function Fsurrounding_flag (domain, vari, args)
1850   {
1851     return new Xex.IntTerm (-1);
1852   }
1853
1854   im_domain.DefSubr (Finsert, "insert", false, 1, 1);
1855   im_domain.DefSubr (Finsert_candidates, "insert-candidates", false, 1, 1);
1856   im_domain.DefSubr (Fdelete, "delete", false, 1, 1);
1857   im_domain.DefSubr (Fselect, "select", false, 1, 1);
1858   //im_domain.DefSubr (Fshow, "show-candidates", false, 0, 0);
1859   //im_domain.DefSubr (Fhide, "hide-candidates", false, 0, 0);
1860   im_domain.DefSubr (Fmove, "move", false, 1, 1);
1861   im_domain.DefSubr (Fmark, "mark", false, 1, 1);
1862   im_domain.DefSubr (Fpushback, "pushback", false, 1, 1);
1863   //im_domain.DefSubr (Fpop, "pop", false, 0, 0);
1864   im_domain.DefSubr (Fundo, "undo", false, 0, 1);
1865   im_domain.DefSubr (Fcommit, "commit", false, 0, 0);
1866   im_domain.DefSubr (Funhandle, "unhandle", false, 0, 0);
1867   im_domain.DefSubr (Fshift, "shift", false, 1, 1);
1868   //im_domain.DefSubr (Fshiftback, "shiftback", false, 0, 0);
1869   im_domain.DefSubr (Fchar_at, "char-at", false, 1, 1);
1870   //im_domain.DefSubr (Fkey_count, "key-count", false, 0, 0);
1871   im_domain.DefSubr (Fsurrounding_flag, "surrounding-text-flag", false, 0, 0);
1872 }) ();
1873
1874
1875 (function () {
1876   function get_global_var (vname)
1877   {
1878     if (MIM.im_global.load_status == MIM.LoadStatus.NotLoaded)
1879       MIM.im_global.Load ()
1880     return MIM.im_global.domain.variables[vname];
1881   }
1882
1883   function include (node)
1884   {
1885     node = node.firstElement ();
1886     if (node.nodeName != 'tags')
1887       return null;
1888     
1889     var lang = null, name = null, extra = null;
1890     for (node = node.firstElement (); node; node = node.nextElement ())
1891       {
1892         if (node.nodeName == 'language')
1893           lang = node.firstChild.nodeValue;
1894         else if (node.nodeName == 'name')
1895           name = node.firstChild.nodeValue;
1896         else if (node.nodeName == 'extra-id')
1897           extra = node.firstChild.nodeValue;
1898       }
1899     if (! lang || ! MIM.imlist[lang])
1900       return null;
1901     if (! extra)
1902       {
1903         if (! name || ! (im = MIM.imlist[lang][name]))
1904           return null;
1905       }
1906     else
1907       {
1908         if (! (im = MIM.imextra[lang][extra]))
1909           return null;
1910       }
1911     if (im.load_status != MIM.LoadStatus.Loaded
1912         && (im.load_status != MIM.LoadStatus.NotLoaded || ! im.Load ()))
1913       return null;
1914     return im;
1915   }
1916
1917   var parsers = { };
1918
1919   parsers['description'] = function (node)
1920   {
1921     this.description = node.firstChild.nodeValue;
1922   }
1923   parsers['variable-list'] = function (node)
1924   {
1925     for (node = node.firstElement (); node; node = node.nextElement ())
1926       {
1927         var vname = node.attributes['vname'].nodeValue;
1928         if (this != MIM.im_global)
1929           {
1930             var vari = get_global_var (vname);
1931             if (vari != null)
1932               this.domain.Defvar (vname);
1933           }
1934         Xex.Term.Parse (this.domain, node);
1935       }
1936   }
1937   parsers['command-list'] = function (node)
1938   {
1939   }
1940   parsers['macro-list'] = function (node)
1941   {
1942     for (var n = node.firstElement (); n; n = n.nextElement ())
1943       if (n.nodeName == 'xi:include')
1944         {
1945           var im = include (n);
1946           if (! im)
1947             alert ('inclusion fail');
1948           else
1949             for (var macro in im.domain.functions)
1950               {
1951                 var func = im.domain.functions[macro];
1952                 if (func instanceof Xex.Macro)
1953                   im.domain.CopyFunc (this.domain, macro);
1954               }
1955           n = n.previousSibling;
1956           node.removeChild (n.nextSibling);
1957         }
1958     Xex.Term.Parse (this.domain, node.firstElement (), null);
1959   }
1960   parsers['title'] = function (node)
1961   {
1962     this.title = node.firstChild.nodeValue;
1963   }
1964   parsers['map-list'] = function (node)
1965   {
1966     for (node = node.firstElement (); node; node = node.nextElement ())
1967       {
1968         if (node.nodeName == 'xi:include')
1969           {
1970             var im = include (node);
1971             if (! im)
1972               {
1973                 alert ('inclusion fail');
1974                 continue;
1975               }
1976             for (var mapname in im.map_list)
1977               this.map_list[mapname] = im.map_list[mapname];
1978           }
1979         else
1980           {
1981             var map = Xex.Term.Parse (this.domain, node);
1982             this.map_list[map.name] = map;
1983           }
1984       }
1985   }
1986   parsers['state-list'] = function (node)
1987   {
1988     this.domain.map_list = this.map_list;
1989     for (node = node.firstElement (); node; node = node.nextElement ())
1990       {
1991         if (node.nodeName == 'state')
1992           {
1993             var state = Xex.Term.Parse (this.domain, node);
1994             if (! state.title)
1995               state.title = this.title;
1996             if (! this.initial_state)
1997               this.initial_state = state;
1998             this.state_list[state.name] = state;
1999           }
2000       }
2001     delete this.domain.map_list;
2002   }
2003
2004   MIM.IM = function (lang, name, extra_id, file)
2005   {
2006     this.lang = lang;
2007     this.name = name;
2008     this.extra_id = extra_id;
2009     this.file = file;
2010     this.load_status = MIM.LoadStatus.NotLoaded;
2011     this.domain = new Xex.Domain (this.lang + '-'
2012                                   + (this.name != 'nil'
2013                                      ? this.name : this.extra_id),
2014                                   MIM.im_domain, null);
2015   }
2016
2017   var proto = {
2018     Load: function ()
2019     {
2020       var node = Xex.Load (null, this.file);
2021       if (! node)
2022         {
2023           this.load_status = MIM.LoadStatus.Error;
2024           return false;
2025         }
2026       this.map_list = {};
2027       this.initial_state = null;
2028       this.state_list = {};
2029       for (node = node.firstElement (); node; node = node.nextElement ())
2030         {
2031           var name = node.nodeName;
2032           var parser = parsers[name];
2033           if (parser)
2034             parser.call (this, node);
2035         }
2036       this.load_status = MIM.LoadStatus.Loaded;
2037       MIM.log ('loading done: ' + this.lang + '-' + this.name + '-' + this.extra_id);
2038       return true;
2039     }
2040   }
2041
2042   MIM.IM.prototype = proto;
2043
2044   MIM.IC = function (im, target)
2045   {
2046     if (im.load_status == MIM.LoadStatus.NotLoaded)
2047       im.Load ();
2048     if (im.load_status != MIM.LoadStatus.Loaded)
2049       alert ('im:' + im.name + ' error:' + im.load_status);
2050     this.im = im;
2051     this.target = target;
2052     this.domain = new Xex.Domain ('context', im.domain, this);
2053     this.active = true;
2054     this.reset ();
2055     this.spot = 0;
2056   }
2057
2058   MIM.CandidateTable = function ()
2059   {
2060     this.table = new Array ();
2061   }
2062
2063   MIM.CandidateTable.prototype.get = function (from)
2064   {
2065     for (var i = 0; i < this.table.length; i++)
2066       {
2067         var elt = this.table[i];
2068         if (elt.from <= from && elt.to > from)
2069           return elt.val;
2070       }
2071   }
2072
2073   MIM.CandidateTable.prototype.put = function (from, to, candidates)
2074   {
2075     for (var i = 0; i < this.table.length; i++)
2076       {
2077         var elt = this.table[i];
2078         if (elt.from >= from && elt.from < to
2079             || elt.to >= from && elt.to < to)
2080           {
2081             elt.from = from;
2082             elt.to = to;
2083             elt.val = candidates;
2084             return;
2085           }
2086       }
2087     this.table.push ({ from: from, to: to, val: candidates });
2088   }
2089
2090   MIM.CandidateTable.prototype.adjust = function (from, to, inserted)
2091   {
2092     var diff = inserted - (to - from);
2093     for (var i = 0; i < this.table.length; i++)
2094       {
2095         var elt = this.table[i];
2096         if (elt.from >= to)
2097           {
2098             elt.from += diff;
2099             elt.to += diff;
2100           }
2101       }
2102   }
2103
2104   MIM.CandidateTable.prototype.clear = function ()
2105   {
2106     this.table.length = 0;
2107   }
2108
2109   function Block (index, term)
2110   {
2111     this.Index = index;
2112     if (term.IsStr)
2113       this.Data = term.val;
2114     else if (term.IsList)
2115       {
2116         this.Data = new Array ();
2117         for (var i = 0; i < term.val.length; i++)
2118           this.Data.push (term.val[i].val);
2119       }
2120   }
2121
2122   Block.prototype.Count = function () { return this.Data.length; }
2123   Block.prototype.get = function (i)
2124   {
2125     return (this.Data instanceof Array ? this.Data[i] : this.Data.charAt (i));
2126   }
2127
2128   function fill_group (start)
2129   {
2130     var nitems = this.group.length;
2131     var r = this.row;
2132     var b = this.blocks[r];
2133
2134     if (start < b.Index)
2135       while (start < b.Index)
2136         b = this.blocks[--r];
2137     else
2138       while (start >= b.Index + b.Count ())
2139         b = this.blocks[++r];
2140     this.row = r;
2141
2142     var count = b.Count ();
2143     start -= b.Index;
2144     for (var i = 0; i < nitems; i++, start++)
2145       {
2146         if (start >= count)
2147           {
2148             r++;
2149             if (r == this.blocks.Length)
2150               return i;
2151             b = this.blocks[r];
2152             count = b.Count ();
2153             start = 0;
2154           }
2155         this.group[i] = b.get (start);
2156       }
2157     return nitems;
2158   }
2159
2160   function Candidates (candidates, column)
2161   {
2162     this.column = column;
2163     this.row = 0;
2164     this.index = 0;
2165     this.total = 0;
2166     this.blocks = new Array ();
2167
2168     for (var i = 0; i < candidates.length; i++)
2169       {
2170         var block = new Block (this.total, candidates[i]);
2171         this.blocks.push (block);
2172         this.total += block.Count ();
2173       }
2174   }
2175
2176   Candidates.prototype.Column = function ()
2177   {
2178     return (this.column > 0 ? this.index % this.column
2179             : this.index - this.blocks[this.row].Index);
2180   }
2181
2182   Candidates.prototype.GroupLength = function ()
2183   {
2184     if (this.column > 0)
2185       {
2186         var start = this.index - (this.index % this.column);
2187         return (start + this.column <= this.total ? this.column
2188                 : this.total - start);
2189       }
2190     return this.blocks[this.row].Count;
2191   }
2192
2193   Candidates.prototype.Current = function ()
2194   {
2195     var b = this.blocks[this.row];
2196     return b.get (this.index - b.Index);
2197   }
2198
2199   Candidates.prototype.PrevGroup = function ()
2200   {
2201     var col = this.Column ();
2202     var nitems;
2203     if (this.column > 0)
2204       {
2205         this.index -= this.column;
2206         if (this.index >= 0)
2207           nitems = this.column;
2208         else
2209           {
2210             var lastcol = (this.total - 1) % this.column;
2211             this.index = (col < lastcol ? this.total - lastcol + col
2212                           : this.total - 1);
2213             this.row = this.blocks.length - 1;
2214             nitems = lastcol + 1;
2215           }
2216         while (this.blocks[this.row].Index > this.index)
2217           this.row--;
2218       }
2219     else
2220       {
2221         this.row = this.row > 0 ? this.row - 1 : this.blocks.length - 1;
2222         nitems = this.blocks[this.row].Count ();
2223         this.index = (this.blocks[this.row].Index
2224                       + (col < nitems ? col : nitems - 1));
2225       }
2226     return nitems;
2227   }
2228
2229   Candidates.prototype.NextGroup = function ()
2230   {
2231     var col = this.Column ();
2232     var nitems;
2233     if (this.column > 0)
2234       {
2235         this.index += this.column - col;
2236         if (this.index < this.total)
2237           {
2238             if (this.index + col >= this.total)
2239               {
2240                 nitems = this.total - this.index;
2241                 this.index = this.total - 1;
2242               }
2243             else
2244               {
2245                 nitems = this.column;
2246                 this.index += col;
2247               }
2248           }
2249         else
2250           {
2251             this.index = col;
2252             this.row = 0;
2253           }
2254         while (this.blocks[this.row].Index > this.index)
2255           this.row++;
2256       }
2257     else
2258       {
2259         this.row = this.row < this.blocks.length - 1 ? this.row + 1 : 0;
2260         nitems = this.blocks[this.row].Count ();
2261         this.index = (this.blocks[this.row].Index
2262                       + (col < nitems ? col : nitems - 1));
2263       }
2264     return nitems;
2265   }
2266
2267   Candidates.prototype.Prev = function ()
2268   {
2269     if (this.index == 0)
2270       {
2271         this.index = this.total - 1;
2272         this.row = this.blocks.length - 1;
2273       }
2274     else
2275       {
2276         this.index--;
2277         if (this.blocks[this.row].Index > this.index)
2278           this.row--;
2279       }
2280     }
2281
2282   Candidates.prototype.Next = function ()
2283   {
2284     this.index++;
2285     if (this.index == this.total)
2286       {
2287         this.index = 0;
2288         this.row = 0;
2289       }
2290     else
2291       {
2292         var b = this.blocks[this.row];
2293         if (this.index == b.Index + b.Count ())
2294           this.row++;
2295       }
2296   }
2297
2298   Candidates.prototype.First = function ()
2299   {
2300     this.index -= this.Column ();
2301     while (this.blocks[this.row].Index > this.index)
2302       this.row--;
2303   }
2304
2305   Candidates.prototype.Last = function ()
2306   {
2307     var b = this.blocks[this.row];
2308     if (this.column > 0)
2309       {
2310         if (this.index + 1 < this.total)
2311           {
2312             this.index += this.column - this.Column () + 1;
2313             while (b.Index + b.Count () <= this.index)
2314               b = this.blocks[++this.row];
2315           }
2316       }
2317     else
2318       this.index = b.Index + b.Count () - 1;
2319   }
2320
2321   Candidates.prototype.Select = function (selector)
2322   {
2323     if (selector.type == 'selector')
2324       {
2325         switch (selector.val)
2326           {
2327           case '@<': this.First (); break;
2328           case '@>': this.Last (); break;
2329           case '@-': this.Prev (); break;
2330           case '@+': this.Next (); break;
2331           case '@[': this.PrevGroup (); break;
2332           case '@]': this.NextGroup (); break;
2333           default: break;
2334           }
2335         return this.Current ();
2336       }
2337     var col, start, end
2338     if (this.column > 0)
2339       {
2340         col = this.index % this.column;
2341         start = this.index - col;
2342         end = start + this.column;
2343       }
2344     else
2345       {
2346         start = this.blocks[this.row].Index;
2347         col = this.index - start;
2348         end = start + this.blocks[this.row].Count;
2349       }
2350     if (end > this.total)
2351       end = this.total;
2352     this.index += selector.val - col;
2353     if (this.index >= end)
2354       this.index = end - 1;
2355     if (this.column > 0)
2356       {
2357         if (selector.val > col)
2358           while (this.blocks[this.row].Index + this.blocks[this.row].Count
2359                  < this.index)
2360             this.row++;
2361         else
2362           while (this.blocks[this.row].Index > this.index)
2363             this.row--;
2364       }
2365     return this.Current ();
2366   }
2367
2368   function detach_candidates (ic)
2369   {
2370     ic.candidate_table.clear ();
2371     ic.candidates = null;
2372     ic.changed |= (MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos
2373                    | ChangedStatus.CandidateList
2374                    | ChangedStatus.CandidateIndex
2375                    | ChangedStatus.CandidateShow);
2376   }
2377
2378   function set_cursor (prefix, pos)
2379   {
2380     this.cursor_pos = pos;
2381     if (pos > 0)
2382       this.candidates = this.candidate_table.get (pos - 1);
2383     else
2384       this.candidates = null;
2385   }
2386
2387   function save_state ()
2388   {
2389     this.state_var_values = this.domain.SaveValues ();
2390     this.state_preedit = this.preedit;
2391     this.state_key_head = this.key_head;
2392     this.state_pos = this.cursor_pos;
2393   }
2394
2395   function restore_state ()
2396   {
2397     this.domain.RestoreValues (this.state_var_values);
2398     this.preedit = this.state_preedit;
2399     set_cursor.call (this, "restore", this.state_pos);
2400   }
2401
2402   function handle_key ()
2403   {
2404     var out = this.keymap.Lookup (this.keys, this.key_head);
2405     var sub = out.map;
2406     var branch_actions = this.state.keymap.actions;
2407
2408     MIM.log ('handling ' + this.keys.val[this.key_head]
2409              + ' in ' + this.state.name + ':' + this.keymap.name);
2410     this.key_head = out.index;
2411     if (sub != this.keymap)
2412       {
2413
2414         restore_state.call (this);
2415         this.keymap = sub;
2416         MIM.log ('submap found');
2417         if (this.keymap.actions)
2418           {
2419             MIM.log ('taking map actions:');
2420             if (! this.take_actions (this.keymap.actions))
2421               return false;
2422           }
2423         else if (this.keymap.submaps)
2424           {
2425             MIM.log ('no map actions');
2426             for (var i = this.state_key_head; i < this.key_head; i++)
2427               {
2428                 MIM.log ('inserting key:' + this.keys.val[i].key);
2429                 this.insert (this.keys.val[i].key, null);
2430               }
2431           }
2432         if (! this.keymap.submaps)
2433           {
2434             MIM.log ('terminal:');
2435             if (this.keymap.branch_actions != null)
2436               {
2437                 MIM.log ('branch actions:');
2438                 if (! this.take_actions (branch_actions))
2439                   return false;
2440               }
2441             if (this.keymap != this.state.keymap)
2442               this.shift (this.state);
2443           }
2444       }
2445     else
2446       {
2447         MIM.log ('no submap');
2448         var current_state = this.state;
2449         var map = this.keymap;
2450
2451         if (branch_actions)
2452           {
2453             MIM.log ('branch actions');
2454             if (! this.take_actions (this.keymap.branch_actions))
2455               return false;
2456           }
2457
2458         if (map == this.keymap)
2459           {
2460             MIM.log ('no state change');
2461             if (map == this.initial_state.keymap
2462                 && this.key_head < this.keys.val.length)
2463               {
2464                 MIM.log ('unhandled');
2465                 return false;
2466               }
2467             if (this.keymap != current_state.keymap)
2468               this.shift (current_state);
2469             else if (this.keymap.actions == null)
2470               this.shift (this.initial_state);
2471           }
2472       }
2473     return true;
2474   }
2475
2476   proto = {
2477     reset: function ()
2478     {
2479       this.produced = null;
2480       this.preedit = '';
2481       this.preedit_saved = '';
2482       this.cursor_pos = 0;
2483       this.marker_positions = {};
2484       this.candidates = null;
2485       this.candidate_show = false;
2486       this.state = null;
2487       this.prev_state = null;
2488       this.initial_state = this.im.initial_state;
2489       this.title = this.initial_state.title;
2490       this.state_preedit = '';
2491       this.state_key_head = 0;
2492       this.state_var_values = {};
2493       this.state_pos = 0;
2494       this.keymap = null;
2495       this.keys = new MIM.KeySeq ();
2496       this.key_head = 0;
2497       this.key_unhandled = false;
2498       this.unhandled_key = null;
2499       this.changed = MIM.ChangedStatus.None;
2500       this.error_message = '';
2501       this.title = this.initial_state.title;
2502       this.produced = '';
2503       this.preedit = '';
2504       this.preedit_saved = '';
2505       this.marker_positions = {};
2506       this.candidate_table = new MIM.CandidateTable ();
2507       this.candidates = null;
2508       this.candidate_show = false;
2509       this.shift (this.initial_state);
2510     },
2511
2512     catch_args: new Array (Xex.CatchTag._mimtag, null),
2513
2514     take_actions: function (actions)
2515     {
2516       var func_progn = this.domain.GetFunc ('progn');
2517       var func_catch = this.domain.GetFunc ('catch');
2518       this.catch_args[1] = new Xex.Funcall (func_progn, null, actions);
2519       var term = new Xex.Funcall (func_catch, null, this.catch_args);
2520       term = term.Eval (this.domain);
2521       return (! term.IsSymbol || term.val != '@mimtag');
2522     },
2523
2524     GetSurroundingChar: function (pos)
2525     {
2526       if (pos < 0 ? this.caret_pos < - pos : this.target.value.length < pos)
2527         return 0;
2528       return this.target.value.charCodeAt (this.caret_pos + pos);
2529     },
2530     
2531     adjust_markers: function (from, to, inserted)
2532     {
2533       var diff = inserted - (to - from);
2534
2535       for (var m in this.marker_positions)
2536         if (this.marker_positions[m] > from)
2537           this.marker_positions[m] = (this.marker_positions[m] >= to
2538                                       ? pos + diff : from);
2539       if (this.cursor_pos >= to)
2540         set_cursor.call (this, 'adjust', this.cursor_pos + diff);
2541       else if (this.cursor_pos > from)
2542         set_cursor.call (this, 'adjust', from)
2543     },
2544
2545     preedit_replace: function (from, to, text, candidates)
2546     {
2547       this.preedit = (this.preedit.substring (0, from)
2548                       + text + this.preedit.substring (to));
2549       this.adjust_markers (from, to, text.length);
2550       this.candidate_table.adjust (from, to, text.length);
2551       if (candidates)
2552         this.candidate_table.put (from, from + text.length, candidates)
2553     },
2554
2555     insert: function (text, candidates)
2556     {
2557       this.preedit_replace (this.cursor_pos, this.cursor_pos, text, candidates);
2558       this.changed = MIM.ChangedStatus.Preedit | MIM.ChangedStatus.CursorPos;
2559     },
2560
2561     del: function (pos)
2562     {
2563       var deleted = pos - this.cursor_pos;
2564       if (pos < 0)
2565         {
2566           this.DelSurroundText (pos);
2567           pos = 0;
2568         }
2569       else if (pos > this.preedit.length)
2570         {
2571           this.DelSurroundText (pos - this.preedit.length);
2572           pos = this.preedit.length;
2573         }
2574       if  (pos < this.cursor_pos)
2575         this.preedit = (this.predit.substring (0, pos)
2576                         + this.preedit.substring (this.cursor_pos));
2577       else
2578         this.preedit = (this.preedit.substring (0, this.cursor_pos)
2579                         + this.predit.substring (pos));
2580       return deleted;
2581     },
2582
2583     show: function ()
2584     {
2585       this.candidate_show = true;
2586       this.changed |= MIM.ChangedStatus.CandidateShow;
2587     },
2588
2589     hide: function ()
2590     {
2591       this.candidate_show = false;
2592       this.changed |= MIM.ChangedStatus.CandidateShow;
2593     },
2594
2595     move: function (pos)
2596     {
2597       if (pos < 0)
2598         pos = 0;
2599       else if (pos > this.preedit.length)
2600         pos = this.preedit.length;
2601       if (pos != this.cursor_pos)
2602         {
2603           set_cursor.call (this, 'move', pos);
2604           this.changed |= MIM.ChangedStatus.Preedit;
2605         }
2606     },
2607
2608     pushback: function (n)
2609     {
2610       if (n instanceof MIM.KeySeq)
2611         {
2612           if (this.key_head > 0)
2613             this.key_head--;
2614           if (this.key_head < this.keys.val.length)
2615             this.keys.val.splice (this.key_head,
2616                                   this.keys.val.length - this.key_head);
2617           for (var i = 0; i < n.val.length; i++)
2618             this.keys.val.push (n.val[i]);
2619           return;
2620         }
2621       if (n > 0)
2622         {
2623           this.key_head -= n;
2624           if (this.key_head < 0)
2625             this.key_head = 0;
2626         }
2627       else if (n == 0)
2628         this.key_head = 0;
2629       else
2630       {
2631         this.key_head = - n;
2632         if (this.key_head > this.keys.val.length)
2633           this.key_head = this.keys.val.length;
2634       }
2635     },
2636
2637     pop: function ()
2638     {
2639       if (this.key_head < this.keys.val.length)
2640         this.keys.val.splice (this.key_head, 1);
2641     },
2642
2643     commit: function ()
2644     {
2645       if (this.preedit.length > 0)
2646       {
2647         this.candidate_table.clear ();
2648         this.produced += this.preedit;
2649         this.preedit_replace.call (this, 0, this.preedit.length, '', null);
2650       }
2651     },
2652
2653     shift: function (state)
2654     {
2655       if (state == null)
2656         {
2657           MIM.log ("shifting back to previous");
2658           if (this.prev_state == null)
2659             return;
2660           state = this.prev_state;
2661         }
2662       else
2663         MIM.log ("shifting to " + state.name);
2664
2665       if (state == this.initial_state)
2666         {
2667           if (this.state)
2668             {
2669               this.commit ();
2670               this.keys.val.splice (0, this.key_head);
2671               this.key_head = 0;
2672               this.prev_state = null;
2673             }
2674         }
2675       else
2676         {
2677           if (state != this.state)
2678             this.prev_state = this.state;
2679         }
2680       if (state != this.state && state.enter_actions)
2681         this.take_actions (state.enter_actions);
2682       if (! this.state || this.state.title != state.title)
2683         this.changed |= MIM.ChangedStatus.StateTitle;
2684       this.state = state;
2685       this.keymap = state.keymap;
2686       this.state_key_head = this.key_head;
2687       save_state.call (this);
2688     },
2689
2690     Filter: function (key)
2691     {
2692       if (! this.active)
2693         {
2694           this.key_unhandled = true;
2695           this.unhandled_key = key;
2696           return false;
2697         }
2698       if (key.key == '_reload')
2699         return true;
2700       this.changed = MIM.ChangedStatus.None;
2701       this.produced = '';
2702       this.key_unhandled = false;
2703       this.keys.val.push (key);
2704       var count = 0;
2705       while (this.key_head < this.keys.val.length)
2706         {
2707           if (! handle_key.call (this))
2708             {
2709               if (this.key_head < this.keys.val.length)
2710                 {
2711                   this.unhandled_key = this.keys.val[this.key_head];
2712                   this.keys.val.splice (this.key_head, this.key_head + 1);
2713                 }
2714               this.key_unhandled = true;
2715               break;
2716             }
2717           if (++count == 10)
2718             {
2719               this.reset ();
2720               this.key_unhandled = true;
2721               break;
2722             }
2723         }
2724       if (this.key_unhandled)
2725         {
2726           this.keys.val.length = 0;
2727           this.key_head = this.state_key_head = this.commit_key_head = 0;
2728         }
2729       return (! this.key_unhandled
2730               && this.produced.length == 0
2731               && this.preedit.length == 0);
2732     }
2733   }
2734
2735   MIM.IC.prototype = proto;
2736
2737   var node = Xex.Load (null, "imlist.xml");
2738   for (node = node.firstChild; node; node = node.nextSibling)
2739     if (node.nodeName == 'input-method')
2740       {
2741         var lang = null, name = null, extra_id = null, file = null;
2742
2743         for (var n = node.firstChild; n; n = n.nextSibling)
2744           {
2745             if (n.nodeName == 'language')
2746               lang = n.firstChild.nodeValue;
2747             else if (n.nodeName == 'name')
2748               name = n.firstChild.nodeValue;
2749             else if (n.nodeName == 'extra-id')
2750               extra_id = n.firstChild.nodeValue;
2751             else if (n.nodeName == 'filename')
2752               file = n.firstChild.nodeValue;
2753           }
2754         if (name && name != 'nil')
2755           {
2756             if (! MIM.imlist[lang])
2757               MIM.imlist[lang] = {};
2758             MIM.imlist[lang][name] = new MIM.IM (lang, name, extra_id, file);
2759           }
2760         else if (extra_id && extra_id != 'nil')
2761           {
2762             if (! MIM.imextra[lang])
2763               MIM.imextra[lang] = {};
2764             MIM.imextra[lang][extra_id] = new MIM.IM (lang, name, extra_id, file);
2765           }
2766       }
2767   if (MIM.imextra.t && MIM.imextra.t.global)
2768     MIM.im_global = MIM.imextra.t.global;
2769   else
2770     {
2771       MIM.im_global = new MIM.IM ('t', 'nil', 'global', null);
2772       MIM.im_global.load_status = MIM.LoadStatus.Error;
2773     }
2774   node = undefined;
2775 }) ();
2776
2777 (function () {
2778   var keys = new Array ();
2779   keys[0x09] = 'tab';
2780   keys[0x08] = 'backspace';
2781   keys[0x0D] = 'return';
2782   keys[0x1B] = 'escape';
2783   keys[0x20] = 'space';
2784   keys[0x21] = 'pageup';
2785   keys[0x22] = 'pagedown';
2786   keys[0x23] = 'end';
2787   keys[0x24] = 'home';
2788   keys[0x25] = 'left';
2789   keys[0x26] = 'up';
2790   keys[0x27] = 'right';
2791   keys[0x28] = 'down';
2792   keys[0x2D] = 'insert';
2793   keys[0x2E] = 'delete';
2794   for (var i = 1; i <= 12; i++)
2795     keys[111 + i] = "f" + i;
2796   keys[0x90] = "numlock";
2797   keys[0xF0] = "capslock";
2798
2799   MIM.decode_key_event = function (event)
2800   {
2801     var key = ((event.type == 'keydown' || event.keyCode) ? event.keyCode
2802                : event.charCode ? event.charCode
2803                : false);
2804     if (! key)
2805       return false;
2806     if (event.type == 'keydown')
2807       {
2808         key = keys[key];
2809         if (! key)
2810           return false;
2811         if (event.shiftKey) key = "S-" + key ;
2812       }
2813     else
2814       key = String.fromCharCode (key);
2815     if (event.altKey) key = "A-" + key ;
2816     if (event.ctrlKey) key = "C-" + key ;
2817     return new MIM.Key (key);
2818   }
2819 }) ();
2820
2821 MIM.add_event_listener
2822   = (window.addEventListener
2823      ? function (target, type, listener) {
2824        target.addEventListener (type, listener, false);
2825      }
2826      : window.attachEvent
2827      ? function (target, type, listener) {
2828        target.attachEvent ('on' + type,
2829                            function() {
2830                              listener.call (target, window.event);
2831                            });
2832      }
2833      : function (target, type, listener) {
2834        target['on' + type]
2835          = function (e) { listener.call (target, e || window.event); };
2836      });
2837
2838 MIM.log = function (msg)
2839 {
2840   var node = document.getElementById ('log');
2841   node.value = msg + "\n" + node.value;
2842 }
2843
2844 MIM.debug_print = function (event, ic)
2845 {
2846   if (! MIM.debug)
2847     return;
2848   if (! MIM.debug_nodes)
2849     {
2850       MIM.debug_nodes = new Array ();
2851       MIM.debug_nodes['keydown'] = document.getElementById ('keydown');
2852       MIM.debug_nodes['keypress'] = document.getElementById ('keypress');
2853       MIM.debug_nodes['status0'] = document.getElementById ('status0');
2854       MIM.debug_nodes['status1'] = document.getElementById ('status1');
2855       MIM.debug_nodes['keymap0'] = document.getElementById ('keymap0');
2856       MIM.debug_nodes['keymap1'] = document.getElementById ('keymap1');
2857       MIM.debug_nodes['preedit0'] = document.getElementById ('preedit0');
2858       MIM.debug_nodes['preedit1'] = document.getElementById ('preedit1');
2859     }
2860   var target = event.target;
2861   var code = event.keyCode;
2862   var ch = event.type == 'keydown' ? 0 : event.charCode;
2863   var key = MIM.decode_key_event (event);
2864   var index;
2865
2866   MIM.debug_nodes[event.type].innerHTML = "" + code + "/" + ch + " : " + key;
2867   index = (event.type == 'keydown' ? '0' : '1');
2868   if (ic)
2869     MIM.debug_nodes['status' + index].innerHTML = ic.im.load_status;
2870   else
2871     MIM.debug_nodes['status' + index].innerHTML = 'no IM';
2872   MIM.debug_nodes['keymap' + index].innerHTML = ic.state.name;
2873   MIM.debug_nodes['preedit' + index].innerHTML = ic.preedit;
2874 };
2875
2876 MIM.get_range = function (target, range)
2877 {
2878   if (target.selectionStart != null) // for Mozilla
2879     {
2880       range[0] = target.selectionStart;
2881       range[1] = target.selectionEnd;
2882     }
2883   else                          // for IE
2884     {
2885       var r = document.selection.createRange ();
2886       var rr = r.duplicate ();
2887
2888       rr.moveToElementText (target);
2889       rr.setEndPoint ('EndToEnd', range);
2890       range[0] = rr.text.length - r.text.length;
2891       range[1] = rr.text.length;
2892     }
2893 }
2894
2895 MIM.set_caret = function (target, ic)
2896 {
2897   if (target.setSelectionRange) // Mozilla
2898     {
2899       var scrollTop = target.scrollTop;
2900       target.setSelectionRange (ic.spot, ic.spot + ic.preedit.length);
2901       target.scrollTop = scrollTop;
2902     }
2903   else                          // IE
2904     {
2905       var range = target.createTextRange ();
2906       range.moveStart ('character', ic.spot);
2907       range.moveEnd ('character', ic.spot + ic.preedit.length);
2908       range.select ();
2909     }
2910 };
2911
2912 (function () {
2913   var range = new Array ();
2914
2915   MIM.check_range = function (target, ic)
2916   {
2917     MIM.get_range (target, range);
2918     if (range[0] != ic.spot || range[1] - range[0] != ic.preedit.length
2919         || target.value.substring (range[0], range[1]) != ic.preedit)
2920       {
2921         MIM.log ('reset:' + ic.spot + '-' + (ic.spot + ic.preedit.length)
2922                  + '/' + range[0] + '-' + range[1]);
2923         ic.reset ();
2924       }
2925     target.value = (target.value.substring (0, range[0])
2926                     + target.value.substring (range[1]));
2927     ic.spot = range[0];
2928   }
2929 }) ();
2930
2931 MIM.update = function (target, ic)
2932 {
2933   var text = target.value;
2934   target.value = (text.substring (0, ic.spot)
2935                   + ic.produced
2936                   + ic.preedit
2937                   + text.substring (ic.spot));
2938   ic.spot += ic.produced.length;
2939   MIM.set_caret (target, ic);
2940 };
2941
2942 MIM.reset_ic = function (event)
2943 {
2944   if (event.target.mim_ic)
2945     {
2946       var ic = event.target.mim_ic;
2947       var pos = ic.spot + ic.preedit.length;
2948       ic.reset ();
2949       if (pos > ic.spot)
2950         event.target.setSelectionRange (pos, pos);
2951     }
2952 };
2953
2954 MIM.keydown = function (event)
2955 {
2956   var target = event.target;
2957   if (! (target.type == "text" || target.type == "textarea"))
2958     return;
2959
2960   var ic = target.mim_ic;
2961   if (! ic || ic.im != MIM.current)
2962     {
2963       MIM.log ('creating IC');
2964       ic = new MIM.IC (MIM.current, target);
2965       target.mim_ic = ic;
2966       MIM.add_event_listener (target, 'blur', MIM.reset_ic);
2967     }
2968   if (ic.im.load_status != MIM.LoadStatus.Loaded)
2969     return;
2970   MIM.check_range (target, ic);
2971   MIM.debug_print (event, ic);
2972   ic.key = MIM.decode_key_event (event);
2973 };
2974
2975 MIM.keypress = function (event)
2976 {
2977   if (! (event.target.type == "text" || event.target.type == "textarea"))
2978     return;
2979
2980   var ic = event.target.mim_ic;
2981   var i;
2982
2983   try {
2984     if (ic.im.load_status != MIM.LoadStatus.Loaded)
2985       return;
2986     if (! ic.key)
2987       ic.key = MIM.decode_key_event (event);
2988     if (! ic.key)
2989       {
2990         ic.reset ();
2991         return;
2992       }
2993     
2994     MIM.log ("filtering " + ic.key);
2995     var result = ic.Filter (ic.key);
2996     MIM.update (event.target, ic);
2997     if (! ic.key_unhandled)
2998       event.preventDefault ();
2999   } finally {
3000     MIM.debug_print (event, ic);
3001   }
3002   return;
3003 };
3004
3005 MIM.select_im = function (event)
3006 {
3007   var target = event.target.parentNode;
3008   while (target.tagName != "SELECT")
3009     target = target.parentNode;
3010   var idx = 0;
3011   var im = false;
3012   for (var lang in MIM.imlist)
3013     for (var name in MIM.imlist[lang])
3014       if (idx++ == target.selectedIndex)
3015         {
3016           im = MIM.imlist[lang][name];
3017           break;
3018         }
3019   document.getElementsByTagName ('body')[0].removeChild (target);
3020   target.target.focus ();
3021   if (im && im != MIM.current)
3022     {
3023       MIM.current = im;
3024       MIM.log ('select IM: ' + im.name);
3025     }
3026 };
3027
3028 MIM.destroy_menu = function (event)
3029 {
3030   if (event.target.tagName == "SELECT")
3031     document.getElementsByTagName ('body')[0].removeChild (event.target);
3032 };
3033
3034 MIM.select_menu = function (event)
3035 {
3036   var target = event.target;
3037
3038   if (! ((target.type == "text" || target.type == "textarea")
3039          && event.which == 1 && event.ctrlKey))
3040     return;
3041
3042   var sel = document.createElement ('select');
3043   sel.onclick = MIM.select_im;
3044   sel.onmouseout = MIM.destroy_menu;
3045   sel.style.position='absolute';
3046   sel.style.left = (event.clientX - 10) + "px";
3047   sel.style.top = (event.clientY - 10) + "px";
3048   sel.target = target;
3049   var idx = 0;
3050   for (var lang in MIM.imlist)
3051     for (var name in MIM.imlist[lang])
3052       {
3053         var option = document.createElement ('option');
3054         var imname = lang + "-" + name;
3055         option.appendChild (document.createTextNode (imname));
3056         option.value = imname;
3057         sel.appendChild (option);
3058         if (MIM.imlist[lang][name] == MIM.current)
3059           sel.selectedIndex = idx;
3060         idx++;
3061       }
3062   sel.size = idx;
3063   document.getElementsByTagName ('body')[0].appendChild (sel);
3064 };
3065
3066 MIM.test = function ()
3067 {
3068   var im = MIM.imlist['t']['latn-post'];
3069   var ic = new MIM.IC (im, null);
3070
3071   ic.Filter (new MIM.Key ('a'));
3072   ic.Filter (new MIM.Key ("'"));
3073
3074   if (true)
3075     document.getElementById ('text').value = ic.produced + ic.preedit;
3076   else {
3077     try {
3078       document.getElementById ('text').value
3079         = Xex.Term.Parse (domain, body).Eval (domain).toString ();
3080     } catch (e) {
3081       if (e instanceof Xex.ErrTerm)
3082         alert (e);
3083       throw e;
3084     }
3085   }
3086 }
3087
3088
3089 MIM.init = function ()
3090 {
3091   MIM.add_event_listener (window, 'keydown', MIM.keydown);
3092   MIM.add_event_listener (window, 'keypress', MIM.keypress);
3093   MIM.add_event_listener (window, 'mousedown', MIM.select_menu);
3094   if (window.location == 'http://localhost/mim/index.html')
3095     MIM.server = 'http://localhost/mim';
3096   MIM.current = MIM.imlist['vi']['telex'];
3097 };
3098
3099 MIM.init_debug = function ()
3100 {
3101   MIM.debug = true;
3102   MIM.init ();
3103 };