mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-19 18:20:22 +02:00
Reimplement JS module system primitives.
* module/language/js-il/runtime.js (scm_hash, scheme.HashTable): moved for bootstrapping purposes. (define!, cached-toplevel-box, cached-module-box, current-module, resolve): Reimplement primitives. (define!, module-local-variable, module-variable, %get-pre-modules-obarray, set-current-module): Reimplement builtin procedures. (make-undefined-variable): New builtin procedure. (scm_pre_modules_obarray, the_root_module, scm_public_lookup, scm_public_variable, scm_private_lookup, scm_current_module, scm_lookup, scm_module_ensure_local_variable, scm_module_variable, scm_module_define, module_system_is_booted, module_make_local_var_x_var, the_module, k_ensure, resolve_module_var, scm_post_boot_init_modules): New helper variables and procedures, designed to resemble C versions. (scheme.call): New helper procedure (def_guile0, def_guile_val): Reimplement helper procedure.
This commit is contained in:
parent
166def2da0
commit
e57f9bc06a
1 changed files with 232 additions and 72 deletions
|
@ -324,11 +324,36 @@ scheme.Syntax = function (expr, wrap, module) {
|
|||
return this;
|
||||
};
|
||||
|
||||
// Hashtables
|
||||
var scm_hash = function (obj) {
|
||||
if (obj instanceof scheme.Symbol) {
|
||||
return obj.name;
|
||||
}
|
||||
|
||||
console.log("Can't hash object", obj);
|
||||
throw "BadHash";
|
||||
};
|
||||
|
||||
scheme.HashTable = function ( ) {
|
||||
// HashTable definition needs to come before scm_pre_modules_obarray
|
||||
this.table = {};
|
||||
this.lookup = function (obj, dflt) {
|
||||
var hash = scm_hash(obj);
|
||||
if (this.table.hasOwnProperty(hash)) {
|
||||
return this.table[hash];
|
||||
} else {
|
||||
return dflt;
|
||||
}
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// Modules
|
||||
scheme.primitives["define!"] = function(sym) {
|
||||
var b = new scheme.Box(scheme.UNDEFINED);
|
||||
scheme.env[sym.name] = b;
|
||||
return b;
|
||||
var mod = scm_current_module ();
|
||||
var v = scm_module_ensure_local_variable (mod, sym);
|
||||
return v;
|
||||
};
|
||||
|
||||
scheme.primitives["cache-current-module!"] = function (module, scope) {
|
||||
|
@ -336,33 +361,178 @@ scheme.primitives["cache-current-module!"] = function (module, scope) {
|
|||
};
|
||||
|
||||
scheme.primitives["cached-toplevel-box"] = function (scope, sym, is_bound) {
|
||||
return scheme.cache[scope][sym.name];
|
||||
var module = scheme.cache[scope]; // FIXME: what if not there?
|
||||
|
||||
if (!scheme.is_true(module)) {
|
||||
module = scm_the_root_module();
|
||||
}
|
||||
|
||||
var v = scm_module_lookup(module, sym);
|
||||
|
||||
if (is_bound) {
|
||||
// not_implemented_yet();
|
||||
}
|
||||
|
||||
return v;
|
||||
};
|
||||
|
||||
var scm_pre_modules_obarray = new scheme.HashTable();
|
||||
var the_root_module;
|
||||
|
||||
function scm_the_root_module() {
|
||||
if (module_system_is_booted)
|
||||
return the_root_module.x;
|
||||
else
|
||||
return scheme.FALSE;
|
||||
}
|
||||
|
||||
scheme.primitives["cached-module-box"] = function (module_name, sym, is_public, is_bound) {
|
||||
var cache = scheme.module_cache;
|
||||
var v;
|
||||
|
||||
while (scheme.EMPTY != module_name.cdr) {
|
||||
cache = cache[module_name.car.name];
|
||||
}
|
||||
|
||||
cache = cache[module_name.car.name];
|
||||
var r = cache[sym.name];
|
||||
if (typeof r === 'undefined') {
|
||||
throw {r : "cached-module-box", s : sym, m : module_name};
|
||||
if (!module_system_is_booted) {
|
||||
if (module_name instanceof scheme.Pair
|
||||
&& module_name.car.name === "guile"
|
||||
&& module_name.cdr === scheme.EMPTY) {
|
||||
v = scm_lookup (sym);
|
||||
} else {
|
||||
not_implemented_yet();
|
||||
}
|
||||
} else if (sym.name === "equal?") {
|
||||
// FIXME: this hack exists to work around a miscompilation of
|
||||
// equal? which is not being handled as a toplevel reference.
|
||||
// This leads to an infinite loop in the temporary definition of
|
||||
// resolve-module, which is called by cache-module-box.
|
||||
v = scm_pre_modules_obarray.table["equal?"];
|
||||
} else if (scheme.is_true(is_public)) {
|
||||
v = scm_public_lookup (module_name, sym);
|
||||
} else {
|
||||
return r;
|
||||
v = scm_private_lookup (module_name, sym);
|
||||
}
|
||||
|
||||
if (is_bound) {
|
||||
// not_implemented_yet();
|
||||
}
|
||||
|
||||
return v;
|
||||
};
|
||||
|
||||
scheme.primitives["current-module"] = function () {
|
||||
return scheme.env;
|
||||
};
|
||||
function scm_public_lookup(module_name, name) {
|
||||
var v = scm_public_variable (module_name, name);
|
||||
// if false, error
|
||||
return v;
|
||||
}
|
||||
|
||||
function scm_public_variable(module_name, name) {
|
||||
var mod = scheme.call(resolve_module_var.x, module_name, k_ensure, scheme.FALSE);
|
||||
|
||||
// if (scm_is_false (mod))
|
||||
// scm_misc_error ("public-lookup", "Module named ~s does not exist",
|
||||
// scm_list_1 (module_name));
|
||||
|
||||
// iface = scm_module_public_interface (mod);
|
||||
|
||||
// if (scm_is_false (iface))
|
||||
// scm_misc_error ("public-lookup", "Module ~s has no public interface",
|
||||
// scm_list_1 (mod));
|
||||
|
||||
return scm_module_variable (mod, name);
|
||||
}
|
||||
|
||||
function scm_private_lookup(module_name, sym) {
|
||||
// FIXME: scm_private_variable + miscerror if not bound
|
||||
return scm_public_lookup(module_name, sym);
|
||||
}
|
||||
|
||||
scheme.primitives["current-module"] = scm_current_module;
|
||||
|
||||
scheme.primitives["resolve"] = function (sym, is_bound) {
|
||||
return scheme.env[sym.name];
|
||||
var v = scm_lookup(sym);
|
||||
|
||||
if (is_bound) {
|
||||
// not_implemented_yet();
|
||||
};
|
||||
|
||||
return v;
|
||||
};
|
||||
|
||||
function scm_current_module() {
|
||||
if (module_system_is_booted) {
|
||||
return the_module.value;
|
||||
} else {
|
||||
return scheme.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
function scm_lookup(sym) {
|
||||
return scm_module_lookup(scm_current_module(), sym);
|
||||
};
|
||||
|
||||
scheme.call = function (func) {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
args.unshift(scheme.initial_cont);
|
||||
args.unshift(func);
|
||||
return func.fun.apply(func, args);
|
||||
};
|
||||
|
||||
function scm_module_ensure_local_variable(module, sym) {
|
||||
if (module_system_is_booted) {
|
||||
// SCM_VALIDATE_MODULE (1, module);
|
||||
// SCM_VALIDATE_SYMBOL (2, sym);
|
||||
// FIXME: this will need a specific continuation
|
||||
return scheme.call(module_make_local_var_x_var.x, module, sym);
|
||||
} else {
|
||||
var box = scm_pre_modules_obarray.lookup(sym, false);
|
||||
if (box) {
|
||||
return box;
|
||||
} else {
|
||||
var v = new scheme.Box(scheme.UNDEFINED);
|
||||
scm_pre_modules_obarray.table[sym.name] = v;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function scm_module_variable(module, sym) {
|
||||
// if booted, validate module
|
||||
// validate symbol
|
||||
if (scheme.is_true(module)) {
|
||||
// 1. Check Module Obarray
|
||||
if (module instanceof scheme.Struct) {
|
||||
var obarray = module.fields[0];
|
||||
return obarray.lookup(sym, scheme.UNDEFINED);
|
||||
}
|
||||
// 2. Search among the imported variables
|
||||
// 3. Query the custom binder
|
||||
// 4. Return False
|
||||
not_implemented_yet();
|
||||
}
|
||||
|
||||
return scm_pre_modules_obarray.lookup(sym, scheme.UNDEFINED);
|
||||
}
|
||||
|
||||
function scm_module_define(module, sym, val) {
|
||||
var v = scm_module_ensure_local_variable(module, sym);
|
||||
v.x = val;
|
||||
return v;
|
||||
}
|
||||
|
||||
function scm_module_lookup(module, sym) {
|
||||
var v = scm_module_variable(module, sym);
|
||||
if (scheme.is_true(v)) {
|
||||
return v;
|
||||
}
|
||||
not_implemented_yet(); // FIXME: unbound
|
||||
}
|
||||
|
||||
|
||||
var module_system_is_booted = false;
|
||||
|
||||
var module_make_local_var_x_var =
|
||||
scm_module_define(scm_current_module(),
|
||||
new scheme.Symbol("module-make-local-var!"),
|
||||
scheme.UNDEFINED);
|
||||
|
||||
|
||||
// bleh
|
||||
scheme.initial_cont = function (x) { return x; };
|
||||
scheme.primitives.return = function (x) { return x; };
|
||||
|
@ -510,6 +680,8 @@ scheme.Fluid = function (x) {
|
|||
return this;
|
||||
};
|
||||
|
||||
var the_module = new scheme.Fluid(scheme.FALSE);
|
||||
|
||||
scheme.primitives["pop-fluid"] = function () {
|
||||
var frame = scheme.dynstack.shift();
|
||||
if (frame instanceof scheme.frame.Fluid) {
|
||||
|
@ -639,20 +811,15 @@ scheme.frame.DynWind = function(wind, unwind) {
|
|||
this.unwind = unwind;
|
||||
};
|
||||
|
||||
// Module Cache
|
||||
scheme.module_cache["guile"] = scheme.env;
|
||||
|
||||
function def_guile0 (name, fn) {
|
||||
var sym = new scheme.Symbol(name); // put in obarray
|
||||
var clos = new scheme.Closure(fn, 0);
|
||||
var box = new scheme.Box(clos);
|
||||
scheme.module_cache["guile"][name] = box;
|
||||
def_guile_val(name, clos);
|
||||
};
|
||||
|
||||
function def_guile_val (name, val) {
|
||||
var sym = new scheme.Symbol(name); // put in obarray
|
||||
var box = new scheme.Box(val);
|
||||
scheme.module_cache["guile"][name] = box;
|
||||
scm_pre_modules_obarray.table[name] = box;
|
||||
};
|
||||
|
||||
function scm_list (self, cont) {
|
||||
|
@ -1041,28 +1208,9 @@ def_guile0("hashq-remove!", function (self, cont, htable, key) {
|
|||
}
|
||||
});
|
||||
|
||||
var scm_hash = function (obj) {
|
||||
if (obj instanceof scheme.Symbol) {
|
||||
return obj.name;
|
||||
}
|
||||
|
||||
console.log("Can't hash object", obj);
|
||||
throw "BadHash";
|
||||
};
|
||||
|
||||
scheme.HashTable = function ( ) {
|
||||
this.table = {};
|
||||
this.lookup = function (obj, dflt) {
|
||||
var hash = scm_hash(obj);
|
||||
if (this.table.hasOwnProperty(hash)) {
|
||||
return this.table[hash];
|
||||
} else {
|
||||
return dflt;
|
||||
}
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
def_guile0("hashq-ref", function(self, cont, obarray, sym, dflt) {
|
||||
|
||||
|
@ -1094,15 +1242,13 @@ def_guile0("hash-for-each", function (self, cont, module, symbol) {
|
|||
def_guile0("make-variable", function (self, cont, val) {
|
||||
return cont(new scheme.Box(val));
|
||||
});
|
||||
def_guile0("make-undefined-variable", function (self, cont, val) {
|
||||
return cont(new scheme.Box(scheme.UNDEFINED));
|
||||
});
|
||||
|
||||
def_guile0("define!", function (self, cont, symbol, value) {
|
||||
// FIXME: reuse module-define!
|
||||
if (symbol.name in scheme.env) {
|
||||
scheme.env[symbol.name].x = value;
|
||||
} else {
|
||||
scheme.env[symbol.name] = new scheme.Box(value);
|
||||
}
|
||||
return cont();
|
||||
// FIXME: validate symbol
|
||||
return cont(scm_module_define(scm_current_module(), symbol, value));
|
||||
});
|
||||
|
||||
var boot_modules = {};
|
||||
|
@ -1124,39 +1270,53 @@ boot_modules["ice-9/threads"] = function () {};
|
|||
boot_modules["srfi/srfi-4"] = function () {};
|
||||
|
||||
def_guile0("module-local-variable", function (self, cont, module, symbol) {
|
||||
if (module instanceof scheme.Struct) {
|
||||
// Assumes we get a module with a hashtable
|
||||
var obarray = scheme.primitives["struct-ref"](module, 0);
|
||||
return cont(obarray.lookup(symbol, scheme.FALSE)); // hashq-ref
|
||||
} else {
|
||||
// FIXME: could be #f, then should use the pre-mod obarray
|
||||
console.log("module-local-variable needs real modules");
|
||||
throw "fail";
|
||||
// module system is booted, then validate module
|
||||
// validate symbol
|
||||
if (!scheme.is_true(module)) {
|
||||
// hashq ref
|
||||
return cont(scm_pre_modules_obarray.lookup(symbol, scheme.UNDEFINED));
|
||||
}
|
||||
// 1. check module_obarray
|
||||
var obarray = module.fields[0]; // SCM_MODULE_OBARRAY
|
||||
var b = obarray.lookup(symbol, scheme.UNDEFINED);
|
||||
if (b != scheme.UNDEFINED) { // is_true
|
||||
return cont(b);
|
||||
}
|
||||
|
||||
// FIXME: check binders
|
||||
return cont(scheme.FALSE);
|
||||
});
|
||||
|
||||
def_guile0("module-variable", function (self, cont, module, symbol) {
|
||||
if (module instanceof scheme.Struct) {
|
||||
console.log("FIXME: should only be called pre-bootstrap");
|
||||
throw "fail";
|
||||
}
|
||||
if (module instanceof scheme.HashTable) {
|
||||
console.log("modvar htable");
|
||||
throw "fail";
|
||||
}
|
||||
return cont(module[symbol.name]);
|
||||
return cont(scm_module_variable(module, symbol));
|
||||
});
|
||||
|
||||
def_guile0("%get-pre-modules-obarray", function (self, cont) {
|
||||
var obarray = new scheme.HashTable();
|
||||
obarray.table = scheme.env;
|
||||
return cont(obarray);
|
||||
return cont(scm_pre_modules_obarray);
|
||||
});
|
||||
|
||||
def_guile0("set-current-module", function (self, cont, module) {
|
||||
return cont(scheme.FALSE);
|
||||
|
||||
if (!module_system_is_booted) {
|
||||
scm_post_boot_init_modules ();
|
||||
}
|
||||
// SCM_VALIDATE_MODULE (SCM_ARG1, module);
|
||||
|
||||
var old = scm_current_module ();
|
||||
the_module.value = module;
|
||||
return cont(old);
|
||||
});
|
||||
|
||||
var k_ensure;
|
||||
var resolve_module_var;
|
||||
|
||||
function scm_post_boot_init_modules() {
|
||||
module_system_is_booted = true;
|
||||
the_root_module = scm_lookup (new scheme.Symbol("the-root-module"));
|
||||
k_ensure = new scheme.Keyword("ensure");
|
||||
resolve_module_var = scm_lookup (new scheme.Symbol("resolve-module"));
|
||||
}
|
||||
|
||||
// Stubs
|
||||
function stub(name) {
|
||||
function scm_fn (self, cont) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue