*** empty log message ***
[m17n/m17n-lib-cs.git] / MExpression.cs
index 7da715e..560a6b1 100644 (file)
@@ -11,25 +11,26 @@ namespace M17N.Core
   {
     public delegate object Evaluator (object[] args, MPlist bindings);
 
-    internal delegate void PretyPrinter (MFunction func,
-                                        string indent, object[] args);
+    internal delegate void PrettyPrinter (Function func,
+                                         string indent, object[] args);
 
-    internal class MFunction
+    internal class Function
     {
-      internal MSymbol name;
+      internal readonly MSymbol name;
       internal readonly Evaluator eval;
-      internal int min_arg;
-      internal int max_arg;
-      internal Type[] arg_types;
+      internal readonly int min_arg;
+      internal readonly int max_arg;
+      internal readonly Type[] arg_types;
+      internal object[] data;
 
-      public PretyPrinter pp;
+      public PrettyPrinter pp;
 
-      private static PretyPrinter default_prety_printer;
-      private static PretyPrinter set_prety_printer;
-      internal static MFunction literal, varref, block;
+      private static PrettyPrinter default_pretty_printer;
+      private static PrettyPrinter set_pretty_printer;
+      internal static Function literal, varref, block, defun;
 
-      public MFunction (MSymbol name, Evaluator eval,
-                       int min_arg, int max_arg, Type[] arg_types)
+      public Function (MSymbol name, Evaluator eval,
+                      int min_arg, int max_arg, params Type[] arg_types)
       {
        this.name = name;
        this.eval = eval;
@@ -37,15 +38,15 @@ namespace M17N.Core
        this.max_arg = max_arg;
        this.arg_types = (Type []) arg_types.Clone ();
        if (arg_types.Length == 2 && arg_types[0] == typeof (MSymbol))
-         pp = set_prety_printer;
+         pp = set_pretty_printer;
        else
-         pp = default_prety_printer;
+         pp = default_pretty_printer;
       }
 
-      static MFunction ()
+      static Function ()
       {
-       default_prety_printer = new PretyPrinter (default_pp);
-       set_prety_printer = new PretyPrinter (set_pp);
+       default_pretty_printer = new PrettyPrinter (default_pp);
+       set_pretty_printer = new PrettyPrinter (set_pp);
        literal = Defun ("nil", null, 1, 1);
        varref = Defun ("symbol", new Evaluator (get_value), 1, 1);
        block = Defun ("plist", new Evaluator (progn), 1, -1);
@@ -88,20 +89,19 @@ namespace M17N.Core
        Defun (">", new Evaluator (more), 2, -1);
        Defun (">=", new Evaluator (moreeq), 2, -1);
        block = Defun ("progn", new Evaluator (progn), 1, -1);
-       block.pp = new PretyPrinter (block_pp);
+       block.pp = new PrettyPrinter (block_pp);
        Defun ("cond", new Evaluator (cond), 1, -1,
-              typeof (MExpression[])).pp = new PretyPrinter (cond_pp);
+              typeof (MExpression[])).pp = new PrettyPrinter (cond_pp);
        Defun ("if", new Evaluator (ifclause), 2, -1,
-              typeof (MExpression)).pp = new PretyPrinter (if_pp);
+              typeof (MExpression)).pp = new PrettyPrinter (if_pp);
        Defun ("while", new Evaluator (whileclause), 1, -1,
-              typeof (MExpression)).pp = new PretyPrinter (while_pp);
-      }
-
-      public object Call (object[] args, MPlist bindings)
-      {
-       if (name == MSymbol.nil)
-         return args[0];
-       return eval (args, bindings);
+              typeof (MExpression)).pp = new PrettyPrinter (while_pp);
+       defun = Defun ("defun", new Evaluator (define_function), 4, -1,
+                      typeof (FunctionTable),
+                      typeof (MSymbol),
+                      typeof (MPlist),
+                      typeof (MExpression));
+       defun.pp = new PrettyPrinter (defun_pp);
       }
 
       private static MPlist find_binding (object[] args, MPlist bindings)
@@ -114,19 +114,48 @@ namespace M17N.Core
        return slot;
       }
 
