*** empty log message ***
[m17n/m17n-lib-cs.git] / MExpression.cs
index ccc4878..560a6b1 100644 (file)
@@ -11,26 +11,26 @@ namespace M17N.Core
   {
     public delegate object Evaluator (object[] args, MPlist bindings);
 
-    internal delegate void PrettyPrinter (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 PrettyPrinter pp;
 
       private static PrettyPrinter default_pretty_printer;
       private static PrettyPrinter set_pretty_printer;
-      internal static MFunction literal, varref, block, defun;
+      internal static Function literal, varref, block, defun;
 
-      public MFunction (MSymbol name, Evaluator eval,
-                       int min_arg, int max_arg, params 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;
@@ -43,7 +43,7 @@ namespace M17N.Core
          pp = default_pretty_printer;
       }
 
-      static MFunction ()
+      static Function ()
       {
        default_pretty_printer = new PrettyPrinter (default_pp);
        set_pretty_printer = new PrettyPrinter (set_pp);
@@ -133,20 +133,23 @@ namespace M17N.Core
 
       // Commonly used pretty-printers.
 
-      public static void default_pp (MFunction func,
+      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 (MFunction func, string indent, object[] args)
+      private static void set_pp (Function func, string indent, object[] args)
       {
        Console.Write ("(" + func.name + " " + (MSymbol) args[0] + " ");
        ((MExpression) args[1]).pp (indent);
@@ -424,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;
@@ -442,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 += "  ";
@@ -479,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++)
@@ -487,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 ");
@@ -537,9 +542,10 @@ namespace M17N.Core
              Console.Write (" ");
            ((MExpression) args[i]).pp (indent);
          }
+       Console.Write (")");
       }
 
-      private static object define_function (object[] args, MPlist bindings)
+      public static object define_function (object[] args, MPlist bindings)
       {
        FunctionTable table = (FunctionTable) args[0];
        MSymbol sym = (MSymbol) args[1];
@@ -551,14 +557,14 @@ namespace M17N.Core
        for (int i = 3; i < args.Length; i++)
          data[i - 2] = args[i];
 
-       MFunction func = new MFunction (sym, null, nargs, nargs,
-                                       typeof (MExpression));
+       Function func = new Function (sym, null, nargs, nargs,
+                                     typeof (MExpression));
        table.table[sym] = func;
        func.data = data;
        return null;
       }
 
-      private static void defun_pp (MFunction func,
+      private static void defun_pp (Function func,
                                    string indent, object[] args)
       {
        Console.Write ("(defun " + args[1] + " " + args[2]);
@@ -575,13 +581,36 @@ namespace M17N.Core
              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 ();
@@ -590,34 +619,45 @@ namespace M17N.Core
                              Evaluator evaluator, int min_arg, int max_arg,
                              params Type[] arg_types)
     {
-      MFunction func = Defun (name, evaluator, min_arg, max_arg, arg_types);
+      Function func = Defun (name, evaluator, min_arg, max_arg, arg_types);
       table.table[func.name] = func;
     }
 
-    private static MFunction Defun (string name, Evaluator evaluator,
-                                   int min_arg, int max_arg,
-                                   params Type[] arg_types)
+    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 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))
@@ -632,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,
@@ -645,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 ();
     }
 
@@ -681,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);
     }
 
@@ -695,7 +736,9 @@ 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);
+       throw new Exception (String.Format
+                            ("Invalid number of arguments to {0}: {1}",
+                             function.name, nargs));
 
       int i = 0;
       Type arg_type = typeof (MExpression);
@@ -750,20 +793,20 @@ namespace M17N.Core
          else
            args[i++] = p.val;
        }
-      if (function == MFunction.defun)
+      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;
     }
@@ -775,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]);