Merge branch 'pitweb' into mcode2
This commit is contained in:
111
internal/shop.cm
111
internal/shop.cm
@@ -80,12 +80,12 @@ function get_packages_dir() {
|
||||
}
|
||||
|
||||
// Get the core directory (in the global shop)
|
||||
var core_package = 'core'
|
||||
|
||||
Shop.get_core_dir = function() {
|
||||
return get_packages_dir() + '/' + core_package
|
||||
}
|
||||
|
||||
var core_package = 'core'
|
||||
|
||||
// Get the links file path (in the global shop)
|
||||
function get_links_path() {
|
||||
return global_shop_path + '/link.toml'
|
||||
@@ -400,98 +400,54 @@ Shop.get_script_capabilities = function(path) {
|
||||
return Shop.script_inject_for(file_info)
|
||||
}
|
||||
|
||||
// Build the env object for a module, with runtime fns and $-prefixed capabilities.
|
||||
// Matches engine.cm's approach: env properties become free variables in the module.
|
||||
function inject_env(inject) {
|
||||
// Start with runtime functions from engine
|
||||
var env = {}
|
||||
var rt = my$_.os ? my$_.os.runtime_env : null
|
||||
if (rt) {
|
||||
arrfor(array(rt), function(k) { env[k] = rt[k] })
|
||||
}
|
||||
|
||||
// Add capability injections
|
||||
// Add capability injections with $ prefix
|
||||
var i = 0
|
||||
var inj = null
|
||||
var key = null
|
||||
for (i = 0; i < length(inject); i++) {
|
||||
inj = inject[i]
|
||||
key = trim(inj, '$')
|
||||
if (key == 'fd') env[key] = fd
|
||||
else env[key] = my$_[key]
|
||||
key = inj
|
||||
if (key && key[0] == '$') key = text(key, 1)
|
||||
if (key == 'fd') env['$fd'] = fd
|
||||
else env['$' + key] = my$_[key]
|
||||
}
|
||||
return env
|
||||
}
|
||||
|
||||
function inject_bindings_code(inject) {
|
||||
var lines = []
|
||||
|
||||
// Runtime function bindings
|
||||
var runtime_fns = ['logical', 'some', 'every', 'starts_with', 'ends_with',
|
||||
'actor', 'is_actor', 'log', 'send',
|
||||
'fallback', 'parallel', 'race', 'sequence']
|
||||
var i = 0
|
||||
var fn = null
|
||||
var inj = null
|
||||
var key = null
|
||||
for (i = 0; i < length(runtime_fns); i++) {
|
||||
fn = runtime_fns[i]
|
||||
push(lines, `var ${fn} = env["${fn}"];`)
|
||||
}
|
||||
|
||||
// Capability bindings ($delay, $start, etc.)
|
||||
for (i = 0; i < length(inject); i++) {
|
||||
inj = inject[i]
|
||||
key = trim(inj, '$')
|
||||
push(lines, `var $${key} = env["${key}"];`)
|
||||
}
|
||||
return text(lines, '\n')
|
||||
}
|
||||
|
||||
// Build the use function for a specific package context
|
||||
function make_use_fn_code(pkg_arg) {
|
||||
return `function(path) { return globalThis.use(path, ${pkg_arg}); }`
|
||||
}
|
||||
|
||||
// for script forms, path is the canonical path of the module
|
||||
var script_form = function(path, script, pkg, inject) {
|
||||
var pkg_arg = pkg ? "'" + pkg + "'" : 'null'
|
||||
var binds = inject_bindings_code(inject)
|
||||
|
||||
var fn = "(function setup_module(args, use, env){\n" +
|
||||
"def arg = args;\n" +
|
||||
"def PACKAGE = " + pkg_arg + ";\n" +
|
||||
binds + "\n" +
|
||||
script + "\n" +
|
||||
"})"
|
||||
return fn
|
||||
}
|
||||
|
||||
// Resolve module function, hashing it in the process
|
||||
// path is the exact path to the script file
|
||||
// Compile a module and return its bytecode blob.
|
||||
// The bytecode is cached on disk by content hash.
|
||||
function resolve_mod_fn(path, pkg) {
|
||||
if (!fd.is_file(path)) { print(`path ${path} is not a file`); disrupt }
|
||||
|
||||
var file_info = Shop.file_info(path)
|
||||
var file_pkg = file_info.package
|
||||
var inject = Shop.script_inject_for(file_info)
|
||||
var content = text(fd.slurp(path))
|
||||
var script = script_form(path, content, file_pkg, inject)
|
||||
|
||||
// Check cache for pre-compiled .mach blob
|
||||
var cached = pull_from_cache(stone(blob(script)))
|
||||
var cached = pull_from_cache(stone(blob(content)))
|
||||
var ast = null
|
||||
var ast_json = null
|
||||
var compiled = null
|
||||
if (cached) {
|
||||
return mach_load(cached)
|
||||
return cached
|
||||
}
|
||||
|
||||
// Compile via new pipeline
|
||||
var ast = analyze(script, path)
|
||||
var ast_json = shop_json.encode(ast)
|
||||
ast = analyze(content, path)
|
||||
ast_json = shop_json.encode(ast)
|
||||
|
||||
// Cache compiled binary
|
||||
var compiled = mach_compile_ast(path, ast_json)
|
||||
put_into_cache(stone(blob(script)), compiled)
|
||||
compiled = mach_compile_ast(path, ast_json)
|
||||
put_into_cache(stone(blob(content)), compiled)
|
||||
|
||||
// Evaluate to get the function object
|
||||
return mach_eval_ast(path, ast_json)
|
||||
return compiled
|
||||
}
|
||||
|
||||
// given a path and a package context
|
||||
@@ -854,29 +810,26 @@ function execute_module(info)
|
||||
var mod_resolve = info.mod_resolve
|
||||
|
||||
var used = null
|
||||
var context = null
|
||||
var file_info = null
|
||||
var inject = null
|
||||
var env = null
|
||||
var pkg = null
|
||||
var use_fn = null
|
||||
|
||||
if (mod_resolve.scope < 900) {
|
||||
context = null
|
||||
if (c_resolve.scope < 900) {
|
||||
context = call_c_module(c_resolve)
|
||||
}
|
||||
|
||||
// Get file info to determine inject list
|
||||
// Build env with runtime fns, capabilities, and use function
|
||||
file_info = Shop.file_info(mod_resolve.path)
|
||||
inject = Shop.script_inject_for(file_info)
|
||||
env = inject_env(inject)
|
||||
pkg = file_info.package
|
||||
use_fn = make_use_fn(pkg)
|
||||
env.use = make_use_fn(pkg)
|
||||
|
||||
// Call with signature: setup_module(args, use, env)
|
||||
// args is null for module loading
|
||||
used = call(mod_resolve.symbol, context, [null, use_fn, env])
|
||||
// Add C module as native context if available
|
||||
if (c_resolve.scope < 900) {
|
||||
env.native = call_c_module(c_resolve)
|
||||
}
|
||||
|
||||
// Load compiled bytecode with env
|
||||
used = mach_load(mod_resolve.symbol, env)
|
||||
} else if (c_resolve.scope < 900) {
|
||||
// C only
|
||||
used = call_c_module(c_resolve)
|
||||
@@ -884,12 +837,8 @@ function execute_module(info)
|
||||
print(`Module ${info.path} could not be found`); disrupt
|
||||
}
|
||||
|
||||
// if (is_function(used))
|
||||
// throw Error('C module loader returned a function; did you forget to call it?')
|
||||
|
||||
if (!used) { print(`Module ${info} returned null`); disrupt }
|
||||
|
||||
// stone(used)
|
||||
return used
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user