-      public static void default_pp (MFunction func,
+      public object Call (object[] args, MPlist bindings)
+      {
+       if (name == MSymbol.nil)
+         return args[0];
+       if (eval != null)
+         return eval (args, bindings);
+
+       MPlist arg_symbols = (MPlist) data[0];
+       for (int i = 0; i < args.Length; i++, arg_symbols = arg_symbols.next)
+         bindings = bindings.Cons (arg_symbols.Symbol,
+                                   ((MExpression) args[i]).Eval (bindings));
+       object result = 0;
+       for (int i = 1; i < data.Length; i++)
+         result = ((MExpression) data[i]).Eval (bindings);
+       return result;
+      }
+
+      // Commonly used pretty-printers.
+
+      public static void default_pp (Function func,
                                     string indent, object[] args)
       {
        Console.Write ("(" + func.name);
        indent += "  ";
-       foreach (MExpression o in args)
+       foreach (object o in args)
          {
            Console.Write (" ");
-           o.pp (indent);
+           if (o is MExpression)
+             ((MExpression) o).pp (indent);
+           else
+             Console.Write (o);
          }
        Console.Write (")");
       }
 
+      private static void set_pp (Function func, string indent, object[] args)
+      {
+       Console.Write ("(" + func.name + " " + (MSymbol) args[0] + " ");
+       ((MExpression) args[1]).pp (indent);
+       Console.Write (")");
+      }
+
       private static object get_value (object[] args, MPlist bindings)
       {
        return find_binding (args, bindings).val;
@@ -145,13 +174,6 @@ namespace M17N.Core
        return slot.val;
       }
 
-      private static void set_pp (MFunction func, string indent, object[] args)
-      {
-       Console.Write ("(set " + (MSymbol) args[0] + " ");
-       ((MExpression) args[1]).pp (indent);
-       Console.Write (")");
-      }
-
       private static object plus (object[] args, MPlist bindings)
       {
        object val = ((MExpression) args[0]).Eval (bindings);
@@ -405,7 +427,7 @@ namespace M17N.Core
        return result;
       }
 
-      private static void block_pp (MFunction func,
+      private static void block_pp (Function func,
                                    string indent, object[] args)
       {
        bool first = true;
@@ -423,19 +445,27 @@ namespace M17N.Core
        Console.Write (")");
       }
 
+      private static bool check_condition (MExpression e, MPlist bindings)
+      {
+       object result = e.Eval (bindings);
+       return (! (result is int) || (int) result != 0);
+      }
+
       private static object cond (object[] args, MPlist bindings)
       {
        foreach (MExpression[] elist in args)
-         {
-           int i = (int) elist[0].Eval (bindings);
-           if (i != 0)
-             return progn ((object[]) elist, bindings);
-         }
+         if (check_condition (elist[0], bindings))
+           {
+             object result = 0;
+             for (int i = 1; i < elist.Length; i++)
+               result = elist[i].Eval (bindings);
+             return result;
+           }
        return 0;
       }
 
-      private static void cond_pp (MFunction func,
-                                   string indent, object[] args)
+      private static void cond_pp (Function func,
+                                  string indent, object[] args)
       {
        Console.Write ("(cond");
        indent += "  ";
@@ -460,7 +490,7 @@ namespace M17N.Core
       {
        object result = 0;
 
-       if ((int) ((MExpression) args[0]).Eval (bindings) != 0)
+       if (check_condition ((MExpression) args[0], bindings))
          result = ((MExpression) args[1]).Eval (bindings);
        else
          for (int i = 2; i < args.Length; i++)
@@ -468,39 +498,33 @@ namespace M17N.Core
        return result;
       }
 
-      private static void if_pp (MFunction func,
+      private static void if_pp (Function func,
                                 string indent, object[] args)
       {
        Console.Write ("(if ");
        ((MExpression) args[0]).pp (indent + "    ");
        Console.Write ("\n" + indent + "    ");
        ((MExpression) args[1]).pp (indent + "    ");
-       bool first = true;
        indent += "  ";
        for (int i = 2; i < args.Length; i++)
          {
-           if (first)
-             {
-               Console.Write ("\n" + indent);
-               first = false;
-             }
-           else
-             Console.Write (" ");
+           Console.Write ("\n" + indent);
            ((MExpression) args[i]).pp (indent);
          }
+       Console.Write (")");
       }
 
       private static object whileclause (object[] args, MPlist bindings)
       {
        object result = 0;
 
-       while ((int) ((MExpression) args[0]).Eval (bindings) != 0)
+       while (check_condition ((MExpression) args[0], bindings))
          for (int i = 1; i < args.Length; i++)
            result = ((MExpression) args[i]).Eval (bindings);
        return result;
       }
 
-      private static void while_pp (MFunction func,
+      private static void while_pp (Function func,
                                    string indent, object[] args)
       {
        Console.Write ("(while ");
@@ -518,13 +542,75 @@ namespace M17N.Core
              Console.Write (" ");
            ((MExpression) args[i]).pp (indent);
          }
+       Console.Write (")");
+      }
+
+      public static object define_function (object[] args, MPlist bindings)
+      {
+       FunctionTable table = (FunctionTable) args[0];
+       MSymbol sym = (MSymbol) args[1];
+       MPlist arg_symbols = (MPlist) args[2];
+       int nargs = arg_symbols.Count;
+       object[] data = new object[args.Length - 2];
+
+       data[0] = args[2];
+       for (int i = 3; i < args.Length; i++)
+         data[i - 2] = args[i];
+
+       Function func = new Function (sym, null, nargs, nargs,
+                                     typeof (MExpression));
+       table.table[sym] = func;
+       func.data = data;
+       return null;
+      }
+
+      private static void defun_pp (Function func,
+                                   string indent, object[] args)
+      {
+       Console.Write ("(defun " + args[1] + " " + args[2]);
+       bool first = true;
+       indent += "  ";
+       for (int i = 3; i < args.Length; i++)
+         {
+           if (first)
+             {
+               Console.Write ("\n" + indent);
+               first = false;
+             }
+           else
+             Console.Write (" ");
+           ((MExpression) args[i]).pp (indent);
+         }
+       Console.Write (")");
       }
     }
 
     public class FunctionTable
     {
-      internal Dictionary<MSymbol, MFunction> table
-       = new Dictionary<MSymbol, MFunction> ();
+      internal Dictionary<MSymbol, Function> table;
+
+      public FunctionTable ()
+      {
+       table = new Dictionary<MSymbol, Function> ();
+      }
+
+      public FunctionTable (FunctionTable table)
+      {
+       this.table = new Dictionary<MSymbol, Function> (table.table);
+      }
+
+      public void Copy (FunctionTable table)
+      {
+       foreach (KeyValuePair<MSymbol, Function> kv in this.table)
+         table.table[kv.Key] = kv.Value;
+      }
+
+      public void Copy (MSymbol name, FunctionTable table)
+      {
+       Function func;
+       if (this.table.TryGetValue (name, out func))
+         table.table[name] = func;
+      }
     }
 
     private static FunctionTable basic_table = new FunctionTable ();
@@ -533,36 +619,45 @@ namespace M17N.Core
                              Evaluator evaluator, int min_arg, int max_arg,
                              params Type[] arg_types)
     {
-      MSymbol sym = MSymbol.Of (name);
-      MFunction func = new MFunction (sym, evaluator, min_arg, max_arg,
-                                     arg_types);
-      table.table[sym] = func;
+      Function func = Defun (name, evaluator, min_arg, max_arg, arg_types);
+      table.table[func.name] = func;
+    }
+
+    public static void Defmacro (FunctionTable table, MSymbol name,
+                                MExpression expr)
+    {
+      object[] args = new object[4];
+      args[0] = table;
+      args[1] = name;
+      args[2] = new MPlist ();
+      args[3] = expr;
+      Function.define_function (args, null);
     }
 
-    private static MFunction Defun (string name, Evaluator evaluator,
-                                   int min_arg, int max_arg,
-                                   params Type[] arg_types)
+    private static Function Defun (string name, Evaluator evaluator,
+                                  int min_arg, int max_arg,
+                                  params Type[] arg_types)
     {
       MSymbol sym = MSymbol.Of (name);
-      MFunction func = new MFunction (sym, evaluator, min_arg, max_arg,
-                                     arg_types);
+      Function func = new Function (sym, evaluator, min_arg, max_arg,
+                                   arg_types);
       basic_table.table[sym] = func;
       return func;
     }
 
-    private static MFunction Defun (string name, Evaluator evaluator,
-                                   int min_arg, int max_arg)
+    private static Function Defun (string name, Evaluator evaluator,
+                                  int min_arg, int max_arg)
     {
       return Defun (name, evaluator, min_arg, max_arg, typeof (MExpression));
     }
 
-    private static MFunction Find (MSymbol name, FunctionTable table)
+    private static Function Find (MSymbol name, FunctionTable table)
     {
       if (name == MSymbol.integer
          || name == MSymbol.mtext)
-       return MFunction.literal;
+       return Function.literal;
 
-      MFunction func;
+      Function func;
       if ((table == null
           || ! table.table.TryGetValue (name, out func))
          && ! basic_table.table.TryGetValue (name, out func))
@@ -577,10 +672,11 @@ namespace M17N.Core
 
     private void invalid_argument (object o)
     {
-      throw new Exception ("Invalid argument: " + o);
+      throw new Exception (String.Format ("Invalid argument to {0}: {1}",
+                                         function.name, o));
     }
 
-    private MFunction function;
+    private Function function;
     private object[] args;
 
     public MExpression (MSymbol function_name, object[] args,
@@ -590,7 +686,7 @@ namespace M17N.Core
       int nargs = args.Length;
       if (nargs < function.min_arg
          || (function.max_arg >= 0 && nargs > function.max_arg))
-       throw new Exception ("Invalid number of arguments: " + args);
+       throw new Exception (String.Format ("Invalid number of arguments to {0}: {1}", function.name, nargs));
       this.args = (object[]) args.Clone ();
     }
 
@@ -626,7 +722,7 @@ namespace M17N.Core
     // EXPRLIST: PLIST = EXPR ...
     public MExpression (MPlist plist, FunctionTable table)
     {
-      function = MFunction.block;
+      function = Function.block;
       args = expression_list (plist, table);
     }
 
@@ -640,11 +736,27 @@ namespace M17N.Core
       int nargs = arg_list.Count;
       if (nargs < function.min_arg
          || (function.max_arg >= 0 && nargs > function.max_arg))
-       throw new Exception ("Invalid number of arguments: " + nargs);
-      args = new object[nargs];
+       throw new Exception (String.Format
+                            ("Invalid number of arguments to {0}: {1}",
+                             function.name, nargs));
 
       int i = 0;
       Type arg_type = typeof (MExpression);
+      if (function.arg_types.Length > 0)
+       {
+         arg_type = function.arg_types[0];
+         if (arg_type == typeof (FunctionTable))
+           {
+             nargs++;
+             args = new object[nargs];
+             args[i++] = table;
+           }
+         else
+           args = new object[nargs];
+       }
+      else
+       args = new object[nargs];
+
       foreach (MPlist p in arg_list)
        {
          if (i < function.arg_types.Length)
@@ -681,18 +793,20 @@ namespace M17N.Core
          else
            args[i++] = p.val;
        }
+      if (function == Function.defun)
+       function.Call (args, null);
     }
 
     public MExpression (MSymbol sym)
     {
-      function = MFunction.varref;
+      function = Function.varref;
       args = new object[1];
       args[0] = sym;
     }
 
     public MExpression (object obj)
     {
-      function = MFunction.literal;
+      function = Function.literal;
       args = new object[1];
       args[0] = obj;
     }
@@ -704,8 +818,8 @@ namespace M17N.Core
 
     private void pp (string indent)
     {
-      if (function == MFunction.varref
-         || function == MFunction.literal)
+      if (function == Function.varref
+         || function == Function.literal)
        {
          if (args[0] is MText)
            Console.Write ("\"{0}\"", args[0]);
@@ -716,6 +830,6 @@ namespace M17N.Core
        function.pp (function, indent, args);
     }
 
-    public void PretyPrint () { pp (""); }
+    public void PrettyPrint () { pp (""); }
   }
 }