5381 lines
151 KiB
C
5381 lines
151 KiB
C
/*
|
|
MzScheme
|
|
Copyright (c) 2004-2009 PLT Scheme Inc.
|
|
Copyright (c) 1995-2001 Matthew Flatt
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 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
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library 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.
|
|
|
|
libscheme
|
|
Copyright (c) 1994 Brent Benson
|
|
All rights reserved.
|
|
*/
|
|
|
|
/* This file implements environments (both compile-time and top-level
|
|
envionments, a.k.a. namespaces), and also implements much of the
|
|
initialization sequence (filling the initial namespace). */
|
|
|
|
#include "schpriv.h"
|
|
#include "mzrt.h"
|
|
#include "schminc.h"
|
|
#include "schmach.h"
|
|
#include "schexpobs.h"
|
|
|
|
#define GLOBAL_TABLE_SIZE 500
|
|
#define TABLE_CACHE_MAX_SIZE 2048
|
|
|
|
/* #define TIME_STARTUP_PROCESS */
|
|
|
|
/* global flags */
|
|
int scheme_allow_set_undefined;
|
|
void scheme_set_allow_set_undefined(int v) { scheme_allow_set_undefined = v; }
|
|
int scheme_get_allow_set_undefined() { return scheme_allow_set_undefined; }
|
|
int scheme_starting_up;
|
|
|
|
/* global counters just need to be atomically incremented */
|
|
static int intdef_counter = 0;
|
|
static int builtin_ref_counter = 0;
|
|
static int env_uid_counter = 0;
|
|
|
|
/* globals READ-ONLY SHARED */
|
|
static Scheme_Object *kernel_symbol;
|
|
static Scheme_Env *kernel_env;
|
|
|
|
#define MAX_CONST_LOCAL_POS 64
|
|
#define MAX_CONST_LOCAL_TYPES 2
|
|
#define MAX_CONST_LOCAL_FLAG_VAL 2
|
|
#define SCHEME_LOCAL_FLAGS_MASK 0x3
|
|
static Scheme_Object *scheme_local[MAX_CONST_LOCAL_POS][MAX_CONST_LOCAL_TYPES][MAX_CONST_LOCAL_FLAG_VAL + 1];
|
|
#define MAX_CONST_TOPLEVEL_DEPTH 16
|
|
#define MAX_CONST_TOPLEVEL_POS 16
|
|
#define SCHEME_TOPLEVEL_FLAGS_MASK 0x3
|
|
static Scheme_Object *toplevels[MAX_CONST_TOPLEVEL_DEPTH][MAX_CONST_TOPLEVEL_POS][SCHEME_TOPLEVEL_FLAGS_MASK + 1];
|
|
|
|
/* globals THREAD_LOCAL
|
|
* if locked theses are probably sharable*/
|
|
static THREAD_LOCAL Scheme_Hash_Table *toplevels_ht;
|
|
static THREAD_LOCAL Scheme_Hash_Table *locals_ht[2];
|
|
|
|
/* local functions */
|
|
static void make_kernel_env(void);
|
|
static void init_scheme_local();
|
|
static void init_toplevels();
|
|
|
|
static Scheme_Env *make_env(Scheme_Env *base, int toplevel_size);
|
|
static Scheme_Env *make_empty_inited_env(int toplevel_size);
|
|
static Scheme_Env *make_empty_not_inited_env(int toplevel_size);
|
|
|
|
static Scheme_Object *namespace_identifier(int, Scheme_Object *[]);
|
|
static Scheme_Object *namespace_module_identifier(int, Scheme_Object *[]);
|
|
static Scheme_Object *namespace_base_phase(int, Scheme_Object *[]);
|
|
static Scheme_Object *namespace_variable_value(int, Scheme_Object *[]);
|
|
static Scheme_Object *namespace_set_variable_value(int, Scheme_Object *[]);
|
|
static Scheme_Object *namespace_undefine_variable(int, Scheme_Object *[]);
|
|
static Scheme_Object *namespace_mapped_symbols(int, Scheme_Object *[]);
|
|
static Scheme_Object *namespace_module_registry(int, Scheme_Object *[]);
|
|
static Scheme_Object *variable_p(int, Scheme_Object *[]);
|
|
static Scheme_Object *variable_module_path(int, Scheme_Object *[]);
|
|
static Scheme_Object *variable_namespace(int, Scheme_Object *[]);
|
|
static Scheme_Object *variable_top_level_namespace(int, Scheme_Object *[]);
|
|
static Scheme_Object *variable_phase(int, Scheme_Object *[]);
|
|
static Scheme_Object *now_transforming(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_exp_time_value(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_exp_time_value_one(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_exp_time_name(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_context(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_phase_level(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_make_intdef_context(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *intdef_context_seal(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *intdef_context_p(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *id_intdef_remove(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_introduce(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_module_introduce(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_get_shadower(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_certify(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_module_exports(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_module_definitions(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_module_imports(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_module_expanding_provides(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_lift_expr(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_lift_context(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_lift_end_statement(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_lift_require(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *make_introducer(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *local_make_delta_introduce(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *make_set_transformer(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *set_transformer_p(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *set_transformer_proc(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *make_rename_transformer(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *rename_transformer_target(int argc, Scheme_Object *argv[]);
|
|
static Scheme_Object *rename_transformer_p(int argc, Scheme_Object *argv[]);
|
|
|
|
static Scheme_Object *write_toplevel(Scheme_Object *obj);
|
|
static Scheme_Object *read_toplevel(Scheme_Object *obj);
|
|
static Scheme_Object *write_variable(Scheme_Object *obj);
|
|
static Scheme_Object *read_variable(Scheme_Object *obj);
|
|
static Scheme_Object *write_module_variable(Scheme_Object *obj);
|
|
static Scheme_Object *read_module_variable(Scheme_Object *obj);
|
|
static Scheme_Object *write_local(Scheme_Object *obj);
|
|
static Scheme_Object *read_local(Scheme_Object *obj);
|
|
static Scheme_Object *read_local_unbox(Scheme_Object *obj);
|
|
static Scheme_Object *write_resolve_prefix(Scheme_Object *obj);
|
|
static Scheme_Object *read_resolve_prefix(Scheme_Object *obj);
|
|
|
|
static void skip_certain_things(Scheme_Object *o, Scheme_Close_Custodian_Client *f, void *data);
|
|
int scheme_is_module_begin_env(Scheme_Comp_Env *env);
|
|
|
|
Scheme_Env *scheme_engine_instance_init();
|
|
Scheme_Env *scheme_place_instance_init();
|
|
static void place_instance_init_pre_kernel();
|
|
static Scheme_Env *place_instance_init_post_kernel();
|
|
|
|
#ifdef MZ_PRECISE_GC
|
|
static void register_traversers(void);
|
|
#endif
|
|
|
|
typedef Scheme_Object *(*Lazy_Macro_Fun)(Scheme_Object *, int);
|
|
|
|
#define ARBITRARY_USE 0x1
|
|
#define CONSTRAINED_USE 0x2
|
|
#define WAS_SET_BANGED 0x4
|
|
#define ONE_ARBITRARY_USE 0x8
|
|
/* See also SCHEME_USE_COUNT_MASK */
|
|
|
|
typedef struct Compile_Data {
|
|
int num_const;
|
|
Scheme_Object **const_names;
|
|
Scheme_Object **const_vals;
|
|
Scheme_Object **const_uids;
|
|
int *sealed; /* NULL => already sealed */
|
|
int *use;
|
|
Scheme_Object *lifts;
|
|
} Compile_Data;
|
|
|
|
typedef struct Scheme_Full_Comp_Env {
|
|
Scheme_Comp_Env base;
|
|
Compile_Data data;
|
|
} Scheme_Full_Comp_Env;
|
|
static void init_compile_data(Scheme_Comp_Env *env);
|
|
|
|
/* Precise GC WARNING: this macro produces unaligned pointers: */
|
|
#define COMPILE_DATA(e) (&((Scheme_Full_Comp_Env *)e)->data)
|
|
|
|
#define SCHEME_NON_SIMPLE_FRAME (SCHEME_NO_RENAME | SCHEME_CAPTURE_WITHOUT_RENAME \
|
|
| SCHEME_FOR_STOPS | SCHEME_FOR_INTDEF | SCHEME_CAPTURE_LIFTED)
|
|
|
|
#define ASSERT_IS_VARIABLE_BUCKET(b) /* if (((Scheme_Object *)b)->type != scheme_variable_type) abort() */
|
|
|
|
/*========================================================================*/
|
|
/* initialization */
|
|
/*========================================================================*/
|
|
|
|
|
|
#ifdef DONT_USE_FOREIGN
|
|
static void init_dummy_foreign(Scheme_Env *env)
|
|
{
|
|
/* Works just well enough that the `mzscheme' module can
|
|
import it (so that attaching `mzscheme' to a namespace
|
|
also attaches `#%foreign'). */
|
|
Scheme_Env *menv;
|
|
menv = scheme_primitive_module(scheme_intern_symbol("#%foreign"), env);
|
|
scheme_finish_primitive_module(menv);
|
|
scheme_protect_primitive_provide(menv, NULL);
|
|
}
|
|
#endif
|
|
|
|
static void boot_module_resolver()
|
|
{
|
|
Scheme_Object *boot, *a[2];
|
|
a[0] = scheme_make_pair(scheme_intern_symbol("quote"),
|
|
scheme_make_pair(scheme_intern_symbol("#%boot"),
|
|
scheme_null));
|
|
a[1] = scheme_intern_symbol("boot");
|
|
boot = scheme_dynamic_require(2, a);
|
|
scheme_apply(boot, 0, NULL);
|
|
}
|
|
|
|
void os_platform_init() {
|
|
#ifdef UNIX_LIMIT_STACK
|
|
struct rlimit rl;
|
|
|
|
getrlimit(RLIMIT_STACK, &rl);
|
|
if (rl.rlim_cur > UNIX_LIMIT_STACK) {
|
|
rl.rlim_cur = UNIX_LIMIT_STACK;
|
|
setrlimit(RLIMIT_STACK, &rl);
|
|
}
|
|
#endif
|
|
#ifdef UNIX_LIMIT_FDSET_SIZE
|
|
struct rlimit rl;
|
|
|
|
getrlimit(RLIMIT_NOFILE, &rl);
|
|
if (rl.rlim_cur > FD_SETSIZE) {
|
|
rl.rlim_cur = FD_SETSIZE;
|
|
setrlimit(RLIMIT_NOFILE, &rl);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
Scheme_Env *scheme_restart_instance() {
|
|
Scheme_Env *env;
|
|
void *stack_base;
|
|
stack_base = (void *) scheme_get_current_os_thread_stack_base();
|
|
|
|
/* Reset everything: */
|
|
scheme_do_close_managed(NULL, skip_certain_things);
|
|
scheme_main_thread = NULL;
|
|
|
|
scheme_reset_finalizations();
|
|
scheme_init_stack_check();
|
|
#ifndef MZ_PRECISE_GC
|
|
scheme_init_setjumpup();
|
|
#endif
|
|
scheme_reset_overflow();
|
|
|
|
scheme_make_thread(stack_base);
|
|
scheme_init_error_escape_proc(NULL);
|
|
scheme_init_module_resolver();
|
|
|
|
env = scheme_make_empty_env();
|
|
scheme_install_initial_module_set(env);
|
|
scheme_set_param(scheme_current_config(), MZCONFIG_ENV, (Scheme_Object *)env);
|
|
|
|
scheme_init_port_config();
|
|
scheme_init_port_fun_config();
|
|
scheme_init_error_config();
|
|
#ifndef NO_SCHEME_EXNS
|
|
scheme_init_exn_config();
|
|
#endif
|
|
|
|
boot_module_resolver();
|
|
|
|
return env;
|
|
}
|
|
|
|
Scheme_Env *scheme_basic_env()
|
|
{
|
|
Scheme_Env *env;
|
|
|
|
if (scheme_main_thread) {
|
|
return scheme_restart_instance();
|
|
}
|
|
|
|
env = scheme_engine_instance_init();
|
|
|
|
return env;
|
|
}
|
|
|
|
static void init_toplevel_local_offsets_hashtable_caches()
|
|
{
|
|
REGISTER_SO(toplevels_ht);
|
|
REGISTER_SO(locals_ht[0]);
|
|
REGISTER_SO(locals_ht[1]);
|
|
|
|
{
|
|
Scheme_Hash_Table *ht;
|
|
toplevels_ht = scheme_make_hash_table_equal();
|
|
ht = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
locals_ht[0] = ht;
|
|
ht = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
locals_ht[1] = ht;
|
|
}
|
|
}
|
|
|
|
/* READ-ONLY GLOBAL structures ONE-TIME initialization */
|
|
Scheme_Env *scheme_engine_instance_init() {
|
|
Scheme_Env *env;
|
|
void *stack_base;
|
|
stack_base = (void *) scheme_get_current_os_thread_stack_base();
|
|
|
|
os_platform_init();
|
|
|
|
#ifdef TIME_STARTUP_PROCESS
|
|
printf("#if 0\nengine_instance_init @ %ld\n", scheme_get_process_milliseconds());
|
|
#endif
|
|
|
|
scheme_starting_up = 1;
|
|
|
|
scheme_init_portable_case();
|
|
init_scheme_local();
|
|
init_toplevels();
|
|
|
|
scheme_init_true_false();
|
|
|
|
#ifdef MZ_PRECISE_GC
|
|
scheme_register_traversers();
|
|
register_traversers();
|
|
scheme_init_hash_key_procs();
|
|
#endif
|
|
|
|
scheme_init_getenv(); /* checks PLTNOJIT */
|
|
|
|
#ifdef WINDOWS_PROCESSES
|
|
/* Must be called before first scheme_make_thread() */
|
|
scheme_init_thread_memory();
|
|
#endif
|
|
|
|
#ifndef MZ_PRECISE_GC
|
|
scheme_init_ephemerons();
|
|
#endif
|
|
|
|
/* These calls must be made here so that they allocate out of the master GC */
|
|
scheme_init_symbol_table();
|
|
scheme_init_module_path_table();
|
|
|
|
|
|
#if defined(MZ_PRECISE_GC) && defined(MZ_USE_PLACES)
|
|
GC_switch_out_master_gc();
|
|
spawn_master_scheme_place();
|
|
#endif
|
|
|
|
place_instance_init_pre_kernel(stack_base);
|
|
make_kernel_env();
|
|
scheme_init_parameterization_readonly_globals();
|
|
env = place_instance_init_post_kernel();
|
|
|
|
return env;
|
|
}
|
|
|
|
static void place_instance_init_pre_kernel(void *stack_base) {
|
|
|
|
#ifdef TIME_STARTUP_PROCESS
|
|
printf("place_init @ %ld\n", scheme_get_process_milliseconds());
|
|
#endif
|
|
scheme_set_current_os_thread_stack_base(stack_base);
|
|
|
|
#ifndef MZ_PRECISE_GC
|
|
scheme_init_setjumpup();
|
|
#endif
|
|
|
|
scheme_init_stack_check();
|
|
scheme_init_overflow();
|
|
|
|
init_toplevel_local_offsets_hashtable_caches();
|
|
|
|
|
|
#ifdef TIME_STARTUP_PROCESS
|
|
printf("pre-process @ %ld\n", scheme_get_process_milliseconds());
|
|
#endif
|
|
|
|
scheme_make_thread(stack_base);
|
|
|
|
scheme_init_module_resolver();
|
|
|
|
#ifdef TIME_STARTUP_PROCESS
|
|
printf("process @ %ld\n", scheme_get_process_milliseconds());
|
|
#endif
|
|
}
|
|
|
|
static Scheme_Env *place_instance_init_post_kernel() {
|
|
Scheme_Env *env;
|
|
/* error handling and buffers */
|
|
/* this check prevents initializing orig ports twice for the first initial
|
|
* place. The kernel initializes orig_ports early. */
|
|
if (!scheme_orig_stdout_port) {
|
|
scheme_init_port_places();
|
|
}
|
|
scheme_init_error_escape_proc(NULL);
|
|
scheme_init_print_buffers_places();
|
|
scheme_init_eval_places();
|
|
|
|
env = scheme_make_empty_env();
|
|
scheme_set_param(scheme_current_config(), MZCONFIG_ENV, (Scheme_Object *)env);
|
|
|
|
/*initialize config */
|
|
scheme_init_port_config();
|
|
scheme_init_port_fun_config();
|
|
scheme_init_error_config();
|
|
#ifndef NO_SCHEME_EXNS
|
|
scheme_init_exn_config();
|
|
#endif
|
|
|
|
scheme_init_memtrace(env);
|
|
#ifndef NO_TCP_SUPPORT
|
|
scheme_init_network(env);
|
|
#endif
|
|
scheme_init_parameterization(env);
|
|
scheme_init_expand_observe(env);
|
|
scheme_init_place(env);
|
|
|
|
#ifndef DONT_USE_FOREIGN
|
|
scheme_init_foreign(env);
|
|
#else
|
|
init_dummy_foreign(env);
|
|
#endif
|
|
|
|
scheme_add_embedded_builtins(env);
|
|
|
|
boot_module_resolver();
|
|
|
|
scheme_save_initial_module_set(env);
|
|
|
|
|
|
scheme_starting_up = 0;
|
|
|
|
--scheme_current_thread->suspend_break; /* created with breaks suspended */
|
|
|
|
#ifdef TIME_STARTUP_PROCESS
|
|
printf("done @ %ld\n#endif\n", scheme_get_process_milliseconds());
|
|
#endif
|
|
|
|
return env;
|
|
}
|
|
|
|
Scheme_Env *scheme_place_instance_init(void *stack_base) {
|
|
place_instance_init_pre_kernel(stack_base);
|
|
return place_instance_init_post_kernel();
|
|
}
|
|
|
|
static void make_kernel_env(void)
|
|
{
|
|
Scheme_Env *env;
|
|
#ifdef TIME_STARTUP_PROCESS
|
|
long startt;
|
|
#endif
|
|
|
|
env = make_empty_inited_env(GLOBAL_TABLE_SIZE);
|
|
|
|
scheme_set_param(scheme_current_config(), MZCONFIG_ENV,
|
|
(Scheme_Object *)env);
|
|
|
|
REGISTER_SO(kernel_env);
|
|
kernel_env = env;
|
|
|
|
scheme_defining_primitives = 1;
|
|
builtin_ref_counter = 0;
|
|
|
|
#ifdef TIME_STARTUP_PROCESS
|
|
printf("init @ %ld\n", scheme_get_process_milliseconds());
|
|
# define MZTIMEIT(n, f) (MARK_START_TIME(), f, DONE_TIME(n))
|
|
# define MARK_START_TIME() startt = scheme_get_process_milliseconds()
|
|
# define DONE_TIME(n) (printf(#n ": %ld\n", (long)(scheme_get_process_milliseconds() - startt)))
|
|
#else
|
|
# define MZTIMEIT(n, f) f
|
|
# define MARK_START_TIME() /**/
|
|
# define DONE_TIME(n) /**/
|
|
#endif
|
|
|
|
/* The ordering of the first few init calls is important, so add to
|
|
the end of the list, not the beginning. */
|
|
MZTIMEIT(type, scheme_init_type(env));
|
|
MZTIMEIT(symbol-type, scheme_init_symbol_type(env));
|
|
MZTIMEIT(fun, scheme_init_fun(env));
|
|
MZTIMEIT(symbol, scheme_init_symbol(env));
|
|
MZTIMEIT(list, scheme_init_list(env));
|
|
MZTIMEIT(number, scheme_init_number(env));
|
|
MZTIMEIT(numarith, scheme_init_numarith(env));
|
|
MZTIMEIT(numcomp, scheme_init_numcomp(env));
|
|
MZTIMEIT(numstr, scheme_init_numstr(env));
|
|
MZTIMEIT(stx, scheme_init_stx(env));
|
|
MZTIMEIT(module, scheme_init_module(env));
|
|
MZTIMEIT(port, scheme_init_port(env));
|
|
MZTIMEIT(portfun, scheme_init_port_fun(env));
|
|
MZTIMEIT(string, scheme_init_string(env));
|
|
MZTIMEIT(vector, scheme_init_vector(env));
|
|
MZTIMEIT(char, scheme_init_char(env));
|
|
MZTIMEIT(bool, scheme_init_bool(env));
|
|
MZTIMEIT(syntax, scheme_init_syntax(env));
|
|
MZTIMEIT(eval, scheme_init_eval(env));
|
|
MZTIMEIT(error, scheme_init_error(env));
|
|
MZTIMEIT(struct, scheme_init_struct(env));
|
|
#ifndef NO_SCHEME_EXNS
|
|
MZTIMEIT(exn, scheme_init_exn(env));
|
|
#endif
|
|
MZTIMEIT(process, scheme_init_thread(env));
|
|
#ifndef NO_SCHEME_THREADS
|
|
MZTIMEIT(sema, scheme_init_sema(env));
|
|
#endif
|
|
MZTIMEIT(read, scheme_init_read(env));
|
|
MZTIMEIT(print, scheme_init_print(env));
|
|
MZTIMEIT(file, scheme_init_file(env));
|
|
MZTIMEIT(dynamic-extension, scheme_init_dynamic_extension(env));
|
|
#ifndef NO_REGEXP_UTILS
|
|
MZTIMEIT(regexp, scheme_regexp_initialize(env));
|
|
#endif
|
|
|
|
MARK_START_TIME();
|
|
|
|
GLOBAL_PRIM_W_ARITY("namespace-symbol->identifier", namespace_identifier, 1, 2, env);
|
|
GLOBAL_PRIM_W_ARITY("namespace-module-identifier", namespace_module_identifier, 0, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("namespace-base-phase", namespace_base_phase, 0, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("namespace-variable-value", namespace_variable_value, 1, 4, env);
|
|
GLOBAL_PRIM_W_ARITY("namespace-set-variable-value!", namespace_set_variable_value, 2, 4, env);
|
|
GLOBAL_PRIM_W_ARITY("namespace-undefine-variable!", namespace_undefine_variable, 1, 2, env);
|
|
GLOBAL_PRIM_W_ARITY("namespace-mapped-symbols", namespace_mapped_symbols, 0, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("namespace-module-registry", namespace_module_registry, 1, 1, env);
|
|
|
|
GLOBAL_PRIM_W_ARITY("variable-reference?", variable_p, 1, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("variable-reference->resolved-module-path", variable_module_path, 1, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("variable-reference->empty-namespace", variable_namespace, 1, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("variable-reference->namespace", variable_top_level_namespace, 1, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("variable-reference->phase", variable_phase, 1, 1, env);
|
|
|
|
GLOBAL_PRIM_W_ARITY("syntax-transforming?", now_transforming, 0, 0, env);
|
|
GLOBAL_PRIM_W_ARITY("syntax-local-value", local_exp_time_value, 1, 3, env);
|
|
GLOBAL_PRIM_W_ARITY("syntax-local-value/immediate", local_exp_time_value_one, 1, 3, env);
|
|
GLOBAL_PRIM_W_ARITY("syntax-local-name", local_exp_time_name, 0, 0, env);
|
|
GLOBAL_PRIM_W_ARITY("syntax-local-context", local_context, 0, 0, env);
|
|
GLOBAL_PRIM_W_ARITY("syntax-local-phase-level", local_phase_level, 0, 0, env);
|
|
GLOBAL_PRIM_W_ARITY("syntax-local-make-definition-context", local_make_intdef_context, 0, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("internal-definition-context-seal", intdef_context_seal, 1, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("internal-definition-context?", intdef_context_p, 1, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("identifier-remove-from-definition-context", id_intdef_remove, 2, 2, env);
|
|
GLOBAL_PRIM_W_ARITY("syntax-local-get-shadower", local_get_shadower, 1, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("syntax-local-introduce", local_introduce, 1, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("make-syntax-introducer", make_introducer, 0, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("syntax-local-make-delta-introducer", local_make_delta_introduce, 1, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("syntax-local-certifier", local_certify, 0, 1, env);
|
|
|
|
GLOBAL_PRIM_W_ARITY("syntax-local-module-exports", local_module_exports, 1, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("syntax-local-module-defined-identifiers", local_module_definitions, 0, 0, env);
|
|
GLOBAL_PRIM_W_ARITY("syntax-local-module-required-identifiers", local_module_imports, 2, 2, env);
|
|
GLOBAL_PRIM_W_ARITY("syntax-local-transforming-module-provides?", local_module_expanding_provides, 0, 0, env);
|
|
|
|
GLOBAL_PRIM_W_ARITY("make-set!-transformer", make_set_transformer, 1, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("set!-transformer?", set_transformer_p, 1, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("set!-transformer-procedure", set_transformer_proc, 1, 1, env);
|
|
|
|
GLOBAL_PRIM_W_ARITY("make-rename-transformer", make_rename_transformer, 1, 2, env);
|
|
GLOBAL_PRIM_W_ARITY("rename-transformer?", rename_transformer_p, 1, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("rename-transformer-target", rename_transformer_target, 1, 1, env);
|
|
|
|
GLOBAL_PRIM_W_ARITY("syntax-local-lift-expression", local_lift_expr, 1, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("syntax-local-lift-context", local_lift_context, 0, 0, env);
|
|
GLOBAL_PRIM_W_ARITY("syntax-local-lift-module-end-declaration", local_lift_end_statement, 1, 1, env);
|
|
GLOBAL_PRIM_W_ARITY("syntax-local-lift-require", local_lift_require, 2, 2, env);
|
|
|
|
{
|
|
Scheme_Object *sym;
|
|
sym = scheme_intern_symbol("mzscheme");
|
|
scheme_current_thread->name = sym;
|
|
}
|
|
|
|
DONE_TIME(env);
|
|
|
|
scheme_install_type_writer(scheme_toplevel_type, write_toplevel);
|
|
scheme_install_type_reader(scheme_toplevel_type, read_toplevel);
|
|
scheme_install_type_writer(scheme_variable_type, write_variable);
|
|
scheme_install_type_reader(scheme_variable_type, read_variable);
|
|
scheme_install_type_writer(scheme_module_variable_type, write_module_variable);
|
|
scheme_install_type_reader(scheme_module_variable_type, read_module_variable);
|
|
scheme_install_type_writer(scheme_local_type, write_local);
|
|
scheme_install_type_reader(scheme_local_type, read_local);
|
|
scheme_install_type_writer(scheme_local_unbox_type, write_local);
|
|
scheme_install_type_reader(scheme_local_unbox_type, read_local_unbox);
|
|
scheme_install_type_writer(scheme_resolve_prefix_type, write_resolve_prefix);
|
|
scheme_install_type_reader(scheme_resolve_prefix_type, read_resolve_prefix);
|
|
|
|
REGISTER_SO(kernel_symbol);
|
|
kernel_symbol = scheme_intern_symbol("#%kernel");
|
|
|
|
MARK_START_TIME();
|
|
|
|
scheme_finish_kernel(env);
|
|
|
|
#if USE_COMPILED_STARTUP
|
|
if (builtin_ref_counter != EXPECTED_PRIM_COUNT) {
|
|
printf("Primitive count %d doesn't match expected count %d\n"
|
|
"Turn off USE_COMPILED_STARTUP in src/schminc.h\n",
|
|
builtin_ref_counter, EXPECTED_PRIM_COUNT);
|
|
exit(1);
|
|
}
|
|
#endif
|
|
|
|
scheme_defining_primitives = 0;
|
|
}
|
|
|
|
int scheme_is_kernel_env(Scheme_Env *env) {
|
|
return (env == kernel_env);
|
|
}
|
|
|
|
Scheme_Env *scheme_get_kernel_env() {
|
|
return kernel_env;
|
|
}
|
|
|
|
static void init_scheme_local()
|
|
{
|
|
int i, k, cor;
|
|
|
|
#ifndef USE_TAGGED_ALLOCATION
|
|
GC_CAN_IGNORE Scheme_Local *all;
|
|
|
|
all = (Scheme_Local *)scheme_malloc_eternal(sizeof(Scheme_Local) * 3 * 2 * MAX_CONST_LOCAL_POS);
|
|
# ifdef MEMORY_COUNTING_ON
|
|
scheme_misc_count += sizeof(Scheme_Local) * 3 * 2 * MAX_CONST_LOCAL_POS;
|
|
# endif
|
|
#endif
|
|
|
|
for (i = 0; i < MAX_CONST_LOCAL_POS; i++) {
|
|
for (k = 0; k < 2; k++) {
|
|
for (cor = 0; cor < 3; cor++) {
|
|
Scheme_Object *v;
|
|
|
|
#ifndef USE_TAGGED_ALLOCATION
|
|
v = (Scheme_Object *)(all++);
|
|
#else
|
|
v = (Scheme_Object *)scheme_malloc_eternal_tagged(sizeof(Scheme_Local));
|
|
#endif
|
|
v->type = k + scheme_local_type;
|
|
SCHEME_LOCAL_POS(v) = i;
|
|
SCHEME_LOCAL_FLAGS(v) = cor;
|
|
|
|
scheme_local[i][k][cor] = v;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void init_toplevels()
|
|
{
|
|
int i, k, cnst;
|
|
|
|
#ifndef USE_TAGGED_ALLOCATION
|
|
GC_CAN_IGNORE Scheme_Toplevel *all;
|
|
|
|
all = (Scheme_Toplevel *)scheme_malloc_eternal(sizeof(Scheme_Toplevel)
|
|
* MAX_CONST_TOPLEVEL_DEPTH
|
|
* MAX_CONST_TOPLEVEL_POS
|
|
* (SCHEME_TOPLEVEL_FLAGS_MASK + 1));
|
|
# ifdef MEMORY_COUNTING_ON
|
|
scheme_misc_count += (sizeof(Scheme_Toplevel)
|
|
* MAX_CONST_TOPLEVEL_DEPTH
|
|
* MAX_CONST_TOPLEVEL_POS
|
|
* (SCHEME_TOPLEVEL_FLAGS_MASK + 1));
|
|
# endif
|
|
#endif
|
|
|
|
for (i = 0; i < MAX_CONST_TOPLEVEL_DEPTH; i++) {
|
|
for (k = 0; k < MAX_CONST_TOPLEVEL_POS; k++) {
|
|
for (cnst = 0; cnst <= SCHEME_TOPLEVEL_FLAGS_MASK; cnst++) {
|
|
Scheme_Toplevel *v;
|
|
|
|
#ifndef USE_TAGGED_ALLOCATION
|
|
v = (all++);
|
|
#else
|
|
v = (Scheme_Toplevel *)scheme_malloc_eternal_tagged(sizeof(Scheme_Toplevel));
|
|
#endif
|
|
v->iso.so.type = scheme_toplevel_type;
|
|
v->depth = i;
|
|
v->position = k;
|
|
SCHEME_TOPLEVEL_FLAGS(v) = cnst;
|
|
|
|
toplevels[i][k][cnst] = (Scheme_Object *)v;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Shutdown procedure for resetting a namespace: */
|
|
static void skip_certain_things(Scheme_Object *o, Scheme_Close_Custodian_Client *f, void *data)
|
|
{
|
|
if ((o == scheme_orig_stdin_port)
|
|
|| (o == scheme_orig_stdout_port)
|
|
|| (o == scheme_orig_stderr_port))
|
|
return;
|
|
|
|
/* f is NULL for threads */
|
|
if (f)
|
|
f(o, data);
|
|
}
|
|
|
|
/*========================================================================*/
|
|
/* namespace constructors */
|
|
/*========================================================================*/
|
|
|
|
void scheme_prepare_env_renames(Scheme_Env *env, int kind)
|
|
{
|
|
if (!env->rename_set) {
|
|
Scheme_Object *rns;
|
|
|
|
rns = scheme_make_module_rename_set(kind, NULL);
|
|
env->rename_set = rns;
|
|
}
|
|
}
|
|
|
|
Scheme_Env *scheme_make_empty_env(void)
|
|
{
|
|
Scheme_Env *e;
|
|
|
|
e = make_empty_inited_env(7);
|
|
|
|
return e;
|
|
}
|
|
|
|
Scheme_Env *make_empty_inited_env(int toplevel_size)
|
|
{
|
|
Scheme_Env *env;
|
|
Scheme_Object *vector;
|
|
Scheme_Hash_Table* hash_table;
|
|
|
|
env = make_env(NULL, toplevel_size);
|
|
|
|
vector = scheme_make_vector(5, scheme_false);
|
|
hash_table = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
SCHEME_VEC_ELS(vector)[0] = (Scheme_Object *)hash_table;
|
|
env->modchain = vector;
|
|
|
|
hash_table = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
env->module_registry = hash_table;
|
|
env->module_registry->iso.so.type = scheme_module_registry_type;
|
|
|
|
hash_table = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
env->export_registry = hash_table;
|
|
env->label_env = NULL;
|
|
|
|
return env;
|
|
}
|
|
|
|
Scheme_Env *make_empty_not_inited_env(int toplevel_size)
|
|
{
|
|
Scheme_Env *e;
|
|
|
|
e = make_env(NULL, toplevel_size);
|
|
|
|
return e;
|
|
}
|
|
|
|
static Scheme_Env *make_env(Scheme_Env *base, int toplevel_size)
|
|
{
|
|
Scheme_Env *env;
|
|
Scheme_Bucket_Table *bucket_table;
|
|
|
|
env = MALLOC_ONE_TAGGED(Scheme_Env);
|
|
env->so.type = scheme_namespace_type;
|
|
|
|
bucket_table = scheme_make_bucket_table(toplevel_size, SCHEME_hash_ptr);
|
|
env->toplevel = bucket_table;
|
|
env->toplevel->with_home = 1;
|
|
|
|
bucket_table = scheme_make_bucket_table(7, SCHEME_hash_ptr);
|
|
env->syntax = bucket_table;
|
|
|
|
if (base) {
|
|
env->modchain = base->modchain;
|
|
env->module_registry = base->module_registry;
|
|
env->export_registry = base->export_registry;
|
|
env->label_env = base->label_env;
|
|
} else {
|
|
env->modchain = NULL;
|
|
env->module_registry = NULL;
|
|
env->export_registry = NULL;
|
|
env->label_env = NULL;
|
|
}
|
|
|
|
return env;
|
|
}
|
|
|
|
Scheme_Env *
|
|
scheme_new_module_env(Scheme_Env *env, Scheme_Module *m, int new_exp_module_tree)
|
|
{
|
|
Scheme_Env *menv;
|
|
|
|
menv = make_env(env, 7);
|
|
|
|
menv->module = m;
|
|
|
|
scheme_prepare_label_env(env);
|
|
menv->label_env = env->label_env;
|
|
|
|
if (new_exp_module_tree) {
|
|
Scheme_Object *p;
|
|
Scheme_Hash_Table *modules;
|
|
|
|
modules = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
p = scheme_make_vector(5, scheme_false);
|
|
SCHEME_VEC_ELS(p)[0] = (Scheme_Object *)modules;
|
|
menv->modchain = p;
|
|
}
|
|
|
|
if (SAME_OBJ(env, env->exp_env)) {
|
|
/* label phase */
|
|
menv->exp_env = menv;
|
|
menv->template_env = menv;
|
|
}
|
|
|
|
return menv;
|
|
}
|
|
|
|
void scheme_prepare_exp_env(Scheme_Env *env)
|
|
{
|
|
if (!env->exp_env) {
|
|
Scheme_Env *eenv;
|
|
Scheme_Object *modchain;
|
|
|
|
scheme_prepare_label_env(env);
|
|
|
|
eenv = make_empty_not_inited_env(7);
|
|
eenv->phase = env->phase + 1;
|
|
eenv->mod_phase = env->mod_phase + 1;
|
|
|
|
eenv->module = env->module;
|
|
eenv->module_registry = env->module_registry;
|
|
eenv->export_registry = env->export_registry;
|
|
eenv->insp = env->insp;
|
|
|
|
modchain = SCHEME_VEC_ELS(env->modchain)[1];
|
|
if (SCHEME_FALSEP(modchain)) {
|
|
Scheme_Hash_Table *next_modules;
|
|
|
|
next_modules = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
modchain = scheme_make_vector(5, scheme_false);
|
|
SCHEME_VEC_ELS(modchain)[0] = (Scheme_Object *)next_modules;
|
|
SCHEME_VEC_ELS(env->modchain)[1] = modchain;
|
|
SCHEME_VEC_ELS(modchain)[2] = env->modchain;
|
|
}
|
|
eenv->modchain = modchain;
|
|
|
|
env->exp_env = eenv;
|
|
eenv->template_env = env;
|
|
eenv->label_env = env->label_env;
|
|
|
|
scheme_prepare_env_renames(env, mzMOD_RENAME_TOPLEVEL);
|
|
eenv->rename_set = env->rename_set;
|
|
|
|
if (env->disallow_unbound)
|
|
eenv->disallow_unbound = 1;
|
|
}
|
|
}
|
|
|
|
void scheme_prepare_template_env(Scheme_Env *env)
|
|
{
|
|
if (!env->template_env) {
|
|
Scheme_Env *eenv;
|
|
Scheme_Object *modchain;
|
|
|
|
scheme_prepare_label_env(env);
|
|
|
|
eenv = make_empty_not_inited_env(7);
|
|
eenv->phase = env->phase - 1;
|
|
eenv->mod_phase = env->mod_phase - 1;
|
|
|
|
eenv->module = env->module;
|
|
eenv->module_registry = env->module_registry;
|
|
eenv->export_registry = env->export_registry;
|
|
eenv->insp = env->insp;
|
|
|
|
modchain = SCHEME_VEC_ELS(env->modchain)[2];
|
|
if (SCHEME_FALSEP(modchain)) {
|
|
Scheme_Hash_Table *prev_modules;
|
|
|
|
prev_modules = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
modchain = scheme_make_vector(5, scheme_false);
|
|
SCHEME_VEC_ELS(modchain)[0] = (Scheme_Object *)prev_modules;
|
|
SCHEME_VEC_ELS(env->modchain)[2] = modchain;
|
|
SCHEME_VEC_ELS(modchain)[1] = env->modchain;
|
|
}
|
|
eenv->modchain = modchain;
|
|
|
|
scheme_prepare_env_renames(env, mzMOD_RENAME_TOPLEVEL);
|
|
eenv->rename_set = env->rename_set;
|
|
|
|
env->template_env = eenv;
|
|
eenv->exp_env = env;
|
|
eenv->label_env = env->label_env;
|
|
|
|
if (env->disallow_unbound)
|
|
eenv->disallow_unbound = 1;
|
|
}
|
|
}
|
|
|
|
void scheme_prepare_label_env(Scheme_Env *env)
|
|
{
|
|
if (!env->label_env) {
|
|
Scheme_Env *lenv;
|
|
Scheme_Object *modchain;
|
|
Scheme_Hash_Table *prev_modules;
|
|
|
|
lenv = make_empty_not_inited_env(7);
|
|
lenv->phase = 0;
|
|
lenv->mod_phase = 0;
|
|
|
|
lenv->module = env->module;
|
|
lenv->module_registry = env->module_registry;
|
|
lenv->export_registry = env->export_registry;
|
|
lenv->insp = env->insp;
|
|
|
|
modchain = scheme_make_vector(5, scheme_false);
|
|
prev_modules = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
SCHEME_VEC_ELS(modchain)[0] = (Scheme_Object *)prev_modules;
|
|
SCHEME_VEC_ELS(modchain)[2] = modchain;
|
|
SCHEME_VEC_ELS(modchain)[1] = modchain;
|
|
lenv->modchain = modchain;
|
|
|
|
env->label_env = lenv;
|
|
|
|
lenv->exp_env = lenv;
|
|
lenv->label_env = lenv;
|
|
lenv->template_env = lenv;
|
|
}
|
|
}
|
|
|
|
Scheme_Env *scheme_copy_module_env(Scheme_Env *menv, Scheme_Env *ns, Scheme_Object *modchain, int clone_phase)
|
|
{
|
|
/* New env should have the same syntax and globals table, but it lives in
|
|
a different namespace. */
|
|
Scheme_Env *menv2;
|
|
Scheme_Bucket_Table *bucket_table;
|
|
|
|
scheme_prepare_label_env(ns);
|
|
|
|
menv2 = MALLOC_ONE_TAGGED(Scheme_Env);
|
|
menv2->so.type = scheme_namespace_type;
|
|
|
|
menv2->module = menv->module;
|
|
menv2->module_registry = ns->module_registry;
|
|
menv2->export_registry = ns->export_registry;
|
|
menv2->insp = menv->insp;
|
|
|
|
if (menv->phase < clone_phase)
|
|
menv2->syntax = menv->syntax;
|
|
else {
|
|
bucket_table = scheme_make_bucket_table(7, SCHEME_hash_ptr);
|
|
menv2->syntax = bucket_table;
|
|
}
|
|
|
|
menv2->phase = menv->phase;
|
|
menv2->mod_phase = menv->mod_phase;
|
|
menv2->link_midx = menv->link_midx;
|
|
if (menv->phase <= clone_phase) {
|
|
menv2->running = menv->running;
|
|
menv2->ran = menv->ran;
|
|
}
|
|
if (menv->phase < clone_phase)
|
|
menv2->et_running = menv->et_running;
|
|
|
|
menv2->require_names = menv->require_names;
|
|
menv2->et_require_names = menv->et_require_names;
|
|
|
|
if (menv->phase <= clone_phase) {
|
|
menv2->toplevel = menv->toplevel;
|
|
} else {
|
|
bucket_table = scheme_make_bucket_table(7, SCHEME_hash_ptr);
|
|
menv2->toplevel = bucket_table;
|
|
menv2->toplevel->with_home = 1;
|
|
}
|
|
|
|
menv2->modchain = modchain;
|
|
|
|
if (SAME_OBJ(menv->exp_env, menv)) {
|
|
/* label phase */
|
|
menv2->exp_env = menv2;
|
|
menv2->template_env = menv2;
|
|
} else if (menv->phase < clone_phase) {
|
|
if (!SCHEME_NULLP(menv2->module->et_requires)) {
|
|
/* We'll need the next link in the modchain: */
|
|
modchain = SCHEME_VEC_ELS(modchain)[1];
|
|
if (SCHEME_FALSEP(modchain)) {
|
|
Scheme_Hash_Table *next_modules;
|
|
|
|
next_modules = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
modchain = scheme_make_vector(5, scheme_false);
|
|
SCHEME_VEC_ELS(modchain)[0] = (Scheme_Object *)next_modules;
|
|
SCHEME_VEC_ELS(menv2->modchain)[1] = modchain;
|
|
SCHEME_VEC_ELS(modchain)[2] = menv2->modchain;
|
|
}
|
|
}
|
|
|
|
if (menv->exp_env) {
|
|
/* Share for-syntax bindings, too: */
|
|
scheme_prepare_exp_env(menv2);
|
|
menv2->exp_env->toplevel = menv->exp_env->toplevel;
|
|
}
|
|
}
|
|
|
|
scheme_prepare_label_env(ns);
|
|
menv2->label_env = ns->label_env;
|
|
|
|
return menv2;
|
|
}
|
|
|
|
Scheme_Bucket_Table *scheme_clone_toplevel(Scheme_Bucket_Table *ht, Scheme_Env *home)
|
|
{
|
|
Scheme_Bucket_Table *r;
|
|
Scheme_Bucket **bs;
|
|
int i;
|
|
|
|
r = scheme_make_bucket_table(ht->size, SCHEME_hash_ptr);
|
|
if (home)
|
|
r->with_home = 1;
|
|
|
|
bs = ht->buckets;
|
|
|
|
for (i = ht->size; i--; ) {
|
|
Scheme_Bucket *b = bs[i];
|
|
if (b && b->val) {
|
|
Scheme_Object *name = (Scheme_Object *)b->key;
|
|
Scheme_Object *val = (Scheme_Object *)b->val;
|
|
|
|
b = scheme_bucket_from_table(r, (const char *)name);
|
|
b->val = val;
|
|
if (home) {
|
|
ASSERT_IS_VARIABLE_BUCKET(b);
|
|
((Scheme_Bucket_With_Home *)b)->home = home;
|
|
}
|
|
}
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
void scheme_clean_dead_env(Scheme_Env *env)
|
|
{
|
|
Scheme_Object *modchain, *next;
|
|
|
|
if (env->exp_env) {
|
|
env->exp_env->template_env = NULL;
|
|
scheme_clean_dead_env(env->exp_env);
|
|
env->exp_env = NULL;
|
|
}
|
|
if (env->template_env) {
|
|
env->template_env->exp_env = NULL;
|
|
scheme_clean_dead_env(env->template_env);
|
|
env->template_env = NULL;
|
|
}
|
|
|
|
env->modvars = NULL;
|
|
|
|
modchain = env->modchain;
|
|
env->modchain = NULL;
|
|
while (modchain && !SCHEME_VECTORP(modchain)) {
|
|
next = SCHEME_VEC_ELS(modchain)[1];
|
|
SCHEME_VEC_ELS(modchain)[1] = scheme_void;
|
|
modchain = next;
|
|
}
|
|
}
|
|
|
|
/*========================================================================*/
|
|
/* namespace bindings */
|
|
/*========================================================================*/
|
|
|
|
/********** Lookup **********/
|
|
|
|
Scheme_Object *
|
|
scheme_lookup_global(Scheme_Object *symbol, Scheme_Env *env)
|
|
{
|
|
Scheme_Bucket *b;
|
|
|
|
b = scheme_bucket_or_null_from_table(env->toplevel, (char *)symbol, 0);
|
|
if (b) {
|
|
ASSERT_IS_VARIABLE_BUCKET(b);
|
|
if (!((Scheme_Bucket_With_Home *)b)->home)
|
|
((Scheme_Bucket_With_Home *)b)->home = env;
|
|
return (Scheme_Object *)b->val;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
Scheme_Bucket *
|
|
scheme_global_bucket(Scheme_Object *symbol, Scheme_Env *env)
|
|
{
|
|
Scheme_Bucket *b;
|
|
|
|
b = scheme_bucket_from_table(env->toplevel, (char *)symbol);
|
|
ASSERT_IS_VARIABLE_BUCKET(b);
|
|
if (!((Scheme_Bucket_With_Home *)b)->home)
|
|
((Scheme_Bucket_With_Home *)b)->home = env;
|
|
|
|
return b;
|
|
}
|
|
|
|
Scheme_Bucket *
|
|
scheme_global_keyword_bucket(Scheme_Object *symbol, Scheme_Env *env)
|
|
{
|
|
Scheme_Bucket *b;
|
|
|
|
b = scheme_bucket_from_table(env->syntax, (char *)symbol);
|
|
|
|
return b;
|
|
}
|
|
|
|
/********** Set **********/
|
|
|
|
void
|
|
scheme_do_add_global_symbol(Scheme_Env *env, Scheme_Object *sym,
|
|
Scheme_Object *obj,
|
|
int valvar, int constant)
|
|
{
|
|
if (valvar) {
|
|
Scheme_Bucket *b;
|
|
b = scheme_bucket_from_table(env->toplevel, (const char *)sym);
|
|
b->val = obj;
|
|
ASSERT_IS_VARIABLE_BUCKET(b);
|
|
((Scheme_Bucket_With_Home *)b)->home = env;
|
|
if (constant && scheme_defining_primitives) {
|
|
((Scheme_Bucket_With_Flags *)b)->id = builtin_ref_counter++;
|
|
((Scheme_Bucket_With_Flags *)b)->flags |= (GLOB_HAS_REF_ID | GLOB_IS_CONST);
|
|
}
|
|
} else
|
|
scheme_add_to_table(env->syntax, (const char *)sym, obj, constant);
|
|
}
|
|
|
|
void
|
|
scheme_add_global(const char *name, Scheme_Object *obj, Scheme_Env *env)
|
|
{
|
|
scheme_do_add_global_symbol(env, scheme_intern_symbol(name), obj, 1, 0);
|
|
}
|
|
|
|
void
|
|
scheme_add_global_symbol(Scheme_Object *sym, Scheme_Object *obj, Scheme_Env *env)
|
|
{
|
|
scheme_do_add_global_symbol(env, sym, obj, 1, 0);
|
|
}
|
|
|
|
void
|
|
scheme_add_global_constant(const char *name, Scheme_Object *obj,
|
|
Scheme_Env *env)
|
|
{
|
|
scheme_do_add_global_symbol(env, scheme_intern_symbol(name), obj, 1, 1);
|
|
}
|
|
|
|
void
|
|
scheme_add_global_constant_symbol(Scheme_Object *name, Scheme_Object *obj,
|
|
Scheme_Env *env)
|
|
{
|
|
scheme_do_add_global_symbol(env, name, obj, 1, 1);
|
|
}
|
|
|
|
void
|
|
scheme_add_global_keyword(const char *name, Scheme_Object *obj,
|
|
Scheme_Env *env)
|
|
{
|
|
scheme_do_add_global_symbol(env, scheme_intern_symbol(name), obj, 0, 0);
|
|
}
|
|
|
|
void
|
|
scheme_add_global_keyword_symbol(Scheme_Object *name, Scheme_Object *obj,
|
|
Scheme_Env *env)
|
|
{
|
|
scheme_do_add_global_symbol(env, name, obj, 0, 0);
|
|
}
|
|
|
|
void scheme_shadow(Scheme_Env *env, Scheme_Object *n, int stxtoo)
|
|
{
|
|
Scheme_Object *rn;
|
|
|
|
if (env->rename_set) {
|
|
rn = scheme_get_module_rename_from_set(env->rename_set,
|
|
scheme_make_integer(env->phase),
|
|
0);
|
|
if (rn) {
|
|
scheme_remove_module_rename(rn, n);
|
|
if (env->module) {
|
|
scheme_extend_module_rename(rn,
|
|
env->module->self_modidx,
|
|
n, n,
|
|
env->module->self_modidx,
|
|
n,
|
|
env->mod_phase,
|
|
NULL,
|
|
NULL,
|
|
0);
|
|
}
|
|
}
|
|
} else
|
|
rn = NULL;
|
|
|
|
if (stxtoo) {
|
|
if (!env->module || rn) {
|
|
if (!env->shadowed_syntax) {
|
|
Scheme_Hash_Table *ht;
|
|
ht = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
env->shadowed_syntax = ht;
|
|
}
|
|
|
|
scheme_hash_set(env->shadowed_syntax, n, scheme_true);
|
|
}
|
|
} else {
|
|
if (env->shadowed_syntax)
|
|
scheme_hash_set(env->shadowed_syntax, n, NULL);
|
|
|
|
if (rn) {
|
|
/* If the syntax binding is a rename transformer, need to install
|
|
a mapping. */
|
|
Scheme_Object *v;
|
|
v = scheme_lookup_in_table(env->syntax, (const char *)n);
|
|
if (v) {
|
|
v = SCHEME_PTR_VAL(v);
|
|
if (scheme_is_binding_rename_transformer(v)) {
|
|
scheme_install_free_id_rename(n,
|
|
scheme_rename_transformer_id(v),
|
|
rn,
|
|
scheme_make_integer(env->phase));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/********** Auxilliary tables **********/
|
|
|
|
Scheme_Object **scheme_make_builtin_references_table(void)
|
|
{
|
|
Scheme_Bucket_Table *ht;
|
|
Scheme_Object **t;
|
|
Scheme_Bucket **bs;
|
|
Scheme_Env *kenv;
|
|
long i;
|
|
|
|
t = MALLOC_N(Scheme_Object *, (builtin_ref_counter + 1));
|
|
#ifdef MEMORY_COUNTING_ON
|
|
scheme_misc_count += sizeof(Scheme_Object *) * (builtin_ref_counter + 1);
|
|
#endif
|
|
|
|
kenv = scheme_get_kernel_env();
|
|
|
|
ht = kenv->toplevel;
|
|
|
|
bs = ht->buckets;
|
|
|
|
for (i = ht->size; i--; ) {
|
|
Scheme_Bucket *b = bs[i];
|
|
if (b && (((Scheme_Bucket_With_Flags *)b)->flags & GLOB_HAS_REF_ID))
|
|
t[((Scheme_Bucket_With_Ref_Id *)b)->id] = (Scheme_Object *)b->val;
|
|
}
|
|
|
|
return t;
|
|
}
|
|
|
|
Scheme_Hash_Table *scheme_map_constants_to_globals(void)
|
|
{
|
|
Scheme_Bucket_Table *ht;
|
|
Scheme_Hash_Table*result;
|
|
Scheme_Bucket **bs;
|
|
Scheme_Env *kenv;
|
|
long i;
|
|
|
|
kenv = scheme_get_kernel_env();
|
|
|
|
ht = kenv->toplevel;
|
|
bs = ht->buckets;
|
|
|
|
result = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
|
|
for (i = ht->size; i--; ) {
|
|
Scheme_Bucket *b = bs[i];
|
|
if (b && (((Scheme_Bucket_With_Flags *)b)->flags & GLOB_IS_CONST)) {
|
|
scheme_hash_set(result, b->val, (Scheme_Object *)b);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*========================================================================*/
|
|
/* compile-time env, constructors and simple queries */
|
|
/*========================================================================*/
|
|
|
|
static void init_compile_data(Scheme_Comp_Env *env)
|
|
{
|
|
Compile_Data *data;
|
|
int i, c, *use;
|
|
|
|
c = env->num_bindings;
|
|
if (c)
|
|
use = MALLOC_N_ATOMIC(int, c);
|
|
else
|
|
use = NULL;
|
|
|
|
data = COMPILE_DATA(env);
|
|
|
|
data->use = use;
|
|
for (i = 0; i < c; i++) {
|
|
use[i] = 0;
|
|
}
|
|
}
|
|
|
|
Scheme_Comp_Env *scheme_new_compilation_frame(int num_bindings, int flags,
|
|
Scheme_Comp_Env *base, Scheme_Object *certs)
|
|
{
|
|
Scheme_Comp_Env *frame;
|
|
int count;
|
|
|
|
count = num_bindings;
|
|
|
|
frame = (Scheme_Comp_Env *)MALLOC_ONE_RT(Scheme_Full_Comp_Env);
|
|
#ifdef MZTAG_REQUIRED
|
|
frame->type = scheme_rt_comp_env;
|
|
#endif
|
|
|
|
{
|
|
Scheme_Object **vals;
|
|
vals = MALLOC_N(Scheme_Object *, count);
|
|
frame->values = vals;
|
|
}
|
|
|
|
frame->certs = certs;
|
|
frame->num_bindings = num_bindings;
|
|
frame->flags = flags | (base->flags & SCHEME_NO_RENAME);
|
|
frame->next = base;
|
|
frame->genv = base->genv;
|
|
frame->insp = base->insp;
|
|
frame->prefix = base->prefix;
|
|
frame->in_modidx = base->in_modidx;
|
|
|
|
if (flags & SCHEME_NON_SIMPLE_FRAME)
|
|
frame->skip_depth = 0;
|
|
else if (base->next)
|
|
frame->skip_depth = base->skip_depth + 1;
|
|
else
|
|
frame->skip_depth = 0;
|
|
|
|
init_compile_data(frame);
|
|
|
|
return frame;
|
|
}
|
|
|
|
Scheme_Comp_Env *scheme_new_comp_env(Scheme_Env *genv, Scheme_Object *insp, int flags)
|
|
{
|
|
Scheme_Comp_Env *e;
|
|
Comp_Prefix *cp;
|
|
|
|
if (!insp)
|
|
insp = scheme_get_param(scheme_current_config(), MZCONFIG_CODE_INSPECTOR);
|
|
|
|
e = (Scheme_Comp_Env *)MALLOC_ONE_RT(Scheme_Full_Comp_Env);
|
|
#ifdef MZTAG_REQUIRED
|
|
e->type = scheme_rt_comp_env;
|
|
#endif
|
|
e->num_bindings = 0;
|
|
e->next = NULL;
|
|
e->genv = genv;
|
|
e->insp = insp;
|
|
e->flags = flags;
|
|
init_compile_data(e);
|
|
|
|
cp = MALLOC_ONE_RT(Comp_Prefix);
|
|
#ifdef MZTAG_REQUIRED
|
|
cp->type = scheme_rt_comp_prefix;
|
|
#endif
|
|
|
|
e->prefix = cp;
|
|
|
|
return e;
|
|
}
|
|
|
|
Scheme_Comp_Env *scheme_new_expand_env(Scheme_Env *genv, Scheme_Object *insp, int flags)
|
|
{
|
|
Scheme_Comp_Env *e;
|
|
|
|
e = scheme_new_comp_env(genv, insp, flags);
|
|
e->prefix = NULL;
|
|
|
|
return e;
|
|
}
|
|
|
|
int scheme_is_sub_env(Scheme_Comp_Env *stx_env, Scheme_Comp_Env *env)
|
|
{
|
|
Scheme_Comp_Env *se;
|
|
|
|
for (se = stx_env; NOT_SAME_OBJ(se, env); se = se->next) {
|
|
if (!(se->flags & SCHEME_FOR_INTDEF))
|
|
break;
|
|
}
|
|
return SAME_OBJ(se, env);
|
|
}
|
|
|
|
int scheme_used_ever(Scheme_Comp_Env *env, int which)
|
|
{
|
|
Compile_Data *data = COMPILE_DATA(env);
|
|
|
|
return !!data->use[which];
|
|
}
|
|
|
|
int scheme_is_env_variable_boxed(Scheme_Comp_Env *env, int which)
|
|
{
|
|
Compile_Data *data = COMPILE_DATA(env);
|
|
|
|
return !!(data->use[which] & WAS_SET_BANGED);
|
|
}
|
|
|
|
void
|
|
scheme_add_compilation_binding(int index, Scheme_Object *val, Scheme_Comp_Env *frame)
|
|
{
|
|
if ((index >= frame->num_bindings) || (index < 0))
|
|
scheme_signal_error("internal error: scheme_add_binding: "
|
|
"index out of range: %d", index);
|
|
|
|
frame->values[index] = val;
|
|
frame->skip_table = NULL;
|
|
}
|
|
|
|
void scheme_frame_captures_lifts(Scheme_Comp_Env *env, Scheme_Lift_Capture_Proc cp, Scheme_Object *data,
|
|
Scheme_Object *end_stmts, Scheme_Object *context_key, Scheme_Object *requires)
|
|
{
|
|
Scheme_Lift_Capture_Proc *pp;
|
|
Scheme_Object *vec;
|
|
|
|
pp = (Scheme_Lift_Capture_Proc *)scheme_malloc_atomic(sizeof(Scheme_Lift_Capture_Proc));
|
|
*pp = cp;
|
|
|
|
vec = scheme_make_vector(7, NULL);
|
|
SCHEME_VEC_ELS(vec)[0] = scheme_null;
|
|
SCHEME_VEC_ELS(vec)[1] = (Scheme_Object *)pp;
|
|
SCHEME_VEC_ELS(vec)[2] = data;
|
|
SCHEME_VEC_ELS(vec)[3] = end_stmts;
|
|
SCHEME_VEC_ELS(vec)[4] = context_key;
|
|
SCHEME_VEC_ELS(vec)[5] = (requires ? requires : scheme_false);
|
|
SCHEME_VEC_ELS(vec)[6] = scheme_null; /* accumulated requires */
|
|
|
|
COMPILE_DATA(env)->lifts = vec;
|
|
}
|
|
|
|
void scheme_propagate_require_lift_capture(Scheme_Comp_Env *orig_env, Scheme_Comp_Env *env)
|
|
{
|
|
while (orig_env) {
|
|
if ((COMPILE_DATA(orig_env)->lifts)
|
|
&& SCHEME_TRUEP(SCHEME_VEC_ELS(COMPILE_DATA(orig_env)->lifts)[5]))
|
|
break;
|
|
orig_env = orig_env->next;
|
|
}
|
|
|
|
if (orig_env) {
|
|
Scheme_Object *vec, *p;
|
|
|
|
p = scheme_make_raw_pair(NULL, (Scheme_Object *)orig_env);
|
|
|
|
vec = scheme_make_vector(7, NULL);
|
|
SCHEME_VEC_ELS(vec)[0] = scheme_false;
|
|
SCHEME_VEC_ELS(vec)[1] = scheme_void;
|
|
SCHEME_VEC_ELS(vec)[2] = scheme_void;
|
|
SCHEME_VEC_ELS(vec)[3] = scheme_false;
|
|
SCHEME_VEC_ELS(vec)[4] = scheme_false;
|
|
SCHEME_VEC_ELS(vec)[5] = p; /* (rcons NULL env) => continue with env */
|
|
SCHEME_VEC_ELS(vec)[6] = scheme_null;
|
|
|
|
COMPILE_DATA(env)->lifts = vec;
|
|
}
|
|
}
|
|
|
|
Scheme_Object *scheme_frame_get_lifts(Scheme_Comp_Env *env)
|
|
{
|
|
return SCHEME_VEC_ELS(COMPILE_DATA(env)->lifts)[0];
|
|
}
|
|
|
|
Scheme_Object *scheme_frame_get_end_statement_lifts(Scheme_Comp_Env *env)
|
|
{
|
|
return SCHEME_VEC_ELS(COMPILE_DATA(env)->lifts)[3];
|
|
}
|
|
|
|
Scheme_Object *scheme_frame_get_require_lifts(Scheme_Comp_Env *env)
|
|
{
|
|
return SCHEME_VEC_ELS(COMPILE_DATA(env)->lifts)[6];
|
|
}
|
|
|
|
void scheme_add_local_syntax(int cnt, Scheme_Comp_Env *env)
|
|
{
|
|
Scheme_Object **ns, **vs;
|
|
|
|
if (cnt) {
|
|
ns = MALLOC_N(Scheme_Object *, cnt);
|
|
vs = MALLOC_N(Scheme_Object *, cnt);
|
|
|
|
COMPILE_DATA(env)->num_const = cnt;
|
|
COMPILE_DATA(env)->const_names = ns;
|
|
COMPILE_DATA(env)->const_vals = vs;
|
|
|
|
}
|
|
}
|
|
|
|
void scheme_set_local_syntax(int pos,
|
|
Scheme_Object *name, Scheme_Object *val,
|
|
Scheme_Comp_Env *env)
|
|
{
|
|
COMPILE_DATA(env)->const_names[pos] = name;
|
|
COMPILE_DATA(env)->const_vals[pos] = val;
|
|
env->skip_table = NULL;
|
|
}
|
|
|
|
Scheme_Comp_Env *
|
|
scheme_add_compilation_frame(Scheme_Object *vals, Scheme_Comp_Env *env, int flags, Scheme_Object *certs)
|
|
{
|
|
Scheme_Comp_Env *frame;
|
|
int len, i, count;
|
|
|
|
len = scheme_stx_list_length(vals);
|
|
count = len;
|
|
|
|
frame = scheme_new_compilation_frame(count, flags, env, certs);
|
|
|
|
for (i = 0; i < len ; i++) {
|
|
if (SCHEME_STX_SYMBOLP(vals))
|
|
frame->values[i] = vals;
|
|
else {
|
|
Scheme_Object *a;
|
|
a = SCHEME_STX_CAR(vals);
|
|
frame->values[i] = a;
|
|
vals = SCHEME_STX_CDR(vals);
|
|
}
|
|
}
|
|
|
|
init_compile_data(frame);
|
|
|
|
return frame;
|
|
}
|
|
|
|
Scheme_Comp_Env *scheme_no_defines(Scheme_Comp_Env *env)
|
|
{
|
|
if (scheme_is_toplevel(env)
|
|
|| scheme_is_module_env(env)
|
|
|| scheme_is_module_begin_env(env)
|
|
|| (env->flags & SCHEME_INTDEF_FRAME))
|
|
return scheme_new_compilation_frame(0, 0, env, NULL);
|
|
else
|
|
return env;
|
|
}
|
|
|
|
Scheme_Comp_Env *scheme_require_renames(Scheme_Comp_Env *env)
|
|
{
|
|
if (env->flags & SCHEME_NO_RENAME) {
|
|
env = scheme_new_compilation_frame(0, 0, env, NULL);
|
|
env->flags -= SCHEME_NO_RENAME;
|
|
}
|
|
|
|
return env;
|
|
}
|
|
|
|
int scheme_is_toplevel(Scheme_Comp_Env *env)
|
|
{
|
|
return !env->next || (env->flags & SCHEME_TOPLEVEL_FRAME);
|
|
}
|
|
|
|
int scheme_is_module_env(Scheme_Comp_Env *env)
|
|
{
|
|
return !!(env->flags & SCHEME_MODULE_BEGIN_FRAME); /* name is backwards compared to symbol! */
|
|
}
|
|
|
|
int scheme_is_module_begin_env(Scheme_Comp_Env *env)
|
|
{
|
|
return !!(env->flags & SCHEME_MODULE_FRAME); /* name is backwards compared to symbol! */
|
|
}
|
|
|
|
Scheme_Comp_Env *scheme_extend_as_toplevel(Scheme_Comp_Env *env)
|
|
{
|
|
if (scheme_is_toplevel(env))
|
|
return env;
|
|
else
|
|
return scheme_new_compilation_frame(0, SCHEME_TOPLEVEL_FRAME, env, NULL);
|
|
}
|
|
|
|
static Scheme_Object *make_toplevel(mzshort depth, int position, int resolved, int flags)
|
|
{
|
|
Scheme_Toplevel *tl;
|
|
Scheme_Object *v, *pr;
|
|
|
|
/* Important: non-resolved can't be cached, because the ISCONST
|
|
field is modified to track mutated module-level variables. But
|
|
the value for a specific toplevel is cached in the environment
|
|
layer. */
|
|
|
|
if (resolved) {
|
|
if ((depth < MAX_CONST_TOPLEVEL_DEPTH)
|
|
&& (position < MAX_CONST_TOPLEVEL_POS))
|
|
return toplevels[depth][position][flags];
|
|
|
|
pr = (flags
|
|
? scheme_make_pair(scheme_make_integer(position),
|
|
scheme_make_integer(flags))
|
|
: scheme_make_integer(position));
|
|
pr = scheme_make_pair(scheme_make_integer(depth), pr);
|
|
v = scheme_hash_get_atomic(toplevels_ht, pr);
|
|
if (v)
|
|
return v;
|
|
} else
|
|
pr = NULL;
|
|
|
|
tl = (Scheme_Toplevel *)scheme_malloc_atomic_tagged(sizeof(Scheme_Toplevel));
|
|
tl->iso.so.type = (resolved ? scheme_toplevel_type : scheme_compiled_toplevel_type);
|
|
tl->depth = depth;
|
|
tl->position = position;
|
|
SCHEME_TOPLEVEL_FLAGS(tl) = flags;
|
|
|
|
if (resolved) {
|
|
if (toplevels_ht->count > TABLE_CACHE_MAX_SIZE) {
|
|
toplevels_ht = scheme_make_hash_table_equal();
|
|
}
|
|
scheme_hash_set_atomic(toplevels_ht, pr, (Scheme_Object *)tl);
|
|
}
|
|
|
|
return (Scheme_Object *)tl;
|
|
}
|
|
|
|
Scheme_Object *scheme_register_toplevel_in_prefix(Scheme_Object *var, Scheme_Comp_Env *env,
|
|
Scheme_Compile_Info *rec, int drec)
|
|
{
|
|
Comp_Prefix *cp = env->prefix;
|
|
Scheme_Hash_Table *ht;
|
|
Scheme_Object *o;
|
|
|
|
if (rec && rec[drec].dont_mark_local_use) {
|
|
/* Make up anything; it's going to be ignored. */
|
|
return make_toplevel(0, 0, 0, 0);
|
|
}
|
|
|
|
ht = cp->toplevels;
|
|
if (!ht) {
|
|
ht = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
cp->toplevels = ht;
|
|
}
|
|
|
|
o = scheme_hash_get(ht, var);
|
|
if (o)
|
|
return o;
|
|
|
|
o = make_toplevel(0, cp->num_toplevels, 0, 0);
|
|
|
|
cp->num_toplevels++;
|
|
scheme_hash_set(ht, var, o);
|
|
|
|
return o;
|
|
}
|
|
|
|
Scheme_Object *scheme_toplevel_to_flagged_toplevel(Scheme_Object *_tl, int flags)
|
|
{
|
|
Scheme_Toplevel *tl = (Scheme_Toplevel *)_tl;
|
|
return make_toplevel(tl->depth, tl->position, 0, flags);
|
|
}
|
|
|
|
Scheme_Object *scheme_register_stx_in_prefix(Scheme_Object *var, Scheme_Comp_Env *env,
|
|
Scheme_Compile_Info *rec, int drec)
|
|
{
|
|
Comp_Prefix *cp = env->prefix;
|
|
Scheme_Local *l;
|
|
Scheme_Object *o;
|
|
int pos;
|
|
|
|
if (rec && rec[drec].dont_mark_local_use) {
|
|
/* Make up anything; it's going to be ignored. */
|
|
l = (Scheme_Local *)scheme_malloc_atomic_tagged(sizeof(Scheme_Local));
|
|
l->iso.so.type = scheme_compiled_quote_syntax_type;
|
|
l->position = 0;
|
|
|
|
return (Scheme_Object *)l;
|
|
}
|
|
|
|
if (!cp->stxes) {
|
|
Scheme_Hash_Table *ht;
|
|
ht = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
cp->stxes = ht;
|
|
}
|
|
|
|
pos = cp->num_stxes;
|
|
|
|
l = (Scheme_Local *)scheme_malloc_atomic_tagged(sizeof(Scheme_Local));
|
|
l->iso.so.type = scheme_compiled_quote_syntax_type;
|
|
l->position = pos;
|
|
|
|
cp->num_stxes++;
|
|
o = (Scheme_Object *)l;
|
|
|
|
scheme_hash_set(cp->stxes, var, o);
|
|
|
|
return o;
|
|
}
|
|
|
|
/*========================================================================*/
|
|
/* compile-time env, lookup bindings */
|
|
/*========================================================================*/
|
|
|
|
static Scheme_Object *alloc_local(short type, int pos)
|
|
{
|
|
Scheme_Object *v;
|
|
|
|
v = (Scheme_Object *)scheme_malloc_atomic_tagged(sizeof(Scheme_Local));
|
|
v->type = type;
|
|
SCHEME_LOCAL_POS(v) = pos;
|
|
|
|
return (Scheme_Object *)v;
|
|
}
|
|
|
|
Scheme_Object *scheme_make_local(Scheme_Type type, int pos, int flags)
|
|
{
|
|
int k;
|
|
Scheme_Object *v, *key;
|
|
|
|
k = type - scheme_local_type;
|
|
|
|
/* Helper for reading bytecode: make sure flags is a valid value */
|
|
switch (flags) {
|
|
case 0:
|
|
case SCHEME_LOCAL_CLEAR_ON_READ:
|
|
case SCHEME_LOCAL_OTHER_CLEARS:
|
|
break;
|
|
default:
|
|
flags = SCHEME_LOCAL_OTHER_CLEARS;
|
|
break;
|
|
}
|
|
|
|
if (pos < MAX_CONST_LOCAL_POS) {
|
|
return scheme_local[pos][k][flags];
|
|
}
|
|
|
|
key = scheme_make_integer(pos);
|
|
if (flags) {
|
|
key = scheme_make_pair(scheme_make_integer(flags), key);
|
|
}
|
|
|
|
v = scheme_hash_get(locals_ht[k], key);
|
|
if (v)
|
|
return v;
|
|
|
|
v = alloc_local(type, pos);
|
|
SCHEME_LOCAL_FLAGS(v) = flags;
|
|
|
|
if (locals_ht[k]->count > TABLE_CACHE_MAX_SIZE) {
|
|
Scheme_Hash_Table *ht;
|
|
ht = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
locals_ht[k] = ht;
|
|
}
|
|
|
|
scheme_hash_set(locals_ht[k], key, v);
|
|
|
|
return v;
|
|
}
|
|
|
|
static Scheme_Object *force_lazy_macro(Scheme_Object *val, long phase)
|
|
{
|
|
Lazy_Macro_Fun f = (Lazy_Macro_Fun)SCHEME_PTR1_VAL(val);
|
|
Scheme_Object *data = SCHEME_PTR2_VAL(val);
|
|
return f(data, phase);
|
|
}
|
|
|
|
static Scheme_Local *get_frame_loc(Scheme_Comp_Env *frame,
|
|
int i, int j, int p, int flags)
|
|
/* Generates a Scheme_Local record for a static distance coodinate, and also
|
|
marks the variable as used for closures. */
|
|
{
|
|
int cnt, u;
|
|
|
|
u = COMPILE_DATA(frame)->use[i];
|
|
|
|
u |= (((flags & (SCHEME_APP_POS | SCHEME_SETTING | SCHEME_REFERENCING))
|
|
? CONSTRAINED_USE
|
|
: ((u & (ARBITRARY_USE | ONE_ARBITRARY_USE)) ? ARBITRARY_USE : ONE_ARBITRARY_USE))
|
|
| ((flags & (SCHEME_SETTING | SCHEME_REFERENCING | SCHEME_LINKING_REF))
|
|
? WAS_SET_BANGED
|
|
: 0));
|
|
|
|
cnt = ((u & SCHEME_USE_COUNT_MASK) >> SCHEME_USE_COUNT_SHIFT);
|
|
if (cnt < SCHEME_USE_COUNT_INF)
|
|
cnt++;
|
|
u -= (u & SCHEME_USE_COUNT_MASK);
|
|
u |= (cnt << SCHEME_USE_COUNT_SHIFT);
|
|
|
|
COMPILE_DATA(frame)->use[i] = u;
|
|
|
|
return (Scheme_Local *)scheme_make_local(scheme_local_type, p + i, 0);
|
|
}
|
|
|
|
Scheme_Object *scheme_hash_module_variable(Scheme_Env *env, Scheme_Object *modidx,
|
|
Scheme_Object *stxsym, Scheme_Object *insp,
|
|
int pos, int mod_phase)
|
|
{
|
|
Scheme_Object *val;
|
|
Scheme_Hash_Table *ht;
|
|
|
|
if (!env->modvars) {
|
|
ht = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
env->modvars = ht;
|
|
}
|
|
|
|
stxsym = SCHEME_STX_SYM(stxsym);
|
|
|
|
ht = (Scheme_Hash_Table *)scheme_hash_get(env->modvars, modidx);
|
|
|
|
if (!ht) {
|
|
ht = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
scheme_hash_set(env->modvars, modidx, (Scheme_Object *)ht);
|
|
}
|
|
|
|
/* Loop for inspector-specific hash table, maybe: */
|
|
while (1) {
|
|
|
|
val = scheme_hash_get(ht, stxsym);
|
|
|
|
if (!val) {
|
|
Module_Variable *mv;
|
|
|
|
mv = MALLOC_ONE_TAGGED(Module_Variable);
|
|
mv->so.type = scheme_module_variable_type;
|
|
|
|
mv->modidx = modidx;
|
|
mv->sym = stxsym;
|
|
mv->insp = insp;
|
|
mv->pos = pos;
|
|
mv->mod_phase = mod_phase;
|
|
|
|
val = (Scheme_Object *)mv;
|
|
|
|
scheme_hash_set(ht, stxsym, val);
|
|
|
|
break;
|
|
} else {
|
|
/* Check that inspector is the same. */
|
|
Module_Variable *mv = (Module_Variable *)val;
|
|
|
|
if (!SAME_OBJ(mv->insp, insp)) {
|
|
/* Need binding for a different inspector. Try again. */
|
|
val = scheme_hash_get(ht, insp);
|
|
if (!val) {
|
|
Scheme_Hash_Table *ht2;
|
|
/* Make a table for this specific inspector */
|
|
ht2 = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
scheme_hash_set(ht, insp, (Scheme_Object *)ht2);
|
|
ht = ht2;
|
|
/* loop... */
|
|
} else
|
|
ht = (Scheme_Hash_Table *)val;
|
|
} else
|
|
break;
|
|
}
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
Scheme_Object *scheme_tl_id_sym(Scheme_Env *env, Scheme_Object *id, Scheme_Object *bdg,
|
|
int mode, /* -1, 0 => lookup; 2, 3 => define
|
|
-1 and 3 => use temp table
|
|
1 would mean define if no match; not currently used */
|
|
Scheme_Object *phase, int *_skipped)
|
|
/* The `env' argument can actually be a hash table. */
|
|
{
|
|
Scheme_Object *marks = NULL, *sym, *map, *l, *a, *amarks, *m, *best_match, *cm, *abdg;
|
|
int best_match_skipped, ms, one_mark;
|
|
Scheme_Hash_Table *marked_names, *temp_marked_names, *dest_marked_names;
|
|
|
|
sym = SCHEME_STX_SYM(id);
|
|
|
|
if (_skipped)
|
|
*_skipped = -1;
|
|
|
|
if (SCHEME_HASHTP((Scheme_Object *)env)) {
|
|
marked_names = (Scheme_Hash_Table *)env;
|
|
temp_marked_names = NULL;
|
|
} else {
|
|
/* If there's no table and we're not defining, bail out fast */
|
|
if ((mode <= 0) && !env->rename_set)
|
|
return sym;
|
|
marked_names = scheme_get_module_rename_marked_names(env->rename_set,
|
|
phase ? phase : scheme_make_integer(env->phase),
|
|
0);
|
|
temp_marked_names = env->temp_marked_names;
|
|
}
|
|
|
|
if (mode > 0) {
|
|
/* If we're defining, see if we need to create a table. Getting
|
|
marks is relatively expensive, but we only do this once per
|
|
definition. */
|
|
if (!bdg)
|
|
bdg = scheme_stx_moduleless_env(id);
|
|
marks = scheme_stx_extract_marks(id);
|
|
if (SCHEME_NULLP(marks) && SCHEME_FALSEP(bdg))
|
|
return sym;
|
|
}
|
|
|
|
if (!marked_names) {
|
|
scheme_prepare_env_renames(env, mzMOD_RENAME_TOPLEVEL);
|
|
marked_names = scheme_get_module_rename_marked_names(env->rename_set,
|
|
phase ? phase : scheme_make_integer(env->phase),
|
|
1);
|
|
}
|
|
if (!temp_marked_names && (mode > 2)) {
|
|
/* The "temp" marked name table is used to correlate marked module
|
|
requires with similarly marked provides. We don't go through
|
|
the normal rename table because (for efficiency) the marks in
|
|
this case are handled more directly in the shared_pes module
|
|
renamings. */
|
|
temp_marked_names = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
env->temp_marked_names = temp_marked_names;
|
|
}
|
|
|
|
map = scheme_hash_get(marked_names, sym);
|
|
if (!map && ((mode < 0) || (mode > 2)) && temp_marked_names)
|
|
map = scheme_hash_get(temp_marked_names, sym);
|
|
|
|
if (!map) {
|
|
/* If we're not defining, we can bail out before extracting marks. */
|
|
if (mode <= 0)
|
|
return sym;
|
|
else
|
|
map = scheme_null;
|
|
}
|
|
|
|
if (!bdg) {
|
|
/* We need lexical binding, if any, too: */
|
|
bdg = scheme_stx_moduleless_env(id);
|
|
}
|
|
|
|
if (!marks) {
|
|
/* We really do need the marks. Get them. */
|
|
marks = scheme_stx_extract_marks(id);
|
|
if (SCHEME_NULLP(marks) && SCHEME_FALSEP(bdg))
|
|
return sym;
|
|
}
|
|
|
|
best_match = NULL;
|
|
best_match_skipped = scheme_list_length(marks);
|
|
if (best_match_skipped == 1) {
|
|
/* A mark list of length 1 is the common case.
|
|
Since the list is otherwise marshaled into .zo, etc.,
|
|
simplify by extracting just the mark: */
|
|
marks = SCHEME_CAR(marks);
|
|
one_mark = 1;
|
|
} else
|
|
one_mark = 0;
|
|
|
|
if (!SCHEME_TRUEP(bdg))
|
|
bdg = NULL;
|
|
|
|
/* Find a mapping that matches the longest tail of marks */
|
|
for (l = map; SCHEME_PAIRP(l); l = SCHEME_CDR(l)) {
|
|
a = SCHEME_CAR(l);
|
|
amarks = SCHEME_CAR(a);
|
|
|
|
if (SCHEME_VECTORP(amarks)) {
|
|
abdg = SCHEME_VEC_ELS(amarks)[1];
|
|
amarks = SCHEME_VEC_ELS(amarks)[0];
|
|
} else
|
|
abdg = NULL;
|
|
|
|
if (SAME_OBJ(abdg, bdg)) {
|
|
if (mode > 0) {
|
|
if (scheme_equal(amarks, marks)) {
|
|
best_match = SCHEME_CDR(a);
|
|
break;
|
|
}
|
|
} else {
|
|
if (!SCHEME_PAIRP(marks)) {
|
|
/* To be better than nothing, could only match exactly: */
|
|
if (scheme_equal(amarks, marks)
|
|
|| SCHEME_NULLP(amarks)) {
|
|
best_match = SCHEME_CDR(a);
|
|
best_match_skipped = 0;
|
|
}
|
|
} else {
|
|
/* amarks can match a tail of marks: */
|
|
for (m = marks, ms = 0;
|
|
SCHEME_PAIRP(m) && (ms < best_match_skipped);
|
|
m = SCHEME_CDR(m), ms++) {
|
|
|
|
cm = m;
|
|
if (!SCHEME_PAIRP(amarks)) {
|
|
/* If we're down to the last element
|
|
of marks, then extract it to try to
|
|
match the symbol amarks. */
|
|
if (SCHEME_NULLP(SCHEME_CDR(m)))
|
|
cm = SCHEME_CAR(m);
|
|
}
|
|
|
|
if (scheme_equal(amarks, cm)) {
|
|
best_match = SCHEME_CDR(a);
|
|
best_match_skipped = ms;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!best_match) {
|
|
if (mode <= 0) {
|
|
return sym;
|
|
}
|
|
|
|
/* Last chance before making up a new name. If we're processing a
|
|
module body generated by `expand', then we picked a name last
|
|
time around. We can't pick a new name now, otherwise
|
|
"redundant" module renamings wouldn't be redundant. (See
|
|
simpify in stxobj.c.) So check for a context-determined
|
|
existing rename. */
|
|
if (!SCHEME_HASHTP((Scheme_Object *)env) && env->module && (mode < 2)) {
|
|
Scheme_Object *mod, *nm = id;
|
|
mod = scheme_stx_module_name(NULL, &nm, scheme_make_integer(env->phase), NULL, NULL, NULL,
|
|
NULL, NULL, NULL, NULL);
|
|
if (mod /* must refer to env->module, otherwise there would
|
|
have been an error before getting here */
|
|
&& NOT_SAME_OBJ(nm, sym))
|
|
/* It has a rename already! */
|
|
best_match = nm;
|
|
}
|
|
|
|
/* Adding a definition. We "gensym" here in a sense; actually, we
|
|
use a symbol table that's in parallel to the normal table, so
|
|
that we get the same parallel-symbol when unmarshalling
|
|
code. We use a counter attached to the environment. Normally,
|
|
this counter just increments, but if a module is re-expanded,
|
|
then the counter starts at 0 for the re-expand, and we may
|
|
re-pick an existing name. To avoid re-picking the same name,
|
|
double-check for a mapping in the environment by inspecting the
|
|
renames attached to id. In the top-level environment, it's
|
|
still possible to get a collision, because separately compiled
|
|
code might be loaded into the same environment (which is just
|
|
too bad). */
|
|
if (!best_match) {
|
|
char onstack[50], *buf;
|
|
int len;
|
|
|
|
while (1) {
|
|
env->id_counter++;
|
|
len = SCHEME_SYM_LEN(sym);
|
|
if (len <= 35)
|
|
buf = onstack;
|
|
else
|
|
buf = scheme_malloc_atomic(len + 15);
|
|
memcpy(buf, SCHEME_SYM_VAL(sym), len);
|
|
|
|
/* The dot here is significant; it might gets stripped away when
|
|
printing the symbol */
|
|
sprintf(buf + len, ".%d", env->id_counter);
|
|
|
|
best_match = scheme_intern_exact_parallel_symbol(buf, strlen(buf));
|
|
|
|
if (!scheme_stx_parallel_is_used(best_match, id)) {
|
|
/* Also check environment's rename tables. This last check
|
|
includes the temp table. It also turns out to matter for
|
|
compiling in `module->namespace' contexts, because no
|
|
renaming is added after expansion to record the rename
|
|
table. */
|
|
if (!scheme_tl_id_is_sym_used(marked_names, best_match)
|
|
&& (!temp_marked_names
|
|
|| !scheme_tl_id_is_sym_used(temp_marked_names, best_match))) {
|
|
/* Ok, no matches, so this name is fine. */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Otherwise, increment counter and try again... */
|
|
}
|
|
}
|
|
if (bdg) {
|
|
a = scheme_make_vector(2, NULL);
|
|
SCHEME_VEC_ELS(a)[0] = marks;
|
|
SCHEME_VEC_ELS(a)[1] = bdg;
|
|
marks = a;
|
|
}
|
|
a = scheme_make_pair(marks, best_match);
|
|
map = scheme_make_pair(a, map);
|
|
|
|
dest_marked_names = ((mode < 0) || (mode > 2)) ? temp_marked_names : marked_names;
|
|
scheme_hash_set(dest_marked_names, sym, map);
|
|
{
|
|
Scheme_Hash_Table *rev_ht;
|
|
rev_ht = (Scheme_Hash_Table *)scheme_hash_get(dest_marked_names, scheme_false);
|
|
if (rev_ht) {
|
|
scheme_hash_set(rev_ht, best_match, scheme_true);
|
|
}
|
|
}
|
|
} else {
|
|
if (_skipped)
|
|
*_skipped = best_match_skipped;
|
|
}
|
|
|
|
return best_match;
|
|
}
|
|
|
|
int scheme_tl_id_is_sym_used(Scheme_Hash_Table *marked_names, Scheme_Object *sym)
|
|
{
|
|
int i;
|
|
Scheme_Object *l, *a;
|
|
Scheme_Hash_Table *rev_ht;
|
|
|
|
if (!marked_names)
|
|
return 0;
|
|
|
|
if (!marked_names->count)
|
|
return 0;
|
|
|
|
rev_ht = (Scheme_Hash_Table *)scheme_hash_get(marked_names, scheme_false);
|
|
|
|
if (!rev_ht) {
|
|
rev_ht = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
|
|
for (i = marked_names->size; i--; ) {
|
|
l = marked_names->vals[i];
|
|
if (l) {
|
|
for (; SCHEME_PAIRP(l); l = SCHEME_CDR(l)) {
|
|
a = SCHEME_CAR(l);
|
|
scheme_hash_set(rev_ht, SCHEME_CDR(a), scheme_true);
|
|
}
|
|
}
|
|
scheme_hash_set(marked_names, scheme_false, (Scheme_Object *)rev_ht);
|
|
}
|
|
}
|
|
|
|
if (scheme_hash_get(rev_ht, sym))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static Scheme_Object *make_uid()
|
|
{
|
|
char name[20];
|
|
|
|
sprintf(name, "env%d", env_uid_counter++);
|
|
return scheme_make_symbol(name); /* uninterned! */
|
|
}
|
|
|
|
Scheme_Object *scheme_env_frame_uid(Scheme_Comp_Env *env)
|
|
{
|
|
if (env->flags & (SCHEME_NO_RENAME | SCHEME_CAPTURE_WITHOUT_RENAME | SCHEME_CAPTURE_LIFTED))
|
|
return NULL;
|
|
|
|
if (!env->uid) {
|
|
Scheme_Object *sym;
|
|
sym = make_uid();
|
|
env->uid = sym;
|
|
}
|
|
return env->uid;
|
|
}
|
|
|
|
static void make_env_renames(Scheme_Comp_Env *env, int rcount, int rstart, int rstart_sec, int force_multi,
|
|
Scheme_Object *stx)
|
|
{
|
|
Scheme_Object *rnm;
|
|
Scheme_Object *uid = NULL;
|
|
int i, pos;
|
|
|
|
if (env->flags & (SCHEME_NO_RENAME | SCHEME_CAPTURE_WITHOUT_RENAME | SCHEME_CAPTURE_LIFTED))
|
|
return;
|
|
|
|
scheme_env_frame_uid(env);
|
|
|
|
if (force_multi) {
|
|
if (env->num_bindings && !env->uids) {
|
|
Scheme_Object **uids;
|
|
uids = MALLOC_N(Scheme_Object *, env->num_bindings);
|
|
env->uids = uids;
|
|
}
|
|
if (COMPILE_DATA(env)->num_const && !COMPILE_DATA(env)->const_uids) {
|
|
Scheme_Object **cuids;
|
|
cuids = MALLOC_N(Scheme_Object *, COMPILE_DATA(env)->num_const);
|
|
COMPILE_DATA(env)->const_uids = cuids;
|
|
}
|
|
if (env->uid && !SCHEME_FALSEP(env->uid)) {
|
|
uid = env->uid;
|
|
env->uid = scheme_false;
|
|
}
|
|
}
|
|
|
|
if (!uid) {
|
|
if (env->uid && SCHEME_TRUEP(env->uid)) {
|
|
/* single-uid mode (at least for now) */
|
|
uid = env->uid;
|
|
} else {
|
|
/* multi-uid mode */
|
|
if (!rstart_sec)
|
|
uid = COMPILE_DATA(env)->const_uids[rstart];
|
|
else
|
|
uid = env->uids[rstart];
|
|
if (!uid)
|
|
uid = make_uid();
|
|
}
|
|
}
|
|
|
|
rnm = scheme_make_rename(uid, rcount);
|
|
pos = 0;
|
|
|
|
if (!rstart_sec) {
|
|
for (i = rstart; (i < COMPILE_DATA(env)->num_const) && (pos < rcount); i++, pos++) {
|
|
if (COMPILE_DATA(env)->const_uids)
|
|
COMPILE_DATA(env)->const_uids[i] = uid;
|
|
scheme_set_rename(rnm, pos, COMPILE_DATA(env)->const_names[i]);
|
|
}
|
|
rstart = 0;
|
|
}
|
|
for (i = rstart; pos < rcount; i++, pos++) {
|
|
if (env->uids)
|
|
env->uids[i] = uid;
|
|
scheme_set_rename(rnm, pos, env->values[i]);
|
|
}
|
|
|
|
if (SCHEME_RIBP(stx))
|
|
scheme_add_rib_rename(stx, rnm);
|
|
|
|
if (env->renames) {
|
|
if (SCHEME_PAIRP(env->renames) || SCHEME_NULLP(env->renames))
|
|
rnm = scheme_make_pair(rnm, env->renames);
|
|
else
|
|
rnm = scheme_make_pair(rnm, scheme_make_pair(env->renames, scheme_null));
|
|
}
|
|
env->renames = rnm;
|
|
}
|
|
|
|
Scheme_Object *scheme_add_env_renames(Scheme_Object *stx, Scheme_Comp_Env *env,
|
|
Scheme_Comp_Env *upto)
|
|
{
|
|
if (!SCHEME_STXP(stx) && !SCHEME_RIBP(stx)) {
|
|
scheme_signal_error("internal error: not syntax or rib");
|
|
return NULL;
|
|
}
|
|
|
|
if (SCHEME_RIBP(stx)) {
|
|
GC_CAN_IGNORE int *s;
|
|
s = scheme_stx_get_rib_sealed(stx);
|
|
COMPILE_DATA(env)->sealed = s;
|
|
}
|
|
|
|
while (env != upto) {
|
|
if (!(env->flags & (SCHEME_NO_RENAME | SCHEME_CAPTURE_WITHOUT_RENAME
|
|
| SCHEME_CAPTURE_LIFTED | SCHEME_INTDEF_SHADOW))) {
|
|
int i, count;
|
|
|
|
/* How many slots filled in the frame so far? This can change
|
|
due to the style of let* compilation, which generates a
|
|
rename record after each binding set. The "const" bindings
|
|
are always all in place before we generate any renames in
|
|
that case. However, the "const" bindings can grow by
|
|
themselves before non-const bindings are installed. */
|
|
count = COMPILE_DATA(env)->num_const;
|
|
for (i = env->num_bindings; i--; ) {
|
|
if (env->values[i])
|
|
count++;
|
|
}
|
|
|
|
if (count) {
|
|
Scheme_Object *l;
|
|
|
|
if (!env->renames || (env->rename_var_count != count)) {
|
|
/* Need to create lexical renaming record(s). We create
|
|
multiple records as necessary to avoid uids that contain
|
|
more than one variable with the same symbol name.
|
|
|
|
This is complicated, because we don't want to allocate a
|
|
hash table in the common case of a binding set with a few
|
|
names. It's also complicated by incremental rename
|
|
building: if env->rename_var_count is not zero, we've
|
|
done this before for a subset of `values' (and there are
|
|
no consts in that case). In the incremental case, we have
|
|
a dup_check hash table left from the previous round. */
|
|
Scheme_Hash_Table *ht;
|
|
Scheme_Object *name;
|
|
int rcount = 0, rstart, rstart_sec = 0, vstart;
|
|
|
|
/* rstart is where the to-be-created rename table starts
|
|
(saved from last time around, or initially zero).
|
|
vstart is where we start looking for new dups.
|
|
rstart_sec is TRUE when the new frame starts in the
|
|
non-constant area. */
|
|
rstart = env->rename_rstart;
|
|
if (env->renames) {
|
|
/* Incremental mode. Drop the most recent (first) rename
|
|
table, because we'll recreate it: */
|
|
if (SCHEME_PAIRP(env->renames))
|
|
env->renames = SCHEME_CDR(env->renames);
|
|
else
|
|
env->renames = NULL;
|
|
if (SCHEME_RIBP(stx))
|
|
scheme_drop_first_rib_rename(stx);
|
|
vstart = env->rename_var_count;
|
|
rstart_sec = 1;
|
|
/* We already know that the first rcount
|
|
are distinct (from the last iteration) */
|
|
rcount = vstart - rstart;
|
|
} else
|
|
vstart = 0;
|
|
|
|
/* Create or find the hash table: */
|
|
if (env->dup_check)
|
|
ht = env->dup_check;
|
|
else if (env->num_bindings + COMPILE_DATA(env)->num_const > 10)
|
|
ht = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
else
|
|
ht = NULL;
|
|
|
|
if (rcount > 16) {
|
|
/* Instead of n^2 growth for the rename, just close the current
|
|
one off and start fresh. */
|
|
make_env_renames(env, rcount, rstart, rstart_sec, 1, stx);
|
|
rcount = 0;
|
|
rstart = vstart;
|
|
rstart_sec = 1;
|
|
if (ht) {
|
|
/* Flush the table for a new set: */
|
|
ht = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
}
|
|
}
|
|
|
|
/* Check for dups among the statics, and build a rename for
|
|
each dup-free set. */
|
|
|
|
/* First: constants. */
|
|
if (!rstart_sec) {
|
|
if (COMPILE_DATA(env)->num_const) {
|
|
/* Start at the beginning, always. */
|
|
for (i = 0; i < COMPILE_DATA(env)->num_const; i++) {
|
|
int found = 0;
|
|
name = SCHEME_STX_VAL(COMPILE_DATA(env)->const_names[i]);
|
|
if (ht) {
|
|
if (scheme_hash_get(ht, name))
|
|
found = 1;
|
|
else
|
|
scheme_hash_set(ht, name, scheme_true);
|
|
} else {
|
|
int j;
|
|
for (j = rstart; j < i; j++) {
|
|
if (SAME_OBJ(name, SCHEME_STX_VAL(COMPILE_DATA(env)->const_names[j]))) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (found) {
|
|
make_env_renames(env, rcount, rstart, rstart_sec, 1, stx);
|
|
rcount = 1;
|
|
rstart = i;
|
|
if (ht) {
|
|
/* Flush the table for a new set: */
|
|
ht = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
scheme_hash_set(ht, name, scheme_true);
|
|
}
|
|
} else
|
|
rcount++;
|
|
}
|
|
} else
|
|
rstart_sec = 1;
|
|
}
|
|
|
|
for (i = vstart; (i < env->num_bindings) && env->values[i]; i++) {
|
|
int found = 0;
|
|
name = SCHEME_STX_VAL(env->values[i]);
|
|
|
|
if (ht) {
|
|
if (scheme_hash_get(ht, name))
|
|
found = 1;
|
|
else
|
|
scheme_hash_set(ht, name, scheme_true);
|
|
} else {
|
|
int j;
|
|
if (!rstart_sec) {
|
|
/* Look in consts, first: */
|
|
for (j = rstart; j < COMPILE_DATA(env)->num_const; j++) {
|
|
if (SAME_OBJ(name, SCHEME_STX_VAL(COMPILE_DATA(env)->const_names[j]))) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
j = 0;
|
|
} else
|
|
j = rstart;
|
|
|
|
if (!found) {
|
|
for (; j < i; j++) {
|
|
if (SAME_OBJ(name, SCHEME_STX_VAL(env->values[j]))) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (found) {
|
|
make_env_renames(env, rcount, rstart, rstart_sec, 1, stx);
|
|
rcount = 1;
|
|
rstart = i;
|
|
rstart_sec = 1;
|
|
if (ht) {
|
|
/* Flush the table for a new set: */
|
|
ht = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
scheme_hash_set(ht, name, scheme_true);
|
|
}
|
|
} else
|
|
rcount++;
|
|
}
|
|
|
|
make_env_renames(env, rcount, rstart, rstart_sec, 0, stx);
|
|
|
|
env->rename_var_count = count;
|
|
env->rename_rstart = rstart;
|
|
if (count < env->num_bindings) {
|
|
/* save for next time around: */
|
|
env->dup_check = ht;
|
|
} else {
|
|
/* drop a saved table if there; we're done with all increments */
|
|
env->dup_check = NULL;
|
|
}
|
|
}
|
|
|
|
if (SCHEME_STXP(stx)) {
|
|
for (l = env->renames; SCHEME_PAIRP(l); l = SCHEME_CDR(l)) {
|
|
stx = scheme_add_rename(stx, SCHEME_CAR(l));
|
|
}
|
|
if (!SCHEME_NULLP(l))
|
|
stx = scheme_add_rename(stx, l);
|
|
}
|
|
}
|
|
} else if (env->flags & SCHEME_INTDEF_SHADOW) {
|
|
/* Just extract existing uids from identifiers, and don't need to
|
|
add renames to syntax objects. */
|
|
if (!env->uids) {
|
|
Scheme_Object **uids, *uid;
|
|
int i;
|
|
|
|
uids = MALLOC_N(Scheme_Object *, env->num_bindings);
|
|
env->uids = uids;
|
|
|
|
for (i = env->num_bindings; i--; ) {
|
|
uid = scheme_stx_moduleless_env(env->values[i]);
|
|
if (SCHEME_FALSEP(uid))
|
|
scheme_signal_error("intdef shadow binding is #f for %d/%s",
|
|
SCHEME_TYPE(env->values[i]),
|
|
scheme_write_to_string(SCHEME_STX_VAL(env->values[i]),
|
|
NULL));
|
|
env->uids[i] = uid;
|
|
}
|
|
}
|
|
}
|
|
|
|
env = env->next;
|
|
}
|
|
|
|
return stx;
|
|
}
|
|
|
|
void scheme_seal_env_renames(Scheme_Comp_Env *env)
|
|
{
|
|
env->dup_check = NULL;
|
|
}
|
|
|
|
/*********************************************************************/
|
|
|
|
void create_skip_table(Scheme_Comp_Env *start_frame)
|
|
{
|
|
Scheme_Comp_Env *end_frame, *frame;
|
|
int depth, dj = 0, dp = 0, i;
|
|
Scheme_Hash_Table *table;
|
|
int stride = 0;
|
|
|
|
depth = start_frame->skip_depth;
|
|
|
|
/* Find frames to be covered by the skip table.
|
|
The theory here is the same as the `mapped' table
|
|
in Scheme_Cert (see stxobj.c) */
|
|
for (end_frame = start_frame->next;
|
|
end_frame && ((depth & end_frame->skip_depth) != end_frame->skip_depth);
|
|
end_frame = end_frame->next) {
|
|
stride++;
|
|
}
|
|
|
|
table = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
|
|
for (frame = start_frame; frame != end_frame; frame = frame->next) {
|
|
if (frame->flags & SCHEME_LAMBDA_FRAME)
|
|
dj++;
|
|
dp += frame->num_bindings;
|
|
for (i = frame->num_bindings; i--; ) {
|
|
if (frame->values[i]) {
|
|
scheme_hash_set(table, SCHEME_STX_VAL(frame->values[i]), scheme_true);
|
|
}
|
|
}
|
|
for (i = COMPILE_DATA(frame)->num_const; i--; ) {
|
|
scheme_hash_set(table, SCHEME_STX_VAL(COMPILE_DATA(frame)->const_names[i]), scheme_true);
|
|
}
|
|
}
|
|
|
|
scheme_hash_set(table, scheme_make_integer(0), (Scheme_Object *)end_frame);
|
|
scheme_hash_set(table, scheme_make_integer(1), scheme_make_integer(dj));
|
|
scheme_hash_set(table, scheme_make_integer(2), scheme_make_integer(dp));
|
|
|
|
start_frame->skip_table = table;
|
|
}
|
|
|
|
/*********************************************************************/
|
|
/*
|
|
|
|
scheme_lookup_binding() is the main resolver of lexical, module,
|
|
and top-level bindings. Depending on the value of `flags', it can
|
|
return a value whose type tag is:
|
|
|
|
scheme_macro_type (id was bound to syntax),
|
|
|
|
scheme_macro_set_type (id was bound to a set!-transformer),
|
|
|
|
scheme_macro_id_type (id was bound to a rename-transformer),
|
|
|
|
scheme_local_type (id was lexical),
|
|
|
|
scheme_variable_type (id is a global or module-bound variable),
|
|
or
|
|
|
|
scheme_module_variable_type (id is a module-bound variable).
|
|
|
|
*/
|
|
|
|
Scheme_Object *
|
|
scheme_lookup_binding(Scheme_Object *find_id, Scheme_Comp_Env *env, int flags,
|
|
Scheme_Object *certs, Scheme_Object *in_modidx,
|
|
Scheme_Env **_menv, int *_protected,
|
|
Scheme_Object **_lexical_binding_id)
|
|
{
|
|
Scheme_Comp_Env *frame;
|
|
int j = 0, p = 0, modpos, skip_stops = 0, module_self_reference = 0;
|
|
Scheme_Bucket *b;
|
|
Scheme_Object *val, *modidx, *modname, *src_find_id, *find_global_id, *mod_defn_phase;
|
|
Scheme_Object *find_id_sym = NULL;
|
|
Scheme_Env *genv;
|
|
long phase;
|
|
|
|
/* Need to know the phase being compiled */
|
|
phase = env->genv->phase;
|
|
|
|
/* Walk through the compilation frames */
|
|
for (frame = env; frame->next != NULL; frame = frame->next) {
|
|
int i;
|
|
Scheme_Object *uid;
|
|
|
|
while (1) {
|
|
if (frame->skip_table) {
|
|
if (!scheme_hash_get(frame->skip_table, SCHEME_STX_VAL(find_id))) {
|
|
/* Skip ahead. 0 maps to frame, 1 maps to j delta, and 2 maps to p delta */
|
|
val = scheme_hash_get(frame->skip_table, scheme_make_integer(1));
|
|
j += SCHEME_INT_VAL(val);
|
|
val = scheme_hash_get(frame->skip_table, scheme_make_integer(2));
|
|
p += SCHEME_INT_VAL(val);
|
|
frame = (Scheme_Comp_Env *)scheme_hash_get(frame->skip_table, scheme_make_integer(0));
|
|
} else
|
|
break;
|
|
} else if (frame->skip_depth && !(frame->skip_depth & 0x1F)) {
|
|
/* We're some multiple of 32 frames deep. Build a skip table and try again. */
|
|
create_skip_table(frame);
|
|
} else
|
|
break;
|
|
}
|
|
|
|
if (frame->flags & SCHEME_LAMBDA_FRAME)
|
|
j++;
|
|
|
|
if (!skip_stops || !(frame->flags & SCHEME_FOR_STOPS)) {
|
|
if (frame->flags & SCHEME_FOR_STOPS)
|
|
skip_stops = 1;
|
|
|
|
uid = scheme_env_frame_uid(frame);
|
|
|
|
if (!find_id_sym
|
|
&& (frame->flags & SCHEME_CAPTURE_WITHOUT_RENAME))
|
|
find_id_sym = scheme_stx_get_module_eq_sym(find_id, scheme_make_integer(phase));
|
|
|
|
for (i = frame->num_bindings; i--; ) {
|
|
if (frame->values[i]) {
|
|
if (frame->uids)
|
|
uid = frame->uids[i];
|
|
if (SAME_OBJ(SCHEME_STX_VAL(find_id), SCHEME_STX_VAL(frame->values[i]))
|
|
&& (scheme_stx_env_bound_eq(find_id, frame->values[i], uid, scheme_make_integer(phase))
|
|
|| ((frame->flags & SCHEME_CAPTURE_WITHOUT_RENAME)
|
|
&& scheme_stx_module_eq2(find_id, frame->values[i], scheme_make_integer(phase), find_id_sym))
|
|
|| ((frame->flags & SCHEME_CAPTURE_LIFTED)
|
|
&& scheme_stx_bound_eq(find_id, frame->values[i], scheme_make_integer(phase))))) {
|
|
/* Found a lambda-, let-, etc. bound variable: */
|
|
/* First, check certs (don't bind with fewer certs): */
|
|
if (!(flags & SCHEME_NO_CERT_CHECKS)
|
|
&& !(frame->flags & (SCHEME_CAPTURE_WITHOUT_RENAME | SCHEME_CAPTURE_LIFTED))) {
|
|
if (scheme_stx_has_more_certs(find_id, certs, frame->values[i], frame->certs)) {
|
|
scheme_wrong_syntax(scheme_compile_stx_string, NULL, find_id,
|
|
"reference is more certified than binding");
|
|
return NULL;
|
|
}
|
|
}
|
|
/* Looks ok; return a lexical reference */
|
|
if (_lexical_binding_id) {
|
|
if (!(frame->flags & SCHEME_CAPTURE_WITHOUT_RENAME))
|
|
val = scheme_stx_remove_extra_marks(find_id, frame->values[i],
|
|
((frame->flags & SCHEME_CAPTURE_LIFTED)
|
|
? NULL
|
|
: uid));
|
|
else
|
|
val = find_id;
|
|
*_lexical_binding_id = val;
|
|
}
|
|
if (flags & SCHEME_DONT_MARK_USE)
|
|
return scheme_make_local(scheme_local_type, 0, 0);
|
|
else
|
|
return (Scheme_Object *)get_frame_loc(frame, i, j, p, flags);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = COMPILE_DATA(frame)->num_const; i--; ) {
|
|
int issame;
|
|
if (frame->flags & SCHEME_CAPTURE_WITHOUT_RENAME)
|
|
issame = scheme_stx_module_eq2(find_id, COMPILE_DATA(frame)->const_names[i],
|
|
scheme_make_integer(phase), find_id_sym);
|
|
else {
|
|
if (COMPILE_DATA(frame)->const_uids) uid = COMPILE_DATA(frame)->const_uids[i];
|
|
issame = (SAME_OBJ(SCHEME_STX_VAL(find_id),
|
|
SCHEME_STX_VAL(COMPILE_DATA(frame)->const_names[i]))
|
|
&& scheme_stx_env_bound_eq(find_id, COMPILE_DATA(frame)->const_names[i], uid,
|
|
scheme_make_integer(phase)));
|
|
}
|
|
|
|
if (issame) {
|
|
if (!(flags & SCHEME_NO_CERT_CHECKS)
|
|
&& !(frame->flags & SCHEME_CAPTURE_WITHOUT_RENAME)) {
|
|
if (scheme_stx_has_more_certs(find_id, certs, COMPILE_DATA(frame)->const_names[i], frame->certs)) {
|
|
scheme_wrong_syntax(scheme_compile_stx_string, NULL, find_id,
|
|
"reference is more certified than binding");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (_lexical_binding_id) {
|
|
if (!(frame->flags & SCHEME_CAPTURE_WITHOUT_RENAME))
|
|
val = scheme_stx_remove_extra_marks(find_id, COMPILE_DATA(frame)->const_names[i],
|
|
((frame->flags & SCHEME_CAPTURE_LIFTED)
|
|
? NULL
|
|
: uid));
|
|
else
|
|
val = find_id;
|
|
*_lexical_binding_id = val;
|
|
}
|
|
|
|
val = COMPILE_DATA(frame)->const_vals[i];
|
|
|
|
if (!val) {
|
|
scheme_wrong_syntax(scheme_compile_stx_string, NULL, find_id,
|
|
"identifier used out of context");
|
|
return NULL;
|
|
}
|
|
|
|
if (SCHEME_FALSEP(val)) {
|
|
/* Corresponds to a run-time binding (but will be replaced later
|
|
through a renaming to a different binding) */
|
|
if (flags & SCHEME_OUT_OF_CONTEXT_LOCAL)
|
|
return scheme_make_local(scheme_local_type, 0, 0);
|
|
return NULL;
|
|
}
|
|
|
|
if (!(flags & SCHEME_ENV_CONSTANTS_OK)) {
|
|
if (SAME_TYPE(SCHEME_TYPE(val), scheme_macro_type))
|
|
return val;
|
|
else if (SAME_TYPE(SCHEME_TYPE(val), scheme_lazy_macro_type))
|
|
return force_lazy_macro(val, phase);
|
|
else
|
|
scheme_wrong_syntax(scheme_set_stx_string, NULL, find_id,
|
|
"local syntax identifier cannot be mutated");
|
|
return NULL;
|
|
}
|
|
|
|
return val;
|
|
}
|
|
}
|
|
}
|
|
|
|
p += frame->num_bindings;
|
|
}
|
|
|
|
src_find_id = find_id;
|
|
modidx = scheme_stx_module_name(NULL, &find_id, scheme_make_integer(phase), NULL, NULL, &mod_defn_phase,
|
|
NULL, NULL, NULL, NULL);
|
|
|
|
/* Used out of context? */
|
|
if (SAME_OBJ(modidx, scheme_undefined)) {
|
|
if (SCHEME_STXP(find_id)) {
|
|
/* Looks like lexically bound, but double-check that it's not bound via a tl_id: */
|
|
find_global_id = scheme_tl_id_sym(env->genv, find_id, NULL, 0, NULL, NULL);
|
|
if (!SAME_OBJ(find_global_id, SCHEME_STX_VAL(find_id)))
|
|
modidx = NULL; /* yes, it is bound */
|
|
}
|
|
|
|
if (modidx) {
|
|
if (!(flags & SCHEME_OUT_OF_CONTEXT_OK)) {
|
|
scheme_wrong_syntax(scheme_compile_stx_string, NULL, find_id,
|
|
"identifier used out of context");
|
|
}
|
|
if (flags & SCHEME_OUT_OF_CONTEXT_LOCAL)
|
|
return scheme_make_local(scheme_local_type, 0, 0);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (modidx) {
|
|
/* If it's an access path, resolve it: */
|
|
modname = scheme_module_resolve(modidx, 1);
|
|
|
|
if (env->genv->module && SAME_OBJ(modname, env->genv->module->modname)) {
|
|
modidx = NULL;
|
|
modname = NULL;
|
|
genv = env->genv;
|
|
/* So we can distinguish between unbound identifiers in a module
|
|
and references to top-level definitions: */
|
|
module_self_reference = 1;
|
|
} else {
|
|
genv = scheme_module_access(modname, env->genv, SCHEME_INT_VAL(mod_defn_phase));
|
|
|
|
if (!genv) {
|
|
if (env->genv->phase) {
|
|
/* The failure might be due a laziness in required-syntax
|
|
execution. Force all laziness at the prior level
|
|
and try again. */
|
|
scheme_module_force_lazy(env->genv, 1);
|
|
genv = scheme_module_access(modname, env->genv, SCHEME_INT_VAL(mod_defn_phase));
|
|
}
|
|
|
|
if (!genv) {
|
|
scheme_wrong_syntax("require", NULL, src_find_id,
|
|
"namespace mismatch; reference (phase %d) to a module"
|
|
" %D that is not available (phase level %d)",
|
|
env->genv->phase, modname, SCHEME_INT_VAL(mod_defn_phase));
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
genv = env->genv;
|
|
modname = NULL;
|
|
|
|
if (genv->module && genv->disallow_unbound) {
|
|
/* Free identifier. Maybe don't continue. */
|
|
if (flags & (SCHEME_SETTING | SCHEME_REFERENCING)) {
|
|
scheme_wrong_syntax(((flags & SCHEME_SETTING)
|
|
? scheme_set_stx_string
|
|
: scheme_var_ref_string),
|
|
NULL, src_find_id, "unbound identifier in module");
|
|
return NULL;
|
|
}
|
|
if (flags & SCHEME_NULL_FOR_UNBOUND)
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (_menv && genv->module)
|
|
*_menv = genv;
|
|
|
|
if (!modname && SCHEME_STXP(find_id))
|
|
find_global_id = scheme_tl_id_sym(env->genv, find_id, NULL, 0, NULL, NULL);
|
|
else
|
|
find_global_id = find_id;
|
|
|
|
/* Try syntax table: */
|
|
if (modname) {
|
|
val = scheme_module_syntax(modname, env->genv, find_id);
|
|
if (val && !(flags & SCHEME_NO_CERT_CHECKS))
|
|
scheme_check_accessible_in_module(genv, env->insp, in_modidx,
|
|
find_id, src_find_id, certs, NULL, -2, 0,
|
|
NULL,
|
|
env->genv);
|
|
} else {
|
|
/* Only try syntax table if there's not an explicit (later)
|
|
variable mapping: */
|
|
if (genv->shadowed_syntax
|
|
&& scheme_hash_get(genv->shadowed_syntax, find_global_id))
|
|
val = NULL;
|
|
else
|
|
val = scheme_lookup_in_table(genv->syntax, (const char *)find_global_id);
|
|
}
|
|
|
|
if (val) {
|
|
if (SAME_TYPE(SCHEME_TYPE(val), scheme_lazy_macro_type))
|
|
return force_lazy_macro(val, phase);
|
|
return val;
|
|
}
|
|
|
|
if (modname) {
|
|
Scheme_Object *pos;
|
|
if (flags & SCHEME_NO_CERT_CHECKS)
|
|
pos = 0;
|
|
else
|
|
pos = scheme_check_accessible_in_module(genv, env->insp, in_modidx,
|
|
find_id, src_find_id, certs, NULL, -1, 1,
|
|
_protected, env->genv);
|
|
modpos = SCHEME_INT_VAL(pos);
|
|
} else
|
|
modpos = -1;
|
|
|
|
if (modname && (flags & SCHEME_SETTING)) {
|
|
if (SAME_OBJ(src_find_id, find_id) || SAME_OBJ(SCHEME_STX_SYM(src_find_id), find_id))
|
|
find_id = NULL;
|
|
scheme_wrong_syntax(scheme_set_stx_string, find_id, src_find_id, "cannot mutate module-required identifier");
|
|
return NULL;
|
|
}
|
|
|
|
if (!modname && (flags & (SCHEME_SETTING | SCHEME_REFERENCING))
|
|
&& (genv->module && genv->disallow_unbound)) {
|
|
/* Check for set! of unbound identifier: */
|
|
if (!scheme_lookup_in_table(genv->toplevel, (const char *)find_global_id)) {
|
|
scheme_wrong_syntax(((flags & SCHEME_SETTING)
|
|
? scheme_set_stx_string
|
|
: scheme_var_ref_string),
|
|
NULL, src_find_id, "unbound identifier in module");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (!modname && (flags & SCHEME_NULL_FOR_UNBOUND)) {
|
|
if (module_self_reference) {
|
|
/* Since the module has a rename for this id, it's certainly defined. */
|
|
if (!(flags & SCHEME_RESOLVE_MODIDS)) {
|
|
/* This is the same thing as #%top handling in compile mode. But
|
|
for expand mode, it prevents wrapping the identifier with #%top. */
|
|
/* Don't need a pos, because the symbol's gensym-ness (if any) will be
|
|
preserved within the module. */
|
|
return scheme_hash_module_variable(genv, genv->module->self_modidx, find_id,
|
|
genv->module->insp,
|
|
-1, genv->mod_phase);
|
|
}
|
|
} else
|
|
return NULL;
|
|
}
|
|
|
|
/* Used to have `&& !SAME_OBJ(modidx, modname)' below, but that was a bad
|
|
idea, because it causes module instances to be preserved. */
|
|
if (modname && !(flags & SCHEME_RESOLVE_MODIDS)
|
|
&& (!scheme_is_kernel_modname(modname) || (flags & SCHEME_REFERENCING))) {
|
|
/* Create a module variable reference, so that idx is preserved: */
|
|
return scheme_hash_module_variable(env->genv, modidx, find_id,
|
|
genv->module->insp,
|
|
modpos, SCHEME_INT_VAL(mod_defn_phase));
|
|
}
|
|
|
|
if (!modname && (flags & (SCHEME_SETTING | SCHEME_REFERENCING)) && genv->module) {
|
|
/* Need to return a variable reference in this case, too. */
|
|
return scheme_hash_module_variable(env->genv, genv->module->self_modidx, find_global_id,
|
|
genv->module->insp,
|
|
modpos, genv->mod_phase);
|
|
}
|
|
|
|
b = scheme_bucket_from_table(genv->toplevel, (char *)find_global_id);
|
|
|
|
if ((flags & SCHEME_ELIM_CONST) && b && b->val
|
|
&& (((Scheme_Bucket_With_Flags *)b)->flags & GLOB_IS_CONST)
|
|
&& !(flags & SCHEME_GLOB_ALWAYS_REFERENCE))
|
|
return (Scheme_Object *)b->val;
|
|
|
|
ASSERT_IS_VARIABLE_BUCKET(b);
|
|
if (!((Scheme_Bucket_With_Home *)b)->home)
|
|
((Scheme_Bucket_With_Home *)b)->home = genv;
|
|
|
|
return (Scheme_Object *)b;
|
|
}
|
|
|
|
int *scheme_env_get_flags(Scheme_Comp_Env *frame, int start, int count)
|
|
{
|
|
int *v, i;
|
|
|
|
v = MALLOC_N_ATOMIC(int, count);
|
|
memcpy(v, COMPILE_DATA(frame)->use + start, sizeof(int) * count);
|
|
|
|
for (i = count; i--; ) {
|
|
int old;
|
|
old = v[i];
|
|
v[i] = 0;
|
|
if (old & (ARBITRARY_USE | ONE_ARBITRARY_USE | CONSTRAINED_USE)) {
|
|
v[i] |= SCHEME_WAS_USED;
|
|
if (!(old & (ARBITRARY_USE | WAS_SET_BANGED))) {
|
|
if (old & ONE_ARBITRARY_USE)
|
|
v[i] |= SCHEME_WAS_APPLIED_EXCEPT_ONCE;
|
|
else
|
|
v[i] |= SCHEME_WAS_ONLY_APPLIED;
|
|
}
|
|
}
|
|
if (old & WAS_SET_BANGED)
|
|
v[i] |= SCHEME_WAS_SET_BANGED;
|
|
v[i] |= (old & SCHEME_USE_COUNT_MASK);
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
/*========================================================================*/
|
|
/* syntax-checking utils */
|
|
/*========================================================================*/
|
|
|
|
void scheme_check_identifier(const char *formname, Scheme_Object *id,
|
|
const char *where, Scheme_Comp_Env *env,
|
|
Scheme_Object *form)
|
|
{
|
|
if (!where)
|
|
where = "";
|
|
|
|
if (!SCHEME_STX_SYMBOLP(id))
|
|
scheme_wrong_syntax(formname, form ? id : NULL,
|
|
form ? form : id,
|
|
"not an identifier%s", where);
|
|
}
|
|
|
|
void scheme_begin_dup_symbol_check(DupCheckRecord *r, Scheme_Comp_Env *env)
|
|
{
|
|
r->phase = env->genv->phase;
|
|
r->count = 0;
|
|
}
|
|
|
|
void scheme_dup_symbol_check(DupCheckRecord *r, const char *where,
|
|
Scheme_Object *symbol, char *what,
|
|
Scheme_Object *form)
|
|
{
|
|
int i;
|
|
|
|
if (r->count <= 5) {
|
|
for (i = 0; i < r->count; i++) {
|
|
if (scheme_stx_bound_eq(symbol, r->syms[i], scheme_make_integer(r->phase)))
|
|
scheme_wrong_syntax(where, symbol, form,
|
|
"duplicate %s name", what);
|
|
}
|
|
|
|
if (r->count < 5) {
|
|
r->syms[r->count++] = symbol;
|
|
return;
|
|
} else {
|
|
Scheme_Hash_Table *ht;
|
|
ht = scheme_make_hash_table(SCHEME_hash_bound_id);
|
|
r->ht = ht;
|
|
for (i = 0; i < r->count; i++) {
|
|
scheme_hash_set(ht, r->syms[i], scheme_true);
|
|
}
|
|
r->count++;
|
|
}
|
|
}
|
|
|
|
if (scheme_hash_get(r->ht, symbol)) {
|
|
scheme_wrong_syntax(where, symbol, form,
|
|
"duplicate %s name", what);
|
|
}
|
|
|
|
scheme_hash_set(r->ht, symbol, scheme_true);
|
|
}
|
|
|
|
int scheme_check_context(Scheme_Env *env, Scheme_Object *name, Scheme_Object *ok_modidx)
|
|
{
|
|
Scheme_Object *mod, *id = name;
|
|
|
|
mod = scheme_stx_source_module(id, 0);
|
|
|
|
if (mod && SCHEME_TRUEP(mod) && NOT_SAME_OBJ(ok_modidx, mod)) {
|
|
return 1;
|
|
} else {
|
|
mod = scheme_stx_module_name(NULL, &id, scheme_make_integer(env->phase), NULL, NULL, NULL,
|
|
NULL, NULL, NULL, NULL);
|
|
if (SAME_OBJ(mod, scheme_undefined))
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*========================================================================*/
|
|
/* compile-time env for optimization */
|
|
/*========================================================================*/
|
|
|
|
Optimize_Info *scheme_optimize_info_create()
|
|
{
|
|
Optimize_Info *info;
|
|
|
|
info = MALLOC_ONE_RT(Optimize_Info);
|
|
#ifdef MZTAG_REQUIRED
|
|
info->type = scheme_rt_optimize_info;
|
|
#endif
|
|
info->inline_fuel = 16;
|
|
|
|
return info;
|
|
}
|
|
|
|
static void register_transitive_use(Optimize_Info *info, int pos, int j);
|
|
|
|
static void register_stat_dist(Optimize_Info *info, int i, int j)
|
|
{
|
|
if (!info->stat_dists) {
|
|
int k, *ia;
|
|
char **ca;
|
|
ca = MALLOC_N(char*, info->new_frame);
|
|
info->stat_dists = ca;
|
|
ia = MALLOC_N_ATOMIC(int, info->new_frame);
|
|
info->sd_depths = ia;
|
|
for (k = info->new_frame; k--; ) {
|
|
info->sd_depths[k] = 0;
|
|
}
|
|
}
|
|
|
|
if (info->sd_depths[i] <= j) {
|
|
char *naya, *a;
|
|
int k;
|
|
|
|
naya = MALLOC_N_ATOMIC(char, (j + 1));
|
|
for (k = j + 1; k--; ) {
|
|
naya[k] = 0;
|
|
}
|
|
a = info->stat_dists[i];
|
|
for (k = info->sd_depths[i]; k--; ) {
|
|
naya[k] = a[k];
|
|
}
|
|
|
|
info->stat_dists[i] = naya;
|
|
info->sd_depths[i] = j + 1;
|
|
}
|
|
|
|
if (info->transitive_use && info->transitive_use[i]) {
|
|
/* We're using a procedure that we weren't sure would be used.
|
|
Transitively mark everything that the procedure uses --- unless
|
|
a transitive accumulation is in effect, in which case we
|
|
don't for this one now, leaving it to be triggered when
|
|
the one we're accumulating is triggered. */
|
|
if (!info->transitive_use_pos) {
|
|
mzshort *map = info->transitive_use[i];
|
|
int len = info->transitive_use_len[i];
|
|
int k;
|
|
|
|
info->transitive_use[i] = NULL;
|
|
|
|
for (k = 0; k < len; k++) {
|
|
register_transitive_use(info, map[k], 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
info->stat_dists[i][j] = 1;
|
|
}
|
|
|
|
static Scheme_Object *transitive_k(void)
|
|
{
|
|
Scheme_Thread *p = scheme_current_thread;
|
|
Optimize_Info *info = (Optimize_Info *)p->ku.k.p1;
|
|
|
|
p->ku.k.p1 = NULL;
|
|
|
|
register_transitive_use(info, p->ku.k.i1, p->ku.k.i2);
|
|
|
|
return scheme_false;
|
|
}
|
|
|
|
static void register_transitive_use(Optimize_Info *info, int pos, int j)
|
|
{
|
|
#ifdef DO_STACK_CHECK
|
|
# include "mzstkchk.h"
|
|
{
|
|
Scheme_Thread *p = scheme_current_thread;
|
|
|
|
p->ku.k.p1 = (void *)info;
|
|
p->ku.k.i1 = pos;
|
|
p->ku.k.i2 = j;
|
|
|
|
scheme_handle_stack_overflow(transitive_k);
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
while (info) {
|
|
if (info->flags & SCHEME_LAMBDA_FRAME)
|
|
j++;
|
|
if (pos < info->new_frame)
|
|
break;
|
|
pos -= info->new_frame;
|
|
info = info->next;
|
|
}
|
|
|
|
if (info->sd_depths[pos] <= j) {
|
|
scheme_signal_error("bad transitive position depth: %d vs. %d",
|
|
info->sd_depths[pos], j);
|
|
}
|
|
|
|
register_stat_dist(info, pos, j);
|
|
}
|
|
|
|
void scheme_env_make_closure_map(Optimize_Info *info, mzshort *_size, mzshort **_map)
|
|
{
|
|
/* A closure map lists the captured variables for a closure; the
|
|
indices are resolved two new indicies in the second phase of
|
|
compilation. */
|
|
Optimize_Info *frame;
|
|
int i, j, pos = 0, lpos = 0, tu;
|
|
mzshort *map, size;
|
|
|
|
/* Count vars used by this closure (skip args): */
|
|
j = 1;
|
|
for (frame = info->next; frame; frame = frame->next) {
|
|
if (frame->flags & SCHEME_LAMBDA_FRAME)
|
|
j++;
|
|
|
|
if (frame->stat_dists) {
|
|
for (i = 0; i < frame->new_frame; i++) {
|
|
if (frame->sd_depths[i] > j) {
|
|
if (frame->stat_dists[i][j]) {
|
|
pos++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
size = pos;
|
|
*_size = size;
|
|
map = MALLOC_N_ATOMIC(mzshort, size);
|
|
*_map = map;
|
|
|
|
if (info->next && info->next->transitive_use_pos) {
|
|
info->next->transitive_use[info->next->transitive_use_pos - 1] = map;
|
|
info->next->transitive_use_len[info->next->transitive_use_pos - 1] = size;
|
|
tu = 1;
|
|
} else
|
|
tu = 0;
|
|
|
|
/* Build map, unmarking locals and marking deeper in parent frame */
|
|
j = 1; pos = 0;
|
|
for (frame = info->next; frame; frame = frame->next) {
|
|
if (frame->flags & SCHEME_LAMBDA_FRAME)
|
|
j++;
|
|
|
|
if (frame->stat_dists) {
|
|
for (i = 0; i < frame->new_frame; i++) {
|
|
if (frame->sd_depths[i] > j) {
|
|
if (frame->stat_dists[i][j]) {
|
|
map[pos++] = lpos;
|
|
frame->stat_dists[i][j] = 0; /* This closure's done with these vars... */
|
|
if (!tu)
|
|
frame->stat_dists[i][j - 1] = 1; /* ... but ensure previous keeps */
|
|
}
|
|
}
|
|
lpos++;
|
|
}
|
|
} else
|
|
lpos += frame->new_frame;
|
|
}
|
|
}
|
|
|
|
int scheme_env_uses_toplevel(Optimize_Info *frame)
|
|
{
|
|
int used;
|
|
|
|
used = frame->used_toplevel;
|
|
|
|
if (used) {
|
|
/* Propagate use to an enclosing lambda, if any: */
|
|
frame = frame->next;
|
|
while (frame) {
|
|
if (frame->flags & SCHEME_LAMBDA_FRAME) {
|
|
frame->used_toplevel = 1;
|
|
break;
|
|
}
|
|
frame = frame->next;
|
|
}
|
|
}
|
|
|
|
return used;
|
|
}
|
|
|
|
void scheme_optimize_info_used_top(Optimize_Info *info)
|
|
{
|
|
while (info) {
|
|
if (info->flags & SCHEME_LAMBDA_FRAME) {
|
|
info->used_toplevel = 1;
|
|
break;
|
|
}
|
|
info = info->next;
|
|
}
|
|
}
|
|
|
|
void scheme_optimize_propagate(Optimize_Info *info, int pos, Scheme_Object *value, int single_use)
|
|
{
|
|
/* A raw-pair `value' is an indicator for whether a letrec-bound
|
|
variable is ready. */
|
|
Scheme_Object *p;
|
|
|
|
p = scheme_make_vector(4, NULL);
|
|
SCHEME_VEC_ELS(p)[0] = info->consts;
|
|
SCHEME_VEC_ELS(p)[1] = scheme_make_integer(pos);
|
|
SCHEME_VEC_ELS(p)[2] = value;
|
|
SCHEME_VEC_ELS(p)[3] = (single_use ? scheme_true : scheme_false);
|
|
|
|
info->consts = p;
|
|
}
|
|
|
|
void scheme_optimize_mutated(Optimize_Info *info, int pos)
|
|
/* pos must be in immediate frame */
|
|
{
|
|
if (!info->use) {
|
|
char *use;
|
|
use = (char *)scheme_malloc_atomic(info->new_frame);
|
|
memset(use, 0, info->new_frame);
|
|
info->use = use;
|
|
}
|
|
info->use[pos] = 1;
|
|
}
|
|
|
|
Scheme_Object *scheme_optimize_reverse(Optimize_Info *info, int pos, int unless_mutated)
|
|
/* pos is in new-frame counts, and we want to produce an old-frame reference if
|
|
it's not mutated */
|
|
{
|
|
int delta = 0;
|
|
|
|
while (1) {
|
|
if (pos < info->new_frame)
|
|
break;
|
|
pos -= info->new_frame;
|
|
delta += info->original_frame;
|
|
info = info->next;
|
|
}
|
|
|
|
if (unless_mutated)
|
|
if (info->use && info->use[pos])
|
|
return NULL;
|
|
|
|
return scheme_make_local(scheme_local_type, pos + delta, 0);
|
|
}
|
|
|
|
int scheme_optimize_is_used(Optimize_Info *info, int pos)
|
|
/* pos must be in immediate frame */
|
|
{
|
|
int i;
|
|
|
|
if (info->stat_dists) {
|
|
for (i = info->sd_depths[pos]; i--; ) {
|
|
if (info->stat_dists[pos][i])
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int scheme_optimize_any_uses(Optimize_Info *info, int start_pos, int end_pos)
|
|
{
|
|
int j, i;
|
|
|
|
if (info->stat_dists) {
|
|
for (i = start_pos; i < end_pos; i++) {
|
|
for (j = info->sd_depths[i]; j--; ) {
|
|
if (info->stat_dists[i][j])
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (info->transitive_use) {
|
|
for (i = info->new_frame; i--; ) {
|
|
if (info->transitive_use[i]) {
|
|
for (j = info->transitive_use_len[i]; j--; ) {
|
|
if ((info->transitive_use[i][j] >= start_pos)
|
|
&& (info->transitive_use[i][j] < end_pos))
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static Scheme_Object *do_optimize_info_lookup(Optimize_Info *info, int pos, int j, int *closure_offset, int *single_use, int *not_ready)
|
|
{
|
|
Scheme_Object *p, *n;
|
|
int delta = 0;
|
|
|
|
while (info) {
|
|
if (info->flags & SCHEME_LAMBDA_FRAME)
|
|
j++;
|
|
if (pos < info->original_frame)
|
|
break;
|
|
pos -= info->original_frame;
|
|
delta += info->new_frame;
|
|
info = info->next;
|
|
}
|
|
|
|
p = info->consts;
|
|
while (p) {
|
|
n = SCHEME_VEC_ELS(p)[1];
|
|
if (SCHEME_INT_VAL(n) == pos) {
|
|
n = SCHEME_VEC_ELS(p)[2];
|
|
if (SCHEME_RPAIRP(n)) {
|
|
/* This was a letrec-bound identifier that may or may not be ready,
|
|
but which wasn't replaced with more information. */
|
|
if (not_ready)
|
|
*not_ready = SCHEME_TRUEP(SCHEME_CAR(n));
|
|
break;
|
|
}
|
|
if (single_use)
|
|
*single_use = SCHEME_TRUEP(SCHEME_VEC_ELS(p)[3]);
|
|
if (SAME_TYPE(SCHEME_TYPE(n), scheme_compiled_unclosed_procedure_type)) {
|
|
if (!closure_offset)
|
|
break;
|
|
else {
|
|
*closure_offset = delta;
|
|
}
|
|
} else if (SAME_TYPE(SCHEME_TYPE(n), scheme_compiled_toplevel_type)) {
|
|
/* Ok */
|
|
} else if (closure_offset) {
|
|
/* Inlining can deal procdures and top-levels, but not other things. */
|
|
return NULL;
|
|
} else if (SAME_TYPE(SCHEME_TYPE(n), scheme_local_type)) {
|
|
int pos;
|
|
|
|
pos = SCHEME_LOCAL_POS(n);
|
|
if (info->flags & SCHEME_LAMBDA_FRAME)
|
|
j--; /* because it will get re-added on recur */
|
|
|
|
/* Marks local as used; we don't expect to get back
|
|
a value, because chaining would normally happen on the
|
|
propagate-call side. Chaining there also means that we
|
|
avoid stack overflow here. */
|
|
if (single_use) {
|
|
if (!*single_use)
|
|
single_use = NULL;
|
|
}
|
|
n = do_optimize_info_lookup(info, pos, j, NULL, single_use, NULL);
|
|
|
|
if (!n) {
|
|
/* Return shifted reference to other local: */
|
|
delta += scheme_optimize_info_get_shift(info, pos);
|
|
n = scheme_make_local(scheme_local_type, pos + delta, 0);
|
|
}
|
|
}
|
|
return n;
|
|
}
|
|
p = SCHEME_VEC_ELS(p)[0];
|
|
}
|
|
|
|
if (!closure_offset)
|
|
register_stat_dist(info, pos, j);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
Scheme_Object *scheme_optimize_info_lookup(Optimize_Info *info, int pos, int *closure_offset, int *single_use)
|
|
{
|
|
return do_optimize_info_lookup(info, pos, 0, closure_offset, single_use, NULL);
|
|
}
|
|
|
|
int scheme_optimize_info_is_ready(Optimize_Info *info, int pos)
|
|
{
|
|
int closure_offset, single_use, ready = 1;
|
|
|
|
do_optimize_info_lookup(info, pos, 0, &closure_offset, &single_use, &ready);
|
|
|
|
return ready;
|
|
}
|
|
|
|
Optimize_Info *scheme_optimize_info_add_frame(Optimize_Info *info, int orig, int current, int flags)
|
|
{
|
|
Optimize_Info *naya;
|
|
|
|
naya = scheme_optimize_info_create();
|
|
naya->flags = (short)flags;
|
|
naya->next = info;
|
|
naya->original_frame = orig;
|
|
naya->new_frame = current;
|
|
naya->inline_fuel = info->inline_fuel;
|
|
naya->letrec_not_twice = info->letrec_not_twice;
|
|
naya->enforce_const = info->enforce_const;
|
|
naya->top_level_consts = info->top_level_consts;
|
|
naya->context = info->context;
|
|
|
|
return naya;
|
|
}
|
|
|
|
int scheme_optimize_info_get_shift(Optimize_Info *info, int pos)
|
|
{
|
|
int delta = 0;
|
|
|
|
while (info) {
|
|
if (pos < info->original_frame)
|
|
break;
|
|
pos -= info->original_frame;
|
|
delta += (info->new_frame - info->original_frame);
|
|
info = info->next;
|
|
}
|
|
|
|
if (!info)
|
|
*(long *)0x0 = 1;
|
|
|
|
return delta;
|
|
}
|
|
|
|
void scheme_optimize_info_done(Optimize_Info *info)
|
|
{
|
|
info->next->size += info->size;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*========================================================================*/
|
|
/* compile-time env for resolve */
|
|
/*========================================================================*/
|
|
|
|
/* See eval.c for information about the compilation phases. */
|
|
|
|
Resolve_Prefix *scheme_resolve_prefix(int phase, Comp_Prefix *cp, int simplify)
|
|
{
|
|
Resolve_Prefix *rp;
|
|
Scheme_Object **tls, **stxes, *simplify_cache, *m;
|
|
Scheme_Hash_Table *ht;
|
|
int i;
|
|
|
|
rp = MALLOC_ONE_TAGGED(Resolve_Prefix);
|
|
rp->so.type = scheme_resolve_prefix_type;
|
|
rp->num_toplevels = cp->num_toplevels;
|
|
rp->num_stxes = cp->num_stxes;
|
|
|
|
if (rp->num_toplevels)
|
|
tls = MALLOC_N(Scheme_Object*, rp->num_toplevels);
|
|
else
|
|
tls = NULL;
|
|
if (rp->num_stxes)
|
|
stxes = MALLOC_N(Scheme_Object*, rp->num_stxes);
|
|
else
|
|
stxes = NULL;
|
|
|
|
rp->toplevels = tls;
|
|
rp->stxes = stxes;
|
|
|
|
ht = cp->toplevels;
|
|
if (ht) {
|
|
for (i = 0; i < ht->size; i++) {
|
|
if (ht->vals[i]) {
|
|
m = ht->keys[i];
|
|
if (SAME_TYPE(SCHEME_TYPE(m), scheme_module_variable_type)) {
|
|
if (SCHEME_FALSEP(((Scheme_Modidx *)((Module_Variable *)m)->modidx)->base)
|
|
&& SCHEME_FALSEP(((Scheme_Modidx *)((Module_Variable *)m)->modidx)->path)) {
|
|
/* Reduce self-referece to just a symbol: */
|
|
m = ((Module_Variable *)m)->sym;
|
|
}
|
|
}
|
|
tls[SCHEME_TOPLEVEL_POS(ht->vals[i])] = m;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (simplify)
|
|
simplify_cache = scheme_new_stx_simplify_cache();
|
|
else
|
|
simplify_cache = NULL;
|
|
|
|
ht = cp->stxes;
|
|
if (ht) {
|
|
for (i = 0; i < ht->size; i++) {
|
|
if (ht->vals[i]) {
|
|
scheme_simplify_stx(ht->keys[i], simplify_cache);
|
|
stxes[SCHEME_LOCAL_POS(ht->vals[i])] = ht->keys[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
return rp;
|
|
}
|
|
|
|
Resolve_Prefix *scheme_remap_prefix(Resolve_Prefix *rp, Resolve_Info *ri)
|
|
{
|
|
/* Rewrite stxes list based on actual uses at resolve pass.
|
|
If we have no lifts, we can just srop unused stxes.
|
|
Otherwise, if any stxes go unused, we just have to replace them
|
|
with NULL. */
|
|
int i, cnt;
|
|
Scheme_Object **new_stxes, *v;
|
|
|
|
if (!rp->num_stxes)
|
|
return rp;
|
|
|
|
if (rp->num_lifts)
|
|
cnt = rp->num_stxes;
|
|
else
|
|
cnt = ri->stx_map->count;
|
|
|
|
new_stxes = MALLOC_N(Scheme_Object *, cnt);
|
|
|
|
for (i = 0; i < rp->num_stxes; i++) {
|
|
if (ri->stx_map)
|
|
v = scheme_hash_get(ri->stx_map, scheme_make_integer(i));
|
|
else
|
|
v = NULL;
|
|
if (v) {
|
|
new_stxes[SCHEME_INT_VAL(v)] = rp->stxes[i];
|
|
}
|
|
}
|
|
|
|
rp->stxes = new_stxes;
|
|
rp->num_stxes = cnt;
|
|
|
|
return rp;
|
|
}
|
|
|
|
Resolve_Info *scheme_resolve_info_create(Resolve_Prefix *rp)
|
|
{
|
|
Resolve_Info *naya;
|
|
Scheme_Object *b;
|
|
Scheme_Hash_Table *ht;
|
|
|
|
naya = MALLOC_ONE_RT(Resolve_Info);
|
|
#ifdef MZTAG_REQUIRED
|
|
naya->type = scheme_rt_resolve_info;
|
|
#endif
|
|
naya->prefix = rp;
|
|
naya->count = 0;
|
|
naya->next = NULL;
|
|
naya->toplevel_pos = -1;
|
|
|
|
ht = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
naya->stx_map = ht;
|
|
|
|
b = scheme_get_param(scheme_current_config(), MZCONFIG_USE_JIT);
|
|
naya->use_jit = SCHEME_TRUEP(b);
|
|
|
|
return naya;
|
|
}
|
|
|
|
Resolve_Info *scheme_resolve_info_extend(Resolve_Info *info, int size, int oldsize, int mapc)
|
|
/* size = number of appended items in run-time frame */
|
|
/* oldisze = number of appended items in original compile-time frame */
|
|
/* mapc = mappings that will be installed */
|
|
{
|
|
Resolve_Info *naya;
|
|
|
|
naya = MALLOC_ONE_RT(Resolve_Info);
|
|
#ifdef MZTAG_REQUIRED
|
|
naya->type = scheme_rt_resolve_info;
|
|
#endif
|
|
naya->prefix = info->prefix;
|
|
naya->stx_map = info->stx_map;
|
|
naya->next = info;
|
|
naya->use_jit = info->use_jit;
|
|
naya->enforce_const = info->enforce_const;
|
|
naya->size = size;
|
|
naya->oldsize = oldsize;
|
|
naya->count = mapc;
|
|
naya->pos = 0;
|
|
naya->toplevel_pos = -1;
|
|
naya->lifts = info->lifts;
|
|
|
|
if (mapc) {
|
|
int i, *ia;
|
|
mzshort *sa;
|
|
|
|
sa = MALLOC_N_ATOMIC(mzshort, mapc);
|
|
naya->old_pos = sa;
|
|
sa = MALLOC_N_ATOMIC(mzshort, mapc);
|
|
naya->new_pos = sa;
|
|
ia = MALLOC_N_ATOMIC(int, mapc);
|
|
naya->flags = ia;
|
|
|
|
/* necessary? added when changed allocation to atomic */
|
|
for (i = mapc; i--; ) {
|
|
naya->old_pos[i] = 0;
|
|
naya->new_pos[i] = 0;
|
|
naya->flags[i] = 0;
|
|
}
|
|
}
|
|
|
|
return naya;
|
|
}
|
|
|
|
void scheme_resolve_info_add_mapping(Resolve_Info *info, int oldp, int newp, int flags, Scheme_Object *lifted)
|
|
{
|
|
if (info->pos == info->count) {
|
|
scheme_signal_error("internal error: add_mapping: "
|
|
"too many: %d", info->pos);
|
|
}
|
|
|
|
info->old_pos[info->pos] = oldp;
|
|
info->new_pos[info->pos] = newp;
|
|
info->flags[info->pos] = flags;
|
|
if (lifted) {
|
|
if (!info->lifted) {
|
|
Scheme_Object **lifteds;
|
|
lifteds = MALLOC_N(Scheme_Object*, info->count);
|
|
info->lifted = lifteds;
|
|
}
|
|
info->lifted[info->pos] = lifted;
|
|
}
|
|
|
|
info->pos++;
|
|
}
|
|
|
|
void scheme_resolve_info_adjust_mapping(Resolve_Info *info, int oldp, int newp, int flags, Scheme_Object *lifted)
|
|
{
|
|
int i;
|
|
|
|
for (i = info->pos; i--; ) {
|
|
if (info->old_pos[i] == oldp) {
|
|
info->new_pos[i] = newp;
|
|
info->flags[i] = flags;
|
|
if (lifted) {
|
|
info->lifted[i] = lifted;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
scheme_signal_error("internal error: adjust_mapping: "
|
|
"couldn't find: %d", oldp);
|
|
}
|
|
|
|
void scheme_resolve_info_set_toplevel_pos(Resolve_Info *info, int pos)
|
|
{
|
|
info->toplevel_pos = pos;
|
|
}
|
|
|
|
static int resolve_info_lookup(Resolve_Info *info, int pos, int *flags, Scheme_Object **_lifted, int convert_shift)
|
|
{
|
|
Resolve_Info *orig_info = info;
|
|
int i, offset = 0, orig = pos;
|
|
|
|
if (_lifted)
|
|
*_lifted = NULL;
|
|
|
|
while (info) {
|
|
for (i = info->pos; i--; ) {
|
|
int oldp = info->old_pos[i];
|
|
if (pos == oldp) {
|
|
if (flags)
|
|
*flags = info->flags[i];
|
|
if (info->lifted && (info->lifted[i])) {
|
|
int skip, shifted;
|
|
Scheme_Object *lifted, *tl, **ca;
|
|
|
|
if (!_lifted)
|
|
scheme_signal_error("unexpected lifted binding");
|
|
|
|
lifted = info->lifted[i];
|
|
|
|
if (SCHEME_RPAIRP(lifted)) {
|
|
tl = SCHEME_CAR(lifted);
|
|
ca = (Scheme_Object **)SCHEME_CDR(lifted);
|
|
if (convert_shift)
|
|
shifted = SCHEME_INT_VAL(ca[0]) + convert_shift - 1;
|
|
else
|
|
shifted = 0;
|
|
} else {
|
|
tl = lifted;
|
|
shifted = 0;
|
|
ca = NULL;
|
|
}
|
|
|
|
if (SAME_TYPE(SCHEME_TYPE(tl), scheme_toplevel_type)) {
|
|
skip = scheme_resolve_toplevel_pos(orig_info);
|
|
tl = make_toplevel(skip + shifted,
|
|
SCHEME_TOPLEVEL_POS(tl),
|
|
1,
|
|
SCHEME_TOPLEVEL_CONST);
|
|
}
|
|
|
|
if (SCHEME_RPAIRP(lifted)) {
|
|
int sz, i;
|
|
mzshort *posmap, *boxmap;
|
|
Scheme_Object *vec, *loc;
|
|
sz = SCHEME_INT_VAL(ca[0]);
|
|
posmap = (mzshort *)ca[1];
|
|
boxmap = (mzshort *)ca[3];
|
|
vec = scheme_make_vector(sz + 1, NULL);
|
|
for (i = 0; i < sz; i++) {
|
|
loc = scheme_make_local(scheme_local_type,
|
|
posmap[i] + offset + shifted,
|
|
0);
|
|
if (boxmap) {
|
|
if (boxmap[i / BITS_PER_MZSHORT] & ((mzshort)1 << (i & (BITS_PER_MZSHORT - 1))))
|
|
loc = scheme_box(loc);
|
|
}
|
|
SCHEME_VEC_ELS(vec)[i+1] = loc;
|
|
}
|
|
SCHEME_VEC_ELS(vec)[0] = ca[2];
|
|
lifted = scheme_make_raw_pair(tl, vec);
|
|
} else
|
|
lifted = tl;
|
|
|
|
*_lifted = lifted;
|
|
|
|
return 0;
|
|
} else
|
|
return info->new_pos[i] + offset;
|
|
}
|
|
}
|
|
|
|
if (info->in_proc) {
|
|
scheme_signal_error("internal error: scheme_resolve_info_lookup: "
|
|
"searching past procedure");
|
|
}
|
|
|
|
pos -= info->oldsize;
|
|
offset += info->size;
|
|
info = info->next;
|
|
}
|
|
|
|
scheme_signal_error("internal error: scheme_resolve_info_lookup: "
|
|
"variable %d not found", orig);
|
|
|
|
return 0;
|
|
}
|
|
|
|
Scheme_Object *scheme_resolve_generate_stub_lift()
|
|
{
|
|
return make_toplevel(0, 0, 1, SCHEME_TOPLEVEL_CONST);
|
|
}
|
|
|
|
int scheme_resolve_info_flags(Resolve_Info *info, int pos, Scheme_Object **lifted)
|
|
{
|
|
int flags;
|
|
|
|
resolve_info_lookup(info, pos, &flags, lifted, 0);
|
|
|
|
return flags;
|
|
}
|
|
|
|
int scheme_resolve_info_lookup(Resolve_Info *info, int pos, int *flags, Scheme_Object **lifted, int convert_shift)
|
|
{
|
|
return resolve_info_lookup(info, pos, flags, lifted, convert_shift);
|
|
}
|
|
|
|
int scheme_resolve_toplevel_pos(Resolve_Info *info)
|
|
{
|
|
int pos = 0;
|
|
|
|
while (info && (info->toplevel_pos < 0)) {
|
|
if (info->in_proc) {
|
|
scheme_signal_error("internal error: scheme_resolve_toplevel_pos: "
|
|
"searching past procedure");
|
|
}
|
|
pos += info->size;
|
|
info = info->next;
|
|
}
|
|
|
|
if (!info)
|
|
return pos;
|
|
else
|
|
return info->toplevel_pos + pos;
|
|
}
|
|
|
|
int scheme_resolve_is_toplevel_available(Resolve_Info *info)
|
|
{
|
|
while (info) {
|
|
if (info->toplevel_pos >= 0)
|
|
return 1;
|
|
if (info->in_proc)
|
|
return 0;
|
|
info = info->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int scheme_resolve_quote_syntax_offset(int i, Resolve_Info *info)
|
|
{
|
|
Scheme_Hash_Table *ht;
|
|
Scheme_Object *v;
|
|
|
|
ht = info->stx_map;
|
|
|
|
v = scheme_hash_get(ht, scheme_make_integer(i));
|
|
if (!v) {
|
|
v = scheme_make_integer(ht->count);
|
|
scheme_hash_set(ht, scheme_make_integer(i), v);
|
|
}
|
|
|
|
return SCHEME_INT_VAL(v);
|
|
}
|
|
|
|
int scheme_resolve_quote_syntax_pos(Resolve_Info *info)
|
|
{
|
|
return info->prefix->num_toplevels;
|
|
}
|
|
|
|
Scheme_Object *scheme_resolve_toplevel(Resolve_Info *info, Scheme_Object *expr, int keep_ready)
|
|
{
|
|
int skip;
|
|
|
|
skip = scheme_resolve_toplevel_pos(info);
|
|
|
|
return make_toplevel(skip + SCHEME_TOPLEVEL_DEPTH(expr), /* depth is 0 (normal) or 1 (exp-time) */
|
|
SCHEME_TOPLEVEL_POS(expr),
|
|
1,
|
|
SCHEME_TOPLEVEL_FLAGS(expr) & (SCHEME_TOPLEVEL_CONST
|
|
| (keep_ready
|
|
? SCHEME_TOPLEVEL_READY
|
|
: 0)));
|
|
}
|
|
|
|
Scheme_Object *scheme_shift_toplevel(Scheme_Object *expr, int delta)
|
|
{
|
|
return make_toplevel(SCHEME_TOPLEVEL_DEPTH(expr) + delta,
|
|
SCHEME_TOPLEVEL_POS(expr),
|
|
1,
|
|
SCHEME_TOPLEVEL_FLAGS(expr) & SCHEME_TOPLEVEL_FLAGS_MASK);
|
|
}
|
|
|
|
Scheme_Object *scheme_resolve_invent_toplevel(Resolve_Info *info)
|
|
{
|
|
int skip, pos;
|
|
Scheme_Object *count;
|
|
|
|
skip = scheme_resolve_toplevel_pos(info);
|
|
|
|
count = SCHEME_VEC_ELS(info->lifts)[1];
|
|
pos = (SCHEME_INT_VAL(count)
|
|
+ info->prefix->num_toplevels
|
|
+ info->prefix->num_stxes
|
|
+ (info->prefix->num_stxes ? 1 : 0));
|
|
count = scheme_make_integer(SCHEME_INT_VAL(count) + 1);
|
|
SCHEME_VEC_ELS(info->lifts)[1] = count;
|
|
|
|
return make_toplevel(skip,
|
|
pos,
|
|
1,
|
|
SCHEME_TOPLEVEL_CONST);
|
|
}
|
|
|
|
Scheme_Object *scheme_resolve_invented_toplevel_to_defn(Resolve_Info *info, Scheme_Object *tl)
|
|
{
|
|
return make_toplevel(0,
|
|
SCHEME_TOPLEVEL_POS(tl),
|
|
1,
|
|
SCHEME_TOPLEVEL_CONST);
|
|
}
|
|
|
|
int scheme_resolving_in_procedure(Resolve_Info *info)
|
|
{
|
|
while (info) {
|
|
if (info->in_proc)
|
|
return 1;
|
|
info = info->next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*========================================================================*/
|
|
/* run-time "stack" */
|
|
/*========================================================================*/
|
|
|
|
Scheme_Object *scheme_make_envunbox(Scheme_Object *value)
|
|
{
|
|
Scheme_Object *obj;
|
|
|
|
obj = (Scheme_Object *)scheme_malloc_envunbox(sizeof(Scheme_Object*));
|
|
SCHEME_ENVBOX_VAL(obj) = value;
|
|
|
|
return obj;
|
|
}
|
|
|
|
/*========================================================================*/
|
|
/* run-time and expansion-time Scheme interface */
|
|
/*========================================================================*/
|
|
|
|
static Scheme_Object *
|
|
namespace_identifier(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Object *obj;
|
|
Scheme_Env *genv;
|
|
|
|
if (!SCHEME_SYMBOLP(argv[0]))
|
|
scheme_wrong_type("namespace-symbol->identifier", "symbol", 0, argc, argv);
|
|
if ((argc > 1) && !SCHEME_NAMESPACEP(argv[1]))
|
|
scheme_wrong_type("namespace-symbol->identifier", "namespace", 1, argc, argv);
|
|
|
|
if (argc > 1)
|
|
genv = (Scheme_Env *)argv[1];
|
|
else
|
|
genv = scheme_get_env(NULL);
|
|
|
|
obj = argv[0];
|
|
obj = scheme_datum_to_syntax(obj, scheme_false, scheme_false, 1, 0);
|
|
|
|
/* Renamings: */
|
|
if (genv->rename_set)
|
|
obj = scheme_add_rename(obj, genv->rename_set);
|
|
|
|
return obj;
|
|
}
|
|
|
|
static Scheme_Object *
|
|
namespace_module_identifier(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Env *genv;
|
|
Scheme_Object *phase;
|
|
|
|
if (argc > 0) {
|
|
if (SCHEME_NAMESPACEP(argv[0])) {
|
|
genv = (Scheme_Env *)argv[0];
|
|
phase = scheme_make_integer(genv->phase);
|
|
} else if (SCHEME_FALSEP(argv[0])) {
|
|
phase = scheme_false;
|
|
} else if (SCHEME_INTP(argv[0]) || SCHEME_BIGNUMP(argv[0])) {
|
|
phase = argv[0];
|
|
} else {
|
|
scheme_wrong_type("namespace-module-identifier", "namespace, #f, or exact integer", 0, argc, argv);
|
|
return NULL;
|
|
}
|
|
} else {
|
|
genv = scheme_get_env(NULL);
|
|
phase = scheme_make_integer(genv->phase);
|
|
}
|
|
|
|
return scheme_datum_to_syntax(scheme_intern_symbol("module"), scheme_false,
|
|
scheme_sys_wraps_phase(phase), 0, 0);
|
|
}
|
|
|
|
static Scheme_Object *
|
|
namespace_base_phase(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Env *genv;
|
|
|
|
if ((argc > 0) && !SCHEME_NAMESPACEP(argv[0]))
|
|
scheme_wrong_type("namespace-base-phase", "namespace", 0, argc, argv);
|
|
|
|
if (argc)
|
|
genv = (Scheme_Env *)argv[0];
|
|
else
|
|
genv = scheme_get_env(NULL);
|
|
|
|
return scheme_make_integer(genv->phase);
|
|
}
|
|
|
|
static Scheme_Object *
|
|
namespace_variable_value(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Object *v, *id = NULL;
|
|
Scheme_Env *genv;
|
|
int use_map;
|
|
|
|
if (!SCHEME_SYMBOLP(argv[0]))
|
|
scheme_wrong_type("namespace-variable-value", "symbol", 0, argc, argv);
|
|
use_map = ((argc > 1) ? SCHEME_TRUEP(argv[1]) : 1);
|
|
if ((argc > 2) && SCHEME_TRUEP(argv[2])
|
|
&& !scheme_check_proc_arity(NULL, 0, 2, argc, argv))
|
|
scheme_wrong_type("namespace-variable-value", "procedure (arity 0) or #f", 1, argc, argv);
|
|
if ((argc > 3) && !SCHEME_NAMESPACEP(argv[3]))
|
|
scheme_wrong_type("namespace-variable-value", "namespace", 3, argc, argv);
|
|
|
|
if (argc > 3)
|
|
genv = (Scheme_Env *)argv[3];
|
|
else
|
|
genv = scheme_get_env(NULL);
|
|
|
|
if (!use_map)
|
|
v = scheme_lookup_global(argv[0], genv);
|
|
else {
|
|
Scheme_Full_Comp_Env inlined_e;
|
|
|
|
scheme_prepare_env_renames(genv, mzMOD_RENAME_TOPLEVEL);
|
|
scheme_prepare_compile_env(genv);
|
|
|
|
id = scheme_make_renamed_stx(argv[0], genv->rename_set);
|
|
|
|
inlined_e.base.num_bindings = 0;
|
|
inlined_e.base.next = NULL;
|
|
inlined_e.base.genv = genv;
|
|
inlined_e.base.flags = SCHEME_TOPLEVEL_FRAME;
|
|
init_compile_data((Scheme_Comp_Env *)&inlined_e);
|
|
inlined_e.base.prefix = NULL;
|
|
|
|
v = scheme_lookup_binding(id, (Scheme_Comp_Env *)&inlined_e, SCHEME_RESOLVE_MODIDS, NULL, NULL, NULL, NULL, NULL);
|
|
if (v) {
|
|
if (!SAME_TYPE(SCHEME_TYPE(v), scheme_variable_type)) {
|
|
use_map = -1;
|
|
v = NULL;
|
|
} else
|
|
v = (Scheme_Object *)(SCHEME_VAR_BUCKET(v))->val;
|
|
}
|
|
}
|
|
|
|
if (!v) {
|
|
if ((argc > 2) && SCHEME_TRUEP(argv[2]))
|
|
return _scheme_tail_apply(argv[2], 0, NULL);
|
|
else if (use_map == -1) {
|
|
scheme_wrong_syntax("namespace-variable-value", NULL, id, "bound to syntax");
|
|
return NULL;
|
|
} else {
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT_VARIABLE, argv[0],
|
|
"namespace-variable-value: %S is not defined",
|
|
argv[0]);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
static Scheme_Object *
|
|
namespace_set_variable_value(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Env *env;
|
|
Scheme_Bucket *bucket;
|
|
|
|
if (!SCHEME_SYMBOLP(argv[0]))
|
|
scheme_wrong_type("namespace-set-variable-value!", "symbol", 0, argc, argv);
|
|
if ((argc > 3) && !SCHEME_NAMESPACEP(argv[3]))
|
|
scheme_wrong_type("namespace-set-variable-value!", "namespace", 3, argc, argv);
|
|
|
|
if (argc > 3)
|
|
env = (Scheme_Env *)argv[3];
|
|
else
|
|
env = scheme_get_env(NULL);
|
|
|
|
bucket = scheme_global_bucket(argv[0], env);
|
|
|
|
scheme_set_global_bucket("namespace-set-variable-value!", bucket, argv[1], 1);
|
|
|
|
if ((argc > 2) && SCHEME_TRUEP(argv[2])) {
|
|
scheme_shadow(env, argv[0], 1);
|
|
}
|
|
|
|
return scheme_void;
|
|
}
|
|
|
|
static Scheme_Object *
|
|
namespace_undefine_variable(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Env *env;
|
|
Scheme_Bucket *bucket;
|
|
|
|
if (!SCHEME_SYMBOLP(argv[0]))
|
|
scheme_wrong_type("namespace-undefine-variable!", "symbol", 0, argc, argv);
|
|
if ((argc > 1) && !SCHEME_NAMESPACEP(argv[1]))
|
|
scheme_wrong_type("namespace-undefine-variable!", "namespace", 1, argc, argv);
|
|
|
|
if (argc > 1)
|
|
env = (Scheme_Env *)argv[1];
|
|
else
|
|
env = scheme_get_env(NULL);
|
|
|
|
if (scheme_lookup_global(argv[0], env)) {
|
|
bucket = scheme_global_bucket(argv[0], env);
|
|
scheme_set_global_bucket("namespace-undefine-variable!",
|
|
bucket,
|
|
NULL,
|
|
0);
|
|
bucket->val = NULL;
|
|
} else {
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT_VARIABLE, argv[0],
|
|
"namespace-undefine-variable!: %S is not defined",
|
|
argv[0]);
|
|
}
|
|
|
|
return scheme_void;
|
|
}
|
|
|
|
static Scheme_Object *
|
|
namespace_mapped_symbols(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Object *l;
|
|
Scheme_Env *env;
|
|
Scheme_Hash_Table *mapped;
|
|
Scheme_Bucket_Table *ht;
|
|
Scheme_Bucket **bs;
|
|
int i, j;
|
|
|
|
if ((argc > 0) && !SCHEME_NAMESPACEP(argv[0]))
|
|
scheme_wrong_type("namespace-mapped-symbols", "namespace", 0, argc, argv);
|
|
|
|
if (argc)
|
|
env = (Scheme_Env *)argv[0];
|
|
else
|
|
env = scheme_get_env(NULL);
|
|
|
|
mapped = scheme_make_hash_table(SCHEME_hash_ptr);
|
|
|
|
for (j = 0; j < 2; j++) {
|
|
if (j)
|
|
ht = env->syntax;
|
|
else
|
|
ht = env->toplevel;
|
|
|
|
bs = ht->buckets;
|
|
for (i = ht->size; i--; ) {
|
|
Scheme_Bucket *b = bs[i];
|
|
if (b && b->val) {
|
|
scheme_hash_set(mapped, (Scheme_Object *)b->key, scheme_true);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (env->rename_set)
|
|
scheme_list_module_rename(env->rename_set, mapped);
|
|
|
|
l = scheme_null;
|
|
for (i = mapped->size; i--; ) {
|
|
if (mapped->vals[i])
|
|
l = scheme_make_pair(mapped->keys[i], l);
|
|
}
|
|
|
|
return l;
|
|
}
|
|
|
|
static Scheme_Object *namespace_module_registry(int argc, Scheme_Object **argv)
|
|
{
|
|
if (!SCHEME_NAMESPACEP(argv[0]))
|
|
scheme_wrong_type("namespace-module-registry", "namespace", 0, argc, argv);
|
|
|
|
return (Scheme_Object *)((Scheme_Env *)argv[0])->module_registry;
|
|
}
|
|
|
|
static Scheme_Object *do_variable_namespace(const char *who, int tl, int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Object *v;
|
|
Scheme_Env *env;
|
|
int ph;
|
|
|
|
if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_global_ref_type))
|
|
env = NULL;
|
|
else {
|
|
v = SCHEME_PTR_VAL(argv[0]);
|
|
env = ((Scheme_Bucket_With_Home *)v)->home;
|
|
}
|
|
|
|
if (!env)
|
|
scheme_wrong_type(who,
|
|
"variable-reference",
|
|
0, argc, argv);
|
|
|
|
ph = env->phase;
|
|
if (tl == 2) {
|
|
return scheme_make_integer(ph);
|
|
} else if (tl) {
|
|
/* return env directly; need to set up */
|
|
if (!env->phase)
|
|
scheme_prep_namespace_rename(env);
|
|
} else {
|
|
/* new namespace: */
|
|
Scheme_Env *new_env;
|
|
new_env = make_env(env, 0);
|
|
new_env->phase = env->phase;
|
|
env = new_env;
|
|
}
|
|
|
|
return (Scheme_Object *)env;
|
|
}
|
|
|
|
static Scheme_Object *variable_namespace(int argc, Scheme_Object *argv[])
|
|
{
|
|
return do_variable_namespace("variable-reference->empty-namespace", 0, argc, argv);
|
|
}
|
|
|
|
static Scheme_Object *variable_top_level_namespace(int argc, Scheme_Object *argv[])
|
|
{
|
|
return do_variable_namespace("variable-reference->namespace", 1, argc, argv);
|
|
}
|
|
|
|
static Scheme_Object *variable_phase(int argc, Scheme_Object *argv[])
|
|
{
|
|
return do_variable_namespace("variable-reference->phase", 2, argc, argv);
|
|
}
|
|
|
|
static Scheme_Object *variable_p(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Env *env;
|
|
|
|
if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_global_ref_type))
|
|
env = NULL;
|
|
else
|
|
env = ((Scheme_Bucket_With_Home *)SCHEME_PTR_VAL(argv[0]))->home;
|
|
|
|
return env ? scheme_true : scheme_false;
|
|
}
|
|
|
|
static Scheme_Object *variable_module_path(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Env *env;
|
|
|
|
if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_global_ref_type))
|
|
env = NULL;
|
|
else
|
|
env = ((Scheme_Bucket_With_Home *)SCHEME_PTR_VAL(argv[0]))->home;
|
|
|
|
if (!env)
|
|
scheme_wrong_type("variable-reference->resolved-module-path", "variable-reference", 0, argc, argv);
|
|
|
|
if (env->module)
|
|
return env->module->modname;
|
|
else
|
|
return scheme_false;
|
|
}
|
|
|
|
static Scheme_Object *
|
|
now_transforming(int argc, Scheme_Object *argv[])
|
|
{
|
|
return (scheme_current_thread->current_local_env
|
|
? scheme_true
|
|
: scheme_false);
|
|
}
|
|
|
|
static Scheme_Object *
|
|
do_local_exp_time_value(const char *name, int argc, Scheme_Object *argv[], int recur)
|
|
{
|
|
Scheme_Object *v, *sym, *a[2];
|
|
Scheme_Env *menv;
|
|
Scheme_Comp_Env *env;
|
|
int renamed = 0;
|
|
|
|
env = scheme_current_thread->current_local_env;
|
|
if (!env)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
|
|
"%s: not currently transforming",
|
|
name);
|
|
|
|
sym = argv[0];
|
|
|
|
if (!(SCHEME_STXP(sym) && SCHEME_SYMBOLP(SCHEME_STX_VAL(sym))))
|
|
scheme_wrong_type(name, "syntax identifier", 0, argc, argv);
|
|
|
|
if (argc > 1) {
|
|
scheme_check_proc_arity2(name, 0, 1, argc, argv, 1);
|
|
if ((argc > 2)
|
|
&& SCHEME_TRUEP(argv[2])) {
|
|
Scheme_Comp_Env *stx_env;
|
|
if (!SAME_TYPE(scheme_intdef_context_type, SCHEME_TYPE(argv[2])))
|
|
scheme_wrong_type(name, "internal-definition context or #f", 2, argc, argv);
|
|
stx_env = (Scheme_Comp_Env *)SCHEME_PTR1_VAL(argv[2]);
|
|
if (!scheme_is_sub_env(stx_env, env)) {
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT, "%s: transforming context does "
|
|
"not match given internal-definition context",
|
|
name);
|
|
}
|
|
env = stx_env;
|
|
}
|
|
}
|
|
|
|
if (scheme_current_thread->current_local_mark)
|
|
sym = scheme_add_remove_mark(sym, scheme_current_thread->current_local_mark);
|
|
|
|
menv = NULL;
|
|
|
|
sym = scheme_stx_activate_certs(sym);
|
|
|
|
while (1) {
|
|
v = scheme_lookup_binding(sym, env,
|
|
(SCHEME_NULL_FOR_UNBOUND
|
|
+ SCHEME_RESOLVE_MODIDS
|
|
+ SCHEME_APP_POS + SCHEME_ENV_CONSTANTS_OK
|
|
+ SCHEME_OUT_OF_CONTEXT_OK + SCHEME_ELIM_CONST),
|
|
scheme_current_thread->current_local_certs,
|
|
scheme_current_thread->current_local_modidx,
|
|
&menv, NULL, NULL);
|
|
|
|
/* Deref globals */
|
|
if (v && SAME_TYPE(SCHEME_TYPE(v), scheme_variable_type))
|
|
v = (Scheme_Object *)(SCHEME_VAR_BUCKET(v))->val;
|
|
|
|
if (!v || NOT_SAME_TYPE(SCHEME_TYPE(v), scheme_macro_type)) {
|
|
if ((argc > 1) && SCHEME_TRUEP(argv[1]))
|
|
return _scheme_tail_apply(argv[1], 0, NULL);
|
|
else
|
|
scheme_arg_mismatch(name,
|
|
(renamed
|
|
? "not defined as syntax (after renaming): "
|
|
: "not defined as syntax: "),
|
|
argv[0]);
|
|
}
|
|
|
|
v = SCHEME_PTR_VAL(v);
|
|
if (scheme_is_rename_transformer(v)) {
|
|
sym = scheme_rename_transformer_id(v);
|
|
sym = scheme_stx_cert(sym, scheme_false, menv, sym, NULL, 1);
|
|
renamed = 1;
|
|
menv = NULL;
|
|
SCHEME_USE_FUEL(1);
|
|
if (!recur) {
|
|
a[0] = v;
|
|
a[1] = sym;
|
|
return scheme_values(2, a);
|
|
}
|
|
} else if (!recur) {
|
|
a[0] = v;
|
|
a[1] = scheme_false;
|
|
return scheme_values(2, a);
|
|
} else
|
|
return v;
|
|
}
|
|
}
|
|
|
|
static Scheme_Object *
|
|
local_exp_time_value(int argc, Scheme_Object *argv[])
|
|
{
|
|
return do_local_exp_time_value("syntax-local-value", argc, argv, 1);
|
|
}
|
|
|
|
static Scheme_Object *
|
|
local_exp_time_value_one(int argc, Scheme_Object *argv[])
|
|
{
|
|
return do_local_exp_time_value("syntax-local-value/immediate", argc, argv, 0);
|
|
}
|
|
|
|
static Scheme_Object *
|
|
local_exp_time_name(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Object *sym;
|
|
|
|
sym = scheme_current_thread->current_local_name;
|
|
if (!sym)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
|
|
"syntax-local-name: not currently transforming");
|
|
|
|
return sym;
|
|
}
|
|
|
|
static Scheme_Object *
|
|
local_context(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Comp_Env *env;
|
|
|
|
env = scheme_current_thread->current_local_env;
|
|
if (!env)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
|
|
"syntax-local-context: not currently transforming");
|
|
|
|
if (env->flags & SCHEME_INTDEF_FRAME) {
|
|
if (!env->intdef_name) {
|
|
Scheme_Object *sym, *pr, *prev = NULL;
|
|
Scheme_Comp_Env *lenv = env;
|
|
char buf[22];
|
|
while (1) {
|
|
if (env->flags & SCHEME_FOR_INTDEF)
|
|
lenv = lenv->next;
|
|
else {
|
|
sprintf(buf, "internal-define%d", intdef_counter++);
|
|
sym = scheme_make_symbol(buf); /* uninterned! */
|
|
pr = scheme_make_pair(sym, scheme_null);
|
|
lenv->intdef_name = pr;
|
|
if (prev)
|
|
SCHEME_CDR(prev) = pr;
|
|
if (lenv->next->flags & SCHEME_INTDEF_FRAME) {
|
|
if (lenv->next->intdef_name) {
|
|
SCHEME_CDR(pr) = lenv->next->intdef_name;
|
|
break;
|
|
} else {
|
|
prev = pr;
|
|
lenv = lenv->next;
|
|
/* Go again to continue building the list */
|
|
}
|
|
} else
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return env->intdef_name;
|
|
} else if (scheme_is_module_env(env))
|
|
return scheme_intern_symbol("module");
|
|
else if (scheme_is_module_begin_env(env))
|
|
return scheme_intern_symbol("module-begin");
|
|
else if (scheme_is_toplevel(env))
|
|
return scheme_intern_symbol("top-level");
|
|
else
|
|
return scheme_intern_symbol("expression");
|
|
}
|
|
|
|
static Scheme_Object *
|
|
local_phase_level(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Thread *p = scheme_current_thread;
|
|
int phase;
|
|
|
|
phase = (p->current_local_env
|
|
? p->current_local_env->genv->phase
|
|
: 0);
|
|
|
|
return scheme_make_integer(phase);
|
|
}
|
|
|
|
static Scheme_Object *
|
|
local_make_intdef_context(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Comp_Env *env, *senv;
|
|
Scheme_Object *c, *rib;
|
|
|
|
env = scheme_current_thread->current_local_env;
|
|
if (!env)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT, "syntax-local-make-definition-context: not currently transforming");
|
|
|
|
if (argc && SCHEME_TRUEP(argv[0])) {
|
|
if (!SAME_TYPE(scheme_intdef_context_type, SCHEME_TYPE(argv[0])))
|
|
scheme_wrong_type("syntax-local-bind-syntaxes", "internal-definition context or #f", 0, argc, argv);
|
|
senv = (Scheme_Comp_Env *)SCHEME_PTR1_VAL(argv[0]);
|
|
if (!scheme_is_sub_env(senv, env)) {
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT, "syntax-local-make-definition-context: transforming context does "
|
|
"not match given internal-definition context");
|
|
}
|
|
env = senv;
|
|
}
|
|
|
|
rib = scheme_make_rename_rib();
|
|
|
|
c = scheme_alloc_object();
|
|
c->type = scheme_intdef_context_type;
|
|
SCHEME_PTR1_VAL(c) = env;
|
|
SCHEME_PTR2_VAL(c) = rib;
|
|
|
|
return c;
|
|
}
|
|
|
|
static Scheme_Object *
|
|
intdef_context_p(int argc, Scheme_Object *argv[])
|
|
{
|
|
return (SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_intdef_context_type)
|
|
? scheme_true
|
|
: scheme_false);
|
|
}
|
|
|
|
static Scheme_Object *intdef_context_seal(int argc, Scheme_Object *argv[])
|
|
{
|
|
if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_intdef_context_type))
|
|
scheme_wrong_type("internal-definition-context-seal",
|
|
"internal-definition context", 0, argc, argv);
|
|
|
|
scheme_stx_seal_rib(SCHEME_PTR2_VAL(argv[0]));
|
|
return scheme_void;
|
|
}
|
|
|
|
static Scheme_Object *
|
|
id_intdef_remove(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Object *l, *res, *skips;
|
|
|
|
if (!SCHEME_STXP(argv[0]) || !SCHEME_SYMBOLP(SCHEME_STX_VAL(argv[0])))
|
|
scheme_wrong_type("identifier-from-from-definition-context",
|
|
"syntax identifier", 0, argc, argv);
|
|
|
|
l = argv[1];
|
|
if (!SAME_TYPE(SCHEME_TYPE(l), scheme_intdef_context_type)) {
|
|
while (SCHEME_PAIRP(l)) {
|
|
if (!SAME_TYPE(SCHEME_TYPE(SCHEME_CAR(l)), scheme_intdef_context_type))
|
|
break;
|
|
l = SCHEME_CDR(l);
|
|
}
|
|
if (!SCHEME_NULLP(l))
|
|
scheme_wrong_type("identifier-remove-from-definition-context",
|
|
"internal-definition context or list of internal-definition contexts",
|
|
1, argc, argv);
|
|
}
|
|
|
|
l = argv[1];
|
|
if (SAME_TYPE(SCHEME_TYPE(l), scheme_intdef_context_type))
|
|
l = scheme_make_pair(l, scheme_null);
|
|
|
|
res = argv[0];
|
|
skips = scheme_null;
|
|
|
|
while (SCHEME_PAIRP(l)) {
|
|
res = scheme_stx_id_remove_rib(res, SCHEME_PTR2_VAL(SCHEME_CAR(l)));
|
|
skips = scheme_make_pair(SCHEME_PTR2_VAL(SCHEME_CAR(l)), skips);
|
|
l = SCHEME_CDR(l);
|
|
}
|
|
|
|
if (scheme_stx_ribs_matter(res, skips)) {
|
|
/* Removing ribs leaves the binding for this identifier in limbo, because
|
|
the rib that binds it depends on the removed ribs. Invent in inaccessible
|
|
identifier. */
|
|
res = scheme_add_remove_mark(res, scheme_new_mark());
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static Scheme_Object *
|
|
local_introduce(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Comp_Env *env;
|
|
Scheme_Object *s;
|
|
|
|
env = scheme_current_thread->current_local_env;
|
|
if (!env)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
|
|
"syntax-local-introduce: not currently transforming");
|
|
|
|
s = argv[0];
|
|
if (!SCHEME_STXP(s))
|
|
scheme_wrong_type("syntax-local-introduce", "syntax", 0, argc, argv);
|
|
|
|
if (scheme_current_thread->current_local_mark)
|
|
s = scheme_add_remove_mark(s, scheme_current_thread->current_local_mark);
|
|
|
|
return s;
|
|
}
|
|
|
|
static Scheme_Object *
|
|
local_module_introduce(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Comp_Env *env;
|
|
Scheme_Object *s, *v;
|
|
|
|
env = scheme_current_thread->current_local_env;
|
|
if (!env)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
|
|
"syntax-local-module-introduce: not currently transforming");
|
|
|
|
s = argv[0];
|
|
if (!SCHEME_STXP(s))
|
|
scheme_wrong_type("syntax-local-module-introduce", "syntax", 0, argc, argv);
|
|
|
|
v = scheme_stx_source_module(s, 0);
|
|
if (SCHEME_FALSEP(v)) {
|
|
if (env->genv->module) {
|
|
if (env->genv->module->rn_stx && !SAME_OBJ(scheme_true, env->genv->module->rn_stx)) {
|
|
v = scheme_stx_to_rename(env->genv->module->rn_stx);
|
|
s = scheme_add_rename(s, v);
|
|
}
|
|
} else {
|
|
if (env->genv->rename_set)
|
|
s = scheme_add_rename(s, env->genv->rename_set);
|
|
}
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
static Scheme_Object *
|
|
local_get_shadower(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Comp_Env *env, *frame;
|
|
Scheme_Object *sym, *esym, *sym_marks = NULL, *orig_sym, *uid = NULL, *env_marks;
|
|
|
|
env = scheme_current_thread->current_local_env;
|
|
if (!env)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
|
|
"syntax-local-get-shadower: not currently transforming");
|
|
|
|
sym = argv[0];
|
|
orig_sym = sym;
|
|
|
|
if (!(SCHEME_STXP(sym) && SCHEME_SYMBOLP(SCHEME_STX_VAL(sym))))
|
|
scheme_wrong_type("syntax-local-get-shadower", "syntax identifier", 0, argc, argv);
|
|
|
|
sym_marks = scheme_stx_extract_marks(sym);
|
|
|
|
/* Walk backward through the frames, looking for a renaming binding
|
|
with the same marks as the given identifier, sym. Skip over
|
|
unsealed ribs, though. When we find a match, rename the given
|
|
identifier so that it matches frame. */
|
|
for (frame = env; frame->next != NULL; frame = frame->next) {
|
|
int i;
|
|
|
|
for (i = frame->num_bindings; i--; ) {
|
|
if (frame->values[i]) {
|
|
if (SAME_OBJ(SCHEME_STX_VAL(sym), SCHEME_STX_VAL(frame->values[i]))) {
|
|
esym = frame->values[i];
|
|
env_marks = scheme_stx_extract_marks(esym);
|
|
if (scheme_equal(env_marks, sym_marks)) {
|
|
sym = esym;
|
|
if (frame->uids)
|
|
uid = frame->uids[i];
|
|
else
|
|
uid = frame->uid;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (uid)
|
|
break;
|
|
|
|
if (!COMPILE_DATA(frame)->sealed || *COMPILE_DATA(frame)->sealed) {
|
|
for (i = COMPILE_DATA(frame)->num_const; i--; ) {
|
|
if (!(frame->flags & SCHEME_CAPTURE_WITHOUT_RENAME)) {
|
|
if (SAME_OBJ(SCHEME_STX_VAL(sym),
|
|
SCHEME_STX_VAL(COMPILE_DATA(frame)->const_names[i]))) {
|
|
esym = COMPILE_DATA(frame)->const_names[i];
|
|
env_marks = scheme_stx_extract_marks(esym);
|
|
if (scheme_equal(env_marks, sym_marks)) { /* This used to have 1 || --- why? */
|
|
sym = esym;
|
|
if (COMPILE_DATA(frame)->const_uids)
|
|
uid = COMPILE_DATA(frame)->const_uids[i];
|
|
else
|
|
uid = frame->uid;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (uid)
|
|
break;
|
|
}
|
|
|
|
if (!uid) {
|
|
/* No lexical shadower, but strip module context, if any */
|
|
sym = scheme_stx_strip_module_context(sym);
|
|
/* Add current module context, if any */
|
|
sym = local_module_introduce(1, &sym);
|
|
return sym;
|
|
}
|
|
|
|
{
|
|
Scheme_Object *rn, *result;
|
|
|
|
result = scheme_datum_to_syntax(SCHEME_STX_VAL(sym), orig_sym, sym, 0, 0);
|
|
((Scheme_Stx *)result)->props = ((Scheme_Stx *)orig_sym)->props;
|
|
|
|
rn = scheme_make_rename(uid, 1);
|
|
scheme_set_rename(rn, 0, result);
|
|
|
|
result = scheme_add_rename(result, rn);
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
static Scheme_Object *
|
|
introducer_proc(void *mark, int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Object *s;
|
|
|
|
s = argv[0];
|
|
if (!SCHEME_STXP(s))
|
|
scheme_wrong_type("syntax-introducer", "syntax", 0, argc, argv);
|
|
|
|
return scheme_add_remove_mark(s, (Scheme_Object *)mark);
|
|
}
|
|
|
|
static Scheme_Object *
|
|
make_introducer(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Object *mark;
|
|
|
|
mark = scheme_new_mark();
|
|
|
|
return scheme_make_closed_prim_w_arity(introducer_proc, mark,
|
|
"syntax-introducer", 1, 1);
|
|
}
|
|
|
|
static Scheme_Object *
|
|
delta_introducer_proc(void *_i_plus_m, int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Object *p = (Scheme_Object *)_i_plus_m, *l, *v, *a[1];
|
|
const char *who = "delta introducer attached to a rename transformer";
|
|
|
|
v = argv[0];
|
|
if (!SCHEME_STXP(v) || !SCHEME_SYMBOLP(SCHEME_STX_VAL(v))) {
|
|
scheme_wrong_type(who, "identifier", 0, argc, argv);
|
|
}
|
|
|
|
/* Apply mapping functions: */
|
|
l = SCHEME_CDR(p);
|
|
while (SCHEME_PAIRP(l)) {
|
|
a[0] = v;
|
|
v = _scheme_apply(SCHEME_CAR(l), 1, a);
|
|
l = SCHEME_CDR(l);
|
|
}
|
|
|
|
/* Apply delta-introducing functions: */
|
|
l = SCHEME_CAR(p);
|
|
while (SCHEME_PAIRP(l)) {
|
|
a[0] = v;
|
|
v = _scheme_apply(SCHEME_CAR(l), 1, a);
|
|
if (!SCHEME_STXP(v) || !SCHEME_SYMBOLP(SCHEME_STX_VAL(v))) {
|
|
a[0] = v;
|
|
scheme_wrong_type(who, "identifier", -1, -1, a);
|
|
}
|
|
l = SCHEME_CDR(l);
|
|
}
|
|
|
|
return v;
|
|
}
|
|
|
|
static Scheme_Object *
|
|
local_make_delta_introduce(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Object *sym, *binder, *introducer, *a[2], *v;
|
|
Scheme_Object *introducers = scheme_null, *mappers = scheme_null;
|
|
int renamed = 0;
|
|
Scheme_Comp_Env *env;
|
|
Scheme_Object *certs;
|
|
|
|
env = scheme_current_thread->current_local_env;
|
|
if (!env)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
|
|
"syntax-local-make-delta-introducer: not currently transforming");
|
|
|
|
if (!SCHEME_STXP(argv[0]) || !SCHEME_SYMBOLP(SCHEME_STX_VAL(argv[0])))
|
|
scheme_wrong_type("syntax-local-make-delta-introducer", "syntax identifier", 0, argc, argv);
|
|
|
|
sym = argv[0];
|
|
|
|
sym = scheme_stx_activate_certs(sym);
|
|
|
|
certs = scheme_current_thread->current_local_certs;
|
|
|
|
while (1) {
|
|
binder = NULL;
|
|
|
|
v = scheme_lookup_binding(sym, env,
|
|
(SCHEME_NULL_FOR_UNBOUND
|
|
+ SCHEME_RESOLVE_MODIDS
|
|
+ SCHEME_APP_POS + SCHEME_ENV_CONSTANTS_OK
|
|
+ SCHEME_OUT_OF_CONTEXT_OK + SCHEME_ELIM_CONST),
|
|
certs,
|
|
scheme_current_thread->current_local_modidx,
|
|
NULL, NULL, &binder);
|
|
|
|
/* Deref globals */
|
|
if (v && SAME_TYPE(SCHEME_TYPE(v), scheme_variable_type))
|
|
v = (Scheme_Object *)(SCHEME_VAR_BUCKET(v))->val;
|
|
|
|
if (!v || NOT_SAME_TYPE(SCHEME_TYPE(v), scheme_macro_type)) {
|
|
scheme_arg_mismatch("syntax-local-make-delta-introducer",
|
|
(renamed
|
|
? "not defined as syntax (after renaming): "
|
|
: "not defined as syntax: "),
|
|
argv[0]);
|
|
}
|
|
|
|
if (!binder) {
|
|
/* Not a lexical biding. Tell make-syntax-delta-introducer to
|
|
use module-binding information. */
|
|
binder = scheme_false;
|
|
}
|
|
|
|
a[0] = sym;
|
|
a[1] = binder;
|
|
introducer = scheme_syntax_make_transfer_intro(2, a);
|
|
introducers = scheme_make_pair(introducer, introducers);
|
|
|
|
v = SCHEME_PTR_VAL(v);
|
|
if (scheme_is_rename_transformer(v)) {
|
|
certs = scheme_stx_extract_certs(sym, certs);
|
|
|
|
sym = scheme_rename_transformer_id(v);
|
|
sym = scheme_stx_activate_certs(sym);
|
|
|
|
v = SCHEME_PTR2_VAL(v);
|
|
if (!SCHEME_FALSEP(v))
|
|
mappers = scheme_make_pair(v, mappers);
|
|
|
|
renamed = 1;
|
|
SCHEME_USE_FUEL(1);
|
|
} else {
|
|
/* that's the end of the chain */
|
|
mappers = scheme_reverse(mappers);
|
|
return scheme_make_closed_prim_w_arity(delta_introducer_proc,
|
|
scheme_make_pair(introducers, mappers),
|
|
"syntax-delta-introducer", 1, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
static Scheme_Object *
|
|
certifier(void *_data, int argc, Scheme_Object **argv)
|
|
{
|
|
Scheme_Object *s, **cert_data = (Scheme_Object **)_data;
|
|
Scheme_Object *mark = scheme_false;
|
|
|
|
s = argv[0];
|
|
if (!SCHEME_STXP(s))
|
|
scheme_wrong_type("certifier", "syntax", 0, argc, argv);
|
|
|
|
if (argc > 2) {
|
|
if (SCHEME_TRUEP(argv[2])) {
|
|
if (SCHEME_CLSD_PRIMP(argv[2])
|
|
&& (((Scheme_Closed_Primitive_Proc *)argv[2])->prim_val == introducer_proc))
|
|
mark = (Scheme_Object *)((Scheme_Closed_Primitive_Proc *)argv[2])->data;
|
|
else {
|
|
scheme_wrong_type("certifier",
|
|
"procedure from make-syntax-introducer or #f",
|
|
2, argc, argv);
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cert_data[0] || cert_data[1] || cert_data[2]) {
|
|
int as_active = SCHEME_TRUEP(cert_data[3]);
|
|
s = scheme_stx_cert(s, mark,
|
|
(Scheme_Env *)(cert_data[1] ? cert_data[1] : cert_data[2]),
|
|
cert_data[0],
|
|
((argc > 1) && SCHEME_TRUEP(argv[1])) ? argv[1] : NULL,
|
|
as_active);
|
|
if (cert_data[1] && cert_data[2] && !SAME_OBJ(cert_data[1], cert_data[2])) {
|
|
/* Have module we're expanding, in addition to module that bound
|
|
the expander. */
|
|
s = scheme_stx_cert(s, mark, (Scheme_Env *)cert_data[2],
|
|
NULL,
|
|
((argc > 1) && SCHEME_TRUEP(argv[1])) ? argv[1] : NULL,
|
|
as_active);
|
|
}
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
static Scheme_Object *
|
|
local_certify(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Object **cert_data;
|
|
Scheme_Env *menv;
|
|
int active = 0;
|
|
|
|
if (!scheme_current_thread->current_local_env)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
|
|
"syntax-local-certifier: not currently transforming");
|
|
menv = scheme_current_thread->current_local_menv;
|
|
|
|
if (argc)
|
|
active = SCHEME_TRUEP(argv[0]);
|
|
|
|
cert_data = MALLOC_N(Scheme_Object*, 4);
|
|
cert_data[0] = scheme_current_thread->current_local_certs;
|
|
/* Module that bound the macro we're now running: */
|
|
cert_data[1] = (Scheme_Object *)((menv && menv->module) ? menv : NULL);
|
|
/* Module that we're currently expanding: */
|
|
menv = scheme_current_thread->current_local_env->genv;
|
|
cert_data[2] = (Scheme_Object *)((menv && menv->module) ? menv : NULL);
|
|
cert_data[3] = (active ? scheme_true : scheme_false);
|
|
|
|
return scheme_make_closed_prim_w_arity(certifier,
|
|
cert_data,
|
|
"certifier",
|
|
1, 3);
|
|
}
|
|
|
|
static Scheme_Object *
|
|
local_module_exports(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Comp_Env *env;
|
|
|
|
env = scheme_current_thread->current_local_env;
|
|
|
|
if (!env)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
|
|
"syntax-local-module-exports: not currently transforming");
|
|
|
|
return scheme_module_exported_list(argv[0], env->genv);
|
|
}
|
|
|
|
static Scheme_Object *
|
|
local_module_definitions(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Object *a[2];
|
|
|
|
if (!scheme_current_thread->current_local_env
|
|
|| !scheme_current_thread->current_local_bindings)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
|
|
"syntax-local-module-defined-identifiers: not currently transforming module provides");
|
|
|
|
a[0] = SCHEME_CDR(scheme_current_thread->current_local_bindings);
|
|
a[1] = SCHEME_CDR(a[0]);
|
|
a[0] = SCHEME_CAR(a[0]);
|
|
|
|
return scheme_values(2, a);
|
|
}
|
|
|
|
static Scheme_Object *
|
|
local_module_imports(int argc, Scheme_Object *argv[])
|
|
{
|
|
if (!scheme_current_thread->current_local_env
|
|
|| !scheme_current_thread->current_local_bindings)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
|
|
"syntax-local-module-required-identifiers: not currently transforming module provides");
|
|
|
|
if (SCHEME_TRUEP(argv[0]) && !scheme_is_module_path(argv[0]))
|
|
scheme_wrong_type("syntax-local-module-required-identifiers", "module-path or #f", 0, argc, argv);
|
|
|
|
if (!SCHEME_FALSEP(argv[1])
|
|
&& !SAME_OBJ(scheme_true, argv[1])
|
|
&& !SCHEME_INTP(argv[1])
|
|
&& !SCHEME_BIGNUMP(argv[1]))
|
|
scheme_wrong_type("syntax-local-module-required-identifiers", "exact integer, #f, or #t", 1, argc, argv);
|
|
|
|
return scheme_module_imported_list(scheme_current_thread->current_local_env->genv,
|
|
scheme_current_thread->current_local_bindings,
|
|
argv[0],
|
|
argv[1]);
|
|
}
|
|
|
|
static Scheme_Object *
|
|
local_module_expanding_provides(int argc, Scheme_Object *argv[])
|
|
{
|
|
if (scheme_current_thread->current_local_env
|
|
&& scheme_current_thread->current_local_bindings)
|
|
return scheme_true;
|
|
else
|
|
return scheme_false;
|
|
}
|
|
|
|
static Scheme_Object *
|
|
local_lift_expr(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Env *menv;
|
|
Scheme_Comp_Env *env, *orig_env;
|
|
Scheme_Object *id, *local_mark, *expr, *data, *vec, *id_sym;
|
|
Scheme_Lift_Capture_Proc cp;
|
|
Scheme_Object *orig_expr;
|
|
char buf[24];
|
|
|
|
expr = argv[0];
|
|
if (!SCHEME_STXP(expr))
|
|
scheme_wrong_type("syntax-local-lift-expression", "syntax", 0, argc, argv);
|
|
|
|
env = orig_env = scheme_current_thread->current_local_env;
|
|
local_mark = scheme_current_thread->current_local_mark;
|
|
|
|
if (!env)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
|
|
"syntax-local-lift-expression: not currently transforming");
|
|
|
|
while (env && !COMPILE_DATA(env)->lifts) {
|
|
env = env->next;
|
|
}
|
|
|
|
if (env)
|
|
if (SCHEME_FALSEP(SCHEME_VEC_ELS(COMPILE_DATA(env)->lifts)[0]))
|
|
env = NULL;
|
|
|
|
if (!env)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
|
|
"syntax-local-lift-expression: no lift target");
|
|
|
|
expr = scheme_add_remove_mark(expr, local_mark);
|
|
|
|
/* We don't really need a new symbol each time, since the mark
|
|
will generate new bindings. But lots of things work better or faster
|
|
when different bindings have different symbols. Use env->genv->id_counter
|
|
to help keep name generation deterministic within a module. */
|
|
sprintf(buf, "lifted.%d", env->genv->id_counter++);
|
|
id_sym = scheme_intern_exact_parallel_symbol(buf, strlen(buf));
|
|
|
|
id = scheme_datum_to_syntax(id_sym, scheme_false, scheme_false, 0, 0);
|
|
id = scheme_add_remove_mark(id, scheme_new_mark());
|
|
|
|
vec = COMPILE_DATA(env)->lifts;
|
|
cp = *(Scheme_Lift_Capture_Proc *)SCHEME_VEC_ELS(vec)[1];
|
|
data = SCHEME_VEC_ELS(vec)[2];
|
|
|
|
menv = scheme_current_thread->current_local_menv;
|
|
|
|
expr = scheme_stx_cert(expr, scheme_false,
|
|
(menv && menv->module) ? menv : NULL,
|
|
scheme_current_thread->current_local_certs,
|
|
NULL, 1);
|
|
|
|
expr = scheme_stx_activate_certs(expr);
|
|
orig_expr = expr;
|
|
|
|
expr = cp(data, &id, expr, orig_env);
|
|
|
|
expr = scheme_make_pair(expr, SCHEME_VEC_ELS(vec)[0]);
|
|
SCHEME_VEC_ELS(vec)[0] = expr;
|
|
|
|
SCHEME_EXPAND_OBSERVE_LOCAL_LIFT(scheme_get_expand_observe(), id, orig_expr);
|
|
|
|
id = scheme_add_remove_mark(id, local_mark);
|
|
return id;
|
|
}
|
|
|
|
static Scheme_Object *
|
|
local_lift_context(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Comp_Env *env;
|
|
|
|
env = scheme_current_thread->current_local_env;
|
|
|
|
if (!env)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
|
|
"syntax-local-lift-context: not currently transforming");
|
|
|
|
while (env && !COMPILE_DATA(env)->lifts) {
|
|
env = env->next;
|
|
}
|
|
|
|
if (!env)
|
|
return scheme_false;
|
|
|
|
return SCHEME_VEC_ELS(COMPILE_DATA(env)->lifts)[4];
|
|
}
|
|
|
|
static Scheme_Object *
|
|
local_lift_end_statement(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Comp_Env *env;
|
|
Scheme_Object *local_mark, *expr, *pr;
|
|
Scheme_Object *orig_expr;
|
|
|
|
expr = argv[0];
|
|
if (!SCHEME_STXP(expr))
|
|
scheme_wrong_type("syntax-local-lift-module-end-declaration", "syntax", 0, argc, argv);
|
|
|
|
env = scheme_current_thread->current_local_env;
|
|
local_mark = scheme_current_thread->current_local_mark;
|
|
|
|
if (!env)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
|
|
"syntax-local-lift-module-end-declaration: not currently transforming");
|
|
|
|
while (env) {
|
|
if ((COMPILE_DATA(env)->lifts)
|
|
&& SCHEME_TRUEP(SCHEME_VEC_ELS(COMPILE_DATA(env)->lifts)[3]))
|
|
break;
|
|
env = env->next;
|
|
}
|
|
|
|
if (!env)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
|
|
"syntax-local-lift-module-end-declaration: not currently transforming"
|
|
" a run-time expression in a module declaration");
|
|
|
|
expr = scheme_add_remove_mark(expr, local_mark);
|
|
orig_expr = expr;
|
|
|
|
pr = scheme_make_pair(expr, SCHEME_VEC_ELS(COMPILE_DATA(env)->lifts)[3]);
|
|
SCHEME_VEC_ELS(COMPILE_DATA(env)->lifts)[3] = pr;
|
|
|
|
SCHEME_EXPAND_OBSERVE_LIFT_STATEMENT(scheme_get_expand_observe(), orig_expr);
|
|
|
|
return scheme_void;
|
|
}
|
|
|
|
static Scheme_Object *local_lift_require(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Comp_Env *env;
|
|
Scheme_Object *local_mark, *mark, *data, *pr, *form;
|
|
long phase;
|
|
|
|
if (!SCHEME_STXP(argv[1]))
|
|
scheme_wrong_type("syntax-local-lift-require", "syntax", 1, argc, argv);
|
|
|
|
env = scheme_current_thread->current_local_env;
|
|
local_mark = scheme_current_thread->current_local_mark;
|
|
phase = env->genv->phase;
|
|
|
|
if (!env)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
|
|
"syntax-local-lift-require: not currently transforming");
|
|
|
|
data = NULL;
|
|
|
|
while (env) {
|
|
if (COMPILE_DATA(env)->lifts
|
|
&& SCHEME_TRUEP(SCHEME_VEC_ELS(COMPILE_DATA(env)->lifts)[5])) {
|
|
data = SCHEME_VEC_ELS(COMPILE_DATA(env)->lifts)[5];
|
|
if (SCHEME_RPAIRP(data)
|
|
&& !SCHEME_CAR(data)) {
|
|
env = (Scheme_Comp_Env *)SCHEME_CDR(data);
|
|
} else
|
|
break;
|
|
} else
|
|
env = env->next;
|
|
}
|
|
|
|
if (!env)
|
|
scheme_raise_exn(MZEXN_FAIL_CONTRACT,
|
|
"syntax-local-lift-requires: could not find target context");
|
|
|
|
|
|
mark = scheme_new_mark();
|
|
|
|
if (SCHEME_RPAIRP(data))
|
|
form = scheme_parse_lifted_require(argv[0], phase, mark, SCHEME_CAR(data));
|
|
else
|
|
form = scheme_toplevel_require_for_expand(argv[0], phase, env, mark);
|
|
|
|
pr = scheme_make_pair(form, SCHEME_VEC_ELS(COMPILE_DATA(env)->lifts)[6]);
|
|
SCHEME_VEC_ELS(COMPILE_DATA(env)->lifts)[6] = pr;
|
|
|
|
form = argv[1];
|
|
form = scheme_add_remove_mark(form, local_mark);
|
|
form = scheme_add_remove_mark(form, mark);
|
|
form = scheme_add_remove_mark(form, local_mark);
|
|
|
|
return form;
|
|
}
|
|
|
|
static Scheme_Object *
|
|
make_set_transformer(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Object *v;
|
|
|
|
scheme_check_proc_arity("make-set!-transformer", 1, 0, argc, argv);
|
|
|
|
v = scheme_alloc_small_object();
|
|
v->type = scheme_set_macro_type;
|
|
SCHEME_PTR_VAL(v) = argv[0];
|
|
|
|
return v;
|
|
}
|
|
|
|
static Scheme_Object *
|
|
set_transformer_p(int argc, Scheme_Object *argv[])
|
|
{
|
|
return (scheme_is_set_transformer(argv[0])
|
|
? scheme_true
|
|
: scheme_false);
|
|
}
|
|
|
|
static Scheme_Object *
|
|
set_transformer_proc(int argc, Scheme_Object *argv[])
|
|
{
|
|
if (!scheme_is_set_transformer(argv[0]))
|
|
scheme_wrong_type("set!-transformer-procedure", "set!-transformer", 1, argc, argv);
|
|
|
|
return scheme_set_transformer_proc(argv[0]);
|
|
}
|
|
|
|
static Scheme_Object *
|
|
make_rename_transformer(int argc, Scheme_Object *argv[])
|
|
{
|
|
Scheme_Object *v;
|
|
|
|
if (!SCHEME_STXP(argv[0]) || !SCHEME_SYMBOLP(SCHEME_STX_VAL(argv[0])))
|
|
scheme_wrong_type("make-rename-transformer", "syntax identifier", 0, argc, argv);
|
|
|
|
if (argc > 1)
|
|
scheme_check_proc_arity("make-rename-transformer", 1, 1, argc, argv);
|
|
|
|
v = scheme_alloc_object();
|
|
v->type = scheme_id_macro_type;
|
|
SCHEME_PTR1_VAL(v) = argv[0];
|
|
SCHEME_PTR2_VAL(v) = ((argc > 1) ? argv[1] : scheme_false);
|
|
|
|
return v;
|
|
}
|
|
|
|
static Scheme_Object *
|
|
rename_transformer_target(int argc, Scheme_Object *argv[])
|
|
{
|
|
if (!scheme_is_rename_transformer(argv[0]))
|
|
scheme_wrong_type("rename-transformer-target", "rename transformer", 0, argc, argv);
|
|
|
|
return scheme_rename_transformer_id(argv[0]);
|
|
}
|
|
|
|
static Scheme_Object *
|
|
rename_transformer_p(int argc, Scheme_Object *argv[])
|
|
{
|
|
return (scheme_is_rename_transformer(argv[0])
|
|
? scheme_true
|
|
: scheme_false);
|
|
}
|
|
|
|
|
|
/*========================================================================*/
|
|
/* [un]marshalling variable reference */
|
|
/*========================================================================*/
|
|
|
|
static Scheme_Object *write_toplevel(Scheme_Object *obj)
|
|
{
|
|
int pos, flags;
|
|
Scheme_Object *pr;
|
|
|
|
pos = SCHEME_TOPLEVEL_POS(obj);
|
|
flags = (SCHEME_TOPLEVEL_FLAGS(obj) & SCHEME_TOPLEVEL_FLAGS_MASK);
|
|
|
|
pr = (flags
|
|
? scheme_make_pair(scheme_make_integer(pos),
|
|
scheme_make_integer(flags))
|
|
: scheme_make_integer(pos));
|
|
|
|
return scheme_make_pair(scheme_make_integer(SCHEME_TOPLEVEL_DEPTH(obj)),
|
|
pr);
|
|
}
|
|
|
|
static Scheme_Object *read_toplevel(Scheme_Object *obj)
|
|
{
|
|
int pos, depth, flags;
|
|
|
|
if (!SCHEME_PAIRP(obj)) return NULL;
|
|
|
|
depth = SCHEME_INT_VAL(SCHEME_CAR(obj));
|
|
obj = SCHEME_CDR(obj);
|
|
|
|
if (SCHEME_PAIRP(obj)) {
|
|
pos = SCHEME_INT_VAL(SCHEME_CAR(obj));
|
|
flags = SCHEME_INT_VAL(SCHEME_CDR(obj)) & SCHEME_TOPLEVEL_FLAGS_MASK;
|
|
} else {
|
|
pos = SCHEME_INT_VAL(obj);
|
|
flags = 0;
|
|
}
|
|
|
|
return make_toplevel(depth, pos, 1, flags);
|
|
}
|
|
|
|
static Scheme_Object *write_variable(Scheme_Object *obj)
|
|
/* #%kernel references are handled in print.c, instead */
|
|
{
|
|
Scheme_Object *sym;
|
|
Scheme_Env *home;
|
|
Scheme_Module *m;
|
|
|
|
sym = (Scheme_Object *)(SCHEME_VAR_BUCKET(obj))->key;
|
|
|
|
home = ((Scheme_Bucket_With_Home *)obj)->home;
|
|
m = home->module;
|
|
|
|
/* If we get a writeable variable (instead of a module variable),
|
|
it must be a reference to a module referenced directly by its
|
|
a symbolic name (i.e., no path). */
|
|
|
|
if (m) {
|
|
sym = scheme_make_pair(m->modname, sym);
|
|
if (home->mod_phase)
|
|
sym = scheme_make_pair(scheme_make_integer(home->mod_phase), sym);
|
|
}
|
|
|
|
return sym;
|
|
}
|
|
|
|
static Scheme_Object *read_variable(Scheme_Object *obj)
|
|
/* #%kernel references are handled in read.c, instead */
|
|
{
|
|
Scheme_Env *env;
|
|
|
|
env = scheme_get_env(NULL);
|
|
|
|
if (!SCHEME_SYMBOLP(obj)) return NULL;
|
|
|
|
return (Scheme_Object *)scheme_global_bucket(obj, env);
|
|
}
|
|
|
|
static Scheme_Object *write_module_variable(Scheme_Object *obj)
|
|
{
|
|
scheme_signal_error("module variables should have been handled in print.c");
|
|
return NULL;
|
|
}
|
|
|
|
static Scheme_Object *read_module_variable(Scheme_Object *obj)
|
|
{
|
|
scheme_signal_error("module variables should have been handled in read.c");
|
|
return NULL;
|
|
}
|
|
|
|
static Scheme_Object *write_local(Scheme_Object *obj)
|
|
{
|
|
return scheme_make_integer(SCHEME_LOCAL_POS(obj));
|
|
}
|
|
|
|
static Scheme_Object *do_read_local(Scheme_Type t, Scheme_Object *obj)
|
|
{
|
|
int n, flags;
|
|
|
|
if (SCHEME_PAIRP(obj)) {
|
|
flags = SCHEME_INT_VAL(SCHEME_CAR(obj));
|
|
obj = SCHEME_CDR(obj);
|
|
} else
|
|
flags = 0;
|
|
|
|
n = SCHEME_INT_VAL(obj);
|
|
|
|
return scheme_make_local(t, n, flags);
|
|
}
|
|
|
|
static Scheme_Object *read_local(Scheme_Object *obj)
|
|
{
|
|
return do_read_local(scheme_local_type, obj);
|
|
}
|
|
|
|
static Scheme_Object *read_local_unbox(Scheme_Object *obj)
|
|
{
|
|
return do_read_local(scheme_local_unbox_type, obj);
|
|
}
|
|
|
|
static Scheme_Object *write_resolve_prefix(Scheme_Object *obj)
|
|
{
|
|
Resolve_Prefix *rp = (Resolve_Prefix *)obj;
|
|
Scheme_Object *tv, *sv, *ds;
|
|
int i;
|
|
|
|
i = rp->num_toplevels;
|
|
tv = scheme_make_vector(i, NULL);
|
|
while (i--) {
|
|
SCHEME_VEC_ELS(tv)[i] = rp->toplevels[i];
|
|
}
|
|
|
|
i = rp->num_stxes;
|
|
sv = scheme_make_vector(i, NULL);
|
|
while (i--) {
|
|
if (rp->stxes[i]) {
|
|
if (SCHEME_INTP(rp->stxes[i])) {
|
|
/* Need to foce this object, so we can write it.
|
|
This should only happen if we're writing back
|
|
code loaded from bytecode. */
|
|
scheme_load_delayed_syntax(rp, i);
|
|
}
|
|
|
|
ds = scheme_alloc_small_object();
|
|
ds->type = scheme_delay_syntax_type;
|
|
SCHEME_PTR_VAL(ds) = rp->stxes[i];
|
|
} else
|
|
ds = scheme_false;
|
|
SCHEME_VEC_ELS(sv)[i] = ds;
|
|
}
|
|
|
|
return scheme_make_pair(scheme_make_integer(rp->num_lifts), scheme_make_pair(tv, sv));
|
|
}
|
|
|
|
static Scheme_Object *read_resolve_prefix(Scheme_Object *obj)
|
|
{
|
|
Resolve_Prefix *rp;
|
|
Scheme_Object *tv, *sv, **a, *stx;
|
|
int i;
|
|
|
|
if (!SCHEME_PAIRP(obj)) return NULL;
|
|
|
|
i = SCHEME_INT_VAL(SCHEME_CAR(obj));
|
|
if (i < 0) return NULL;
|
|
|
|
obj = SCHEME_CDR(obj);
|
|
if (!SCHEME_PAIRP(obj)) return NULL;
|
|
|
|
tv = SCHEME_CAR(obj);
|
|
sv = SCHEME_CDR(obj);
|
|
|
|
if (!SCHEME_VECTORP(tv)) return NULL;
|
|
if (!SCHEME_VECTORP(sv)) return NULL;
|
|
|
|
rp = MALLOC_ONE_TAGGED(Resolve_Prefix);
|
|
rp->so.type = scheme_resolve_prefix_type;
|
|
rp->num_toplevels = SCHEME_VEC_SIZE(tv);
|
|
rp->num_stxes = SCHEME_VEC_SIZE(sv);
|
|
rp->num_lifts = i;
|
|
|
|
i = rp->num_toplevels;
|
|
a = MALLOC_N(Scheme_Object *, i);
|
|
while (i--) {
|
|
a[i] = SCHEME_VEC_ELS(tv)[i];
|
|
}
|
|
rp->toplevels = a;
|
|
|
|
i = rp->num_stxes;
|
|
a = MALLOC_N(Scheme_Object *, i);
|
|
while (i--) {
|
|
stx = SCHEME_VEC_ELS(sv)[i];
|
|
if (SCHEME_FALSEP(stx)) {
|
|
stx = NULL;
|
|
} else if (SCHEME_RPAIRP(stx)) {
|
|
struct Scheme_Load_Delay *d;
|
|
Scheme_Object *pr;
|
|
d = (struct Scheme_Load_Delay *)SCHEME_CDR(stx);
|
|
stx = SCHEME_CAR(stx);
|
|
pr = rp->delay_info_rpair;
|
|
if (!pr) {
|
|
pr = scheme_make_raw_pair(scheme_make_integer(0), (Scheme_Object *)d);
|
|
rp->delay_info_rpair = pr;
|
|
}
|
|
SCHEME_CAR(pr) = scheme_make_integer(SCHEME_INT_VAL(SCHEME_CAR(pr)) + 1);
|
|
} else {
|
|
if (!SCHEME_STXP(stx)) return NULL;
|
|
}
|
|
a[i] = stx;
|
|
}
|
|
rp->stxes = a;
|
|
|
|
return (Scheme_Object *)rp;
|
|
}
|
|
|
|
/*========================================================================*/
|
|
/* precise GC traversers */
|
|
/*========================================================================*/
|
|
|
|
#ifdef MZ_PRECISE_GC
|
|
|
|
START_XFORM_SKIP;
|
|
|
|
#define MARKS_FOR_ENV_C
|
|
#include "mzmark.c"
|
|
|
|
static void register_traversers(void)
|
|
{
|
|
GC_REG_TRAV(scheme_rt_comp_env, mark_comp_env);
|
|
GC_REG_TRAV(scheme_rt_resolve_info, mark_resolve_info);
|
|
GC_REG_TRAV(scheme_rt_optimize_info, mark_optimize_info);
|
|
GC_REG_TRAV(scheme_rt_sfs_info, mark_sfs_info);
|
|
}
|
|
|
|
END_XFORM_SKIP;
|
|
|
|
#endif
|