2acb104ec1268cb3dad8e3311f0ff15c0c68ad59
[m17n/m17n-lib-cs.git] / MExpression.cs
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.IO;
5 using M17N;
6 using M17N.Core;
7
8 namespace M17N.Core
9 {
10   public class MExpression
11   {
12     public delegate object Evaluator (object[] args, MPlist bindings,
13                                       object context);
14
15     internal delegate void PrettyPrinter (Function func,
16                                           string indent, object[] args);
17
18     public enum ArgType
19       {
20         FIXED,
21         MANY,
22         UNEVALLED,
23       };
24
25     internal class Function
26     {
27       internal readonly MSymbol name;
28       internal readonly Evaluator eval;
29       internal readonly int min_arg;
30       internal readonly ArgType arg_type;
31       internal object[] data;
32
33       public PrettyPrinter pp;
34
35       private static PrettyPrinter default_pretty_printer;
36       private static PrettyPrinter set_pretty_printer;
37       internal static Function literal, varref, block, defun;
38
39       public Function (MSymbol name, Evaluator eval,
40                        int min_arg, enum ArgType arg_type)
41       {
42         this.name = name;
43         this.eval = eval;
44         this.min_arg = min_arg;
45         this.arg_type = arg_type;
46         if (min_arg == 2 && arg_type = ArgType.FIXED)
47           pp = set_pretty_printer;
48         else
49           pp = default_pretty_printer;
50       }
51
52       static Function ()
53       {
54         default_pretty_printer = new PrettyPrinter (default_pp);
55         set_pretty_printer = new PrettyPrinter (set_pp);
56         literal = Defun ("nil", null, 1, 1);
57         varref = Defun ("symbol", new Evaluator (get_value), 1, 1);
58         block = Defun ("plist", new Evaluator (progn), 1, -1);
59
60         Defun ("set", new Evaluator (set_value), 2, 2,
61                typeof (MSymbol), typeof (MExpression));
62         Defun ("=", new Evaluator (set_value), 2, 2,
63                typeof (MSymbol), typeof (MExpression));
64         Defun ("+", new Evaluator (plus), 1, -1);
65         Defun ("*", new Evaluator (multi), 2, -1);
66         Defun ("-", new Evaluator (minus), 1, -1);
67         Defun ("/", new Evaluator (divide), 2, -1);
68         Defun ("%", new Evaluator (percent), 2, -1);
69         Defun ("|", new Evaluator (logior), 2, -1);
70         Defun ("&", new Evaluator (logand), 2, -1);
71         Defun ("+=", new Evaluator (pluseq), 2, -1,
72                typeof (MSymbol), typeof (MExpression));
73         Defun ("*=", new Evaluator (multieq), 2, -1,
74                typeof (MSymbol), typeof (MExpression));
75         Defun ("-=", new Evaluator (minuseq), 2, -1,
76                typeof (MSymbol), typeof (MExpression));
77         Defun ("/=", new Evaluator (divideeq), 2, -1,
78                typeof (MSymbol), typeof (MExpression));
79         Defun ("%=", new Evaluator (percenteq), 2, -1,
80                typeof (MSymbol), typeof (MExpression));
81         Defun ("|=", new Evaluator (logioreq), 2, -1,
82                typeof (MSymbol), typeof (MExpression));
83         Defun ("&=", new Evaluator (logandeq), 2, -1,
84                typeof (MSymbol), typeof (MExpression));
85         Defun ("<<", new Evaluator (lshift), 2, 2);
86         Defun (">>", new Evaluator (rshift), 2, 2);
87         Defun ("<<=", new Evaluator (lshifteq), 2, 2,
88                typeof (MSymbol), typeof (MExpression));
89         Defun (">>=", new Evaluator (rshifteq), 2, 2,
90                typeof (MSymbol), typeof (MExpression));
91         Defun ("==", new Evaluator (eq), 2, -1);
92         Defun ("!=", new Evaluator (noteq), 2, 2);
93         Defun ("<", new Evaluator (less), 2, -1);
94         Defun ("<=", new Evaluator (lesseq), 2, -1);
95         Defun (">", new Evaluator (more), 2, -1);
96         Defun (">=", new Evaluator (moreeq), 2, -1);
97         block = Defun ("progn", new Evaluator (progn), 1, -1);
98         block.pp = new PrettyPrinter (block_pp);
99         Defun ("cond", new Evaluator (cond), 1, -1,
100                typeof (MExpression[])).pp = new PrettyPrinter (cond_pp);
101         Defun ("if", new Evaluator (ifclause), 2, -1,
102                typeof (MExpression)).pp = new PrettyPrinter (if_pp);
103         Defun ("while", new Evaluator (whileclause), 1, -1,
104                typeof (MExpression)).pp = new PrettyPrinter (while_pp);
105         defun = Defun ("defun", new Evaluator (define_function), 4, -1,
106                        typeof (FunctionTable),
107                        typeof (MSymbol),
108                        typeof (MPlist),
109                        typeof (MExpression));
110         defun.pp = new PrettyPrinter (defun_pp);
111       }
112
113       private static MPlist find_binding (object[] args, MPlist bindings)
114       {
115         MSymbol var = (MSymbol) args[0];
116         MPlist slot = bindings.Find (var);
117
118         if (slot == null)
119           throw new Exception ("Unbound variable: " + var);
120         return slot;
121       }
122
123       public object Call (object[] args, MPlist bindings, object context)
124       {
125         if (name == MSymbol.nil)
126           return args[0];
127         if (eval != null)
128           return eval (args, bindings, context);
129
130         MPlist arg_symbols = (MPlist) data[0];
131         for (int i = 0; i < args.Length; i++, arg_symbols = arg_symbols.next)
132           bindings = bindings.Cons (arg_symbols.Symbol,
133                                     ((MExpression) args[i]).Eval (bindings,
134                                                                   context));
135         object result = 0;
136         for (int i = 1; i < data.Length; i++)
137           result = ((MExpression) data[i]).Eval (bindings, context);
138         return result;
139       }
140
141       // Commonly used pretty-printers.
142
143       public static void default_pp (Function func,
144                                      string indent, object[] args)
145       {
146         Console.Write ("(" + func.name);
147         indent += "  ";
148         foreach (object o in args)
149           {
150             Console.Write (" ");
151             if (o is MExpression)
152               ((MExpression) o).pp (indent);
153             else
154               Console.Write (o);
155           }
156         Console.Write (")");
157       }
158
159       private static void set_pp (Function func, string indent, object[] args)
160       {
161         Console.Write ("(" + func.name + " " + (MSymbol) args[0] + " ");
162         ((MExpression) args[1]).pp (indent);
163         Console.Write (")");
164       }
165
166       private static object get_value (object[] args, MPlist bindings,
167                                        object context)
168       {
169         return find_binding (args, bindings).val;
170       }
171
172       private static object set_value (object[] args, MPlist bindings,
173                                        object context)
174       {
175         MSymbol var = (MSymbol) args[0];
176         MPlist slot = bindings.Find (var);
177
178         if (slot == null)
179           slot = bindings.Push (var, null);
180         slot.val = ((MExpression) args[1]).Eval (bindings, context);
181         if (slot.val is MText)
182           slot.val = ((MText) slot.val).Dup ();
183         return slot.val;
184       }
185
186       private static object plus (object[] args, MPlist bindings,
187                                   object context)
188       {
189         object val = ((MExpression) args[0]).Eval (bindings, context);
190
191         if (val is int)
192           {
193             int n = 0;
194             foreach (MExpression e in args)
195               n += (int) e.Eval (bindings, context);
196             val = n;
197           }
198         else if (val is MText)
199           {
200             MText mt = new MText ();
201             foreach (MExpression e in args)
202               mt += (MText) e.Eval (bindings, context);
203             val = mt;
204           }
205         return val;
206       }
207
208       private static object multi (object[] args, MPlist bindings,
209                                    object context)
210       {
211         int n = 1;
212         foreach (MExpression e in args)
213           n *= (int) e.Eval (bindings, context);
214         return n;
215       }
216
217       private static object minus (object[] args, MPlist bindings,
218                                    object context)
219       {
220         int n = (int) ((MExpression) args[0]).Eval (bindings, context);
221         if (args.Length == 1)
222           return - n;
223         for (int i = 1; i < args.Length; i++)
224           n -= (int) ((MExpression) args[i]).Eval (bindings, context);
225         return n;
226       }
227
228       private static object divide (object[] args, MPlist bindings,
229                                     object context)
230       {
231         int n = (int) ((MExpression) args[0]).Eval (bindings, context);
232         for (int i = 1; i < args.Length; i++)
233           n /= (int) ((MExpression) args[i]).Eval (bindings, context);
234         return n;
235       }
236
237       private static object percent (object[] args, MPlist bindings,
238                                      object context)
239       {
240         int n = (int) ((MExpression) args[0]).Eval (bindings, context);
241         for (int i = 1; i < args.Length; i++)
242           n %= (int) ((MExpression) args[i]).Eval (bindings, context);
243         return n;
244       }
245
246       private static object logior (object[] args, MPlist bindings,
247                                     object context)
248       {
249         int n = (int) ((MExpression) args[0]).Eval (bindings, context);
250         for (int i = 1; i < args.Length; i++)
251           n |= (int) ((MExpression) args[i]).Eval (bindings, context);
252         return n;
253       }
254
255       private static object logand (object[] args, MPlist bindings,
256                                     object context)
257       {
258         int n = (int) ((MExpression) args[0]).Eval (bindings, context);
259         for (int i = 1; i < args.Length; i++)
260           n &= (int) ((MExpression) args[i]).Eval (bindings, context);
261         return n;
262       }
263
264       private static object pluseq (object[] args, MPlist bindings,
265                                     object context)
266       {
267         MPlist slot = find_binding (args, bindings);
268         object val = slot.val;
269
270         if (val is int)
271           {
272             int n = (int) val;
273             for (int i = 1; i < args.Length; i++)
274               n += (int) ((MExpression) args[i]).Eval (bindings, context);
275             slot.val = n;
276           }
277         else if (val is MText)
278           {
279             MText mt = (MText) val;
280             for (int i = 1; i < args.Length; i++)
281               mt.Cat ((MText) ((MExpression) args[i]).Eval (bindings, context));
282           }
283         return slot.val;
284       }
285
286       private static object multieq (object[] args, MPlist bindings,
287                                      object context)
288       {
289         MPlist slot = find_binding (args, bindings);
290         int n = (int) slot.val;
291         for (int i = 1; i < args.Length; i++)
292           n *= (int) ((MExpression) args[i]).Eval (bindings, context);
293         return (slot.val = n);
294       }
295
296       private static object minuseq (object[] args, MPlist bindings,
297                                      object context)
298       {
299         MPlist slot = find_binding (args, bindings);
300         int n = (int) slot.val;
301         for (int i = 1; i < args.Length; i++)
302           n -= (int) ((MExpression) args[i]).Eval (bindings, context);
303         return (slot.val = n);
304       }
305
306       private static object divideeq (object[] args, MPlist bindings,
307                                       object context)
308       {
309         MPlist slot = find_binding (args, bindings);
310         int n = (int) slot.val;
311         for (int i = 1; i < args.Length; i++)
312           n /= (int) ((MExpression) args[i]).Eval (bindings, context);
313         return (slot.val = n);
314       }
315
316       private static object percenteq (object[] args, MPlist bindings,
317                                        object context)
318       {
319         MPlist slot = find_binding (args, bindings);
320         int n = (int) slot.val;
321         for (int i = 1; i < args.Length; i++)
322           n %= (int) ((MExpression) args[i]).Eval (bindings, context);
323         return (slot.val = n);
324       }
325
326       private static object logioreq (object[] args, MPlist bindings,
327                                       object context)
328       {
329         MPlist slot = find_binding (args, bindings);
330         int n = (int) slot.val;
331         for (int i = 1; i < args.Length; i++)
332           n |= (int) ((MExpression) args[i]).Eval (bindings, context);
333         return (slot.val = n);
334       }
335
336       private static object logandeq (object[] args, MPlist bindings,
337                                       object context)
338       {
339         MPlist slot = find_binding (args, bindings);
340         int n = (int) slot.val;
341         for (int i = 1; i < args.Length; i++)
342           n &= (int) ((MExpression) args[i]).Eval (bindings, context);
343         return (slot.val = n);
344       }
345
346       private static object lshift (object[] args, MPlist bindings,
347                                     object context)
348       {
349         int n1 = (int) ((MExpression) args[0]).Eval (bindings, context);
350         int n2 = (int) ((MExpression) args[1]).Eval (bindings, context);
351         return n1 << n2;
352       }
353
354       private static object lshifteq (object[] args, MPlist bindings,
355                                       object context)
356       {
357         MPlist slot = find_binding (args, bindings);
358         int n1 = (int) slot.val;
359         int n2 = (int) ((MExpression) args[1]).Eval (bindings, context);
360         return (slot.val = (n1 << n2));
361       }
362
363       private static object rshift (object[] args, MPlist bindings,
364                                     object context)
365       {
366         int n1 = (int) ((MExpression) args[0]).Eval (bindings, context);
367         int n2 = (int) ((MExpression) args[1]).Eval (bindings, context);
368         return n1 >> n2;
369       }
370
371       private static object rshifteq (object[] args, MPlist bindings,
372                                       object context)
373       {
374         MPlist slot = find_binding (args, bindings);
375         int n1 = (int) slot.val;
376         int n2 = (int) ((MExpression) args[1]).Eval (bindings, context);
377         return (slot.val = (n1 >> n2));
378       }
379
380       private static object eq (object[] args, MPlist bindings,
381                                 object context)
382       {
383         int n = (int) ((MExpression) args[0]).Eval (bindings, context);
384         for (int i = 1; i < args.Length; i++)
385           if (n != (int) ((MExpression) args[i]).Eval (bindings, context))
386             return 0;
387         return 1;
388       }
389
390       private static object noteq (object[] args, MPlist bindings,
391                                    object context)
392       {
393         int n1 = (int) ((MExpression) args[0]).Eval (bindings, context);
394         int n2 = (int) ((MExpression) args[1]).Eval (bindings, context);
395         return (n1 != n2);
396       }
397
398       private static object less (object[] args, MPlist bindings,
399                                   object context)
400       {
401         int n = (int) ((MExpression) args[0]).Eval (bindings, context);
402         for (int i = 1; i < args.Length; i++)
403           {
404             int n1 = (int) ((MExpression) args[i]).Eval (bindings, context);
405             if (n >= n1)
406               return 0;
407             n = n1;
408           }
409         return 1;
410       }
411
412       private static object lesseq (object[] args, MPlist bindings,
413                                     object context)
414       {
415         int n = (int) ((MExpression) args[0]).Eval (bindings, context);
416         for (int i = 1; i < args.Length; i++)
417           {
418             int n1 = (int) ((MExpression) args[i]).Eval (bindings, context);
419             if (n > n1)
420               return 0;
421             n = n1;
422           }
423         return 1;
424       }
425
426       private static object more (object[] args, MPlist bindings,
427                                   object context)
428       {
429         int n = (int) ((MExpression) args[0]).Eval (bindings, context);
430         for (int i = 1; i < args.Length; i++)
431           {
432             int n1 = (int) ((MExpression) args[i]).Eval (bindings, context);
433             if (n <= n1)
434               return 0;
435             n = n1;
436           }
437         return 1;
438       }
439
440       private static object moreeq (object[] args, MPlist bindings,
441                                     object context)
442       {
443         int n = (int) ((MExpression) args[0]).Eval (bindings, context);
444         for (int i = 1; i < args.Length; i++)
445           {
446             int n1 = (int) ((MExpression) args[i]).Eval (bindings, context);
447             if (n < n1)
448               return 0;
449             n = n1;
450           }
451         return 1;
452       }
453
454       private static object progn (object[] args, MPlist bindings,
455                                    object context)
456       {
457         object result = null;
458
459         foreach (MExpression e in args)
460           result = e.Eval (bindings, context);
461         return result;
462       }
463
464       private static void block_pp (Function func,
465                                     string indent, object[] args)
466       {
467         bool first = true;
468
469         Console.Write ("(");
470         indent += " ";
471         foreach (MExpression e in args)
472           {
473             if (first)
474               first = false;
475             else
476               Console.Write ("\n" + indent);
477             e.pp (indent);
478           }
479         Console.Write (")");
480       }
481
482       private static bool check_condition (MExpression e, MPlist bindings,
483                                            object context)
484       {
485         object result = e.Eval (bindings, context);
486         return (! (result is int) || (int) result != 0);
487       }
488
489       private static object cond (object[] args, MPlist bindings,
490                                   object context)
491       {
492         foreach (MExpression[] elist in args)
493           if (check_condition (elist[0], bindings, context))
494             {
495               object result = 0;
496               for (int i = 1; i < elist.Length; i++)
497                 result = elist[i].Eval (bindings, context);
498               return result;
499             }
500         return 0;
501       }
502
503       private static void cond_pp (Function func,
504                                    string indent, object[] args)
505       {
506         Console.Write ("(cond");
507         indent += "  ";
508         foreach (MExpression[] expr_list in args)
509           {
510             Console.Write ("\n" + indent + "(");
511             bool first = true;
512             foreach (MExpression e in expr_list)
513               {
514                 if (first)
515                   first = false;
516                 else
517                   Console.Write (" ");
518                 e.pp (indent);
519               }
520             Console.Write (")");
521           }
522         Console.Write (")");
523       }
524
525       private static object ifclause (object[] args, MPlist bindings,
526                                       object context)
527       {
528         object result = 0;
529
530         if (check_condition ((MExpression) args[0], bindings, context))
531           result = ((MExpression) args[1]).Eval (bindings, context);
532         else
533           for (int i = 2; i < args.Length; i++)
534             result = ((MExpression) args[i]).Eval (bindings, context);
535         return result;
536       }
537
538       private static void if_pp (Function func,
539                                  string indent, object[] args)
540       {
541         Console.Write ("(if ");
542         ((MExpression) args[0]).pp (indent + "    ");
543         Console.Write ("\n" + indent + "    ");
544         ((MExpression) args[1]).pp (indent + "    ");
545         indent += "  ";
546         for (int i = 2; i < args.Length; i++)
547           {
548             Console.Write ("\n" + indent);
549             ((MExpression) args[i]).pp (indent);
550           }
551         Console.Write (")");
552       }
553
554       private static object whileclause (object[] args, MPlist bindings,
555                                          object context)
556       {
557         object result = 0;
558
559         while (check_condition ((MExpression) args[0], bindings, context))
560           for (int i = 1; i < args.Length; i++)
561             result = ((MExpression) args[i]).Eval (bindings, context);
562         return result;
563       }
564
565       private static void while_pp (Function func,
566                                     string indent, object[] args)
567       {
568         Console.Write ("(while ");
569         ((MExpression) args[0]).pp (indent + "       ");
570         bool first = true;
571         indent += "  ";
572         for (int i = 1; i < args.Length; i++)
573           {
574             if (first)
575               {
576                 Console.Write ("\n" + indent);
577                 first = false;
578               }
579             else
580               Console.Write (" ");
581             ((MExpression) args[i]).pp (indent);
582           }
583         Console.Write (")");
584       }
585
586       public static object define_function (object[] args, MPlist bindings,
587                                             object context)
588       {
589         FunctionTable table = (FunctionTable) args[0];
590         MSymbol sym = (MSymbol) args[1];
591         MPlist arg_symbols = (MPlist) args[2];
592         int nargs = arg_symbols.Count;
593         object[] data = new object[args.Length - 2];
594
595         data[0] = args[2];
596         for (int i = 3; i < args.Length; i++)
597           data[i - 2] = args[i];
598
599         Function func = new Function (sym, null, nargs, nargs,
600                                       typeof (MExpression));
601         table.table[sym] = func;
602         func.data = data;
603         return null;
604       }
605
606       private static void defun_pp (Function func,
607                                     string indent, object[] args)
608       {
609         Console.Write ("(defun " + args[1] + " " + args[2]);
610         bool first = true;
611         indent += "  ";
612         for (int i = 3; i < args.Length; i++)
613           {
614             if (first)
615               {
616                 Console.Write ("\n" + indent);
617                 first = false;
618               }
619             else
620               Console.Write (" ");
621             ((MExpression) args[i]).pp (indent);
622           }
623         Console.Write (")");
624       }
625     }
626
627     public class FunctionTable
628     {
629       internal Dictionary<MSymbol, Function> table;
630
631       public FunctionTable ()
632       {
633         table = new Dictionary<MSymbol, Function> ();
634       }
635
636       public FunctionTable (FunctionTable table)
637       {
638         this.table = new Dictionary<MSymbol, Function> (table.table);
639       }
640
641       public void Copy (FunctionTable table)
642       {
643         foreach (KeyValuePair<MSymbol, Function> kv in this.table)
644           table.table[kv.Key] = kv.Value;
645       }
646
647       public void Copy (MSymbol name, FunctionTable table)
648       {
649         Function func;
650         if (this.table.TryGetValue (name, out func))
651           table.table[name] = func;
652       }
653     }
654
655     private static FunctionTable basic_table = new FunctionTable ();
656
657     public static void Defun (FunctionTable table, string name,
658                               Evaluator evaluator, int min_arg,
659                               enum ArgType arg_type)
660     {
661       Function func = Defun (name, evaluator, min_arg, arg_type);
662       table.table[func.name] = func;
663     }
664
665     public static void Defmacro (FunctionTable table, MSymbol name,
666                                  MExpression expr)
667     {
668       object[] args = new object[4];
669       args[0] = table;
670       args[1] = name;
671       args[2] = new MPlist ();
672       args[3] = expr;
673       Function.define_function (args, null, null);
674     }
675
676     private static Function Defun (string name, Evaluator evaluator,
677                                    int min_arg, enum ArgType arg_type)
678     {
679       MSymbol sym = MSymbol.Of (name);
680       Function func = new Function (sym, evaluator, min_arg, arg_type);
681       basic_table.table[sym] = func;
682       return func;
683     }
684
685     private static Function Defun (string name, Evaluator evaluator,
686                                    int min_arg, enum ArgType arg_type)
687     {
688       return Defun (name, evaluator, min_arg, arg_type, typeof (MExpression));
689     }
690
691     private static Function Find (MSymbol name, FunctionTable table)
692     {
693       if (name == MSymbol.integer
694           || name == MSymbol.mtext)
695         return Function.literal;
696
697       Function func;
698       if ((table == null
699            || ! table.table.TryGetValue (name, out func))
700           && ! basic_table.table.TryGetValue (name, out func))
701         return null;
702       return func;
703     }
704
705     private static void invalid_expression (object o)
706     {
707       throw new Exception ("Invalid expresssion: " + o);
708     }
709
710     private void invalid_argument (object o)
711     {
712       throw new Exception (String.Format ("Invalid argument to {0}: {1}",
713                                           function.name, o));
714     }
715
716     private Function function;
717     private object[] args;
718
719     public MExpression (MSymbol function_name, object[] args,
720                         FunctionTable function_table)
721     {
722       function = Find (function_name, function_table);
723       int nargs = args.Length;
724       if (nargs < function.min_arg
725           || (function.max_arg >= 0 && nargs > function.max_arg))
726         throw new Exception (String.Format ("Invalid number of arguments to {0}: {1}", function.name, nargs));
727       this.args = (object[]) args.Clone ();
728     }
729
730     private static MExpression[] expression_list (MPlist plist,
731                                                   FunctionTable table)
732     {
733       int len = plist.Count;
734       MExpression[] expr_list = new MExpression[len];
735
736       for (int i = 0; i < len; i++, plist = plist.next)
737         {
738           if (plist.IsSymbol)
739             expr_list[i] = new MExpression (plist.Symbol);
740           else if (plist.IsMText || plist.IsInteger)
741             expr_list[i] = new MExpression (plist.val);
742           else if (plist.IsPlist)
743             {
744               MPlist p = plist.Plist;
745               if (p.IsSymbol)
746                 expr_list[i] = new MExpression (p.Symbol, p.next, table);
747               else
748                 expr_list[i] = new MExpression (p, table);
749             }
750           else
751             invalid_expression (plist.val);
752         }
753       return expr_list;
754     }
755
756     // EXPR = SYMBOL | MTEXT | INTEGER | FUNCALL | EXPRLIST
757     // FUNCALL = '(' SYMBOL EXPR* ')'
758     // EXPRLIST = '(' EXPR* ')'
759
760     // EXPRLIST: PLIST = EXPR ...
761     public MExpression (MPlist plist, FunctionTable table)
762     {
763       function = Function.block;
764       args = expression_list (plist, table);
765     }
766
767     // FUNCALL: NAME = FUNCTION-NAME, ARG-LIST = EXPR ...
768     private MExpression (MSymbol name, MPlist arg_list, FunctionTable table)
769     {
770       function = Find (name, table);
771       if (function == null)
772         throw new Exception ("Unknown function: " + name);
773
774       int nargs = arg_list.Count;
775       if (nargs < function.min_arg
776           || (function.max_arg >= 0 && nargs > function.max_arg))
777         throw new Exception (String.Format
778                              ("Invalid number of arguments to {0}: {1}",
779                               function.name, nargs));
780
781       int i = 0;
782       Type arg_type = typeof (MExpression);
783       if (function.arg_types.Length > 0)
784         {
785           arg_type = function.arg_types[0];
786           if (arg_type == typeof (FunctionTable))
787             {
788               nargs++;
789               args = new object[nargs];
790               args[i++] = table;
791             }
792           else
793             args = new object[nargs];
794         }
795       else
796         args = new object[nargs];
797
798       foreach (MPlist p in arg_list)
799         {
800           if (i < function.arg_types.Length)
801             arg_type = function.arg_types[i];
802           if (arg_type == typeof (MExpression))
803             {
804               if (p.IsSymbol)
805                 args[i++] = new MExpression (p.Symbol);
806               else if (p.IsMText || p.IsInteger)
807                 args[i++] = new MExpression (p.val);
808               else if (p.IsPlist)
809                 {
810                   MPlist p0 = p.Plist;
811                   if (p0.IsSymbol)
812                     args[i++] = new MExpression (p0.Symbol, p0.next, table);
813                   else
814                     args[i++] = new MExpression (p0, table);
815                 }
816               else
817                 invalid_expression (p.val);
818             }
819           else if (arg_type == typeof (MExpression[]))
820             {
821               if (! p.IsPlist)
822                 invalid_argument (p.val);
823               args[i++] = expression_list (p.Plist, table);
824             }
825           else if (arg_type == typeof (MSymbol))
826             {
827               if (! p.IsSymbol)
828                 invalid_argument (p.val);
829               args[i++] = p.Symbol;
830             }
831           else
832             args[i++] = p.val;
833         }
834       if (function == Function.defun)
835         function.Call (args, null, null);
836     }
837
838     public MExpression (MSymbol sym)
839     {
840       function = Function.varref;
841       args = new object[1];
842       args[0] = sym;
843     }
844
845     public MExpression (object obj)
846     {
847       function = Function.literal;
848       args = new object[1];
849       args[0] = obj;
850     }
851
852     public object Eval (MPlist bindings, object context)
853     {
854       return function.Call (args, bindings, context);
855     }
856
857     private void pp (string indent)
858     {
859       if (function == Function.varref
860           || function == Function.literal)
861         {
862           if (args[0] is MText)
863             Console.Write ("\"{0}\"", args[0]);
864           else
865             Console.Write (args[0]);
866         }
867       else
868         function.pp (function, indent, args);
869     }
870
871     public void PrettyPrint () { pp (""); }
872   }
873 }