mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-20 10:40:19 +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;
|
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
|
// Modules
|
||||||
scheme.primitives["define!"] = function(sym) {
|
scheme.primitives["define!"] = function(sym) {
|
||||||
var b = new scheme.Box(scheme.UNDEFINED);
|
var mod = scm_current_module ();
|
||||||
scheme.env[sym.name] = b;
|
var v = scm_module_ensure_local_variable (mod, sym);
|
||||||
return b;
|
return v;
|
||||||
};
|
};
|
||||||
|
|
||||||
scheme.primitives["cache-current-module!"] = function (module, scope) {
|
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) {
|
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) {
|
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) {
|
if (!module_system_is_booted) {
|
||||||
cache = cache[module_name.car.name];
|
if (module_name instanceof scheme.Pair
|
||||||
}
|
&& module_name.car.name === "guile"
|
||||||
|
&& module_name.cdr === scheme.EMPTY) {
|
||||||
cache = cache[module_name.car.name];
|
v = scm_lookup (sym);
|
||||||
var r = cache[sym.name];
|
|
||||||
if (typeof r === 'undefined') {
|
|
||||||
throw {r : "cached-module-box", s : sym, m : module_name};
|
|
||||||
} else {
|
} else {
|
||||||
return r;
|
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 {
|
||||||
|
v = scm_private_lookup (module_name, sym);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_bound) {
|
||||||
|
// not_implemented_yet();
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
};
|
};
|
||||||
|
|
||||||
scheme.primitives["current-module"] = function () {
|
function scm_public_lookup(module_name, name) {
|
||||||
return scheme.env;
|
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) {
|
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
|
// bleh
|
||||||
scheme.initial_cont = function (x) { return x; };
|
scheme.initial_cont = function (x) { return x; };
|
||||||
scheme.primitives.return = function (x) { return x; };
|
scheme.primitives.return = function (x) { return x; };
|
||||||
|
@ -510,6 +680,8 @@ scheme.Fluid = function (x) {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var the_module = new scheme.Fluid(scheme.FALSE);
|
||||||
|
|
||||||
scheme.primitives["pop-fluid"] = function () {
|
scheme.primitives["pop-fluid"] = function () {
|
||||||
var frame = scheme.dynstack.shift();
|
var frame = scheme.dynstack.shift();
|
||||||
if (frame instanceof scheme.frame.Fluid) {
|
if (frame instanceof scheme.frame.Fluid) {
|
||||||
|
@ -639,20 +811,15 @@ scheme.frame.DynWind = function(wind, unwind) {
|
||||||
this.unwind = unwind;
|
this.unwind = unwind;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Module Cache
|
|
||||||
scheme.module_cache["guile"] = scheme.env;
|
|
||||||
|
|
||||||
function def_guile0 (name, fn) {
|
function def_guile0 (name, fn) {
|
||||||
var sym = new scheme.Symbol(name); // put in obarray
|
|
||||||
var clos = new scheme.Closure(fn, 0);
|
var clos = new scheme.Closure(fn, 0);
|
||||||
var box = new scheme.Box(clos);
|
def_guile_val(name, clos);
|
||||||
scheme.module_cache["guile"][name] = box;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function def_guile_val (name, val) {
|
function def_guile_val (name, val) {
|
||||||
var sym = new scheme.Symbol(name); // put in obarray
|
var sym = new scheme.Symbol(name); // put in obarray
|
||||||
var box = new scheme.Box(val);
|
var box = new scheme.Box(val);
|
||||||
scheme.module_cache["guile"][name] = box;
|
scm_pre_modules_obarray.table[name] = box;
|
||||||
};
|
};
|
||||||
|
|
||||||
function scm_list (self, cont) {
|
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) {
|
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) {
|
def_guile0("make-variable", function (self, cont, val) {
|
||||||
return cont(new scheme.Box(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) {
|
def_guile0("define!", function (self, cont, symbol, value) {
|
||||||
// FIXME: reuse module-define!
|
// FIXME: validate symbol
|
||||||
if (symbol.name in scheme.env) {
|
return cont(scm_module_define(scm_current_module(), symbol, value));
|
||||||
scheme.env[symbol.name].x = value;
|
|
||||||
} else {
|
|
||||||
scheme.env[symbol.name] = new scheme.Box(value);
|
|
||||||
}
|
|
||||||
return cont();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var boot_modules = {};
|
var boot_modules = {};
|
||||||
|
@ -1124,39 +1270,53 @@ boot_modules["ice-9/threads"] = function () {};
|
||||||
boot_modules["srfi/srfi-4"] = function () {};
|
boot_modules["srfi/srfi-4"] = function () {};
|
||||||
|
|
||||||
def_guile0("module-local-variable", function (self, cont, module, symbol) {
|
def_guile0("module-local-variable", function (self, cont, module, symbol) {
|
||||||
if (module instanceof scheme.Struct) {
|
// module system is booted, then validate module
|
||||||
// Assumes we get a module with a hashtable
|
// validate symbol
|
||||||
var obarray = scheme.primitives["struct-ref"](module, 0);
|
if (!scheme.is_true(module)) {
|
||||||
return cont(obarray.lookup(symbol, scheme.FALSE)); // hashq-ref
|
// hashq ref
|
||||||
} else {
|
return cont(scm_pre_modules_obarray.lookup(symbol, scheme.UNDEFINED));
|
||||||
// FIXME: could be #f, then should use the pre-mod obarray
|
|
||||||
console.log("module-local-variable needs real modules");
|
|
||||||
throw "fail";
|
|
||||||
}
|
}
|
||||||
|
// 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) {
|
def_guile0("module-variable", function (self, cont, module, symbol) {
|
||||||
if (module instanceof scheme.Struct) {
|
return cont(scm_module_variable(module, symbol));
|
||||||
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]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
def_guile0("%get-pre-modules-obarray", function (self, cont) {
|
def_guile0("%get-pre-modules-obarray", function (self, cont) {
|
||||||
var obarray = new scheme.HashTable();
|
return cont(scm_pre_modules_obarray);
|
||||||
obarray.table = scheme.env;
|
|
||||||
return cont(obarray);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
def_guile0("set-current-module", function (self, cont, module) {
|
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
|
// Stubs
|
||||||
function stub(name) {
|
function stub(name) {
|
||||||
function scm_fn (self, cont) {
|
function scm_fn (self, cont) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue