mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-02 04:40:29 +02:00
* 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.
346 lines
9.7 KiB
C
346 lines
9.7 KiB
C
/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002, 2006, 2008, 2009 Free Software Foundation
|
||
*
|
||
* This library is free software; you can redistribute it and/or
|
||
* modify it under the terms of the GNU Lesser General Public License
|
||
* as published by the Free Software Foundation; either version 3 of
|
||
* the License, or (at your option) any later version.
|
||
*
|
||
* This library 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
|
||
* Lesser General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU Lesser General Public
|
||
* License along with this library; if not, write to the Free Software
|
||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||
* 02110-1301 USA
|
||
*/
|
||
|
||
|
||
|
||
#ifdef HAVE_CONFIG_H
|
||
# include <config.h>
|
||
#endif
|
||
|
||
#include <errno.h>
|
||
|
||
#include "libguile/_scm.h"
|
||
#include "libguile/async.h"
|
||
#include "libguile/smob.h"
|
||
#include "libguile/alist.h"
|
||
#include "libguile/debug.h"
|
||
#include "libguile/hashtab.h"
|
||
#include "libguile/hash.h"
|
||
#include "libguile/ports.h"
|
||
#include "libguile/root.h"
|
||
#include "libguile/weaks.h"
|
||
#include "libguile/gc.h"
|
||
|
||
#include "libguile/validate.h"
|
||
#include "libguile/srcprop.h"
|
||
|
||
/* {Source Properties}
|
||
*
|
||
* Properties of source list expressions.
|
||
* Five of these have special meaning:
|
||
*
|
||
* filename string The name of the source file.
|
||
* copy list A copy of the list expression.
|
||
* line integer The source code line number.
|
||
* column integer The source code column number.
|
||
* breakpoint boolean Sets a breakpoint on this form.
|
||
*
|
||
* Most properties above can be set by the reader.
|
||
*
|
||
*/
|
||
|
||
SCM_GLOBAL_SYMBOL (scm_sym_filename, "filename");
|
||
SCM_GLOBAL_SYMBOL (scm_sym_copy, "copy");
|
||
SCM_GLOBAL_SYMBOL (scm_sym_line, "line");
|
||
SCM_GLOBAL_SYMBOL (scm_sym_column, "column");
|
||
SCM_GLOBAL_SYMBOL (scm_sym_breakpoint, "breakpoint");
|
||
|
||
|
||
|
||
/*
|
||
* Source properties are stored as double cells with the
|
||
* following layout:
|
||
|
||
* car = tag
|
||
* cbr = pos
|
||
* ccr = copy
|
||
* cdr = alist
|
||
*/
|
||
|
||
#define SRCPROPSP(p) (SCM_SMOB_PREDICATE (scm_tc16_srcprops, (p)))
|
||
#define SRCPROPBRK(p) (SCM_SMOB_FLAGS (p) & SCM_SOURCE_PROPERTY_FLAG_BREAK)
|
||
#define SRCPROPPOS(p) (SCM_CELL_WORD(p,1))
|
||
#define SRCPROPLINE(p) (SRCPROPPOS(p) >> 12)
|
||
#define SRCPROPCOL(p) (SRCPROPPOS(p) & 0x0fffL)
|
||
#define SRCPROPCOPY(p) (SCM_CELL_OBJECT(p,2))
|
||
#define SRCPROPALIST(p) (SCM_CELL_OBJECT_3(p))
|
||
#define SETSRCPROPBRK(p) \
|
||
(SCM_SET_SMOB_FLAGS ((p), \
|
||
SCM_SMOB_FLAGS (p) | SCM_SOURCE_PROPERTY_FLAG_BREAK))
|
||
#define CLEARSRCPROPBRK(p) \
|
||
(SCM_SET_SMOB_FLAGS ((p), \
|
||
SCM_SMOB_FLAGS (p) & ~SCM_SOURCE_PROPERTY_FLAG_BREAK))
|
||
#define SRCPROPMAKPOS(l, c) (((l) << 12) + (c))
|
||
#define SETSRCPROPPOS(p, l, c) (SCM_SET_CELL_WORD(p,1, SRCPROPMAKPOS (l, c)))
|
||
#define SETSRCPROPLINE(p, l) SETSRCPROPPOS (p, l, SRCPROPCOL (p))
|
||
#define SETSRCPROPCOL(p, c) SETSRCPROPPOS (p, SRCPROPLINE (p), c)
|
||
#define SETSRCPROPCOPY(p, c) (SCM_SET_CELL_WORD(p, 2, c))
|
||
#define SETSRCPROPALIST(p, l) (SCM_SET_CELL_WORD(p, 3, l))
|
||
|
||
|
||
static SCM scm_srcprops_to_alist (SCM obj);
|
||
|
||
|
||
scm_t_bits scm_tc16_srcprops;
|
||
|
||
static int
|
||
srcprops_print (SCM obj, SCM port, scm_print_state *pstate)
|
||
{
|
||
int writingp = SCM_WRITINGP (pstate);
|
||
scm_puts ("#<srcprops ", port);
|
||
SCM_SET_WRITINGP (pstate, 1);
|
||
scm_iprin1 (scm_srcprops_to_alist (obj), port, pstate);
|
||
SCM_SET_WRITINGP (pstate, writingp);
|
||
scm_putc ('>', port);
|
||
return 1;
|
||
}
|
||
|
||
|
||
int
|
||
scm_c_source_property_breakpoint_p (SCM form)
|
||
{
|
||
SCM obj = scm_whash_lookup (scm_source_whash, form);
|
||
return SRCPROPSP (obj) && SRCPROPBRK (obj);
|
||
}
|
||
|
||
|
||
/*
|
||
* We remember the last file name settings, so we can share that alist
|
||
* entry. This works because scm_set_source_property_x does not use
|
||
* assoc-set! for modifying the alist.
|
||
*
|
||
* This variable contains a protected cons, whose cdr is the cached
|
||
* alist
|
||
*/
|
||
static SCM scm_last_alist_filename;
|
||
|
||
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 (old_alist == SCM_EOL
|
||
&& SCM_CDAR (last_acons) == filename)
|
||
{
|
||
alist = last_acons;
|
||
}
|
||
else
|
||
{
|
||
alist = scm_acons (scm_sym_filename, filename, alist);
|
||
if (old_alist == SCM_EOL)
|
||
SCM_SETCDR (scm_last_alist_filename, alist);
|
||
}
|
||
}
|
||
|
||
SCM_RETURN_NEWSMOB3 (scm_tc16_srcprops,
|
||
SRCPROPMAKPOS (line, col),
|
||
copy,
|
||
alist);
|
||
}
|
||
|
||
|
||
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);
|
||
alist = scm_acons (scm_sym_breakpoint, scm_from_bool (SRCPROPBRK (obj)), alist);
|
||
return alist;
|
||
}
|
||
|
||
SCM_DEFINE (scm_source_properties, "source-properties", 1, 0, 0,
|
||
(SCM obj),
|
||
"Return the source property association list of @var{obj}.")
|
||
#define FUNC_NAME s_scm_source_properties
|
||
{
|
||
SCM p;
|
||
SCM_VALIDATE_NIM (1, obj);
|
||
p = scm_hashq_ref (scm_source_whash, obj, SCM_EOL);
|
||
if (SRCPROPSP (p))
|
||
return scm_srcprops_to_alist (p);
|
||
else
|
||
/* list from set-source-properties!, or SCM_EOL for not found */
|
||
return p;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
/* Perhaps this procedure should look through an alist
|
||
and try to make a srcprops-object...? */
|
||
SCM_DEFINE (scm_set_source_properties_x, "set-source-properties!", 2, 0, 0,
|
||
(SCM obj, SCM alist),
|
||
"Install the association list @var{alist} as the source property\n"
|
||
"list for @var{obj}.")
|
||
#define FUNC_NAME s_scm_set_source_properties_x
|
||
{
|
||
SCM handle;
|
||
SCM_VALIDATE_NIM (1, obj);
|
||
handle = scm_hashq_create_handle_x (scm_source_whash, obj, alist);
|
||
SCM_SETCDR (handle, alist);
|
||
return alist;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_source_property, "source-property", 2, 0, 0,
|
||
(SCM obj, SCM key),
|
||
"Return the source property specified by @var{key} from\n"
|
||
"@var{obj}'s source property list.")
|
||
#define FUNC_NAME s_scm_source_property
|
||
{
|
||
SCM p;
|
||
SCM_VALIDATE_NIM (1, obj);
|
||
p = scm_hashq_ref (scm_source_whash, obj, SCM_EOL);
|
||
if (!SRCPROPSP (p))
|
||
goto alist;
|
||
if (scm_is_eq (scm_sym_breakpoint, key)) p = scm_from_bool (SRCPROPBRK (p));
|
||
else if (scm_is_eq (scm_sym_line, key)) p = scm_from_int (SRCPROPLINE (p));
|
||
else if (scm_is_eq (scm_sym_column, key)) p = scm_from_int (SRCPROPCOL (p));
|
||
else if (scm_is_eq (scm_sym_copy, key)) p = SRCPROPCOPY (p);
|
||
else
|
||
{
|
||
p = SRCPROPALIST (p);
|
||
alist:
|
||
p = scm_assoc (key, p);
|
||
return (SCM_NIMP (p) ? SCM_CDR (p) : SCM_BOOL_F);
|
||
}
|
||
return SCM_UNBNDP (p) ? SCM_BOOL_F : p;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_set_source_property_x, "set-source-property!", 3, 0, 0,
|
||
(SCM obj, SCM key, SCM datum),
|
||
"Set the source property of object @var{obj}, which is specified by\n"
|
||
"@var{key} to @var{datum}. Normally, the key will be a symbol.")
|
||
#define FUNC_NAME s_scm_set_source_property_x
|
||
{
|
||
scm_whash_handle h;
|
||
SCM p;
|
||
SCM_VALIDATE_NIM (1, obj);
|
||
h = scm_whash_get_handle (scm_source_whash, obj);
|
||
if (SCM_WHASHFOUNDP (h))
|
||
p = SCM_WHASHREF (scm_source_whash, h);
|
||
else
|
||
{
|
||
h = scm_whash_create_handle (scm_source_whash, obj);
|
||
p = SCM_EOL;
|
||
}
|
||
if (scm_is_eq (scm_sym_breakpoint, key))
|
||
{
|
||
if (SRCPROPSP (p))
|
||
{
|
||
if (scm_is_false (datum))
|
||
CLEARSRCPROPBRK (p);
|
||
else
|
||
SETSRCPROPBRK (p);
|
||
}
|
||
else
|
||
{
|
||
SCM sp = scm_make_srcprops (0, 0, SCM_UNDEFINED, SCM_UNDEFINED, p);
|
||
SCM_WHASHSET (scm_source_whash, h, sp);
|
||
if (scm_is_false (datum))
|
||
CLEARSRCPROPBRK (sp);
|
||
else
|
||
SETSRCPROPBRK (sp);
|
||
}
|
||
}
|
||
else if (scm_is_eq (scm_sym_line, key))
|
||
{
|
||
if (SRCPROPSP (p))
|
||
SETSRCPROPLINE (p, scm_to_int (datum));
|
||
else
|
||
SCM_WHASHSET (scm_source_whash, h,
|
||
scm_make_srcprops (scm_to_int (datum), 0,
|
||
SCM_UNDEFINED, SCM_UNDEFINED, p));
|
||
}
|
||
else if (scm_is_eq (scm_sym_column, key))
|
||
{
|
||
if (SRCPROPSP (p))
|
||
SETSRCPROPCOL (p, scm_to_int (datum));
|
||
else
|
||
SCM_WHASHSET (scm_source_whash, h,
|
||
scm_make_srcprops (0, scm_to_int (datum),
|
||
SCM_UNDEFINED, SCM_UNDEFINED, p));
|
||
}
|
||
else if (scm_is_eq (scm_sym_copy, key))
|
||
{
|
||
if (SRCPROPSP (p))
|
||
SETSRCPROPCOPY (p, datum);
|
||
else
|
||
SCM_WHASHSET (scm_source_whash, h, scm_make_srcprops (0, 0, SCM_UNDEFINED, datum, p));
|
||
}
|
||
else
|
||
{
|
||
if (SRCPROPSP (p))
|
||
SETSRCPROPALIST (p, scm_acons (key, datum, SRCPROPALIST (p)));
|
||
else
|
||
SCM_WHASHSET (scm_source_whash, h, scm_acons (key, datum, p));
|
||
}
|
||
return SCM_UNSPECIFIED;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
|
||
SCM_DEFINE (scm_cons_source, "cons-source", 3, 0, 0,
|
||
(SCM xorig, SCM x, SCM y),
|
||
"Create and return a new pair whose car and cdr are @var{x} and @var{y}.\n"
|
||
"Any source properties associated with @var{xorig} are also associated\n"
|
||
"with the new pair.")
|
||
#define FUNC_NAME s_scm_cons_source
|
||
{
|
||
SCM p, z;
|
||
z = scm_cons (x, y);
|
||
/* Copy source properties possibly associated with xorig. */
|
||
p = scm_whash_lookup (scm_source_whash, xorig);
|
||
if (scm_is_true (p))
|
||
scm_whash_insert (scm_source_whash, z, p);
|
||
return z;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
|
||
void
|
||
scm_init_srcprop ()
|
||
{
|
||
scm_tc16_srcprops = scm_make_smob_type ("srcprops", 0);
|
||
scm_set_smob_print (scm_tc16_srcprops, srcprops_print);
|
||
|
||
scm_source_whash = scm_make_weak_key_hash_table (scm_from_int (2047));
|
||
scm_c_define ("source-whash", scm_source_whash);
|
||
|
||
scm_last_alist_filename
|
||
= scm_permanent_object (scm_cons (SCM_EOL,
|
||
scm_acons (SCM_EOL, SCM_EOL, SCM_EOL)));
|
||
|
||
#include "libguile/srcprop.x"
|
||
}
|
||
|
||
|
||
/*
|
||
Local Variables:
|
||
c-file-style: "gnu"
|
||
End:
|
||
*/
|