*** empty log message ***
[m17n/m17n-lib-cs.git] / MExpression.cs
index 3c43747..560a6b1 100644 (file)
@@ -7,128 +7,829 @@ using M17N.Core;
 
 namespace M17N.Core
 {
-  public delegate object MEvaluator (MExpression args);
-
-  public class MFunction
+  public class MExpression
   {
-    internal readonly MSymbol name;
-    internal readonly MEvaluator evaluator;
-    public static Dictionary<MSymbol, MFunction> CommonTable
-      = new Dictionary<MSymbol, MFunction> ();
+    public delegate object Evaluator (object[] args, MPlist bindings);
+
+    internal delegate void PrettyPrinter (Function func,
+                                         string indent, object[] args);
+
+    internal class Function
+    {
+      internal readonly MSymbol name;
+      internal readonly Evaluator eval;
+      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 Function literal, varref, block, defun;
+
+      public Function (MSymbol name, Evaluator eval,
+                      int min_arg, int max_arg, params Type[] arg_types)
+      {
+       this.name = name;
+       this.eval = eval;
+       this.min_arg = min_arg;
+       this.max_arg = max_arg;
+       this.arg_types = (Type []) arg_types.Clone ();
+       if (arg_types.Length == 2 && arg_types[0] == typeof (MSymbol))
+         pp = set_pretty_printer;
+       else
+         pp = default_pretty_printer;
+      }
+
+      static Function ()
+      {
+       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);
+
+       Defun ("set", new Evaluator (set_value), 2, 2,
+              typeof (MSymbol), typeof (MExpression));
+       Defun ("=", new Evaluator (set_value), 2, 2,
+              typeof (MSymbol), typeof (MExpression));
+       Defun ("+", new Evaluator (plus), 1, -1);
+       Defun ("*", new Evaluator (multi), 2, -1);
+       Defun ("-", new Evaluator (minus), 1, -1);
+       Defun ("/", new Evaluator (divide), 2, -1);
+       Defun ("%", new Evaluator (percent), 2, -1);
+       Defun ("|", new Evaluator (logior), 2, -1);
+       Defun ("&", new Evaluator (logand), 2, -1);
+       Defun ("+=", new Evaluator (pluseq), 2, -1,
+              typeof (MSymbol), typeof (MExpression));
+       Defun ("*=", new Evaluator (multieq), 2, -1,
+              typeof (MSymbol), typeof (MExpression));
+       Defun ("-=", new Evaluator (minuseq), 2, -1,
+              typeof (MSymbol), typeof (MExpression));
+       Defun ("/=", new Evaluator (divideeq), 2, -1,
+              typeof (MSymbol), typeof (MExpression));
+       Defun ("%=", new Evaluator (percenteq), 2, -1,
+              typeof (MSymbol), typeof (MExpression));
+       Defun ("|=", new Evaluator (logioreq), 2, -1,
+              typeof (MSymbol), typeof (MExpression));
+       Defun ("&=", new Evaluator (logandeq), 2, -1,
+              typeof (MSymbol), typeof (MExpression));
+       Defun ("<<", new Evaluator (lshift), 2, 2);
+       Defun (">>", new Evaluator (rshift), 2, 2);
+       Defun ("<<=", new Evaluator (lshifteq), 2, 2,
+              typeof (MSymbol), typeof (MExpression));
+       Defun (">>=", new Evaluator (rshifteq), 2, 2,
+              typeof (MSymbol), typeof (MExpression));
+       Defun ("==", new Evaluator (eq), 2, -1);
+       Defun ("!=", new Evaluator (noteq), 2, 2);
+       Defun ("<", new Evaluator (less), 2, -1);
+       Defun ("<=", new Evaluator (lesseq), 2, -1);
+       Defun (">", new Evaluator (more), 2, -1);
+       Defun (">=", new Evaluator (moreeq), 2, -1);
+       block = Defun ("progn", new Evaluator (progn), 1, -1);
+       block.pp = new PrettyPrinter (block_pp);
+       Defun ("cond", new Evaluator (cond), 1, -1,
+              typeof (MExpression[])).pp = new PrettyPrinter (cond_pp);
+       Defun ("if", new Evaluator (ifclause), 2, -1,
+              typeof (MExpression)).pp = new PrettyPrinter (if_pp);
+       Defun ("while", new Evaluator (whileclause), 1, -1,
+              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)
+      {
+       MSymbol var = (MSymbol) args[0];
+       MPlist slot = bindings.Find (var);
+
+       if (slot == null)
+         throw new Exception ("Unbound variable: " + var);
+       return slot;
+      }
+
+      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 (object o in args)
+         {
+           Console.Write (" ");
+           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;
+      }
+
+      private static object set_value (object[] args, MPlist bindings)
+      {
+       MSymbol var = (MSymbol) args[0];
+       MPlist slot = bindings.Find (var);
+
+       if (slot == null)
+         slot = bindings.Push (var, null);
+       slot.val = ((MExpression) args[1]).Eval (bindings);
+       if (slot.val is MText)
+         slot.val = ((MText) slot.val).Dup ();
+       return slot.val;
+      }
+
+      private static object plus (object[] args, MPlist bindings)
+      {
+       object val = ((MExpression) args[0]).Eval (bindings);
+
+       if (val is int)
+         {
+           int n = 0;
+           foreach (MExpression e in args)
+             n += (int) e.Eval (bindings);
+           val = n;
+         }
+       else if (val is MText)
+         {
+           MText mt = new MText ();
+           foreach (MExpression e in args)
+             mt += (MText) e.Eval (bindings);
+           val = mt;
+         }
+       return val;
+      }
+
+      private static object multi (object[] args, MPlist bindings)
+      {
+       int n = 1;
+       foreach (MExpression e in args)
+         n *= (int) e.Eval (bindings);
+       return n;
+      }
+
+      private static object minus (object[] args, MPlist bindings)
+      {
+       int n = (int) ((MExpression) args[0]).Eval (bindings);
+       if (args.Length == 1)
+         return - n;
+       for (int i = 1; i < args.Length; i++)
+         n -= (int) ((MExpression) args[i]).Eval (bindings);
+       return n;
+      }
+
+      private static object divide (object[] args, MPlist bindings)
+      {
+       int n = (int) ((MExpression) args[0]).Eval (bindings);
+       for (int i = 1; i < args.Length; i++)
+         n /= (int) ((MExpression) args[i]).Eval (bindings);
+       return n;
+      }
+
+      private static object percent (object[] args, MPlist bindings)
+      {
+       int n = (int) ((MExpression) args[0]).Eval (bindings);
+       for (int i = 1; i < args.Length; i++)
+         n %= (int) ((MExpression) args[i]).Eval (bindings);
+       return n;
+      }
+
+      private static object logior (object[] args, MPlist bindings)
+      {
+       int n = (int) ((MExpression) args[0]).Eval (bindings);
+       for (int i = 1; i < args.Length; i++)
+         n |= (int) ((MExpression) args[i]).Eval (bindings);
+       return n;
+      }
+
+      private static object logand (object[] args, MPlist bindings)
+      {
+       int n = (int) ((MExpression) args[0]).Eval (bindings);
+       for (int i = 1; i < args.Length; i++)
+         n &= (int) ((MExpression) args[i]).Eval (bindings);
+       return n;
+      }
+
+      private static object pluseq (object[] args, MPlist bindings)
+      {
+       MPlist slot = find_binding (args, bindings);
+       object val = slot.val;
+
+       if (val is int)
+         {
+           int n = (int) val;
+           for (int i = 1; i < args.Length; i++)
+             n += (int) ((MExpression) args[i]).Eval (bindings);
+           slot.val = n;
+         }
+       else if (val is MText)
+         {
+           MText mt = (MText) val;
+           for (int i = 1; i < args.Length; i++)
+             mt.Cat ((MText) ((MExpression) args[i]).Eval (bindings));
+         }
+       return slot.val;
+      }
+
+      private static object multieq (object[] args, MPlist bindings)
+      {
+       MPlist slot = find_binding (args, bindings);
+       int n = (int) slot.val;
+       for (int i = 1; i < args.Length; i++)
+         n *= (int) ((MExpression) args[i]).Eval (bindings);
+       return (slot.val = n);
+      }
+
+      private static object minuseq (object[] args, MPlist bindings)
+      {
+       MPlist slot = find_binding (args, bindings);
+       int n = (int) slot.val;
+       for (int i = 1; i < args.Length; i++)
+         n -= (int) ((MExpression) args[i]).Eval (bindings);
+       return (slot.val = n);
+      }
+
+      private static object divideeq (object[] args, MPlist bindings)
+      {
+       MPlist slot = find_binding (args, bindings);
+       int n = (int) slot.val;
+       for (int i = 1; i < args.Length; i++)
+         n /= (int) ((MExpression) args[i]).Eval (bindings);
+       return (slot.val = n);
+      }
+
+      private static object percenteq (object[] args, MPlist bindings)
+      {
+       MPlist slot = find_binding (args, bindings);
+       int n = (int) slot.val;
+       for (int i = 1; i < args.Length; i++)
+         n %= (int) ((MExpression) args[i]).Eval (bindings);
+       return (slot.val = n);
+      }
+
+      private static object logioreq (object[] args, MPlist bindings)
+      {
+       MPlist slot = find_binding (args, bindings);
+       int n = (int) slot.val;
+       for (int i = 1; i < args.Length; i++)
+         n |= (int) ((MExpression) args[i]).Eval (bindings);
+       return (slot.val = n);
+      }
+
+      private static object logandeq (object[] args, MPlist bindings)
+      {
+       MPlist slot = find_binding (args, bindings);
+       int n = (int) slot.val;
+       for (int i = 1; i < args.Length; i++)
+         n &= (int) ((MExpression) args[i]).Eval (bindings);
+       return (slot.val = n);
+      }
+
+      private static object lshift (object[] args, MPlist bindings)
+      {
+       int n1 = (int) ((MExpression) args[0]).Eval (bindings);
+       int n2 = (int) ((MExpression) args[1]).Eval (bindings);
+       return n1 << n2;
+      }
+
+      private static object lshifteq (object[] args, MPlist bindings)
+      {
+       MPlist slot = find_binding (args, bindings);
+       int n1 = (int) slot.val;
+       int n2 = (int) ((MExpression) args[1]).Eval (bindings);
+       return (slot.val = (n1 << n2));
+      }
+
+      private static object rshift (object[] args, MPlist bindings)
+      {
+       int n1 = (int) ((MExpression) args[0]).Eval (bindings);
+       int n2 = (int) ((MExpression) args[1]).Eval (bindings);
+       return n1 >> n2;
+      }
+
+      private static object rshifteq (object[] args, MPlist bindings)
+      {
+       MPlist slot = find_binding (args, bindings);
+       int n1 = (int) slot.val;
+       int n2 = (int) ((MExpression) args[1]).Eval (bindings);
+       return (slot.val = (n1 >> n2));
+      }
+
+      private static object eq (object[] args, MPlist bindings)
+      {
+       int n = (int) ((MExpression) args[0]).Eval (bindings);
+       for (int i = 1; i < args.Length; i++)
+         if (n != (int) ((MExpression) args[i]).Eval (bindings))
+           return 0;
+       return 1;
+      }
+
+      private static object noteq (object[] args, MPlist bindings)
+      {
+       int n1 = (int) ((MExpression) args[0]).Eval (bindings);
+       int n2 = (int) ((MExpression) args[1]).Eval (bindings);
+       return (n1 != n2);
+      }
+
+      private static object less (object[] args, MPlist bindings)
+      {
+       int n = (int) ((MExpression) args[0]).Eval (bindings);
+       for (int i = 1; i < args.Length; i++)
+         {
+           int n1 = (int) ((MExpression) args[i]).Eval (bindings);
+           if (n >= n1)
+             return 0;
+           n = n1;
+         }
+       return 1;
+      }
+
+      private static object lesseq (object[] args, MPlist bindings)
+      {
+       int n = (int) ((MExpression) args[0]).Eval (bindings);
+       for (int i = 1; i < args.Length; i++)
+         {
+           int n1 = (int) ((MExpression) args[i]).Eval (bindings);
+           if (n > n1)
+             return 0;
+           n = n1;
+         }
+       return 1;
+      }
+
+      private static object more (object[] args, MPlist bindings)
+      {
+       int n = (int) ((MExpression) args[0]).Eval (bindings);
+       for (int i = 1; i < args.Length; i++)
+         {
+           int n1 = (int) ((MExpression) args[i]).Eval (bindings);
+           if (n <= n1)
+             return 0;
+           n = n1;
+         }
+       return 1;
+      }
 
-    public MFunction (MSymbol name, MEvaluator evaluator)
+      private static object moreeq (object[] args, MPlist bindings)
+      {
+       int n = (int) ((MExpression) args[0]).Eval (bindings);
+       for (int i = 1; i < args.Length; i++)
+         {
+           int n1 = (int) ((MExpression) args[i]).Eval (bindings);
+           if (n < n1)
+             return 0;
+           n = n1;
+         }
+       return 1;
+      }
+
+      private static object progn (object[] args, MPlist bindings)
+      {
+       object result = null;
+
+       foreach (MExpression e in args)
+         result = e.Eval (bindings);
+       return result;
+      }
+
+      private static void block_pp (Function func,
+                                   string indent, object[] args)
+      {
+       bool first = true;
+
+       Console.Write ("(");
+       indent += " ";
+       foreach (MExpression e in args)
+         {
+           if (first)
+             first = false;
+           else
+             Console.Write ("\n" + indent);
+           e.pp (indent);
+         }
+       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)
+         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 (Function func,
+                                  string indent, object[] args)
+      {
+       Console.Write ("(cond");
+       indent += "  ";
+       foreach (MExpression[] expr_list in args)
+         {
+           Console.Write ("\n" + indent + "(");
+           bool first = true;
+           foreach (MExpression e in expr_list)
+             {
+               if (first)
+                 first = false;
+               else
+                 Console.Write (" ");
+               e.pp (indent);
+             }
+           Console.Write (")");
+         }
+       Console.Write (")");
+      }
+
+      private static object ifclause (object[] args, MPlist bindings)
+      {
+       object result = 0;
+
+       if (check_condition ((MExpression) args[0], bindings))
+         result = ((MExpression) args[1]).Eval (bindings);
+       else
+         for (int i = 2; i < args.Length; i++)
+           result = ((MExpression) args[i]).Eval (bindings);
+       return result;
+      }
+
+      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 + "    ");
+       indent += "  ";
+       for (int i = 2; i < args.Length; i++)
+         {
+           Console.Write ("\n" + indent);
+           ((MExpression) args[i]).pp (indent);
+         }
+       Console.Write (")");
+      }
+
+      private static object whileclause (object[] args, MPlist bindings)
+      {
+       object result = 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 (Function func,
+                                   string indent, object[] args)
+      {
+       Console.Write ("(while ");
+       ((MExpression) args[0]).pp (indent + "       ");
+       bool first = true;
+       indent += "  ";
+       for (int i = 1; i < args.Length; i++)
+         {
+           if (first)
+             {
+               Console.Write ("\n" + indent);
+               first = false;
+             }
+           else
+             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, 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 ();
+
+    public static void Defun (FunctionTable table, string name,
+                             Evaluator evaluator, int min_arg, int max_arg,
+                             params Type[] arg_types)
     {
-      this.evaluator = evaluator;
-      CommonTable[name] = this;
+      Function func = Defun (name, evaluator, min_arg, max_arg, arg_types);
+      table.table[func.name] = func;
     }
 
-    public MFunction (MSymbol name, MEvaluator evaluator,
-                     Dictionary<MSymbol, MFunction> dict)
+    public static void Defmacro (FunctionTable table, MSymbol name,
+                                MExpression expr)
     {
-      this.evaluator = evaluator;
-      dict[name] = this;
+      object[] args = new object[4];
+      args[0] = table;
+      args[1] = name;
+      args[2] = new MPlist ();
+      args[3] = expr;
+      Function.define_function (args, null);
     }
 
-    public object Call (MExpression args)
+    private static Function Defun (string name, Evaluator evaluator,
+                                  int min_arg, int max_arg,
+                                  params Type[] arg_types)
     {
-      return evaluator (args);
+      MSymbol sym = MSymbol.Of (name);
+      Function func = new Function (sym, evaluator, min_arg, max_arg,
+                                   arg_types);
+      basic_table.table[sym] = func;
+      return func;
     }
 
-    private object plus (MExpression args)
+    private static Function Defun (string name, Evaluator evaluator,
+                                  int min_arg, int max_arg)
     {
-      int n = 0;
-      foreach (MExpression expr in args)
-       n += expr.Eval (bindings);
-      return n;
+      return Defun (name, evaluator, min_arg, max_arg, typeof (MExpression));
     }
 
-    private object multiply (MExpression args)
+    private static Function Find (MSymbol name, FunctionTable table)
     {
-      int n = 1;
-      foreach (MExpression expr in args)
-       n *= expr.Eval (bindings);
-      return n;
+      if (name == MSymbol.integer
+         || name == MSymbol.mtext)
+       return Function.literal;
+
+      Function func;
+      if ((table == null
+          || ! table.table.TryGetValue (name, out func))
+         && ! basic_table.table.TryGetValue (name, out func))
+       return null;
+      return func;
     }
 
-#if false
-      if (key == Mminus)
-       {
-         int n = - Plist.Eval (env);
-         foreach (MPlist plist in Plist.next)
-           n -= plist.Eval (env);
-         return n;
-       }
-      if (key == Mslash)
-       {
-         int n = Plist.Eval (env);
-         foreach (MPlist plist in Plist.next)
-           n /= plist.Eval (env);
-         return n;
-       }
-      if (key == Mpercent)
-       {
-         return Plist.Eval (env) % Plist.next.Eval (env);
-       }
-      if (key == Mlogior)
-       {
-         return Plist.Eval (env) | Plist.next.Eval (env);
-       }
-      if (key == Mlogand)
-       {
-         return Plist.Eval (env) & Plist.next.Eval (env);
-       }
-      if (key == Mlshift)
+    private void invalid_expression (object o)
+    {
+      throw new Exception ("Invalid expresssion: " + o);
+    }
+
+    private void invalid_argument (object o)
+    {
+      throw new Exception (String.Format ("Invalid argument to {0}: {1}",
+                                         function.name, o));
+    }
+
+    private Function function;
+    private object[] args;
+
+    public MExpression (MSymbol function_name, object[] args,
+                       FunctionTable function_table)
+    {
+      function = Find (function_name, function_table);
+      int nargs = args.Length;
+      if (nargs < function.min_arg
+         || (function.max_arg >= 0 && nargs > function.max_arg))
+       throw new Exception (String.Format ("Invalid number of arguments to {0}: {1}", function.name, nargs));
+      this.args = (object[]) args.Clone ();
+    }
+
+    private MExpression[] expression_list (MPlist plist, FunctionTable table)
+    {
+      int len = plist.Count;
+      MExpression[] expr_list = new MExpression[len];
+
+      for (int i = 0; i < len; i++, plist = plist.next)
        {
-         return Plist.Eval (env) << Plist.next.Eval (env);
+         if (plist.IsSymbol)
+           expr_list[i] = new MExpression (plist.Symbol);
+         else if (plist.IsMText || plist.IsInteger)
+           expr_list[i] = new MExpression (plist.val);
+         else if (plist.IsPlist)
+           {
+             MPlist p = plist.Plist;
+             if (p.IsSymbol)
+               expr_list[i] = new MExpression (p.Symbol, p.next, table);
+             else
+               expr_list[i] = new MExpression (p, table);
+           }
+         else
+           invalid_expression (plist.val);
        }
-      if (key == Mrshift)
+      return expr_list;
+    }
+
+    // EXPR = SYMBOL | MTEXT | INTEGER | FUNCALL | EXPRLIST
+    // FUNCALL = '(' SYMBOL EXPR* ')'
+    // EXPRLIST = '(' EXPR* ')'
+
+    // EXPRLIST: PLIST = EXPR ...
+    public MExpression (MPlist plist, FunctionTable table)
+    {
+      function = Function.block;
+      args = expression_list (plist, table);
+    }
+
+    // FUNCALL: NAME = FUNCTION-NAME, ARG-LIST = EXPR ...
+    private MExpression (MSymbol name, MPlist arg_list, FunctionTable table)
+    {
+      function = Find (name, table);
+      if (function == null)
+       throw new Exception ("Unknown function: " + name);
+
+      int nargs = arg_list.Count;
+      if (nargs < function.min_arg
+         || (function.max_arg >= 0 && nargs > function.max_arg))
+       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)
        {
-         return Plist.Eval (env) >> Plist.next.Eval (env);
+         arg_type = function.arg_types[0];
+         if (arg_type == typeof (FunctionTable))
+           {
+             nargs++;
+             args = new object[nargs];
+             args[i++] = table;
+           }
+         else
+           args = new object[nargs];
        }
-      if (key == Mset)
-       {
-         MSymbol var = (MSymbol) Plist.val;
+      else
+       args = new object[nargs];
 
+      foreach (MPlist p in arg_list)
+       {
+         if (i < function.arg_types.Length)
+           arg_type = function.arg_types[i];
+         if (arg_type == typeof (MExpression))
+           {
+             if (p.IsSymbol)
+               args[i++] = new MExpression (p.Symbol);
+             else if (p.IsMText || p.IsInteger)
+               args[i++] = new MExpression (p.val);
+             else if (p.IsPlist)
+               {
+                 MPlist p0 = p.Plist;
+                 if (p0.IsSymbol)
+                   args[i++] = new MExpression (p0.Symbol, p0.next, table);
+                 else
+                   args[i++] = new MExpression (p0, table);
+               }
+             else
+               invalid_expression (p.val);
+           }
+         else if (arg_type == typeof (MExpression[]))
+           {
+             if (! p.IsPlist)
+               invalid_argument (p.val);
+             args[i++] = expression_list (p.Plist, table);
+           }
+         else if (arg_type == typeof (MSymbol))
+           {
+             if (! p.IsSymbol)
+               invalid_argument (p.val);
+             args[i++] = p.Symbol;
+           }
+         else
+           args[i++] = p.val;
        }
-#endif
-  }
-
-  public class MBindings : MPlist
-  {
-    public MBindings () : base () { }
+      if (function == Function.defun)
+       function.Call (args, null);
+    }
 
-    public new MBindings Push (MSymbol variable, object value)
+    public MExpression (MSymbol sym)
     {
-      base.Push (variable, value);
+      function = Function.varref;
+      args = new object[1];
+      args[0] = sym;
     }
 
-    public override string ToString ()
-      {
-       string str = "(";
-       foreach (MBindings b in this)
-         {
-           if (b != this)
-             str += ", ";
-           str += b.key + " = " + b.val;
-         }
-       return str + ")";
-      }
-  }
-
-  public class MExpression : MPlist
-  {
-    public MExpression () : base () { }
-
-    public MExpression Append (MFunction func, MExpression args)
+    public MExpression (object obj)
     {
-      base.Add (op, (MPlist) args);
-      return this;
+      function = Function.literal;
+      args = new object[1];
+      args[0] = obj;
     }
 
-    public object Eval ()
+    public object Eval (MPlist bindings)
     {
-      
+      return function.Call (args, bindings);
+    }
 
+    private void pp (string indent)
+    {
+      if (function == Function.varref
+         || function == Function.literal)
+       {
+         if (args[0] is MText)
+           Console.Write ("\"{0}\"", args[0]);
+         else
+           Console.Write (args[0]);
+       }
+      else
+       function.pp (function, indent, args);
     }
+
+    public void PrettyPrint () { pp (""); }
   }
-}
\ No newline at end of file
+}