Merge branch 'pitweb' into mcode2

This commit is contained in:
2026-02-10 17:29:03 -06:00
4 changed files with 753 additions and 511 deletions

View File

@@ -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
}