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