summaryrefslogtreecommitdiff
path: root/module/language/js-il
diff options
context:
space:
mode:
authorIan Price <ianprice90@googlemail.com>2017-08-14 16:52:28 +0100
committerIan Price <ianprice90@googlemail.com>2017-08-14 16:52:28 +0100
commite57f9bc06a765cd8bdc546bf591250974419166f (patch)
treebf2235a427f1495676101d19a44da3b97bae0b79 /module/language/js-il
parent166def2da08da12b776e65ee7086e45e6d8ca498 (diff)
downloadguile-e57f9bc06a765cd8bdc546bf591250974419166f.tar.gz
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.
Diffstat (limited to 'module/language/js-il')
-rw-r--r--module/language/js-il/runtime.js302
1 files changed, 231 insertions, 71 deletions
diff --git a/module/language/js-il/runtime.js b/module/language/js-il/runtime.js
index ec639a4c4..6ce8a7f8a 100644
--- a/module/language/js-il/runtime.js
+++ b/module/language/js-il/runtime.js
@@ -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];
+ 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 {
+ v = scm_private_lookup (module_name, sym);
}
- 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};
- } else {
- return r;
+ if (is_bound) {
+ // not_implemented_yet();
}
-};
-scheme.primitives["current-module"] = function () {
- return scheme.env;
+ return v;
};
+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) {