/* -*-comment-start: "//";comment-end:""-*- * GNU Mes --- Maxwell Equations of Software * Copyright © 2016,2017,2018,2019,2020 Jan (janneke) Nieuwenhuizen * * This file is part of GNU Mes. * * GNU Mes is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or (at * your option) any later version. * * GNU Mes is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Mes. If not, see . */ #include "mes/lib.h" #include "mes/mes.h" #include struct scm * assert_defined (struct scm *x, struct scm *e) /*:((internal)) */ { if (e == cell_undefined) return error (cell_symbol_unbound_variable, x); return e; } struct scm * check_formals (struct scm *f, struct scm *formals, struct scm *args) /*:((internal)) */ { long flen; if (formals->type == TNUMBER) flen = formals->value; else flen = length__ (formals); long alen = length__ (args); if (alen != flen && alen != -1 && flen != -1) { char *s = "apply: wrong number of arguments; expected: "; eputs (s); eputs (itoa (flen)); eputs (", got: "); eputs (itoa (alen)); eputs ("\n"); write_error_ (f); struct scm *e = make_string0 (s); return error (cell_symbol_wrong_number_of_args, cons (e, f)); } return cell_unspecified; } struct scm * check_apply (struct scm *f, struct scm *e) /*:((internal)) */ { char *type = 0; if (f == cell_f || f == cell_t) type = "bool"; if (f == cell_nil) type = "nil"; if (f == cell_unspecified) type = "*unspecified*"; if (f == cell_undefined) type = "*undefined*"; if (f->type == TCHAR) type = "char"; if (f->type == TNUMBER) type = "number"; if (f->type == TSTRING) type = "string"; if (f->type == TSTRUCT && builtin_p (f) == cell_f) type = "#<...>"; if (f->type == TBROKEN_HEART) type = "<3"; if (type != 0) { char *s = "cannot apply: "; eputs (s); eputs (type); eputs ("["); write_error_ (e); eputs ("]\n"); struct scm *e = make_string0 (s); return error (cell_symbol_wrong_type_arg, cons (e, f)); } return cell_unspecified; } struct scm * pairlis (struct scm *x, struct scm *y, struct scm *a) { if (x == cell_nil) return a; if (x->type != TPAIR) return cons (cons (x, y), a); return cons (cons (car (x), car (y)), pairlis (cdr (x), cdr (y), a)); } struct scm * set_car_x (struct scm *x, struct scm *e) { if (x->type != TPAIR) error (cell_symbol_not_a_pair, cons (x, cstring_to_symbol ("set-car!"))); x->car = e; return cell_unspecified; } struct scm * set_cdr_x (struct scm *x, struct scm *e) { if (x->type != TPAIR) error (cell_symbol_not_a_pair, cons (x, cstring_to_symbol ("set-cdr!"))); x->cdr = e; return cell_unspecified; } struct scm * set_env_x (struct scm *x, struct scm *e, struct scm *a) { struct scm *p; if (x->type == TVARIABLE) p = x->variable; else p = assert_defined (x, module_variable (a, x)); if (p->type != TPAIR) error (cell_symbol_not_a_pair, cons (p, x)); return set_cdr_x (p, e); } struct scm * call_lambda (struct scm *e, struct scm *x, struct scm *aa, struct scm *a) /*:((internal)) */ { struct scm *cl = cons (cons (cell_closure, x), x); R1 = e; R0 = cl; return cell_unspecified; } struct scm * make_closure_ (struct scm *args, struct scm *body, struct scm *a) /*:((internal)) */ { return make_cell (TCLOSURE, cell_f, cons (cons (cell_circular, a), cons (args, body))); } struct scm * make_variable_ (struct scm *var) /*:((internal)) */ { return make_cell (TVARIABLE, var, 0); } struct scm * macro_get_handle (struct scm *name) /*:((internal)) */ { if (name->type == TSYMBOL) return hashq_get_handle (g_macros, name, cell_nil); return cell_f; } struct scm * get_macro (struct scm *name) /*:((internal)) */ { struct scm *m = macro_get_handle (name); if (m != cell_f) { struct scm *d = m->cdr; return d->macro; } return cell_f; } struct scm * macro_set_x (struct scm *name, struct scm *value) /*:((internal)) */ { return hashq_set_x (g_macros, name, value); } struct scm * push_cc (struct scm *p1, struct scm *p2, struct scm *a, struct scm *c) /*:((internal)) */ { struct scm *x = R3; R3 = c; R2 = p2; gc_push_frame (); R1 = p1; R0 = a; R3 = x; return cell_unspecified; } struct scm * add_formals (struct scm *formals, struct scm *x) { while (x->type == TPAIR) { formals = cons (x->car, formals); x = x->cdr; } if (x->type == TSYMBOL) formals = cons (x, formals); return formals; } int formal_p (struct scm *x, struct scm *formals) /*:((internal)) */ { if (formals->type == TSYMBOL) { if (x == formals) return 1; else return 0; } while (formals->type == TPAIR) { if (formals->car == x) break; formals = formals->cdr; } if (formals->type == TSYMBOL) return formals == x; return formals->type == TPAIR; } struct scm * expand_variable_ (struct scm *x, struct scm *formals, int top_p) /*:((internal)) */ { struct scm *a; struct scm *f; struct scm *v; while (x->type == TPAIR) { a = x->car; if (a->type == TPAIR) { if (a->car == cell_symbol_lambda) { f = a->cdr->car; formals = add_formals (formals, f); } else if (a->car == cell_symbol_define || a->car == cell_symbol_define_macro) { f = a->cdr->car; formals = add_formals (formals, f); } if (a->car != cell_symbol_quote) expand_variable_ (a, formals, 0); } else { if (a == cell_symbol_lambda) { f = x->cdr->car; formals = add_formals (formals, f); x = x->cdr; } else if (a == cell_symbol_define || a == cell_symbol_define_macro) { f = x->cdr->car; if (top_p != 0 && f->type == TPAIR) f = f->cdr; formals = add_formals (formals, f); x = x->cdr; } else if (a == cell_symbol_quote) return cell_unspecified; else if (a->type == TSYMBOL && a != cell_symbol_boot_module && a != cell_symbol_current_module && a != cell_symbol_primitive_load && formal_p (x->car, formals) == 0) { v = module_variable (R0, a); if (v != cell_f) x->car = make_variable_ (v); } } x = x->cdr; top_p = 0; } return cell_unspecified; } struct scm * expand_variable (struct scm *x, struct scm *formals) /*:((internal)) */ { return expand_variable_ (x, formals, 1); } struct scm * apply_builtin (struct scm *fn, struct scm *x) /*:((internal)) */ { struct scm *a = builtin_arity (fn); struct scm *d; int arity = a->value; if ((arity > 0 || arity == -1) && x != cell_nil) { a = x->car; if (a->type == TVALUES) x = cons (a->cdr->car, x->cdr); } if ((arity > 1 || arity == -1) && x != cell_nil) { a = x->car; d = x->cdr; if (d->type == TPAIR) if (d->car->type == TVALUES) x = cons (a, cons (d->car->cdr->car, d)); } if (arity == 0) return apply_builtin0 (fn); if (arity == 1) return apply_builtin1 (fn, x->car); else if (arity == 2) return apply_builtin2 (fn, x->car, x->cdr->car); else if (arity == 3) return apply_builtin3 (fn, x->car, x->cdr->car, x->cdr->cdr->car); else if (arity == -1) return apply_builtin1 (fn, x); return cell_unspecified; } struct scm * eval_apply () { struct scm *aa; struct scm *args; struct scm *body; struct scm *cl; struct scm *entry; struct scm *expanders; struct scm *formals; struct scm *input; struct scm *name; struct scm *macro; struct scm *p; struct scm *program; struct scm *sc_expand; struct scm *v; struct scm *x; int global_p; int macro_p; struct scm *a; struct scm *c; struct scm *d; int t; long i; eval_apply: if (R3 == cell_vm_evlis2) goto evlis2; else if (R3 == cell_vm_evlis3) goto evlis3; else if (R3 == cell_vm_eval_check_func) goto eval_check_func; else if (R3 == cell_vm_eval2) goto eval2; else if (R3 == cell_vm_apply2) goto apply2; else if (R3 == cell_vm_if_expr) goto if_expr; else if (R3 == cell_vm_begin_eval) goto begin_eval; else if (R3 == cell_vm_eval_set_x) goto eval_set_x; else if (R3 == cell_vm_macro_expand_car) goto macro_expand_car; else if (R3 == cell_vm_return) goto vm_return; else if (R3 == cell_vm_macro_expand_cdr) goto macro_expand_cdr; else if (R3 == cell_vm_eval_define) goto eval_define; else if (R3 == cell_vm_macro_expand) goto macro_expand; else if (R3 == cell_vm_macro_expand_lambda) goto macro_expand_lambda; else if (R3 == cell_vm_eval_pmatch_car) goto eval_pmatch_car; else if (R3 == cell_vm_begin_expand_macro) goto begin_expand_macro; else if (R3 == cell_vm_macro_expand_define) goto macro_expand_define; else if (R3 == cell_vm_begin_expand_eval) goto begin_expand_eval; else if (R3 == cell_vm_call_with_current_continuation2) goto call_with_current_continuation2; else if (R3 == cell_vm_macro_expand_set_x) goto macro_expand_set_x; else if (R3 == cell_vm_eval_pmatch_cdr) goto eval_pmatch_cdr; else if (R3 == cell_vm_macro_expand_define_macro) goto macro_expand_define_macro; else if (R3 == cell_vm_begin_primitive_load) goto begin_primitive_load; else if (R3 == cell_vm_evlis) goto evlis; else if (R3 == cell_vm_apply) goto apply; else if (R3 == cell_vm_eval) goto eval; else if (R3 == cell_vm_eval_macro_expand_eval) goto eval_macro_expand_eval; else if (R3 == cell_vm_eval_macro_expand_expand) goto eval_macro_expand_expand; else if (R3 == cell_vm_begin) goto begin; else if (R3 == cell_vm_begin_expand) goto begin_expand; else if (R3 == cell_vm_begin_expand_primitive_load) goto begin_expand_primitive_load; else if (R3 == cell_vm_if) goto vm_if; else if (R3 == cell_vm_call_with_values2) goto call_with_values2; else if (R3 == cell_unspecified) return R1; else assert_msg (0, "eval/apply unknown continuation"); evlis: if (R1 == cell_nil) goto vm_return; if (R1->type != TPAIR) goto eval; push_cc (R1->car, R1, R0, cell_vm_evlis2); goto eval; evlis2: push_cc (R2->cdr, R1, R0, cell_vm_evlis3); goto evlis; evlis3: R1 = cons (R2, R1); goto vm_return; apply: g_stack_array[g_stack + GC_FRAME_PROCEDURE] = R1->car; a = R1->car; t = a->type; if (t == TSTRUCT && builtin_p (R1->car) == cell_t) { check_formals (R1->car, builtin_arity (R1->car), R1->cdr); R1 = apply_builtin (R1->car, R1->cdr); goto vm_return; } else if (t == TCLOSURE) { cl = R1->car->closure; body = cl->cdr->cdr; formals = cl->cdr->car; args = R1->cdr; aa = cl->car->cdr; aa = aa->cdr; check_formals (R1->car, formals, R1->cdr); p = pairlis (formals, args, aa); call_lambda (body, p, aa, R0); goto begin; } else if (t == TCONTINUATION) { a = R1->car; v = a->continuation; if (v->length != 0) { for (i = 0; i < v->length; i = i + 1) g_stack_array[STACK_SIZE - v->length + i] = vector_ref_ (v, i); g_stack = STACK_SIZE - v->length; } x = R1; gc_pop_frame (); R1 = x->cdr->car; goto eval_apply; } else if (t == TSPECIAL) { c = R1->car; if (c == cell_vm_apply) { push_cc (cons (R1->cdr->car, R1->cdr->cdr->car), R1, R0, cell_vm_return); goto apply; } else if (c == cell_vm_eval) { push_cc (R1->cdr->car, R1, R1->cdr->cdr->car, cell_vm_return); goto eval; } else if (c == cell_vm_begin_expand) { push_cc (cons (R1->cdr->car, cell_nil), R1, R1->cdr->cdr->car, cell_vm_return); goto begin_expand; } else check_apply (cell_f, R1->car); } else if (t == TSYMBOL) { c = R1->car; if (c == cell_symbol_call_with_current_continuation) { R1 = R1->cdr; goto call_with_current_continuation; } if (c == cell_symbol_call_with_values) { R1 = R1->cdr; goto call_with_values; } if (c == cell_symbol_current_module) { R1 = R0; goto vm_return; } if (c == cell_symbol_boot_module) { R1 = M0; goto vm_return; } } else if (t == TPAIR) { if (R1->car->car == cell_symbol_lambda) { formals = R1->car->cdr->car; args = R1->cdr; body = R1->car->cdr->cdr; p = pairlis (formals, R1->cdr, R0); check_formals (R1, formals, args); call_lambda (body, p, p, R0); goto begin; } } push_cc (R1->car, R1, R0, cell_vm_apply2); goto eval; apply2: check_apply (R1, R2->car); R1 = cons (R1, R2->cdr); goto apply; eval: t = R1->type; if (t == TPAIR) { c = R1->car; if (c == cell_symbol_pmatch_car) { push_cc (R1->cdr->car, R1, R0, cell_vm_eval_pmatch_car); goto eval; eval_pmatch_car: x = R1; gc_pop_frame (); R1 = x->car; goto eval_apply; } else if (c == cell_symbol_pmatch_cdr) { push_cc (R1->cdr->car, R1, R0, cell_vm_eval_pmatch_cdr); goto eval; eval_pmatch_cdr: x = R1; gc_pop_frame (); R1 = x->cdr; goto eval_apply; } else if (c == cell_symbol_quote) { x = R1; gc_pop_frame (); R1 = x->cdr->car; goto eval_apply; } else if (c == cell_symbol_begin) goto begin; else if (c == cell_symbol_lambda) { R1 = make_closure_ (R1->cdr->car, R1->cdr->cdr, R0); goto vm_return; } else if (c == cell_symbol_if) { R1 = R1->cdr; goto vm_if; } else if (c == cell_symbol_set_x) { push_cc (R1->cdr->cdr->car, R1, R0, cell_vm_eval_set_x); goto eval; eval_set_x: R1 = set_env_x (R2->cdr->car, R1, R0); goto vm_return; } else if (c == cell_vm_macro_expand) { push_cc (R1->cdr->car, R1, R0, cell_vm_eval_macro_expand_eval); goto eval; eval_macro_expand_eval: push_cc (R1, R2, R0, cell_vm_eval_macro_expand_expand); goto macro_expand; eval_macro_expand_expand: goto vm_return; } else { if (R1->type == TPAIR) if (R1->car == cell_symbol_define || R1->car == cell_symbol_define_macro) { global_p = 0; if (R0->car->car != cell_closure) global_p = 1; macro_p = 0; if (R1->car == cell_symbol_define_macro) macro_p = 1; if (global_p != 0) { name = R1->cdr->car; aa = R1->cdr->car; if (aa->type == TPAIR) name = name->car; if (macro_p != 0) { entry = assq (name, g_macros); if (entry == cell_f) macro_set_x (name, cell_f); } else { entry = module_variable (R0, name); if (entry == cell_f) module_define_x (M0, name, cell_f); } } R2 = R1; aa = R1->cdr->car; if (aa->type != TPAIR) { push_cc (R1->cdr->cdr->car, R2, cons (cons (R1->cdr->car, R1->cdr->car), R0), cell_vm_eval_define); goto eval; } else { p = pairlis (R1->cdr->car, R1->cdr->car, R0); formals = R1->cdr->car->cdr; body = R1->cdr->cdr; if (macro_p != 0 || global_p != 0) expand_variable (body, formals); R1 = cons (cell_symbol_lambda, cons (formals, body)); push_cc (R1, R2, p, cell_vm_eval_define); goto eval; } eval_define: name = R2->cdr->car; aa = R2->cdr->car; if (aa->type == TPAIR) name = name->car; if (macro_p != 0) { entry = macro_get_handle (name); R1 = make_macro (name, R1); set_cdr_x (entry, R1); } else if (global_p != 0) { entry = module_variable (R0, name); set_cdr_x (entry, R1); } else { entry = cons (name, R1); aa = cons (entry, cell_nil); set_cdr_x (aa, cdr (R0)); set_cdr_x (R0, aa); cl = module_variable (R0, cell_closure); set_cdr_x (cl, aa); } R1 = cell_unspecified; goto vm_return; } push_cc (R1->car, R1, R0, cell_vm_eval_check_func); gc_check (); goto eval; eval_check_func: push_cc (R2->cdr, R2, R0, cell_vm_eval2); goto evlis; eval2: R1 = cons (R2->car, R1); goto apply; } } else if (t == TSYMBOL) { if (R1 == cell_symbol_boot_module) goto vm_return; if (R1 == cell_symbol_current_module) goto vm_return; if (R1 == cell_symbol_begin) goto vm_return; if (R1 == cell_symbol_call_with_current_continuation) goto vm_return; R1 = assert_defined (R1, module_ref (R0, R1)); goto vm_return; } else if (t == TVARIABLE) { x = R1->variable; R1 = x->cdr; goto vm_return; } else if (t == TBROKEN_HEART) error (cell_symbol_system_error, R1); else goto vm_return; macro_expand: if (R1->type != TPAIR || R1->car == cell_symbol_quote) goto vm_return; if (R1->car == cell_symbol_lambda) { push_cc (R1->cdr->cdr, R1, R0, cell_vm_macro_expand_lambda); goto macro_expand; macro_expand_lambda: R2->cdr->cdr = R1; R1 = R2; goto vm_return; } if (R1->type == TPAIR) { macro = get_macro (R1->car); if (macro != cell_f) { R1 = cons (macro, R1->cdr); push_cc (R1, cell_nil, R0, cell_vm_macro_expand); goto apply; } } if (R1->car == cell_symbol_define || R1->car == cell_symbol_define_macro) { push_cc (R1->cdr->cdr, R1, R0, cell_vm_macro_expand_define); goto macro_expand; macro_expand_define: R2->cdr->cdr = R1; R1 = R2; if (R1->car == cell_symbol_define_macro) { push_cc (R1, R1, R0, cell_vm_macro_expand_define_macro); goto eval; macro_expand_define_macro: R1 = R2; } goto vm_return; } if (R1->car == cell_symbol_set_x) { push_cc (R1->cdr->cdr, R1, R0, cell_vm_macro_expand_set_x); goto macro_expand; macro_expand_set_x: R2->cdr->cdr = R1; R1 = R2; goto vm_return; } if (R1->type == TPAIR) { a = R1->car; if (a->type == TSYMBOL && a != cell_symbol_begin) { macro = macro_get_handle (cell_symbol_portable_macro_expand); if (macro != cell_f) { expanders = module_ref (R0, cell_symbol_sc_expander_alist); if (expanders != cell_undefined) { macro = assq (R1->car, expanders); if (macro != cell_f) { sc_expand = module_ref (R0, cell_symbol_macro_expand); R2 = R1; if (sc_expand != cell_undefined && sc_expand != cell_f) { R1 = cons (sc_expand, cons (R1, cell_nil)); goto apply; } } } } } } push_cc (R1->car, R1, R0, cell_vm_macro_expand_car); goto macro_expand; macro_expand_car: R2->car = R1; R1 = R2; if (R1->cdr == cell_nil) goto vm_return; push_cc (R1->cdr, R1, R0, cell_vm_macro_expand_cdr); goto macro_expand; macro_expand_cdr: R2->cdr = R1; R1 = R2; goto vm_return; begin: x = cell_unspecified; while (R1 != cell_nil) { gc_check (); if (R1->type == TPAIR) { if (R1->car->car == cell_symbol_primitive_load) { program = cons (R1->car, cell_nil); push_cc (program, R1, R0, cell_vm_begin_primitive_load); goto begin_expand; begin_primitive_load: R2->car = R1; R1 = R2; } } if (R1->type == TPAIR) { a = R1->car; if (a->type == TPAIR) { if (a->car == cell_symbol_begin) R1 = append2 (a->cdr, R1->cdr); } } if (R1->cdr == cell_nil) { R1 = R1->car; goto eval; } push_cc (R1->car, R1, R0, cell_vm_begin_eval); goto eval; begin_eval: x = R1; R1 = R2->cdr; } R1 = x; goto vm_return; begin_expand: x = cell_unspecified; while (R1 != cell_nil) { begin_expand_while: gc_check (); if (R1->type == TPAIR) { a = R1->car; if (a->type == TPAIR) if (R1->car->car == cell_symbol_begin) R1 = append2 (R1->car->cdr, R1->cdr); if (R1->car->car == cell_symbol_primitive_load) { push_cc (R1->car->cdr->car, R1, R0, cell_vm_begin_expand_primitive_load); goto eval; begin_expand_primitive_load: if ((R1->type == TNUMBER) && R1->value == 0) 0; else if (R1->type == TSTRING) input = set_current_input_port (open_input_file (R1)); else if (R1->type == TPORT) input = set_current_input_port (R1); else { eputs ("begin_expand failed, R1="); display_error_ (R1); assert_msg (0, "begin-expand-boom 0"); } push_cc (input, R2, R0, cell_vm_return); x = read_input_file_env (R0); if (g_debug > 5) module_printer (M0); gc_pop_frame (); input = R1; R1 = x; set_current_input_port (input); R1 = cons (cell_symbol_begin, R1); R2->car = R1; R1 = R2; goto begin_expand_while; continue; /* FIXME: M2-PLanet */ } } push_cc (R1->car, R1, R0, cell_vm_begin_expand_macro); goto macro_expand; begin_expand_macro: if (R1 != R2->car) { R2->car = R1; R1 = R2; goto begin_expand_while; continue; /* FIXME: M2-PLanet */ } R1 = R2; expand_variable (R1->car, cell_nil); push_cc (R1->car, R1, R0, cell_vm_begin_expand_eval); goto eval; begin_expand_eval: x = R1; R1 = R2->cdr; } R1 = x; goto vm_return; vm_if: push_cc (R1->car, R1, R0, cell_vm_if_expr); goto eval; if_expr: x = R1; R1 = R2; if (x != cell_f) { R1 = R1->cdr->car; goto eval; } if (R1->cdr->cdr != cell_nil) { R1 = R1->cdr->cdr->car; goto eval; } R1 = cell_unspecified; goto vm_return; call_with_current_continuation: gc_push_frame (); x = make_continuation (g_continuations); g_continuations = g_continuations + 1; v = make_vector_ (STACK_SIZE - g_stack, cell_unspecified); for (i = g_stack; i < STACK_SIZE; i = i + 1) vector_set_x_ (v, i - g_stack, g_stack_array[i]); x->continuation = v; gc_pop_frame (); push_cc (cons (R1->car, cons (x, cell_nil)), x, R0, cell_vm_call_with_current_continuation2); goto apply; call_with_current_continuation2: v = make_vector_ (STACK_SIZE - g_stack, cell_unspecified); for (i = g_stack; i < STACK_SIZE; i = i + 1) vector_set_x_ (v, i - g_stack, g_stack_array[i]); R2->continuation = v; goto vm_return; call_with_values: push_cc (cons (R1->car, cell_nil), R1, R0, cell_vm_call_with_values2); goto apply; call_with_values2: if (R1->type == TVALUES) R1 = R1->cdr; R1 = cons (R2->cdr->car, R1); goto apply; vm_return: x = R1; gc_pop_frame (); R1 = x; goto eval_apply; } struct scm * apply (struct scm *f, struct scm *x, struct scm *a) /*:((internal)) */ { push_cc (cons (f, x), cell_unspecified, R0, cell_unspecified); R3 = cell_vm_apply; return eval_apply (); }