static SCM scm_srcprops_to_alist (SCM obj) { SCM alist = SRCPROPALIST (obj); if (!SCM_UNBNDP (SRCPROPCOPY (obj))) alist = scm_acons (scm_sym_copy, SRCPROPCOPY (obj), alist); alist = scm_acons (scm_sym_column, scm_from_int (SRCPROPCOL (obj)), alist); alist = scm_acons (scm_sym_line, scm_from_int (SRCPROPLINE (obj)), alist); return alist; }
static void env_link_add_flat_var (SCM env_link, SCM var, SCM pos) { SCM vars = env_link_vars (env_link); if (scm_is_false (scm_assq (var, vars))) scm_set_cdr_x (env_link, scm_acons (var, pos, vars)); }
/* FIXME: Remove named let in this boot expander. */ static SCM expand_named_let (const SCM expr, SCM env) { SCM var_names, var_syms, inits; SCM inner_env; SCM name_sym; const SCM cdr_expr = CDR (expr); const SCM name = CAR (cdr_expr); const SCM cddr_expr = CDR (cdr_expr); const SCM bindings = CAR (cddr_expr); check_bindings (bindings, expr); transform_bindings (bindings, expr, &var_names, &var_syms, &inits); name_sym = scm_gensym (SCM_UNDEFINED); inner_env = scm_acons (name, name_sym, env); inner_env = expand_env_extend (inner_env, var_names, var_syms); return LETREC (scm_source_properties (expr), SCM_BOOL_F, scm_list_1 (name), scm_list_1 (name_sym), scm_list_1 (LAMBDA (SCM_BOOL_F, SCM_EOL, LAMBDA_CASE (SCM_BOOL_F, var_names, SCM_BOOL_F, SCM_BOOL_F, SCM_BOOL_F, SCM_BOOL_F, var_syms, expand_sequence (CDDDR (expr), inner_env), SCM_BOOL_F))), CALL (SCM_BOOL_F, LEXICAL_REF (SCM_BOOL_F, name, name_sym), expand_exprs (inits, env))); }
SCM scm_make_srcprops (long line, int col, SCM filename, SCM copy, SCM alist) { if (!SCM_UNBNDP (filename)) { SCM old_alist = alist; /* have to extract the acons, and operate on that, for thread safety. */ SCM last_acons = SCM_CDR (scm_last_alist_filename); if (scm_is_null (old_alist) && scm_is_eq (SCM_CDAR (last_acons), filename)) { alist = last_acons; } else { alist = scm_acons (scm_sym_filename, filename, alist); if (scm_is_null (old_alist)) scm_set_cdr_x (scm_last_alist_filename, alist); } } SCM_RETURN_NEWSMOB3 (scm_tc16_srcprops, SRCPROPMAKPOS (line, col), SCM_UNPACK (copy), SCM_UNPACK (alist)); }
static SCM expand_env_extend (SCM env, SCM names, SCM vars) { while (scm_is_pair (names)) { env = scm_acons (CAR (names), CAR (vars), env); names = CDR (names); vars = CDR (vars); } return env; }
static SCM expand_cond_clauses (SCM clause, SCM rest, int elp, int alp, SCM env) { SCM test; const long length = scm_ilength (clause); ASSERT_SYNTAX (length >= 1, s_bad_cond_clause, clause); test = CAR (clause); if (scm_is_eq (test, scm_sym_else) && elp) { const int last_clause_p = scm_is_null (rest); ASSERT_SYNTAX (length >= 2, s_bad_cond_clause, clause); ASSERT_SYNTAX (last_clause_p, s_misplaced_else_clause, clause); return expand_sequence (CDR (clause), env); } if (scm_is_null (rest)) rest = VOID (SCM_BOOL_F); else rest = expand_cond_clauses (CAR (rest), CDR (rest), elp, alp, env); if (length >= 2 && scm_is_eq (CADR (clause), scm_sym_arrow) && alp) { SCM tmp = scm_gensym (scm_from_locale_string ("cond ")); SCM new_env = scm_acons (tmp, tmp, env); ASSERT_SYNTAX (length > 2, s_missing_recipient, clause); ASSERT_SYNTAX (length == 3, s_extra_expression, clause); return LET (SCM_BOOL_F, scm_list_1 (tmp), scm_list_1 (tmp), scm_list_1 (expand (test, env)), CONDITIONAL (SCM_BOOL_F, LEXICAL_REF (SCM_BOOL_F, tmp, tmp), CALL (SCM_BOOL_F, expand (CADDR (clause), new_env), scm_list_1 (LEXICAL_REF (SCM_BOOL_F, tmp, tmp))), rest)); } /* FIXME length == 1 case */ else return CONDITIONAL (SCM_BOOL_F, expand (test, env), expand_sequence (CDR (clause), env), rest); }
static SCM expand_letstar_clause (SCM bindings, SCM body, SCM env SCM_UNUSED) { if (scm_is_null (bindings)) return expand_sequence (body, env); else { SCM bind, name, sym, init; ASSERT_SYNTAX (scm_is_pair (bindings), s_bad_expression, bindings); bind = CAR (bindings); ASSERT_SYNTAX (scm_ilength (bind) == 2, s_bad_binding, bind); name = CAR (bind); sym = scm_gensym (SCM_UNDEFINED); init = CADR (bind); return LET (SCM_BOOL_F, scm_list_1 (name), scm_list_1 (sym), scm_list_1 (expand (init, env)), expand_letstar_clause (CDR (bindings), body, scm_acons (name, sym, env))); } }
static SCM expand_or (SCM expr, SCM env SCM_UNUSED) { SCM tail = CDR (expr); const long length = scm_ilength (tail); ASSERT_SYNTAX (length >= 0, s_bad_expression, expr); if (scm_is_null (CDR (expr))) return CONST (SCM_BOOL_F, SCM_BOOL_F); else { SCM tmp = scm_gensym (SCM_UNDEFINED); return LET (SCM_BOOL_F, scm_list_1 (tmp), scm_list_1 (tmp), scm_list_1 (expand (CADR (expr), env)), CONDITIONAL (SCM_BOOL_F, LEXICAL_REF (SCM_BOOL_F, tmp, tmp), LEXICAL_REF (SCM_BOOL_F, tmp, tmp), expand_or (CDR (expr), scm_acons (tmp, tmp, env)))); } }
static SCM memoize (SCM exp, SCM env) { if (!SCM_EXPANDED_P (exp)) abort (); switch (SCM_EXPANDED_TYPE (exp)) { case SCM_EXPANDED_VOID: return MAKMEMO_QUOTE (SCM_UNSPECIFIED); case SCM_EXPANDED_CONST: return MAKMEMO_QUOTE (REF (exp, CONST, EXP)); case SCM_EXPANDED_PRIMITIVE_REF: if (scm_is_eq (scm_current_module (), scm_the_root_module ())) return maybe_makmemo_capture_module (MAKMEMO_BOX_REF (MAKMEMO_TOP_BOX (SCM_EXPANDED_TOPLEVEL_REF, REF (exp, PRIMITIVE_REF, NAME))), env); else return MAKMEMO_BOX_REF (MAKMEMO_MOD_BOX (SCM_EXPANDED_MODULE_REF, list_of_guile, REF (exp, PRIMITIVE_REF, NAME), SCM_BOOL_F)); case SCM_EXPANDED_LEXICAL_REF: return MAKMEMO_LEX_REF (lookup (REF (exp, LEXICAL_REF, GENSYM), env)); case SCM_EXPANDED_LEXICAL_SET: return MAKMEMO_LEX_SET (lookup (REF (exp, LEXICAL_SET, GENSYM), env), memoize (REF (exp, LEXICAL_SET, EXP), env)); case SCM_EXPANDED_MODULE_REF: return MAKMEMO_BOX_REF (MAKMEMO_MOD_BOX (SCM_EXPANDED_MODULE_REF, REF (exp, MODULE_REF, MOD), REF (exp, MODULE_REF, NAME), REF (exp, MODULE_REF, PUBLIC))); case SCM_EXPANDED_MODULE_SET: return MAKMEMO_BOX_SET (MAKMEMO_MOD_BOX (SCM_EXPANDED_MODULE_SET, REF (exp, MODULE_SET, MOD), REF (exp, MODULE_SET, NAME), REF (exp, MODULE_SET, PUBLIC)), memoize (REF (exp, MODULE_SET, EXP), env)); case SCM_EXPANDED_TOPLEVEL_REF: return maybe_makmemo_capture_module (MAKMEMO_BOX_REF (MAKMEMO_TOP_BOX (SCM_EXPANDED_TOPLEVEL_REF, REF (exp, TOPLEVEL_REF, NAME))), env); case SCM_EXPANDED_TOPLEVEL_SET: return maybe_makmemo_capture_module (MAKMEMO_BOX_SET (MAKMEMO_TOP_BOX (SCM_EXPANDED_TOPLEVEL_SET, REF (exp, TOPLEVEL_SET, NAME)), memoize (REF (exp, TOPLEVEL_SET, EXP), capture_env (env))), env); case SCM_EXPANDED_TOPLEVEL_DEFINE: return maybe_makmemo_capture_module (MAKMEMO_BOX_SET (MAKMEMO_TOP_BOX (SCM_EXPANDED_TOPLEVEL_DEFINE, REF (exp, TOPLEVEL_DEFINE, NAME)), memoize (REF (exp, TOPLEVEL_DEFINE, EXP), capture_env (env))), env); case SCM_EXPANDED_CONDITIONAL: return MAKMEMO_IF (memoize (REF (exp, CONDITIONAL, TEST), env), memoize (REF (exp, CONDITIONAL, CONSEQUENT), env), memoize (REF (exp, CONDITIONAL, ALTERNATE), env)); case SCM_EXPANDED_CALL: { SCM proc, args; proc = REF (exp, CALL, PROC); args = memoize_exps (REF (exp, CALL, ARGS), env); return MAKMEMO_CALL (memoize (proc, env), args); } case SCM_EXPANDED_PRIMCALL: { SCM name, args; int nargs; name = REF (exp, PRIMCALL, NAME); args = memoize_exps (REF (exp, PRIMCALL, ARGS), env); nargs = scm_ilength (args); if (nargs == 3 && scm_is_eq (name, scm_from_latin1_symbol ("call-with-prompt"))) return MAKMEMO_CALL_WITH_PROMPT (CAR (args), CADR (args), CADDR (args)); else if (nargs == 2 && scm_is_eq (name, scm_from_latin1_symbol ("apply"))) return MAKMEMO_APPLY (CAR (args), CADR (args)); else if (nargs == 1 && scm_is_eq (name, scm_from_latin1_symbol ("call-with-current-continuation"))) return MAKMEMO_CONT (CAR (args)); else if (nargs == 2 && scm_is_eq (name, scm_from_latin1_symbol ("call-with-values"))) return MAKMEMO_CALL_WITH_VALUES (CAR (args), CADR (args)); else if (nargs == 1 && scm_is_eq (name, scm_from_latin1_symbol ("variable-ref"))) return MAKMEMO_BOX_REF (CAR (args)); else if (nargs == 2 && scm_is_eq (name, scm_from_latin1_symbol ("variable-set!"))) return MAKMEMO_BOX_SET (CAR (args), CADR (args)); else if (nargs == 2 && scm_is_eq (name, scm_from_latin1_symbol ("wind"))) return MAKMEMO_CALL (MAKMEMO_QUOTE (wind), args); else if (nargs == 0 && scm_is_eq (name, scm_from_latin1_symbol ("unwind"))) return MAKMEMO_CALL (MAKMEMO_QUOTE (unwind), SCM_EOL); else if (nargs == 2 && scm_is_eq (name, scm_from_latin1_symbol ("push-fluid"))) return MAKMEMO_CALL (MAKMEMO_QUOTE (push_fluid), args); else if (nargs == 0 && scm_is_eq (name, scm_from_latin1_symbol ("pop-fluid"))) return MAKMEMO_CALL (MAKMEMO_QUOTE (pop_fluid), SCM_EOL); else if (nargs == 1 && scm_is_eq (name, scm_from_latin1_symbol ("push-dynamic-state"))) return MAKMEMO_CALL (MAKMEMO_QUOTE (push_dynamic_state), args); else if (nargs == 0 && scm_is_eq (name, scm_from_latin1_symbol ("pop-dynamic-state"))) return MAKMEMO_CALL (MAKMEMO_QUOTE (pop_dynamic_state), SCM_EOL); else if (scm_is_eq (scm_current_module (), scm_the_root_module ())) return MAKMEMO_CALL (maybe_makmemo_capture_module (MAKMEMO_BOX_REF (MAKMEMO_TOP_BOX (SCM_EXPANDED_TOPLEVEL_REF, name)), env), args); else return MAKMEMO_CALL (MAKMEMO_BOX_REF (MAKMEMO_MOD_BOX (SCM_EXPANDED_MODULE_REF, list_of_guile, name, SCM_BOOL_F)), args); } case SCM_EXPANDED_SEQ: return MAKMEMO_SEQ (memoize (REF (exp, SEQ, HEAD), env), memoize (REF (exp, SEQ, TAIL), env)); case SCM_EXPANDED_LAMBDA: /* The body will be a lambda-case. */ { SCM meta, body, proc, new_env; meta = REF (exp, LAMBDA, META); body = REF (exp, LAMBDA, BODY); new_env = push_flat_link (capture_env (env)); proc = memoize (body, new_env); SCM_SETCAR (SCM_CDR (SCM_MEMOIZED_ARGS (proc)), meta); return maybe_makmemo_capture_module (capture_flat_env (proc, new_env), env); } case SCM_EXPANDED_LAMBDA_CASE: { SCM req, rest, opt, kw, inits, vars, body, alt; SCM unbound, arity, rib, new_env; int nreq, nopt, ninits; req = REF (exp, LAMBDA_CASE, REQ); rest = scm_not (scm_not (REF (exp, LAMBDA_CASE, REST))); opt = REF (exp, LAMBDA_CASE, OPT); kw = REF (exp, LAMBDA_CASE, KW); inits = REF (exp, LAMBDA_CASE, INITS); vars = REF (exp, LAMBDA_CASE, GENSYMS); body = REF (exp, LAMBDA_CASE, BODY); alt = REF (exp, LAMBDA_CASE, ALTERNATE); nreq = scm_ilength (req); nopt = scm_is_pair (opt) ? scm_ilength (opt) : 0; ninits = scm_ilength (inits); /* This relies on assignment conversion turning inits into a sequence of CONST expressions whose values are a unique "unbound" token. */ unbound = ninits ? REF (CAR (inits), CONST, EXP) : SCM_BOOL_F; rib = scm_vector (vars); new_env = push_nested_link (rib, env); if (scm_is_true (kw)) { /* (aok? (kw name sym) ...) -> (aok? (kw . index) ...) */ SCM aok = CAR (kw), indices = SCM_EOL; for (kw = CDR (kw); scm_is_pair (kw); kw = CDR (kw)) { SCM k; int idx; k = CAR (CAR (kw)); idx = lookup_rib (CADDR (CAR (kw)), rib); indices = scm_acons (k, SCM_I_MAKINUM (idx), indices); } kw = scm_cons (aok, scm_reverse_x (indices, SCM_UNDEFINED)); } if (scm_is_false (alt) && scm_is_false (kw) && scm_is_false (opt)) { if (scm_is_false (rest)) arity = FIXED_ARITY (nreq); else arity = REST_ARITY (nreq, SCM_BOOL_T); } else if (scm_is_true (alt)) arity = FULL_ARITY (nreq, rest, nopt, kw, ninits, unbound, SCM_MEMOIZED_ARGS (memoize (alt, env))); else arity = FULL_ARITY (nreq, rest, nopt, kw, ninits, unbound, SCM_BOOL_F); return MAKMEMO_LAMBDA (memoize (body, new_env), arity, SCM_EOL /* meta, filled in later */); } case SCM_EXPANDED_LET: { SCM vars, exps, body, varsv, inits, new_env; int i; vars = REF (exp, LET, GENSYMS); exps = REF (exp, LET, VALS); body = REF (exp, LET, BODY); varsv = scm_vector (vars); inits = scm_c_make_vector (VECTOR_LENGTH (varsv), SCM_BOOL_F); new_env = push_nested_link (varsv, capture_env (env)); for (i = 0; scm_is_pair (exps); exps = CDR (exps), i++) VECTOR_SET (inits, i, memoize (CAR (exps), env)); return maybe_makmemo_capture_module (MAKMEMO_LET (inits, memoize (body, new_env)), env); } default: abort (); } }
static SCM push_flat_link (SCM env) { return scm_acons (SCM_BOOL_T, SCM_EOL, env); }
static SCM push_nested_link (SCM vars, SCM env) { return scm_acons (SCM_BOOL_F, vars, env); }
SCM py2scm(PyObject *value) { if (value == Py_None) { return SCM_UNSPECIFIED; } if (PyBool_Check(value)) { int v = PyObject_IsTrue(value); if (v == -1) return NULL; return scm_from_bool(v); } if (PyInt_Check(value)) { long v = PyInt_AsLong(value); if (PyErr_Occurred()) return NULL; return scm_from_long(v); } if (PyFloat_Check(value)) { double v = PyFloat_AsDouble(value); if (PyErr_Occurred()) return NULL; return scm_from_double(v); } if (PyString_Check(value)) { const char *s = PyString_AsString(value); if (s == NULL) return NULL; return scm_from_utf8_stringn(s, PyString_Size(value)); } if (PyUnicode_Check(value)) { scm_dynwind_begin(0); PyObject *utf8_str = PyUnicode_AsUTF8String(value); if (utf8_str == NULL) { scm_dynwind_end(); return NULL; } scm_dynwind_py_decref(utf8_str); const char *s = PyString_AsString(utf8_str); if (s == NULL) { scm_dynwind_end(); return NULL; } SCM result = scm_from_utf8_stringn(s, PyString_Size(utf8_str)); scm_dynwind_end(); return result; } if (PySequence_Check(value)) { unsigned int i = PySequence_Size(value); SCM r = SCM_EOL; while (i-- > 0) { PyObject *item = PySequence_GetItem(value, i); r = scm_cons(py2scm(item), r); } return r; } if (PyObject_TypeCheck(value, &ProcedureType)) return ((Procedure *)value)->proc; if (PyCallable_Check(value)) { SCM gsubr = scm_c_make_gsubr( "<Python function>", 0, 0, 1, &call_callable); Py_INCREF(value); SCM ptr = scm_from_pointer(value, (void (*)(void *))Py_DecRef); gsubr_alist = scm_acons(gsubr, ptr, gsubr_alist); return gsubr; } char buf[BUFSIZ]; snprintf(buf, BUFSIZ, "Python type \"%.50s\" doesn't have a " "corresponding Guile type", value->ob_type->tp_name); scm_error(scm_from_utf8_symbol("misc-error"), NULL, buf, SCM_EOL, SCM_EOL); /* does not return */ fprintf(stderr, "*** scm_error shouldn't have returned ***\n"); return SCM_UNSPECIFIED; }
static SCM expand_lambda_star_case (SCM clause, SCM alternate, SCM env) { SCM req, opt, kw, allow_other_keys, rest, formals, vars, body, tmp; SCM inits; int nreq, nopt; const long length = scm_ilength (clause); ASSERT_SYNTAX (length >= 1, s_bad_expression, scm_cons (sym_lambda_star, clause)); ASSERT_SYNTAX (length >= 2, s_missing_expression, scm_cons (sym_lambda_star, clause)); formals = CAR (clause); body = CDR (clause); nreq = nopt = 0; req = opt = kw = SCM_EOL; rest = allow_other_keys = SCM_BOOL_F; while (scm_is_pair (formals) && scm_is_symbol (CAR (formals))) { nreq++; req = scm_cons (CAR (formals), req); formals = scm_cdr (formals); } if (scm_is_pair (formals) && scm_is_eq (CAR (formals), kw_optional)) { formals = CDR (formals); while (scm_is_pair (formals) && (scm_is_symbol (CAR (formals)) || scm_is_pair (CAR (formals)))) { nopt++; opt = scm_cons (CAR (formals), opt); formals = scm_cdr (formals); } } if (scm_is_pair (formals) && scm_is_eq (CAR (formals), kw_key)) { formals = CDR (formals); while (scm_is_pair (formals) && (scm_is_symbol (CAR (formals)) || scm_is_pair (CAR (formals)))) { kw = scm_cons (CAR (formals), kw); formals = scm_cdr (formals); } } if (scm_is_pair (formals) && scm_is_eq (CAR (formals), kw_allow_other_keys)) { formals = CDR (formals); allow_other_keys = SCM_BOOL_T; } if (scm_is_pair (formals) && scm_is_eq (CAR (formals), kw_rest)) { ASSERT_SYNTAX (scm_ilength (formals) == 2, s_bad_formals, CAR (clause)); rest = CADR (formals); } else if (scm_is_symbol (formals)) rest = formals; else { ASSERT_SYNTAX (scm_is_null (formals), s_bad_formals, CAR (clause)); rest = SCM_BOOL_F; } /* Now, iterate through them a second time, building up an expansion-time environment, checking, expanding and canonicalizing the opt/kw init forms, and eventually memoizing the body as well. Note that the rest argument, if any, is expanded before keyword args, thus necessitating the second pass. Also note that the specific environment during expansion of init expressions here needs to coincide with the environment when psyntax expands. A lot of effort for something that is only used in the bootstrap expandr, you say? Yes. Yes it is. */ vars = SCM_EOL; req = scm_reverse_x (req, SCM_EOL); for (tmp = req; scm_is_pair (tmp); tmp = scm_cdr (tmp)) { vars = scm_cons (scm_gensym (SCM_UNDEFINED), vars); env = scm_acons (CAR (tmp), CAR (vars), env); } /* Build up opt inits and env */ inits = SCM_EOL; opt = scm_reverse_x (opt, SCM_EOL); for (tmp = opt; scm_is_pair (tmp); tmp = scm_cdr (tmp)) { SCM x = CAR (tmp); vars = scm_cons (scm_gensym (SCM_UNDEFINED), vars); env = scm_acons (x, CAR (vars), env); if (scm_is_symbol (x)) inits = scm_cons (CONST (SCM_BOOL_F, SCM_BOOL_F), inits); else { ASSERT_SYNTAX (scm_ilength (x) == 2 && scm_is_symbol (CAR (x)), s_bad_formals, CAR (clause)); inits = scm_cons (expand (CADR (x), env), inits); } env = scm_acons (scm_is_symbol (x) ? x : CAR (x), CAR (vars), env); } if (scm_is_null (opt)) opt = SCM_BOOL_F; /* Process rest before keyword args */ if (scm_is_true (rest)) { vars = scm_cons (scm_gensym (SCM_UNDEFINED), vars); env = scm_acons (rest, CAR (vars), env); } /* Build up kw inits, env, and kw-canon list */ if (scm_is_null (kw)) kw = SCM_BOOL_F; else { SCM kw_canon = SCM_EOL; kw = scm_reverse_x (kw, SCM_UNDEFINED); for (tmp = kw; scm_is_pair (tmp); tmp = scm_cdr (tmp)) { SCM x, sym, k, init; x = CAR (tmp); if (scm_is_symbol (x)) { sym = x; init = SCM_BOOL_F; k = scm_symbol_to_keyword (sym); } else if (scm_ilength (x) == 2 && scm_is_symbol (CAR (x))) { sym = CAR (x); init = CADR (x); k = scm_symbol_to_keyword (sym); } else if (scm_ilength (x) == 3 && scm_is_symbol (CAR (x)) && scm_is_keyword (CADDR (x))) { sym = CAR (x); init = CADR (x); k = CADDR (x); } else syntax_error (s_bad_formals, CAR (clause), SCM_UNDEFINED); inits = scm_cons (expand (init, env), inits); vars = scm_cons (scm_gensym (SCM_UNDEFINED), vars); kw_canon = scm_cons (scm_list_3 (k, sym, CAR (vars)), kw_canon); env = scm_acons (sym, CAR (vars), env); } kw_canon = scm_reverse_x (kw_canon, SCM_UNDEFINED); kw = scm_cons (allow_other_keys, kw_canon); } /* We should check for no duplicates, but given that psyntax does this already, we can punt on it here... */ vars = scm_reverse_x (vars, SCM_UNDEFINED); inits = scm_reverse_x (inits, SCM_UNDEFINED); body = expand_sequence (body, env); return LAMBDA_CASE (SCM_BOOL_F, req, opt, rest, kw, inits, vars, body, alternate); }
static SCM expand_lambda_case (SCM clause, SCM alternate, SCM env) { SCM formals; SCM rest; SCM req = SCM_EOL; SCM vars = SCM_EOL; SCM body; int nreq = 0; ASSERT_SYNTAX (scm_is_pair (clause) && scm_is_pair (CDR (clause)), s_bad_expression, scm_cons (scm_sym_lambda, clause)); /* Before iterating the list of formal arguments, make sure the formals * actually are given as either a symbol or a non-cyclic list. */ formals = CAR (clause); if (scm_is_pair (formals)) { /* Dirk:FIXME:: We should check for a cyclic list of formals, and if * detected, report a 'Bad formals' error. */ } else ASSERT_SYNTAX_2 (scm_is_symbol (formals) || scm_is_null (formals), s_bad_formals, formals, scm_cons (scm_sym_lambda, clause)); /* Now iterate the list of formal arguments to check if all formals are * symbols, and that there are no duplicates. */ while (scm_is_pair (formals)) { const SCM formal = CAR (formals); formals = CDR (formals); ASSERT_SYNTAX_2 (scm_is_symbol (formal), s_bad_formal, formal, scm_cons (scm_sym_lambda, clause)); ASSERT_SYNTAX_2 (!c_improper_memq (formal, formals), s_duplicate_formal, formal, scm_cons (scm_sym_lambda, clause)); nreq++; req = scm_cons (formal, req); vars = scm_cons (scm_gensym (SCM_UNDEFINED), vars); env = scm_acons (formal, CAR (vars), env); } ASSERT_SYNTAX_2 (scm_is_null (formals) || scm_is_symbol (formals), s_bad_formal, formals, scm_cons (scm_sym_lambda, clause)); if (scm_is_symbol (formals)) { rest = formals; vars = scm_cons (scm_gensym (SCM_UNDEFINED), vars); env = scm_acons (rest, CAR (vars), env); } else rest = SCM_BOOL_F; body = expand_sequence (CDR (clause), env); req = scm_reverse_x (req, SCM_UNDEFINED); vars = scm_reverse_x (vars, SCM_UNDEFINED); if (scm_is_true (alternate) && !(SCM_EXPANDED_P (alternate) && SCM_EXPANDED_TYPE (alternate) == SCM_EXPANDED_LAMBDA_CASE)) abort (); return LAMBDA_CASE (SCM_BOOL_F, req, SCM_BOOL_F, rest, SCM_BOOL_F, SCM_EOL, vars, body, alternate); }
static SCM memoize (SCM exp, SCM env) { if (!SCM_EXPANDED_P (exp)) abort (); switch (SCM_EXPANDED_TYPE (exp)) { case SCM_EXPANDED_VOID: return MAKMEMO_QUOTE (SCM_UNSPECIFIED); case SCM_EXPANDED_CONST: return MAKMEMO_QUOTE (REF (exp, CONST, EXP)); case SCM_EXPANDED_PRIMITIVE_REF: if (scm_is_eq (scm_current_module (), scm_the_root_module ())) return MAKMEMO_TOP_REF (REF (exp, PRIMITIVE_REF, NAME)); else return MAKMEMO_MOD_REF (list_of_guile, REF (exp, PRIMITIVE_REF, NAME), SCM_BOOL_F); case SCM_EXPANDED_LEXICAL_REF: return MAKMEMO_LEX_REF (lookup (REF (exp, LEXICAL_REF, GENSYM), env)); case SCM_EXPANDED_LEXICAL_SET: return MAKMEMO_LEX_SET (lookup (REF (exp, LEXICAL_SET, GENSYM), env), memoize (REF (exp, LEXICAL_SET, EXP), env)); case SCM_EXPANDED_MODULE_REF: return MAKMEMO_MOD_REF (REF (exp, MODULE_REF, MOD), REF (exp, MODULE_REF, NAME), REF (exp, MODULE_REF, PUBLIC)); case SCM_EXPANDED_MODULE_SET: return MAKMEMO_MOD_SET (memoize (REF (exp, MODULE_SET, EXP), env), REF (exp, MODULE_SET, MOD), REF (exp, MODULE_SET, NAME), REF (exp, MODULE_SET, PUBLIC)); case SCM_EXPANDED_TOPLEVEL_REF: return MAKMEMO_TOP_REF (REF (exp, TOPLEVEL_REF, NAME)); case SCM_EXPANDED_TOPLEVEL_SET: return MAKMEMO_TOP_SET (REF (exp, TOPLEVEL_SET, NAME), memoize (REF (exp, TOPLEVEL_SET, EXP), env)); case SCM_EXPANDED_TOPLEVEL_DEFINE: return MAKMEMO_DEFINE (REF (exp, TOPLEVEL_DEFINE, NAME), memoize (REF (exp, TOPLEVEL_DEFINE, EXP), env)); case SCM_EXPANDED_CONDITIONAL: return MAKMEMO_IF (memoize (REF (exp, CONDITIONAL, TEST), env), memoize (REF (exp, CONDITIONAL, CONSEQUENT), env), memoize (REF (exp, CONDITIONAL, ALTERNATE), env)); case SCM_EXPANDED_CALL: { SCM proc, args; proc = REF (exp, CALL, PROC); args = memoize_exps (REF (exp, CALL, ARGS), env); return MAKMEMO_CALL (memoize (proc, env), scm_ilength (args), args); } case SCM_EXPANDED_PRIMCALL: { SCM name, args; int nargs; name = REF (exp, PRIMCALL, NAME); args = memoize_exps (REF (exp, PRIMCALL, ARGS), env); nargs = scm_ilength (args); if (nargs == 3 && scm_is_eq (name, scm_from_latin1_symbol ("call-with-prompt"))) return MAKMEMO_CALL_WITH_PROMPT (CAR (args), CADR (args), CADDR (args)); else if (nargs == 2 && scm_is_eq (name, scm_from_latin1_symbol ("apply"))) return MAKMEMO_APPLY (CAR (args), CADR (args)); else if (nargs == 1 && scm_is_eq (name, scm_from_latin1_symbol ("call-with-current-continuation"))) return MAKMEMO_CONT (CAR (args)); else if (nargs == 2 && scm_is_eq (name, scm_from_latin1_symbol ("call-with-values"))) return MAKMEMO_CALL_WITH_VALUES (CAR (args), CADR (args)); else if (nargs == 2 && scm_is_eq (name, scm_from_latin1_symbol ("wind"))) return MAKMEMO_CALL (MAKMEMO_QUOTE (wind), 2, args); else if (nargs == 0 && scm_is_eq (name, scm_from_latin1_symbol ("unwind"))) return MAKMEMO_CALL (MAKMEMO_QUOTE (unwind), 0, SCM_EOL); else if (nargs == 2 && scm_is_eq (name, scm_from_latin1_symbol ("push-fluid"))) return MAKMEMO_CALL (MAKMEMO_QUOTE (push_fluid), 2, args); else if (nargs == 0 && scm_is_eq (name, scm_from_latin1_symbol ("pop-fluid"))) return MAKMEMO_CALL (MAKMEMO_QUOTE (pop_fluid), 0, SCM_EOL); else if (scm_is_eq (scm_current_module (), scm_the_root_module ())) return MAKMEMO_CALL (MAKMEMO_TOP_REF (name), nargs, args); else return MAKMEMO_CALL (MAKMEMO_MOD_REF (list_of_guile, name, SCM_BOOL_F), nargs, args); } case SCM_EXPANDED_SEQ: return MAKMEMO_SEQ (memoize (REF (exp, SEQ, HEAD), env), memoize (REF (exp, SEQ, TAIL), env)); case SCM_EXPANDED_LAMBDA: /* The body will be a lambda-case or #f. */ { SCM meta, docstring, body, proc; meta = REF (exp, LAMBDA, META); docstring = scm_assoc_ref (meta, scm_sym_documentation); body = REF (exp, LAMBDA, BODY); if (scm_is_false (body)) /* Give a body to case-lambda with no clauses. */ proc = MAKMEMO_LAMBDA (MAKMEMO_CALL (MAKMEMO_MOD_REF (list_of_guile, scm_from_latin1_symbol ("throw"), SCM_BOOL_F), 5, scm_list_5 (MAKMEMO_QUOTE (scm_args_number_key), MAKMEMO_QUOTE (SCM_BOOL_F), MAKMEMO_QUOTE (scm_from_latin1_string ("Wrong number of arguments")), MAKMEMO_QUOTE (SCM_EOL), MAKMEMO_QUOTE (SCM_BOOL_F))), FIXED_ARITY (0), SCM_BOOL_F /* docstring */); else proc = memoize (body, env); if (scm_is_string (docstring)) { SCM args = SCM_MEMOIZED_ARGS (proc); SCM_SETCAR (SCM_CDR (args), docstring); } return proc; } case SCM_EXPANDED_LAMBDA_CASE: { SCM req, rest, opt, kw, inits, vars, body, alt; SCM walk, minits, arity, new_env; int nreq, nopt, ntotal; req = REF (exp, LAMBDA_CASE, REQ); rest = scm_not (scm_not (REF (exp, LAMBDA_CASE, REST))); opt = REF (exp, LAMBDA_CASE, OPT); kw = REF (exp, LAMBDA_CASE, KW); inits = REF (exp, LAMBDA_CASE, INITS); vars = REF (exp, LAMBDA_CASE, GENSYMS); body = REF (exp, LAMBDA_CASE, BODY); alt = REF (exp, LAMBDA_CASE, ALTERNATE); nreq = scm_ilength (req); nopt = scm_is_pair (opt) ? scm_ilength (opt) : 0; ntotal = scm_ilength (vars); /* The vars are the gensyms, according to the divine plan. But we need to memoize the inits within their appropriate environment, complicating things. */ new_env = env; for (walk = req; scm_is_pair (walk); walk = CDR (walk), vars = CDR (vars)) new_env = scm_cons (CAR (vars), new_env); minits = SCM_EOL; for (walk = opt; scm_is_pair (walk); walk = CDR (walk), vars = CDR (vars), inits = CDR (inits)) { minits = scm_cons (memoize (CAR (inits), new_env), minits); new_env = scm_cons (CAR (vars), new_env); } if (scm_is_true (rest)) { new_env = scm_cons (CAR (vars), new_env); vars = CDR (vars); } for (; scm_is_pair (inits); vars = CDR (vars), inits = CDR (inits)) { minits = scm_cons (memoize (CAR (inits), new_env), minits); new_env = scm_cons (CAR (vars), new_env); } if (!scm_is_null (vars)) abort (); minits = scm_reverse_x (minits, SCM_UNDEFINED); if (scm_is_true (kw)) { /* (aok? (kw name sym) ...) -> (aok? (kw . index) ...) */ SCM aok = CAR (kw), indices = SCM_EOL; for (kw = CDR (kw); scm_is_pair (kw); kw = CDR (kw)) { SCM k; int idx; k = CAR (CAR (kw)); idx = ntotal - 1 - lookup (CADDR (CAR (kw)), new_env); indices = scm_acons (k, SCM_I_MAKINUM (idx), indices); } kw = scm_cons (aok, scm_reverse_x (indices, SCM_UNDEFINED)); } if (scm_is_false (alt) && scm_is_false (kw) && scm_is_false (opt)) { if (scm_is_false (rest)) arity = FIXED_ARITY (nreq); else arity = REST_ARITY (nreq, SCM_BOOL_T); } else if (scm_is_true (alt)) arity = FULL_ARITY (nreq, rest, nopt, kw, minits, SCM_MEMOIZED_ARGS (memoize (alt, env))); else arity = FULL_ARITY (nreq, rest, nopt, kw, minits, SCM_BOOL_F); return MAKMEMO_LAMBDA (memoize (body, new_env), arity, SCM_BOOL_F /* docstring */); } case SCM_EXPANDED_LET: { SCM vars, exps, body, inits, new_env; vars = REF (exp, LET, GENSYMS); exps = REF (exp, LET, VALS); body = REF (exp, LET, BODY); inits = SCM_EOL; new_env = env; for (; scm_is_pair (vars); vars = CDR (vars), exps = CDR (exps)) { new_env = scm_cons (CAR (vars), new_env); inits = scm_cons (memoize (CAR (exps), env), inits); } return MAKMEMO_LET (scm_reverse_x (inits, SCM_UNDEFINED), memoize (body, new_env)); } case SCM_EXPANDED_LETREC: { SCM vars, exps, body, undefs, new_env; int i, nvars, in_order_p; vars = REF (exp, LETREC, GENSYMS); exps = REF (exp, LETREC, VALS); body = REF (exp, LETREC, BODY); in_order_p = scm_is_true (REF (exp, LETREC, IN_ORDER_P)); nvars = i = scm_ilength (vars); undefs = SCM_EOL; new_env = env; for (; scm_is_pair (vars); vars = CDR (vars)) { new_env = scm_cons (CAR (vars), new_env); undefs = scm_cons (MAKMEMO_QUOTE (SCM_UNDEFINED), undefs); } if (in_order_p) { SCM body_exps = SCM_EOL, seq; for (; scm_is_pair (exps); exps = CDR (exps), i--) body_exps = scm_cons (MAKMEMO_LEX_SET (i-1, memoize (CAR (exps), new_env)), body_exps); seq = memoize (body, new_env); for (; scm_is_pair (body_exps); body_exps = CDR (body_exps)) seq = MAKMEMO_SEQ (CAR (body_exps), seq); return MAKMEMO_LET (undefs, seq); } else { SCM sets = SCM_EOL, inits = SCM_EOL, set_seq; for (; scm_is_pair (exps); exps = CDR (exps), i--) { sets = scm_cons (MAKMEMO_LEX_SET ((i-1) + nvars, MAKMEMO_LEX_REF (i-1)), sets); inits = scm_cons (memoize (CAR (exps), new_env), inits); } inits = scm_reverse_x (inits, SCM_UNDEFINED); sets = scm_reverse_x (sets, SCM_UNDEFINED); if (scm_is_null (sets)) return memoize (body, env); for (set_seq = CAR (sets), sets = CDR (sets); scm_is_pair (sets); sets = CDR (sets)) set_seq = MAKMEMO_SEQ (CAR (sets), set_seq); return MAKMEMO_LET (undefs, MAKMEMO_SEQ (MAKMEMO_LET (inits, set_seq), memoize (body, new_env))); } } default: abort (); } }