mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 03:40:34 +02:00
new evaluator, y'all
* libguile/eval.c: So, ladies & gents, a new evaluator. It's similar to the old one, in that we memoize and then evaluate, but in this incarnation, memoization of an expression happens before evaluation, not lazily as the expression is evaluated. This makes the evaluation itself much cleaner, in addition to being threadsafe. In addition, since this C evaluator will in the future just serve to bootstrap the Scheme evaluator, we don't have to pay much concern for debugging conveniences. So the environment is just a list of values, and the memoizer pre-computes where it's going to find each individual value in the environment. Interface changes are commented below, with eval.h. (scm_evaluator_traps): No need to reset the debug mode after rnning te traps thing. But really, the whole traps system needs some love. * libguile/memoize.h: * libguile/memoize.c: New memoizer, which runs before evaluation, checking all syntax before evaluation begins. Significantly, no debugging information is left for lexical variables, which is not so great for interactive debugging; perhaps we should change this to have a var list in the future as per the classic interpreters. But it's quite fast, and the resulting code is quite good. Also note that it doesn't produce ilocs, memoized code is a smob whose type is in the first word of the smob itself. * libguile/eval.h (scm_sym_and, scm_sym_begin, scm_sym_case) (scm_sym_cond, scm_sym_define, scm_sym_do, scm_sym_if, scm_sym_lambda) (scm_sym_let, scm_sym_letstar, scm_sym_letrec, scm_sym_quote) (scm_sym_quasiquote, scm_sym_unquote, scm_sym_uq_splicing, scm_sym_at) (scm_sym_atat, scm_sym_atapply, scm_sym_atcall_cc) (scm_sym_at_call_with_values, scm_sym_delay, scm_sym_eval_when) (scm_sym_arrow, scm_sym_else, scm_sym_apply, scm_sym_set_x) (scm_sym_args): Remove public declaration of these symbols. (scm_ilookup, scm_lookupcar, scm_eval_car, scm_eval_body) (scm_eval_args, scm_i_eval_x, scm_i_eval): Remove public declaration of these functions. (scm_ceval, scm_deval, scm_ceval_ptr): Remove declarations of these deprecated functions. (scm_i_print_iloc, scm_i_print_isym, scm_i_unmemocopy_expr) (scm_i_unmemocopy_body): Remove declarations of these internal functions. (scm_primitive_eval_x, scm_eval_x): Redefine as macros for their less destructive siblings. * libguile/Makefile.am: Add memoize.[ch] to the build. * libguile/debug.h (scm_debug_mode_p, scm_check_entry_p) (scm_check_apply_p, scm_check_exit_p, scm_check_memoize_p) (scm_debug_eframe_size): Remove these vars that were tied to the old evaluator's execution model. (SCM_RESET_DEBUG_MODE): Remove, no more need for this. (SCM_MEMOIZEDP, SCM_MEMOIZED_EXP, SCM_MEMOIZED_ENV): Remove macros referring to old memoized code representation. (scm_local_eval, scm_procedure_environment, scm_memoized_environment) (scm_make_memoized, scm_memoized_p): Remove functions operating on old memoized code representation. (scm_memcons, scm_mem_to_proc, scm_proc_to_mem): Remove debug-only code for old evaluator. * libguile/debug.c: Remove code to correspond with debug.h removals. (scm_debug_options): No need to set the debug mode or frame limit here, as we don't have C stack limits any more. Perhaps this is a bug, but as long as we can compile eval.scm, we should be fine. * libguile/init.c (scm_i_init_guile): Init memoize.c. * libguile/modules.c (scm_top_level_env, scm_env_top_level) (scm_env_module, scm_system_module_env_p): Remove these functions. * libguile/print.c (iprin1): No more need to handle isyms. Adapt to new form of interpreted procedures. * libguile/procprop.c (scm_i_procedure_arity): Adapt to new form of interpreted procedures. * libguile/procs.c (scm_thunk_p): Adapt to new form of interpreted procedures. * libguile/procs.h (SCM_CLOSURE_FORMALS): Removed, this exists no more. (SCM_CLOSURE_NUM_REQUIRED_ARGS, SCM_CLOSURE_HAS_REST_ARGS): New accessors. * libguile/srcprop.c (scm_source_properties, scm_source_property) (scm_set_source_property_x): Remove special cases for memoized code. * libguile/stacks.c (read_frame): Remove a source-property case for interpreted code. (NEXT_FRAME): Remove a case that I don't fully understand, that seems to be designed to skip over apply frames. Will be obsolete in the futures. (read_frames): Default source value for interpreted frames to #f. (narrow_stack): Don't pay attention to the system_module thing. * libguile/tags.h: Remove isyms and ilocs. Whee! * libguile/validate.h (SCM_VALIDATE_MEMOIZED): Fix to use the new MEMOIZED_P formulation. * module/ice-9/psyntax-pp.scm (do, quasiquote, case): Adapt for these no longer being primitive macros. * module/ice-9/boot-9.scm: Whitespace change, but just a poke to force a rebuild due to and/or/cond/... not being primitives any more. * module/ice-9/deprecated.scm (unmemoize-expr): Deprecate, it's unmemoize-expression now. * test-suite/tests/eval.test ("define set procedure-name"): XFAIL a couple of tests here; I don't know what to do about them. I reckon the expander should ensure that defined values are named. * test-suite/tests/chars.test ("basic char handling"): Fix expected exception when trying to apply a char.
This commit is contained in:
parent
83c7655002
commit
b7742c6b71
24 changed files with 1786 additions and 5094 deletions
312
libguile/debug.c
312
libguile/debug.c
|
@ -48,6 +48,7 @@
|
|||
#include "libguile/root.h"
|
||||
#include "libguile/fluids.h"
|
||||
#include "libguile/programs.h"
|
||||
#include "libguile/memoize.h"
|
||||
|
||||
#include "libguile/validate.h"
|
||||
#include "libguile/debug.h"
|
||||
|
@ -77,11 +78,9 @@ SCM_DEFINE (scm_debug_options, "debug-options-interface", 0, 1, 0,
|
|||
scm_options (ans, scm_debug_opts, FUNC_NAME);
|
||||
SCM_OUT_OF_RANGE (1, setting);
|
||||
}
|
||||
SCM_RESET_DEBUG_MODE;
|
||||
#ifdef STACK_CHECKING
|
||||
scm_stack_checking_enabled_p = SCM_STACK_CHECKING_P;
|
||||
#endif
|
||||
scm_debug_eframe_size = 2 * SCM_N_FRAMES;
|
||||
|
||||
scm_dynwind_end ();
|
||||
return ans;
|
||||
|
@ -131,175 +130,6 @@ SCM_SYMBOL (scm_sym_procname, "procname");
|
|||
SCM_SYMBOL (scm_sym_dots, "...");
|
||||
SCM_SYMBOL (scm_sym_source, "source");
|
||||
|
||||
/* {Memoized Source}
|
||||
*/
|
||||
|
||||
scm_t_bits scm_tc16_memoized;
|
||||
|
||||
static int
|
||||
memoized_print (SCM obj, SCM port, scm_print_state *pstate)
|
||||
{
|
||||
int writingp = SCM_WRITINGP (pstate);
|
||||
scm_puts ("#<memoized ", port);
|
||||
SCM_SET_WRITINGP (pstate, 1);
|
||||
scm_iprin1 (SCM_MEMOIZED_EXP (obj), port, pstate);
|
||||
SCM_SET_WRITINGP (pstate, writingp);
|
||||
scm_putc ('>', port);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SCM_DEFINE (scm_memoized_p, "memoized?", 1, 0, 0,
|
||||
(SCM obj),
|
||||
"Return @code{#t} if @var{obj} is memoized.")
|
||||
#define FUNC_NAME s_scm_memoized_p
|
||||
{
|
||||
return scm_from_bool(SCM_MEMOIZEDP (obj));
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
SCM
|
||||
scm_make_memoized (SCM exp, SCM env)
|
||||
{
|
||||
/* *fixme* Check that env is a valid environment. */
|
||||
SCM_RETURN_NEWSMOB (scm_tc16_memoized, SCM_UNPACK (scm_cons (exp, env)));
|
||||
}
|
||||
|
||||
#ifdef GUILE_DEBUG
|
||||
/*
|
||||
* Some primitives for construction of memoized code
|
||||
*
|
||||
* - procedure: memcons CAR CDR [ENV]
|
||||
*
|
||||
* Construct a pair, encapsulated in a memoized object.
|
||||
*
|
||||
* The CAR and CDR can be either normal or memoized. If ENV isn't
|
||||
* specified, the top-level environment of the current module will
|
||||
* be assumed. All environments must match.
|
||||
*
|
||||
* - procedure: make-iloc FRAME BINDING CDRP
|
||||
*
|
||||
* Return an iloc referring to frame no. FRAME, binding
|
||||
* no. BINDING. If CDRP is non-#f, the iloc is referring to a
|
||||
* frame consisting of a single pair, with the value stored in the
|
||||
* CDR.
|
||||
*
|
||||
* - procedure: iloc? OBJECT
|
||||
*
|
||||
* Return #t if OBJECT is an iloc.
|
||||
*
|
||||
* - procedure: mem->proc MEMOIZED
|
||||
*
|
||||
* Construct a closure from the memoized lambda expression MEMOIZED
|
||||
*
|
||||
* WARNING! The code is not copied!
|
||||
*
|
||||
* - procedure: proc->mem CLOSURE
|
||||
*
|
||||
* Turn the closure CLOSURE into a memoized object.
|
||||
*
|
||||
* WARNING! The code is not copied!
|
||||
*
|
||||
* - constant: SCM_IM_AND
|
||||
* - constant: SCM_IM_BEGIN
|
||||
* - constant: SCM_IM_CASE
|
||||
* - constant: SCM_IM_COND
|
||||
* - constant: SCM_IM_DO
|
||||
* - constant: SCM_IM_IF
|
||||
* - constant: SCM_IM_LAMBDA
|
||||
* - constant: SCM_IM_LET
|
||||
* - constant: SCM_IM_LETSTAR
|
||||
* - constant: SCM_IM_LETREC
|
||||
* - constant: SCM_IM_OR
|
||||
* - constant: SCM_IM_QUOTE
|
||||
* - constant: SCM_IM_SET
|
||||
* - constant: SCM_IM_DEFINE
|
||||
* - constant: SCM_IM_APPLY
|
||||
* - constant: SCM_IM_CONT
|
||||
* - constant: SCM_IM_DISPATCH
|
||||
*/
|
||||
|
||||
#include "libguile/variable.h"
|
||||
#include "libguile/procs.h"
|
||||
|
||||
SCM_DEFINE (scm_memcons, "memcons", 2, 1, 0,
|
||||
(SCM car, SCM cdr, SCM env),
|
||||
"Return a new memoized cons cell with @var{car} and @var{cdr}\n"
|
||||
"as members and @var{env} as the environment.")
|
||||
#define FUNC_NAME s_scm_memcons
|
||||
{
|
||||
if (SCM_MEMOIZEDP (car))
|
||||
{
|
||||
/*fixme* environments may be two different but equal top-level envs */
|
||||
if (!SCM_UNBNDP (env) && SCM_MEMOIZED_ENV (car) != env)
|
||||
SCM_MISC_ERROR ("environment mismatch arg1 <-> arg3",
|
||||
scm_list_2 (car, env));
|
||||
else
|
||||
env = SCM_MEMOIZED_ENV (car);
|
||||
car = SCM_MEMOIZED_EXP (car);
|
||||
}
|
||||
if (SCM_MEMOIZEDP (cdr))
|
||||
{
|
||||
if (!SCM_UNBNDP (env) && SCM_MEMOIZED_ENV (cdr) != env)
|
||||
SCM_MISC_ERROR ("environment mismatch arg2 <-> arg3",
|
||||
scm_list_2 (cdr, env));
|
||||
else
|
||||
env = SCM_MEMOIZED_ENV (cdr);
|
||||
cdr = SCM_MEMOIZED_EXP (cdr);
|
||||
}
|
||||
if (SCM_UNBNDP (env))
|
||||
env = scm_top_level_env (SCM_TOP_LEVEL_LOOKUP_CLOSURE);
|
||||
else
|
||||
SCM_VALIDATE_NULLORCONS (3, env);
|
||||
return scm_make_memoized (scm_cons (car, cdr), env);
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
SCM_DEFINE (scm_mem_to_proc, "mem->proc", 1, 0, 0,
|
||||
(SCM obj),
|
||||
"Convert a memoized object (which must represent a body)\n"
|
||||
"to a procedure.")
|
||||
#define FUNC_NAME s_scm_mem_to_proc
|
||||
{
|
||||
SCM env;
|
||||
SCM_VALIDATE_MEMOIZED (1, obj);
|
||||
env = SCM_MEMOIZED_ENV (obj);
|
||||
obj = SCM_MEMOIZED_EXP (obj);
|
||||
return scm_closure (obj, env);
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
SCM_DEFINE (scm_proc_to_mem, "proc->mem", 1, 0, 0,
|
||||
(SCM obj),
|
||||
"Convert a procedure to a memoized object.")
|
||||
#define FUNC_NAME s_scm_proc_to_mem
|
||||
{
|
||||
SCM_VALIDATE_CLOSURE (1, obj);
|
||||
return scm_make_memoized (SCM_CODE (obj), SCM_ENV (obj));
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
#endif /* GUILE_DEBUG */
|
||||
|
||||
SCM_DEFINE (scm_i_unmemoize_expr, "unmemoize-expr", 1, 0, 0,
|
||||
(SCM m),
|
||||
"Unmemoize the memoized expression @var{m},")
|
||||
#define FUNC_NAME s_scm_i_unmemoize_expr
|
||||
{
|
||||
SCM_VALIDATE_MEMOIZED (1, m);
|
||||
return scm_i_unmemocopy_expr (SCM_MEMOIZED_EXP (m), SCM_MEMOIZED_ENV (m));
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
SCM_DEFINE (scm_memoized_environment, "memoized-environment", 1, 0, 0,
|
||||
(SCM m),
|
||||
"Return the environment of the memoized expression @var{m}.")
|
||||
#define FUNC_NAME s_scm_memoized_environment
|
||||
{
|
||||
SCM_VALIDATE_MEMOIZED (1, m);
|
||||
return SCM_MEMOIZED_ENV (m);
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
SCM_DEFINE (scm_procedure_name, "procedure-name", 1, 0, 0,
|
||||
(SCM proc),
|
||||
"Return the name of the procedure @var{proc}")
|
||||
|
@ -333,74 +163,32 @@ SCM_DEFINE (scm_procedure_source, "procedure-source", 1, 0, 0,
|
|||
"Return the source of the procedure @var{proc}.")
|
||||
#define FUNC_NAME s_scm_procedure_source
|
||||
{
|
||||
SCM_VALIDATE_NIM (1, proc);
|
||||
again:
|
||||
switch (SCM_TYP7 (proc)) {
|
||||
case scm_tcs_closures:
|
||||
{
|
||||
const SCM formals = SCM_CLOSURE_FORMALS (proc);
|
||||
const SCM body = SCM_CLOSURE_BODY (proc);
|
||||
const SCM src = scm_source_property (body, scm_sym_copy);
|
||||
SCM src;
|
||||
SCM_VALIDATE_PROC (1, proc);
|
||||
|
||||
if (scm_is_true (src))
|
||||
{
|
||||
return scm_cons2 (scm_sym_lambda, formals, src);
|
||||
}
|
||||
else
|
||||
{
|
||||
const SCM env = SCM_EXTEND_ENV (formals, SCM_EOL, SCM_ENV (proc));
|
||||
return scm_cons2 (scm_sym_lambda,
|
||||
scm_i_finite_list_copy (formals),
|
||||
scm_i_unmemocopy_body (body, env));
|
||||
}
|
||||
}
|
||||
case scm_tcs_struct:
|
||||
if (!SCM_STRUCT_APPLICABLE_P (proc))
|
||||
break;
|
||||
proc = SCM_STRUCT_PROCEDURE (proc);
|
||||
if (SCM_IMP (proc))
|
||||
break;
|
||||
goto procprop;
|
||||
case scm_tc7_smob:
|
||||
if (!SCM_SMOB_DESCRIPTOR (proc).apply)
|
||||
break;
|
||||
case scm_tcs_subrs:
|
||||
case scm_tc7_program:
|
||||
procprop:
|
||||
/* It would indeed be a nice thing if we supplied source even for
|
||||
built in procedures! */
|
||||
return scm_procedure_property (proc, scm_sym_source);
|
||||
case scm_tc7_pws:
|
||||
do
|
||||
{
|
||||
SCM src = scm_procedure_property (proc, scm_sym_source);
|
||||
src = scm_procedure_property (proc, scm_sym_source);
|
||||
if (scm_is_true (src))
|
||||
return src;
|
||||
proc = SCM_PROCEDURE (proc);
|
||||
goto again;
|
||||
}
|
||||
default:
|
||||
;
|
||||
}
|
||||
SCM_WRONG_TYPE_ARG (1, proc);
|
||||
return SCM_BOOL_F; /* not reached */
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
return src;
|
||||
|
||||
SCM_DEFINE (scm_procedure_environment, "procedure-environment", 1, 0, 0,
|
||||
(SCM proc),
|
||||
"Return the environment of the procedure @var{proc}.")
|
||||
#define FUNC_NAME s_scm_procedure_environment
|
||||
{
|
||||
SCM_VALIDATE_NIM (1, proc);
|
||||
switch (SCM_TYP7 (proc)) {
|
||||
case scm_tcs_closures:
|
||||
return SCM_ENV (proc);
|
||||
case scm_tcs_subrs:
|
||||
return SCM_EOL;
|
||||
default:
|
||||
SCM_WRONG_TYPE_ARG (1, proc);
|
||||
/* not reached */
|
||||
}
|
||||
switch (SCM_TYP7 (proc)) {
|
||||
case scm_tcs_struct:
|
||||
if (!SCM_STRUCT_APPLICABLE_P (proc)
|
||||
|| SCM_IMP (SCM_STRUCT_PROCEDURE (proc)))
|
||||
break;
|
||||
proc = SCM_STRUCT_PROCEDURE (proc);
|
||||
continue;
|
||||
case scm_tc7_pws:
|
||||
proc = SCM_PROCEDURE (proc);
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (0);
|
||||
|
||||
return SCM_BOOL_F;
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
|
@ -413,37 +201,21 @@ SCM_DEFINE (scm_procedure_module, "procedure-module", 1, 0, 0,
|
|||
|
||||
if (scm_is_true (scm_program_p (proc)))
|
||||
return scm_program_module (proc);
|
||||
else if (SCM_CLOSUREP (proc))
|
||||
{
|
||||
SCM env = SCM_ENV (proc);
|
||||
while (scm_is_pair (env))
|
||||
env = scm_cdr (env);
|
||||
return env;
|
||||
}
|
||||
else
|
||||
return scm_env_module (scm_procedure_environment (proc));
|
||||
return SCM_BOOL_F;
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
|
||||
|
||||
|
||||
/* Eval in a local environment. We would like to have the ability to
|
||||
* evaluate in a specified local environment, but due to the
|
||||
* memoization this isn't normally possible. We solve it by copying
|
||||
* the code before evaluating. One solution would be to have eval.c
|
||||
* generate yet another evaluator. They are not very big actually.
|
||||
*/
|
||||
SCM_DEFINE (scm_local_eval, "local-eval", 1, 1, 0,
|
||||
(SCM exp, SCM env),
|
||||
"Evaluate @var{exp} in its environment. If @var{env} is supplied,\n"
|
||||
"it is the environment in which to evaluate @var{exp}. Otherwise,\n"
|
||||
"@var{exp} must be a memoized code object (in which case, its environment\n"
|
||||
"is implicit).")
|
||||
#define FUNC_NAME s_scm_local_eval
|
||||
{
|
||||
if (SCM_UNBNDP (env))
|
||||
{
|
||||
SCM_VALIDATE_MEMOIZED (1, exp);
|
||||
return scm_i_eval_x (SCM_MEMOIZED_EXP (exp), SCM_MEMOIZED_ENV (exp));
|
||||
}
|
||||
return scm_i_eval (exp, env);
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
#if 0
|
||||
SCM_REGISTER_PROC (s_reverse_lookup, "reverse-lookup", 2, 0, 0, scm_reverse_lookup);
|
||||
#endif
|
||||
|
@ -565,31 +337,9 @@ scm_init_debug ()
|
|||
init_stack_limit ();
|
||||
scm_init_opts (scm_debug_options, scm_debug_opts);
|
||||
|
||||
scm_tc16_memoized = scm_make_smob_type ("memoized", 0);
|
||||
scm_set_smob_print (scm_tc16_memoized, memoized_print);
|
||||
|
||||
scm_tc16_debugobj = scm_make_smob_type ("debug-object", 0);
|
||||
scm_set_smob_print (scm_tc16_debugobj, debugobj_print);
|
||||
|
||||
#ifdef GUILE_DEBUG
|
||||
scm_c_define ("SCM_IM_AND", SCM_IM_AND);
|
||||
scm_c_define ("SCM_IM_BEGIN", SCM_IM_BEGIN);
|
||||
scm_c_define ("SCM_IM_CASE", SCM_IM_CASE);
|
||||
scm_c_define ("SCM_IM_COND", SCM_IM_COND);
|
||||
scm_c_define ("SCM_IM_DO", SCM_IM_DO);
|
||||
scm_c_define ("SCM_IM_IF", SCM_IM_IF);
|
||||
scm_c_define ("SCM_IM_LAMBDA", SCM_IM_LAMBDA);
|
||||
scm_c_define ("SCM_IM_LET", SCM_IM_LET);
|
||||
scm_c_define ("SCM_IM_LETSTAR", SCM_IM_LETSTAR);
|
||||
scm_c_define ("SCM_IM_LETREC", SCM_IM_LETREC);
|
||||
scm_c_define ("SCM_IM_OR", SCM_IM_OR);
|
||||
scm_c_define ("SCM_IM_QUOTE", SCM_IM_QUOTE);
|
||||
scm_c_define ("SCM_IM_SET_X", SCM_IM_SET_X);
|
||||
scm_c_define ("SCM_IM_DEFINE", SCM_IM_DEFINE);
|
||||
scm_c_define ("SCM_IM_APPLY", SCM_IM_APPLY);
|
||||
scm_c_define ("SCM_IM_CONT", SCM_IM_CONT);
|
||||
scm_c_define ("SCM_IM_DISPATCH", SCM_IM_DISPATCH);
|
||||
#endif
|
||||
scm_add_feature ("debug-extensions");
|
||||
|
||||
#include "libguile/debug.x"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue