*** empty log message ***
[m17n/m17n-lib-js.git] / xex.js
diff --git a/xex.js b/xex.js
index 932d240..cd440c1 100644 (file)
--- a/xex.js
+++ b/xex.js
-// -* coding: utf-8; -*
+// xex.js -- Xex (XML Expression) interpreter
+// Copyright (C) 2010
+//   National Institute of Advanced Industrial Science and Technology (AIST)
+//   Registration Number H15PRO112
+
+// This file is part of the m17n database; a sub-part of the m17n
+// library.
+
+// The m17n library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public License
+// as published by the Free Software Foundation; either version 2.1 of
+// the License, or (at your option) any later version.
+
+// The m17n library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+
+// You should have received a copy of the GNU Lesser General Public
+// License along with the m17n library; if not, write to the Free
+// Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+// Please note that the code is not yet matured.
+
+var Xex = {};
+
+(function () {                 // Logging
+  // The logging node containing tracing information.
+  var log = null;
+  // Number of lines.
+  var lines;
+  // Style properties of the logging node.
+  var styles = { border: '1px solid black',
+                font: 'normal normal normal small monospace',
+                width: '600px',
+                minHeight: '300px',
+                maxHeight: '300px',
+                overflow: 'auto' };
+  
+  // Toggle logging on and off.  PARENT if non-null specifies the
+  // parent of the log node.  The log node is appended to PARENT.
+  // If PARENT is null, 'body' node is assumed.
+  Xex.LogToggle = function (parent)
+  {
+    if (log)
+      {
+       log.parentNode.removeChild (log);
+       log = null;
+       return;
+      }
+    if (! parent)
+      parent = document.getElementsByTagName ('body')[0];
+    log = document.createElement ('ol');
+    for (var prop in styles)
+      log.style[prop] = styles[prop];
+    parent.appendChild (log);
+    lines = 0;
+    return log;
+  }
 
-var Xex = {
-  LogNode: null,
-  LogNodeLen: 0,
-  Log: function (arg, indent, cont)
+  // Log ARG (string).  INDENT if specified is a number of columns to
+  // indent.  If INDENT is -1, ARG is appended to the last log.
+  Xex.Log = function (arg, indent)
   {
-    if (! Xex.LogNode)
+    if (! log)
       return;
     if (! arg)
       {
-       while (Xex.LogNode.childNodes.length > 0)
-         Xex.LogNode.removeChild (Xex.LogNode.firstChild);
-       LogNodeLen = 0;
+       while (log.childNodes.length > 0)
+         log.removeChild (log.firstChild);
+       lines = 0;
       }
     else
       {
        var node;
-       if (cont)
-         Xex.LogNode.lastChild.innerText += arg;
+       if (indent == -1)
+         log.lastChild.innerText += arg;
        else
          {
-           LogNodeLen++;
-           if (LogNodeLen >= 1000)
-             node = Xex.LogNode.firstElement ();
+           lines++;
+           if (lines >= 256)
+             {
+               node = log.firstElement ();
+               log.start = lines - 254;
+             }
            else
-             node = document.createElement ('div');
+             node = document.createElement ('li');
            if (indent != undefined)
              node.style.textIndent = (indent + 1) + 'em';
            else
              node.style.textIndent = '0px';
-           node.innerText = LogNodeLen + ': ' + arg;
-           Xex.LogNode.appendChild (node);
-           Xex.LogNode.scrollTop = Xex.LogNode.scrollHeight;
+           node.innerText = arg;
+           log.appendChild (node);
+           log.scrollTop = log.scrollHeight;
          }
       }
   }
-};
+}) ();
 
 Xex.Error = {
   UnknownError: "unknown-error",
@@ -63,32 +124,34 @@ Xex.Error = {
   UncaughtThrow: "uncaught-throw"
 };
 
-Xex.Variable = function (domain, name, desc, val, range)
+Xex.Variable = function (name, desc, val, range)
 {
-  this.domain = domain;
-  this.name = name;
-  this.desc = desc;
+  if (name)
+    this.name = name;
+  if (desc)
+    this.desc = desc;
   this.val = val;
-  this.range = range;
+  if (range)
+    this.range = range;
 }
 
-Xex.Variable.prototype.clone = function ()
-{
-  return new Xex.Variable (this.domain, this.name, this.desc,
-                          this.val, this.range);
-}
-    
-Xex.Variable.prototype.Equals = function (obj)
-{
-  return ((obj instanceof Xex.Variable)
-         && obj.name == this.name);
-}
+Xex.Variable.prototype = {
+  clone: function ()
+  {
+    return new Xex.Variable (this.name, this.desc, this.val, this.range);
+  },
+  equals: function (obj)
+  {
+    return ((obj instanceof Xex.Variable)
+           && obj.name == this.name);
+  },
+  SetValue: function (term)
+  {
+    this.val = term;
+    return term;
+  }
+}  
 
-Xex.Variable.prototype.SetValue = function (term)
-{
-  this.val = term;
-  return term;
-}
 
 Xex.Function = function (name, with_var, min_args, max_args)
 {
@@ -100,10 +163,7 @@ Xex.Function = function (name, with_var, min_args, max_args)
 
 Xex.Subrountine = function (builtin, name, with_var, min_args, max_args)
 {
-  this.name = name;
-  this.with_var = with_var;
-  this.min_args = min_args;
-  this.max_args = max_args;
+  Xex.Function.apply (this, [name, with_var, min_args, max_args]);
   this.builtin = builtin;
 }
 
@@ -121,10 +181,7 @@ Xex.Subrountine.prototype.Call = function (domain, vari, args)
 
 Xex.SpecialForm = function (builtin, name, with_var, min_args, max_args)
 {
-  this.name = name;
-  this.with_var = with_var;
-  this.min_args = min_args;
-  this.max_args = max_args;
+  Xex.Function.apply (this, [name, with_var, min_args, max_args]);
   this.builtin = builtin;
 }
 
@@ -135,9 +192,7 @@ Xex.SpecialForm.prototype.Call = function (domain, vari, args)
 
 Xex.Lambda = function (name, min_args, max_args, args, body)
 {
-  this.name = name;
-  this.min_args = min_args;
-  this.max_args = max_args;
+  Xex.Function.apply (this, [name, false, min_args, max_args]);
   this.args = args;
   this.body = body;
 }
@@ -188,9 +243,7 @@ Xex.Lambda.prototype.Call = function (domain, vari, args)
 
 Xex.Macro = function (name, min_args, max_args, args, body)
 {
-  this.name = name;
-  this.min_args = min_args;
-  this.max_args = max_args;
+  Xex.Function.apply (this, [name, false, min_args, max_args]);
   this.args = args;
   this.body = body;
 }
@@ -269,7 +322,7 @@ Xex.Domain = function (name, parent, context)
       for (elt in parent.variables)
        {
          var vari = parent.variables[elt];
-         this.variables[elt] = new Xex.Variable (this, vari.name, vari.desc,
+         this.variables[elt] = new Xex.Variable (vari.name, vari.desc,
                                                  vari.val, vari.range);
        }
     }
@@ -391,7 +444,7 @@ Xex.Domain.prototype = {
   },
   Defvar: function (name, desc, val, range)
   {
-    var vari = new Xex.Variable (this, name, desc, val, range);
+    var vari = new Xex.Variable (name, desc, val, range);
     this.variables[name] = vari;
     return vari;
   },
@@ -418,7 +471,7 @@ Xex.Domain.prototype = {
   {
     var vari = this.variables[name];
     if (! vari)
-      vari = this.variables[name] = new Xex.Variable (this, name, null,
+      vari = this.variables[name] = new Xex.Variable (name, null,
                                                      Xex.Zero, null);
     return vari;
   },
@@ -446,13 +499,13 @@ Xex.Term.prototype = {
   IsTrue: function () { return true; },
   Eval: function (domain) { return this.Clone (); },
   Clone: function (domain) { return this; },
-  Equals: function (obj)
+  equals: function (obj)
   {
     return (this.type == obj.type
            && this.val != undefined
            && obj.val == this.val);
   },
-  Matches: function (obj) { return this.Equals (obj); },
+  Matches: function (obj) { return this.equals (obj); },
   toString: function ()
   {
     if (this.val != undefined)
@@ -722,11 +775,11 @@ Xex.Funcall = function (func, vname, args)
     return new Xex.Funcall (this.func, this.vari, this.args);
   }
 
-  proto.Equals = function (obj)
+  proto.equals = function (obj)
   {
     return (obj.type == 'funcall'
            && obj.func == this.func
-           && obj.vari.Equals (this.vari)
+           && obj.vari.equals (this.vari)
            && obj.args.length == this.func.length);
   }
 
@@ -778,7 +831,7 @@ Xex.ErrTerm = function (ename, message, stack)
     return new Xex.ErrTerm (ename, message, false);
   }
 
-  proto.Equals = function (obj)
+  proto.equals = function (obj)
   {
     return (obj.IsError
            && obj.ename == ename && obj.message == message
@@ -851,13 +904,13 @@ Xex.LstTerm = function (list) { this.val = list; };
   proto.IsTrue = function () { return this.val.length > 0; }
   proto.Clone = function () { return new Xex.LstTerm (this.val.slice (0)); }
 
-  proto.Equals = function (obj)
+  proto.equals = function (obj)
   {
     if (obj.type != 'list' || obj.val.length != this.val.length)
       return false;
     var i, len = this.val.length;
     for (i = 0; i < len; i++)
-      if (! this.val[i].Equals (obj.val[i]))
+      if (! this.val[i].equals (obj.val[i]))
        return false;
     return true;
   }
@@ -1040,7 +1093,7 @@ Xex.LstTerm = function (list) { this.val = list; };
   function Feq (domain, vari, args)
   {
     for (var i = 1; i < args.length; i++)
-      if (! args[i - 1].Equals (args[i]))
+      if (! args[i - 1].equals (args[i]))
        return Xex.Zero;
     return Xex.One;
   }
@@ -1298,12 +1351,44 @@ Xex.Zero = new Xex.IntTerm (0);
 Xex.One = new Xex.IntTerm (1);
 Xex.nil = new Xex.SymTerm ('nil');
 
-Xex.Load = function (server, file)
-{
-  var obj = new XMLHttpRequest ();
-  var url = server ? server + '/' + file : file;
-  obj.open ('GET', url, false);
-  obj.overrideMimeType ('text/xml');
-  obj.send ('');
-  return obj.responseXML.firstChild;
-}
+(function () {
+  var queue = new Array ();
+  var iframe = null;
+
+  function receiver (event)
+  {
+    var request = queue.shift ();
+    //alert ('received: ' + request[0]);
+    var parser = new DOMParser ();
+    var xml = parser.parseFromString (event.data, 'text/xml');
+    if (queue.length > 0)
+      {
+       document.getElementsByTagName ('body')[0].removeChild (iframe);
+       iframe.src = queue[0][0];
+       document.getElementsByTagName ('body')[0].appendChild (iframe);
+      }
+    else
+      {
+       window.removeEventListener ('message', receiver, false);
+       document.getElementsByTagName ('body')[0].removeChild (iframe);
+      }
+    request[1] (xml.firstElement (), request[2]);
+    event.preventDefault ();
+  };
+
+  Xex.Load = function (server, file, callback, arg)
+  {
+    var url = server + '/loadxml.html#' + file;
+    //alert ('loading file:' + file);
+    queue.push ([url, callback, arg]);
+    if (queue.length == 1)
+      {
+       window.addEventListener ('message', receiver, false);
+       iframe = document.createElement ('iframe');
+       iframe.style.display = 'none';
+       iframe.src = url;
+       //alert ('iframe created');
+       document.getElementsByTagName ('body')[0].appendChild (iframe);
+      }
+  }
+}) ();