core: Remove gc_show.
[mes.git] / mes.c
1 /* -*-comment-start: "//";comment-end:""-*-
2  * Mes --- Maxwell Equations of Software
3  * Copyright © 2016 Jan Nieuwenhuizen <janneke@gnu.org>
4  *
5  * This file is part of Mes.
6  *
7  * Mes is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or (at
10  * your option) any later version.
11  *
12  * Mes is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Mes.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #define _GNU_SOURCE
22 #include <assert.h>
23 #include <ctype.h>
24 #include <errno.h>
25 #include <limits.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <stdbool.h>
30
31 #define DEBUG 0
32 #define FIXED_PRIMITIVES 1
33
34 int ARENA_SIZE = 100000;
35 int MAX_ARENA_SIZE = 20000000;
36 int GC_SAFETY = 100;
37
38 typedef int SCM;
39 enum type_t {CHAR, FUNCTION, KEYWORD, MACRO, NUMBER, PAIR, SPECIAL, STRING, SYMBOL, REF, VALUES, VECTOR, BROKEN_HEART};
40 typedef SCM (*function0_t) (void);
41 typedef SCM (*function1_t) (SCM);
42 typedef SCM (*function2_t) (SCM, SCM);
43 typedef SCM (*function3_t) (SCM, SCM, SCM);
44 typedef SCM (*functionn_t) (SCM);
45 typedef struct function_t {
46   union {
47     function0_t function0;
48     function1_t function1;
49     function2_t function2;
50     function3_t function3;
51     functionn_t functionn;
52   };
53   int arity;
54 } function;
55 struct scm_t;
56 typedef struct scm_t {
57   enum type_t type;
58   union {
59     char const *name;
60     SCM string;
61     SCM car;
62     SCM ref;
63     int length;
64   };
65   union {
66     int value;
67     int function;
68     SCM cdr;
69     SCM macro;
70     SCM vector;
71     int hits;
72   };
73 } scm;
74
75 scm scm_nil = {SPECIAL, "()"};
76 scm scm_f = {SPECIAL, "#f"};
77 scm scm_t = {SPECIAL, "#t"};
78 scm scm_dot = {SPECIAL, "."};
79 scm scm_arrow = {SPECIAL, "=>"};
80 scm scm_undefined = {SPECIAL, "*undefined*"};
81 scm scm_unspecified = {SPECIAL, "*unspecified*"};
82 scm scm_closure = {SPECIAL, "*closure*"};
83 scm scm_circular = {SPECIAL, "*circular*"};
84 scm scm_label = {SPECIAL, "label"};
85 scm scm_begin = {SPECIAL, "*begin*"};
86
87 scm scm_symbol_dot = {SYMBOL, "*dot*"};
88 scm scm_symbol_lambda = {SYMBOL, "lambda"};
89 scm scm_symbol_begin = {SYMBOL, "begin"};
90 scm scm_symbol_if = {SYMBOL, "if"};
91 scm scm_symbol_define = {SYMBOL, "define"};
92 scm scm_symbol_define_macro = {SYMBOL, "define-macro"};
93 scm scm_symbol_set_x = {SYMBOL, "set!"};
94
95 scm scm_symbol_quote = {SYMBOL, "quote"};
96 scm scm_symbol_quasiquote = {SYMBOL, "quasiquote"};
97 scm scm_symbol_unquote = {SYMBOL, "unquote"};
98 scm scm_symbol_unquote_splicing = {SYMBOL, "unquote-splicing"};
99
100 scm scm_symbol_sc_expand = {SYMBOL, "sc-expand"};
101 scm scm_symbol_macro_expand = {SYMBOL, "macro-expand"};
102 scm scm_symbol_sc_expander_alist = {SYMBOL, "*sc-expander-alist*"};
103 scm scm_symbol_noexpand = {SYMBOL, "noexpand"};
104 scm scm_symbol_syntax = {SYMBOL, "syntax"};
105 scm scm_symbol_quasisyntax = {SYMBOL, "quasisyntax"};
106 scm scm_symbol_unsyntax = {SYMBOL, "unsyntax"};
107 scm scm_symbol_unsyntax_splicing = {SYMBOL, "unsyntax-splicing"};
108
109 scm scm_symbol_call_with_values = {SYMBOL, "call-with-values"};
110 scm scm_symbol_current_module = {SYMBOL, "current-module"};
111 scm scm_symbol_primitive_load = {SYMBOL, "primitive-load"};
112 scm scm_symbol_read_input_file = {SYMBOL, "read-input-file"};
113
114 scm scm_symbol_car = {SYMBOL, "car"};
115 scm scm_symbol_cdr = {SYMBOL, "cdr"};
116 scm scm_symbol_null_p = {SYMBOL, "null?"};
117 scm scm_symbol_eq_p = {SYMBOL, "eq?"};
118 scm scm_symbol_cons = {SYMBOL, "cons"};
119
120 scm char_eof = {CHAR, .name="*eof*", .value=-1};
121 scm char_nul = {CHAR, .name="nul", .value=0};
122 scm char_alarm = {CHAR, .name="alarm", .value=8};
123 scm char_backspace = {CHAR, .name="backspace", .value=8};
124 scm char_tab = {CHAR, .name="tab", .value=9};
125 scm char_newline = {CHAR, .name="newline", .value=10};
126 scm char_vtab = {CHAR, .name="vtab", .value=11};
127 scm char_page = {CHAR, .name="page", .value=12};
128 scm char_return = {CHAR, .name="return", .value=13};
129 scm char_space = {CHAR, .name="space", .value=32};
130
131 scm g_free = {NUMBER, .value=0};
132 scm *g_cells;
133 scm *g_news = 0;
134
135 #include "mes.symbols.h"
136
137 SCM tmp;
138 SCM tmp_num;
139 SCM tmp_num2;
140 SCM tmp_num3;
141 SCM tmp_num4;
142
143 function functions[200];
144 int g_function = 0;
145
146 SCM g_symbols = 0;
147 SCM stack = 0;
148 SCM r0 = 0; // a/env
149 SCM r1 = 0; // param 1
150 SCM r2 = 0; // param 2
151 SCM r3 = 0; // param 3
152
153 #include "display.h"
154 #include "lib.h"
155 #include "math.h"
156 #include "mes.h"
157 #include "posix.h"
158 #include "reader.h"
159 #include "string.h"
160 #include "type.h"
161
162 #define CAR(x) g_cells[x].car
163 #define CDR(x) g_cells[x].cdr
164 #define HITS(x) g_cells[x].hits
165 #define LENGTH(x) g_cells[x].length
166 #define NAME(x) g_cells[x].name
167 #define STRING(x) g_cells[x].string
168 #define TYPE(x) g_cells[x].type
169 #define MACRO(x) g_cells[x].macro
170 #define REF(x) g_cells[x].ref
171 #define VALUE(x) g_cells[x].value
172 #define VECTOR(x) g_cells[x].vector
173 #define FUNCTION(x) functions[g_cells[x].function]
174 #define NCAR(x) g_news[x].car
175 #define NTYPE(x) g_news[x].type
176
177 #define CAAR(x) CAR (CAR (x))
178 #define CDAR(x) CDR (CAR (x))
179 #define CAAR(x) CAR (CAR (x))
180 #define CADAR(x) CAR (CDR (CAR (x)))
181 #define CADDR(x) CAR (CDR (CDR (x)))
182 #define CDADAR(x) CAR (CDR (CAR (CDR (x))))
183 #define CADR(x) CAR (CDR (x))
184
185 #define MAKE_CHAR(n) make_cell (tmp_num_ (CHAR), 0, tmp_num2_ (n))
186 #define MAKE_NUMBER(n) make_cell (tmp_num_ (NUMBER), 0, tmp_num2_ (n))
187 #define MAKE_REF(n) make_cell (tmp_num_ (REF), n, 0);
188 #define MAKE_STRING(x) make_cell (tmp_num_ (STRING), x, 0);
189
190 SCM display_ (FILE* f, SCM x);
191 SCM vm_call (function0_t f, SCM p1, SCM p2, SCM a);
192
193 SCM
194 alloc (int n)
195 {
196   assert (g_free.value + n < ARENA_SIZE);
197   SCM x = g_free.value;
198   g_free.value += n;
199   return x;
200 }
201
202 SCM
203 make_cell (SCM type, SCM car, SCM cdr)
204 {
205   SCM x = alloc (1);
206   assert (TYPE (type) == NUMBER);
207   TYPE (x) = VALUE (type);
208   if (VALUE (type) == CHAR || VALUE (type) == NUMBER) {
209     if (car) CAR (x) = CAR (car);
210     if (cdr) CDR (x) = CDR (cdr);
211   } else if (VALUE (type) == FUNCTION) {
212     if (car) CAR (x) = car;
213     if (cdr) CDR (x) = CDR (cdr);
214   } else {
215     CAR (x) = car;
216     CDR (x) = cdr;
217   }
218   return x;
219 }
220
221 SCM
222 cons (SCM x, SCM y)
223 {
224   g_cells[tmp_num].value = PAIR;
225   return make_cell (tmp_num, x, y);
226 }
227
228 SCM
229 car (SCM x)
230 {
231   assert (TYPE (x) == PAIR);
232   return CAR (x);
233 }
234
235 SCM
236 cdr (SCM x)
237 {
238   assert (TYPE (x) == PAIR);
239   return CDR (x);
240 }
241
242 SCM
243 eq_p (SCM x, SCM y)
244 {
245   return (x == y
246           || ((TYPE (x) == KEYWORD && TYPE (y) == KEYWORD
247                && STRING (x) == STRING (y)))
248           || (TYPE (x) == CHAR && TYPE (y) == CHAR
249               && VALUE (x) == VALUE (y))
250           || (TYPE (x) == NUMBER && TYPE (y) == NUMBER
251               && VALUE (x) == VALUE (y)))
252     ? cell_t : cell_f;
253 }
254
255 SCM
256 set_car_x (SCM x, SCM e)
257 {
258   assert (TYPE (x) == PAIR);
259   CAR (x) = e;
260   return cell_unspecified;
261 }
262
263 SCM
264 set_cdr_x (SCM x, SCM e)
265 {
266   assert (TYPE (x) == PAIR);
267   CDR (x) = e;
268   return cell_unspecified;
269 }
270
271 SCM
272 set_env_x (SCM x, SCM e, SCM a)
273 {
274   SCM p = assert_defined (x, assq (x, a));
275   return set_cdr_x (p, e);
276 }
277
278 SCM
279 quote (SCM x)
280 {
281   return cons (cell_symbol_quote, x);
282 }
283
284 SCM
285 quasiquote (SCM x)
286 {
287   return cons (cell_symbol_quasiquote, x);
288 }
289
290 SCM
291 quasisyntax (SCM x)
292 {
293   return cons (cell_symbol_quasisyntax, x);
294 }
295
296 SCM
297 pairlis (SCM x, SCM y, SCM a)
298 {
299   if (x == cell_nil)
300     return a;
301   if (pair_p (x) == cell_f)
302     return cons (cons (x, y), a);
303   return cons (cons (car (x), car (y)),
304                pairlis (cdr (x), cdr (y), a));
305 }
306
307 SCM
308 assq (SCM x, SCM a)
309 {
310   while (a != cell_nil && eq_p (x, CAAR (a)) == cell_f)
311     {
312       if (TYPE (a) == BROKEN_HEART || TYPE (CAR (a)) == BROKEN_HEART)
313         fprintf (stderr, "oops, broken heart\n");
314       a = CDR (a);
315     }
316   return a != cell_nil ? car (a) : cell_f;
317 }
318
319 SCM
320 assq_ref_cache (SCM x, SCM a)
321 {
322   x = assq (x, a);
323   if (x == cell_f) return cell_undefined;
324   return cdr (x);
325 }
326
327 SCM
328 assert_defined (SCM x, SCM e)
329 {
330   if (e == cell_undefined)
331     {
332       fprintf (stderr, "eval: unbound variable:");
333       display_ (stderr, x);
334       fprintf (stderr, "\n");
335       assert (!"unbound variable");
336     }
337   return e;
338 }
339
340 enum eval_apply_t {EVLIS, APPLY, EVAL, MACRO_EXPAND, BEGIN, IF, CALL_WITH_VALUES};
341 enum eval_apply_t g_target;
342
343 SCM
344 call_lambda (SCM e, SCM x, SCM aa, SCM a) ///((internal))
345 {
346   SCM cl = cons (cons (cell_closure, x), x);
347   r1 = e;
348   r0 = cl;
349   r2 = a;
350   r3 = aa;
351   return cell_unspecified;
352 }
353
354 SCM
355 eval_apply ()
356 {
357   switch (g_target)
358     {
359     case EVLIS: goto evlis;
360     case APPLY: goto apply;
361     case EVAL: goto eval;
362     case MACRO_EXPAND: goto macro_expand;
363     case BEGIN: goto begin;
364     case IF: goto label_if;
365     case CALL_WITH_VALUES: goto call_with_values;
366     }
367
368  evlis:
369   if (r1 == cell_nil) return cell_nil;
370   if (TYPE (r1) != PAIR) goto eval;
371   r2 = eval_env (car (r1), r0);
372   r1 = evlis_env (cdr (r1), r0);
373   return cons (r2, r1);
374
375  apply:
376   if (TYPE (r1) != PAIR)
377     {
378       if (TYPE (r1) == FUNCTION) return call (r1, r2);
379       if (r1 == cell_symbol_call_with_values)
380         {
381           r1 = car (r2);
382           r2 = cadr (r2);
383           goto call_with_values;
384         }
385       if (r1 == cell_symbol_current_module) return r0;
386     }
387   else
388     switch (car (r1))
389       {
390       case cell_symbol_lambda:
391         {
392           SCM args = cadr (r1);
393           SCM body = cddr (r1);
394           SCM p = pairlis (args, r2, r0);
395           call_lambda (body, p, p, r0);
396           goto begin;
397         }
398       case cell_closure:
399         {
400           SCM args = caddr (r1);
401           SCM body = cdddr (r1);
402           SCM aa = cdadr (r1);
403           aa = cdr (aa);
404           SCM p = pairlis (args, r2, aa);
405           call_lambda (body, p, aa, r0);
406           goto begin;
407         }
408 #if BOOT
409       case cell_symbol_label:
410         {
411           r0 = cons (cons (cadr (r1), caddr (r1)), r0);
412           r1 = caddr (r1);
413           goto apply;
414         }
415 #endif
416       }
417   SCM e = eval_env (r1, r0);
418   char const* type = 0;
419   if (e == cell_f || e == cell_t) type = "bool";
420   if (TYPE (e) == CHAR) type = "char";
421   if (TYPE (e) == NUMBER) type = "number";
422   if (TYPE (e) == STRING) type = "string";
423   if (e == cell_unspecified) type = "*unspecified*";
424   if (e == cell_undefined) type =  "*undefined*";
425   if (type)
426     {
427       fprintf (stderr, "cannot apply: %s: ", type);
428       display_ (stderr, e);
429       fprintf (stderr, " [");
430       display_ (stderr, r1);
431       fprintf (stderr, "]\n");
432       assert (!"cannot apply");
433     }
434   r1 = e;
435   goto apply;
436
437  eval:
438   switch (TYPE (r1))
439     {
440     case PAIR:
441       {
442         switch (car (r1))
443           {
444 #if FIXED_PRIMITIVES
445           case cell_symbol_car: return car (eval_env (CADR (r1), r0));
446           case cell_symbol_cdr: return cdr (eval_env (CADR (r1), r0));
447           case cell_symbol_cons: {SCM m = evlis_env (CDR (r1), r0);
448               return cons (CAR (m), CADR (m));}
449           case cell_symbol_null_p: return null_p (eval_env (CADR (r1), r0));
450 #endif // FIXED_PRIMITIVES
451           case cell_symbol_quote: return cadr (r1);
452           case cell_symbol_begin: goto begin;
453           case cell_symbol_lambda:
454             return make_closure (cadr (r1), cddr (r1), assq (cell_closure, r0));
455           case cell_closure: return r1;
456           case cell_symbol_if: {r1=cdr (r1); goto label_if;}
457           case cell_symbol_set_x: {
458             SCM x = eval_env (caddr (r1), r0); return set_env_x (cadr (r1), x, r0);
459           }
460           default: {
461             SCM x = macro_expand_env (r1, r0);
462             if (x != r1)
463               {
464                 if (TYPE (x) == PAIR)
465                   {
466                     set_cdr_x (r1, cdr (x));
467                     set_car_x (r1, car (x));
468                   }
469                 r1 = x;
470                 goto eval;
471               }
472             SCM m = evlis_env (CDR (r1), r0);
473             r1 = car (r1);
474             r2 = m;
475             goto apply;
476           }
477           }
478       }
479     case SYMBOL: return assert_defined (r1, assq_ref_cache (r1, r0));
480     default: return r1;
481     }
482
483  macro_expand:
484   if (TYPE (CAR (r1)) == STRING && string_to_symbol (CAR (r1)) == cell_symbol_noexpand)
485     return cadr (r1);
486
487   SCM macro;
488   SCM expanders;
489   if (TYPE (r1) == PAIR
490       && (macro = lookup_macro (car (r1), r0)) != cell_f)
491     {
492       r2 = CDR (r1);
493       r1 = macro;
494       goto apply;
495     }
496   else if (TYPE (r1) == PAIR
497            && TYPE (CAR (r1)) == SYMBOL
498            && ((expanders = assq_ref_cache (cell_symbol_sc_expander_alist, r0)) != cell_undefined)
499            && ((macro = assq (CAR (r1), expanders)) != cell_f))
500     {
501       SCM sc_expand = assq_ref_cache (cell_symbol_macro_expand, r0);
502       if (sc_expand != cell_undefined && sc_expand != cell_f)
503         {
504           r2 = cons (r1, cell_nil);
505           r1 = sc_expand;
506           goto apply;
507         }
508     }
509   return r1;
510
511   SCM r;
512  begin:
513   r = cell_unspecified;
514   while (r1 != cell_nil) {
515     if (TYPE (r1) == PAIR && TYPE (CAR (r1)) == PAIR)
516       {
517         if (caar (r1) == cell_symbol_begin)
518           r1 = append2 (cdar (r1), cdr (r1));
519         else if (caar (r1) == cell_symbol_primitive_load)
520           {
521             SCM f = read_input_file_env (r0);
522             r1 = append2 (f, cdr (r1));
523           }
524       }
525     if (CDR (r1) == cell_nil)
526       {
527         r1 = car (r1);
528         goto eval;
529       }
530     r = eval_env (car (r1), r0);
531     r1 = CDR (r1);
532   }
533   return r;
534
535   SCM x;
536  label_if:
537   x = eval_env (car (r1), r0);
538   if (x != cell_f)
539     {
540       r1 = cadr (r1);
541       goto eval;
542     }
543   if (cddr (r1) != cell_nil)
544     {
545       r1 = caddr (r1);
546       goto eval;
547     }
548   return cell_unspecified;
549
550   SCM v;
551  call_with_values:
552   v = apply_env (r1, cell_nil, r0);
553   if (TYPE (v) == VALUES)
554     v = CDR (v);
555   r1 = r2;
556   r2 = v;
557   goto apply;
558 }
559
560 SCM
561 call (SCM fn, SCM x)
562 {
563   if ((FUNCTION (fn).arity > 0 || FUNCTION (fn).arity == -1)
564       && x != cell_nil && TYPE (CAR (x)) == VALUES)
565     x = cons (CADAR (x), CDR (x));
566   if ((FUNCTION (fn).arity > 1 || FUNCTION (fn).arity == -1)
567       && x != cell_nil && TYPE (CDR (x)) == PAIR && TYPE (CADR (x)) == VALUES)
568     x = cons (CAR (x), cons (CDADAR (x), CDR (x)));
569   switch (FUNCTION (fn).arity)
570     {
571     case 0: return FUNCTION (fn).function0 ();
572     case 1: return FUNCTION (fn).function1 (car (x));
573     case 2: return FUNCTION (fn).function2 (car (x), cadr (x));
574     case 3: return FUNCTION (fn).function3 (car (x), cadr (x), caddr (x));
575     case -1: return FUNCTION (fn).functionn (x);
576     }
577   return cell_unspecified;
578 }
579
580 SCM
581 gc_frame (SCM stack)
582 {
583   SCM frame = car (stack);
584   r1 = car (frame);
585   r2 = cadr (frame);
586   r3 = caddr (frame);
587   r0 = cadddr (frame);
588   return frame;
589 }
590
591 SCM
592 gc_stack (SCM a)
593 {
594   SCM frame = cons (r1, cons (r2, cons (r3, cons (r0, cell_nil))));
595   stack = cons (frame, stack);
596   stack = gc (stack);
597   gc_frame (stack);
598   stack = cdr (stack);
599   return stack;
600 }
601
602 SCM
603 vm_call (function0_t f, SCM p1, SCM p2, SCM a)
604 {
605   SCM frame = cons (r1, cons (r2, cons (r3, cons (r0, cell_nil))));
606   stack = cons (frame, stack);
607   r1 = p1;
608   r2 = p2;
609   r0 = a;
610   if (g_free.value + GC_SAFETY > ARENA_SIZE)
611     gc_stack (stack);
612
613   SCM r = f ();
614   frame = gc_frame (stack);
615   stack = cdr (stack);
616   return r;
617 }
618
619 SCM
620 evlis_env (SCM m, SCM a)
621 {
622   g_target = EVLIS;
623   return vm_call (eval_apply, m, cell_undefined, a);
624 }
625
626 SCM
627 apply_env (SCM fn, SCM x, SCM a)
628 {
629   g_target = APPLY;
630   return vm_call (eval_apply, fn, x, a);
631 }
632
633 SCM
634 eval_env (SCM e, SCM a)
635 {
636   g_target = EVAL;
637   return vm_call (eval_apply, e, cell_undefined, a);
638 }
639
640 SCM
641 macro_expand_env (SCM e, SCM a)
642 {
643   g_target = MACRO_EXPAND;
644   return vm_call (eval_apply, e, cell_undefined, a);
645 }
646
647 SCM
648 begin_env (SCM e, SCM a)
649 {
650   g_target = BEGIN;
651   return vm_call (eval_apply, e, cell_undefined, a);
652 }
653
654 SCM
655 if_env (SCM e, SCM a)
656 {
657   g_target = IF;
658   return vm_call (eval_apply, e, cell_undefined, a);
659 }
660
661 SCM
662 call_with_values_env (SCM producer, SCM consumer, SCM a)
663 {
664   g_target = CALL_WITH_VALUES;
665   return vm_call (eval_apply, producer, consumer, a);
666 }
667
668 SCM
669 append2 (SCM x, SCM y)
670 {
671   if (x == cell_nil) return y;
672   assert (TYPE (x) == PAIR);
673   return cons (car (x), append2 (cdr (x), y));
674 }
675
676 SCM
677 append (SCM x) ///((arity . n))
678  {
679   if (x == cell_nil) return cell_nil;
680   if (cdr (x) == cell_nil) return car (x);
681   return append2 (car (x), append (cdr (x)));
682  }
683
684 SCM
685 tmp_num_ (int x)
686 {
687   g_cells[tmp_num].value = x;
688   return tmp_num;
689 }
690
691 SCM
692 tmp_num2_ (int x)
693 {
694   g_cells[tmp_num2].value = x;
695   return tmp_num2;
696 }
697
698 SCM
699 cstring_to_list (char const* s)
700 {
701   SCM p = cell_nil;
702   int i = strlen (s);
703   while (i--)
704     p = cons (MAKE_CHAR (s[i]), p);
705   return p;
706 }
707
708 SCM
709 null_p (SCM x)
710 {
711   return x == cell_nil ? cell_t : cell_f;
712 }
713
714 SCM
715 make_symbol_ (SCM s)
716 {
717   g_cells[tmp_num].value = SYMBOL;
718   SCM x = make_cell (tmp_num, s, 0);
719   g_symbols = cons (x, g_symbols);
720   return x;
721 }
722
723 SCM
724 make_symbol (SCM s)
725 {
726   SCM x = lookup_symbol_ (s);
727   return x ? x : make_symbol_ (s);
728 }
729
730 SCM
731 make_vector (SCM n)
732 {
733   int k = VALUE (n);
734   g_cells[tmp_num].value = VECTOR;
735   SCM v = alloc (k);
736   SCM x = make_cell (tmp_num, k, v);
737   for (int i=0; i<k; i++) g_cells[v+i] = g_cells[vector_entry (cell_unspecified)];
738   return x;
739 }
740
741 SCM
742 values (SCM x) ///((arity . n))
743 {
744   SCM v = cons (0, x);
745   TYPE (v) = VALUES;
746   return v;
747 }
748
749 SCM
750 vector_length (SCM x)
751 {
752   assert (TYPE (x) == VECTOR);
753   return MAKE_NUMBER (LENGTH (x));
754 }
755
756 SCM
757 vector_ref (SCM x, SCM i)
758 {
759   assert (TYPE (x) == VECTOR);
760   assert (VALUE (i) < LENGTH (x));
761   SCM e = VECTOR (x) + VALUE (i);
762   if (TYPE (e) == REF) e = g_cells[e].ref;
763   if (TYPE (e) == CHAR) e = MAKE_CHAR (VALUE (e));
764   if (TYPE (e) == NUMBER) e = MAKE_NUMBER (VALUE (e));
765   return e;
766 }
767
768 SCM
769 vector_entry (SCM x) {
770   if (TYPE (x) == PAIR || TYPE (x) == SPECIAL || TYPE (x) == STRING || TYPE (x) == SYMBOL || TYPE (x) == VECTOR) x = MAKE_REF (x);
771   return x;
772 }
773
774 SCM
775 vector_set_x (SCM x, SCM i, SCM e)
776 {
777   assert (TYPE (x) == VECTOR);
778   assert (VALUE (i) < LENGTH (x));
779   g_cells[VECTOR (x)+g_cells[i].value] = g_cells[vector_entry (e)];
780   return cell_unspecified;
781 }
782
783 SCM
784 list_to_vector (SCM x)
785 {
786   VALUE (tmp_num) = VALUE (length (x));
787   SCM v = make_vector (tmp_num);
788   SCM p = VECTOR (v);
789   while (x != cell_nil)
790     {
791       g_cells[p++] = g_cells[vector_entry (car (x))];
792       x = cdr (x);
793     }
794   return v;
795 }
796
797 FILE *g_stdin;
798 int
799 getchar ()
800 {
801   return getc (g_stdin);
802 }
803
804 int
805 ungetchar (int c)
806 {
807   return ungetc (c, g_stdin);
808 }
809
810 int
811 peekchar ()
812 {
813   int c = getchar ();
814   ungetchar (c);
815   return c;
816 }
817
818 SCM
819 peek_byte ()
820 {
821   return MAKE_NUMBER (peekchar ());
822 }
823
824 SCM
825 read_byte ()
826 {
827   return MAKE_NUMBER (getchar ());
828 }
829
830 SCM
831 unread_byte (SCM i)
832 {
833   ungetchar (VALUE (i));
834   return i;
835 }
836
837 SCM
838 write_char (SCM x) ///((arity . n))
839 {
840   SCM c = car (x);
841   SCM p = cdr (x);
842   int fd = 1;
843   if (TYPE (p) == PAIR && TYPE (car (p)) == NUMBER) fd = VALUE (car (p));
844   FILE *f = fd == 1 ? stdout : stderr;
845   assert (TYPE (c) == NUMBER || TYPE (c) == CHAR);
846   fputc (VALUE (c), f);
847   return c;
848 }
849
850 SCM
851 symbol_to_list (SCM x)
852 {
853   assert (TYPE (x) == SYMBOL);
854   return STRING (x);
855 }
856
857 SCM
858 char_to_integer (SCM x)
859 {
860   assert (TYPE (x) == CHAR);
861   return MAKE_NUMBER (VALUE (x));
862 }
863
864 SCM
865 integer_to_char (SCM x)
866 {
867   assert (TYPE (x) == NUMBER);
868   return MAKE_CHAR (VALUE (x));
869 }
870
871 void
872 make_tmps (scm* cells)
873 {
874   tmp = g_free.value++;
875   cells[tmp].type = CHAR;
876   tmp_num = g_free.value++;
877   cells[tmp_num].type = NUMBER;
878   tmp_num2 = g_free.value++;
879   cells[tmp_num2].type = NUMBER;
880   tmp_num3 = g_free.value++;
881   cells[tmp_num3].type = NUMBER;
882   tmp_num4 = g_free.value++;
883   cells[tmp_num4].type = NUMBER;
884 }
885
886 //\f Jam Collector
887 SCM g_symbol_max;
888 bool g_debug = false;
889
890 SCM
891 gc_up_arena ()
892 {
893   ARENA_SIZE *= 2;
894   void *p = realloc (g_cells-1, 2*ARENA_SIZE*sizeof(scm));
895   if (!p)
896     {
897       if (g_debug) fprintf (stderr, "cannot up arena: %s: arena=%d\n", strerror (errno), 2*ARENA_SIZE);
898       return cell_unspecified;
899     }
900   g_cells = (scm*)p;
901   g_cells++;
902   gc_init_news ();
903 }
904
905 SCM
906 gc ()
907 {
908   if (g_debug) fprintf (stderr, "***gc[%d]...", g_free.value);
909   g_free.value = 1;
910   if (g_cells < g_news && ARENA_SIZE < MAX_ARENA_SIZE) gc_up_arena ();
911   for (int i=g_free.value; i<g_symbol_max; i++)
912     gc_copy (i);
913   make_tmps (g_news);
914   g_symbols = gc_copy (g_symbols);
915   SCM new = gc_copy (stack);
916   if (g_debug) fprintf (stderr, "new=%d\n", new, stack);
917   stack = new;
918   return gc_loop (1);
919 }
920
921 SCM
922 gc_loop (SCM scan)
923 {
924   while (scan < g_free.value)
925     {
926       if (NTYPE (scan) == KEYWORD
927           || NTYPE (scan) == MACRO
928           || NTYPE (scan) == PAIR
929           || NTYPE (scan) == REF
930           || scan == 1 // null
931           || NTYPE (scan) == SPECIAL
932           || NTYPE (scan) == STRING
933           || NTYPE (scan) == SYMBOL)
934         {
935           SCM car = gc_copy (g_news[scan].car);
936           gc_relocate_car (scan, car);
937         }
938       if ((NTYPE (scan) == MACRO
939            || NTYPE (scan) == PAIR
940            || NTYPE (scan) == VALUES)
941           && g_news[scan].cdr) // allow for 0 terminated list of symbols
942         {
943           SCM cdr = gc_copy (g_news[scan].cdr);
944           gc_relocate_cdr (scan, cdr);
945         }
946       scan++;
947     }
948   return gc_flip ();
949 }
950
951 SCM
952 gc_copy (SCM old)
953 {
954   if (TYPE (old) == BROKEN_HEART) return g_cells[old].car;
955   SCM new = g_free.value++;
956   g_news[new] = g_cells[old];
957   if (NTYPE (new) == VECTOR)
958     {
959       g_news[new].vector = g_free.value;
960       for (int i=0; i<LENGTH (old); i++)
961         g_news[g_free.value++] = g_cells[VECTOR (old)+i];
962     }
963   g_cells[old].type = BROKEN_HEART;
964   g_cells[old].car = new;
965   return new;
966 }
967
968 SCM
969 gc_relocate_car (SCM new, SCM car)
970 {
971   g_news[new].car = car;
972   return cell_unspecified;
973 }
974
975 SCM
976 gc_relocate_cdr (SCM new, SCM cdr)
977 {
978   g_news[new].cdr = cdr;
979   return cell_unspecified;
980 }
981
982 SCM
983 gc_flip ()
984 {
985   scm *cells = g_cells;
986   g_cells = g_news;
987   g_news = cells;
988   if (g_debug) fprintf (stderr, " => jam[%d]\n", g_free.value);
989   return stack;
990 }
991
992 //\f Environment setup
993 SCM
994 acons (SCM key, SCM value, SCM alist)
995 {
996   return cons (cons (key, value), alist);
997 }
998
999 SCM
1000 gc_init_cells ()
1001 {
1002   g_cells = (scm *)malloc (2*ARENA_SIZE*sizeof(scm));
1003   g_cells[0].type = VECTOR;
1004   g_cells[0].length = 1000;
1005   g_cells[0].vector = 0;
1006   g_cells++;
1007   g_cells[0].type = CHAR;
1008   g_cells[0].value = 'c';
1009 }
1010
1011 SCM
1012 gc_init_news ()
1013 {
1014   g_news = g_cells-1 + ARENA_SIZE;
1015   g_news[0].type = VECTOR;
1016   g_news[0].length = 1000;
1017   g_news[0].vector = 0;
1018   g_news++;
1019   g_news[0].type = CHAR;
1020   g_news[0].value = 'n';
1021 }
1022
1023 SCM
1024 mes_symbols () ///((internal))
1025 {
1026   gc_init_cells ();
1027   gc_init_news ();
1028
1029 #include "mes.symbols.i"
1030
1031   g_symbol_max = g_free.value;
1032   make_tmps (g_cells);
1033
1034   g_symbols = 0;
1035   for (int i=1; i<g_symbol_max; i++)
1036     g_symbols = cons (i, g_symbols);
1037
1038   SCM a = cell_nil;
1039
1040 #include "mes.symbol-names.i"
1041
1042 #if BOOT
1043   a = acons (cell_symbol_label, cell_t, a);
1044 #endif
1045   a = acons (cell_symbol_dot, cell_dot, a);
1046   a = acons (cell_symbol_begin, cell_begin, a);
1047   a = acons (cell_symbol_sc_expand, cell_f, a);
1048   a = acons (cell_closure, a, a);
1049
1050   return a;
1051 }
1052
1053 SCM
1054 mes_builtins (SCM a)
1055 {
1056 #include "mes.i"
1057
1058 #include "display.i"
1059 #include "lib.i"
1060 #include "math.i"
1061 #include "posix.i"
1062 #include "reader.i"
1063 #include "string.i"
1064 #include "type.i"
1065
1066 #include "display.environment.i"
1067 #include "lib.environment.i"
1068 #include "math.environment.i"
1069 #include "mes.environment.i"
1070 #include "posix.environment.i"
1071 #include "reader.environment.i"
1072 #include "string.environment.i"
1073 #include "type.environment.i"
1074
1075   return a;
1076 }
1077
1078 SCM
1079 mes_stack (SCM a) ///((internal))
1080 {
1081   r0 = a;
1082   r1 = MAKE_CHAR (0);
1083   r2 = MAKE_CHAR (0);
1084   r3 = MAKE_CHAR (0);
1085   stack = cons (cell_nil, cell_nil);
1086   return r0;
1087 }
1088
1089 SCM
1090 mes_environment () ///((internal))
1091 {
1092   SCM a = mes_symbols ();
1093   return mes_stack (a);
1094 }
1095
1096 SCM
1097 make_lambda (SCM args, SCM body)
1098 {
1099   return cons (cell_symbol_lambda, cons (args, body));
1100 }
1101
1102 SCM
1103 make_closure (SCM args, SCM body, SCM a)
1104 {
1105   return cons (cell_closure, cons (cons (cell_circular, a), cons (args, body)));
1106 }
1107
1108 SCM
1109 lookup_macro (SCM x, SCM a)
1110 {
1111   if (TYPE (x) != SYMBOL) return cell_f;
1112   SCM m = assq_ref_cache (x, a);
1113   if (macro_p (m) == cell_t) return MACRO (m);
1114   return cell_f;
1115 }
1116
1117 SCM
1118 read_input_file_env_ (SCM e, SCM a)
1119 {
1120   if (e == cell_nil) return e;
1121   return cons (e, read_input_file_env_ (read_env (a), a));
1122 }
1123
1124 SCM
1125 read_input_file_env (SCM a)
1126 {
1127   r0 = a;
1128   if (assq_ref_cache (cell_symbol_read_input_file, r0) != cell_undefined)
1129     return apply_env (cell_symbol_read_input_file, cell_nil, r0);
1130   return read_input_file_env_ (read_env (r0), r0);
1131 }
1132
1133 SCM
1134 load_env (SCM a) ///((internal))
1135 {
1136   r0 =a;
1137   g_stdin = fopen ("module/mes/read-0.mes", "r");
1138   g_stdin = g_stdin ? g_stdin : fopen (PREFIX "module/mes/read-0.mes", "r");
1139   if (!g_function) r0 = mes_builtins (r0);
1140   r3 = read_input_file_env (r0);
1141   g_stdin = stdin;
1142   return r3;
1143 }
1144
1145 SCM
1146 bload_env (SCM a) ///((internal))
1147 {
1148   g_stdin = fopen ("module/mes/read-0.mo", "r");
1149   g_stdin = g_stdin ? g_stdin : fopen (PREFIX "module/mes/read-0.mo", "r");
1150   char *p = (char*)g_cells;
1151   assert (getchar () == 'M');
1152   assert (getchar () == 'E');
1153   assert (getchar () == 'S');
1154   stack = getchar () << 8;
1155   stack += getchar ();
1156   int c = getchar ();
1157   while (c != EOF)
1158     {
1159       *p++ = c;
1160       c = getchar ();
1161     }
1162   g_free.value = (p-(char*)g_cells) / sizeof (scm);
1163   gc_frame (stack);
1164   g_symbols = r1;
1165   g_stdin = stdin;
1166
1167   r0 = mes_builtins (r0);
1168   return r3;
1169 }
1170
1171 int
1172 dump ()
1173 {
1174   r1 = g_symbols;
1175   SCM frame = cons (r1, cons (r2, cons (r3, cons (r0, cell_nil))));
1176   stack = cons (frame, stack);
1177   stack = gc (stack);
1178   gc_frame (stack);
1179   char *p = (char*)g_cells;
1180   fputc ('M', stdout);
1181   fputc ('E', stdout);
1182   fputc ('S', stdout);
1183   fputc (stack >> 8, stdout);
1184   fputc (stack % 256, stdout);
1185   for (int i=0; i<g_free.value * sizeof(scm); i++)
1186     fputc (*p++, stdout);
1187   return 0;
1188 }
1189
1190 #include "type.c"
1191 #include "display.c"
1192 #include "lib.c"
1193 #include "math.c"
1194 #include "posix.c"
1195 #include "reader.c"
1196 #include "string.c"
1197
1198 int
1199 main (int argc, char *argv[])
1200 {
1201   g_debug = getenv ("MES_DEBUG");
1202   if (getenv ("MES_ARENA")) ARENA_SIZE = atoi (getenv ("MES_ARENA"));
1203   if (argc > 1 && !strcmp (argv[1], "--help")) return puts ("Usage: mes < FILE\n");
1204   if (argc > 1 && !strcmp (argv[1], "--version")) return puts ("Mes 0.3\n");
1205   g_stdin = stdin;
1206   r0 = mes_environment ();
1207   SCM program = (argc > 1 && !strcmp (argv[1], "--load"))
1208     ? bload_env (r0) : load_env (r0);
1209   if (argc > 1 && !strcmp (argv[1], "--dump")) return dump ();
1210   display_ (stderr, begin_env (program, r0));
1211   fputs ("", stderr);
1212   gc (stack);
1213   if (g_debug) fprintf (stderr, "\nstats: [%d]\n", g_free.value);
1214   return 0;
1215 }