Merge branch 'cli_audit' into ir_artifact

This commit is contained in:
2026-02-12 17:20:45 -06:00
7 changed files with 2431 additions and 2970 deletions

View File

@@ -48,12 +48,12 @@ cell_main: source/main.c libcell_runtime.dylib
# Regenerate .mach bytecode when any .cm source changes
.mach.stamp: $(MACH_SOURCES)
./cell --core . regen.cm
./cell --dev regen
@touch $@
# Force-regenerate all .mach bytecode files
regen:
./cell --core . regen.cm
./cell --core . regen
@touch .mach.stamp
# Create the cell shop directories

View File

@@ -1,5 +1,5 @@
// Hidden vars come from env:
// CLI mode (cell_init): os, args, core_path, shop_path, emit_qbe, dump_mach
// CLI mode (cell_init): os, args, core_path, shop_path
// Actor spawn (script_startup): os, json, nota, wota, actorsym, init, core_path, shop_path
// args[0] = script name, args[1..] = user args
var load_internal = os.load_internal
@@ -54,7 +54,6 @@ use_cache['fold'] = fold_mod
var mcode_mod = boot_load("mcode", boot_env)
use_cache['mcode'] = mcode_mod
var streamline_mod = null
var qbe_emit_mod = null
// Warn if any .cm source is newer than its compiled bytecode
function check_mach_stale() {
@@ -101,7 +100,7 @@ function check_mach_stale() {
}
if (length(stale) > 0) {
print("warning: bytecode is stale for: " + text(stale, ", ") + "\n")
print("run 'make regen' or './cell --core . regen.cm' to update\n")
print("run 'make regen' to update\n")
}
}
check_mach_stale()
@@ -169,30 +168,13 @@ function load_module(name, env) {
}
// Load optimization pipeline modules (needs analyze to be defined)
var qbe_macros = null
streamline_mod = load_module("streamline", boot_env)
use_cache['streamline'] = streamline_mod
if (emit_qbe) {
qbe_macros = load_module("qbe", boot_env)
qbe_emit_mod = load_module("qbe_emit", boot_env)
use_cache['qbe'] = qbe_macros
use_cache['qbe_emit'] = qbe_emit_mod
}
// Run AST through mcode pipeline → register VM
function run_ast(name, ast, env) {
var compiled = mcode_mod(ast)
var optimized = streamline_mod(compiled)
var qbe_il = null
if (emit_qbe) {
qbe_il = qbe_emit_mod(optimized, qbe_macros)
print(qbe_il)
return null
}
if (dump_mach) {
mach_dump_mcode(name, json.encode(optimized), env)
return null
}
return mach_eval_mcode(name, json.encode(optimized), env)
}
@@ -277,45 +259,26 @@ function load_engine(env) {
var program = null
var user_args = []
var _j = 0
var script_file = null
var script = null
var ast = null
if (args != null) {
// CLI mode — parse args
// CLI mode — always run as actor program (.ce)
program = args[0]
if (!program) {
print("error: no program specified\n")
disrupt
}
_j = 1
while (_j < length(args)) {
push(user_args, args[_j])
_j = _j + 1
}
// Resolve script file: try .cm then .ce in CWD then core_path
script_file = program
if (!ends_with(script_file, '.ce') && !ends_with(script_file, '.cm'))
script_file = program + '.cm'
if (!fd.is_file(script_file))
script_file = core_path + '/' + program + '.cm'
if (!fd.is_file(script_file))
script_file = program + '.ce'
if (!fd.is_file(script_file))
script_file = core_path + '/' + program + '.ce'
if (ends_with(script_file, '.ce')) {
// Actor script — delegate to engine
load_engine({
os: os, actorsym: actorsym,
init: {program: program, arg: user_args},
core_path: core_path, shop_path: shop_path, json: json,
analyze: analyze, run_ast_fn: run_ast
})
} else {
// Module script — run directly
script = text(fd.slurp(script_file))
ast = analyze(script, script_file)
run_ast(program, ast, {use: use_fn, args: user_args, json: json})
}
load_engine({
os: os, actorsym: actorsym,
init: {program: program, arg: user_args},
core_path: core_path, shop_path: shop_path, json: json,
analyze: analyze, run_ast_fn: run_ast
})
} else {
// Actor spawn mode — load engine.cm with full actor env
load_engine({

File diff suppressed because it is too large Load Diff

View File

@@ -736,7 +736,7 @@ function report_to_overling(msg)
var program = _cell.args.program
if (!program) {
log.error('No program specified. Usage: cell <program.ce> [args...]')
log.error('No program specified. Usage: cell <program> [args...]')
os.exit(1)
}
@@ -827,7 +827,7 @@ actor_mod.setname(_cell.args.program)
var prog = _cell.args.program
if (ends_with(prog, '.cm')) {
os.print(`error: ${prog} is a module (.cm), not an actor (.ce). Run it with: cell --core <path> ${prog}\n`)
os.print(`error: ${prog} is a module (.cm), not a program (.ce)\n`)
os.exit(1)
}
if (ends_with(prog, '.ce')) prog = text(prog, 0, -3)
@@ -876,6 +876,8 @@ $_.clock(_ => {
env.use = function(path) {
var ck = 'core/' + path
if (use_cache[ck]) return use_cache[ck]
var core_mod = use_core(path)
if (core_mod) return core_mod
return shop.use(path, pkg)
}
env.args = _cell.args.arg

View File

@@ -6055,65 +6055,77 @@
},
{
"disruption_pc": 0,
"nr_slots": 22,
"nr_slots": 27,
"nr_close_slots": 0,
"instructions": [
["access", 3, "core/", 877, 14],
["access", 4, "core/", 877, 14],
"_nop_tc_1",
["jump", "add_ni_743", 877, 24],
["is_int", 6, 1, 877, 24],
["jump_false", 6, "add_ni_743", 877, 24],
["add_int", 4, 3, 1, 877, 24],
["is_int", 7, 1, 877, 24],
["jump_false", 7, "add_ni_743", 877, 24],
["add_int", 5, 4, 1, 877, 24],
["jump", "add_done_745", 877, 24],
"add_ni_743",
["is_text", 6, 1, 877, 24],
["jump_false", 6, "add_nt_744", 877, 24],
["concat", 4, 3, 1, 877, 24],
["is_text", 7, 1, 877, 24],
["jump_false", 7, "add_nt_744", 877, 24],
["concat", 5, 4, 1, 877, 24],
["jump", "add_done_745", 877, 24],
"add_nt_744",
["is_num", 5, 3, 877, 24],
["jump_false", 5, "add_err_746", 877, 24],
["is_num", 6, 1, 877, 24],
["is_num", 6, 4, 877, 24],
["jump_false", 6, "add_err_746", 877, 24],
["add_float", 4, 3, 1, 877, 24],
["is_num", 7, 1, 877, 24],
["jump_false", 7, "add_err_746", 877, 24],
["add_float", 5, 4, 1, 877, 24],
["jump", "add_done_745", 877, 24],
"add_err_746",
["disrupt", 877, 24],
"add_done_745",
["move", 2, 4, 877, 24],
["get", 7, 67, 2, 878, 9],
["load_dynamic", 8, 7, 2, 878, 19],
["jump_false", 8, "if_else_747", 878, 19],
["get", 9, 67, 2, 878, 31],
["load_dynamic", 10, 9, 2, 878, 41],
["return", 10, 878, 41],
["move", 2, 5, 877, 24],
["get", 8, 67, 2, 878, 9],
["load_dynamic", 9, 8, 2, 878, 19],
["jump_false", 9, "if_else_747", 878, 19],
["get", 10, 67, 2, 878, 31],
["load_dynamic", 11, 10, 2, 878, 41],
["return", 11, 878, 41],
["jump", "if_end_748", 878, 41],
"if_else_747",
"if_end_748",
["get", 11, 8, 1, 879, 27],
["get", 13, 50, 2, 879, 12],
["is_proxy", 14, 13, 879, 12],
["jump_false", 14, "record_path_749", 879, 12],
["null", 15, 879, 12],
["access", 16, "use", 879, 12],
["array", 17, 2, 1, 11, 879, 12],
["frame", 18, 13, 2, 879, 12],
["setarg", 18, 0, 15, 879, 12],
["setarg", 18, 1, 16, 879, 12],
["setarg", 18, 2, 17, 879, 12],
["invoke", 18, 12, 879, 12],
["jump", "call_done_750", 879, 12],
"record_path_749",
["load_field", 19, 13, "use", 879, 12],
["frame", 20, 19, 2, 879, 12],
["setarg", 20, 0, 13, 879, 12],
["setarg", 20, 1, 1, 879, 12],
["setarg", 20, 2, 11, 879, 12],
["invoke", 20, 12, 879, 12],
"call_done_750",
["return", 12, 879, 12],
["null", 21, 879, 12],
["return", 21, 879, 12]
["get", 13, 32, 2, 879, 20],
["frame", 14, 13, 1, 879, 20],
["null", 15, 879, 20],
["setarg", 14, 0, 15, 879, 20],
["setarg", 14, 1, 1, 879, 20],
["invoke", 14, 12, 879, 20],
["move", 3, 12, 879, 20],
["jump_false", 3, "if_else_749", 880, 9],
["return", 3, 880, 26],
["jump", "if_end_750", 880, 26],
"if_else_749",
"if_end_750",
["get", 16, 8, 1, 881, 27],
["get", 18, 50, 2, 881, 12],
["is_proxy", 19, 18, 881, 12],
["jump_false", 19, "record_path_751", 881, 12],
["null", 20, 881, 12],
["access", 21, "use", 881, 12],
["array", 22, 2, 1, 16, 881, 12],
["frame", 23, 18, 2, 881, 12],
["setarg", 23, 0, 20, 881, 12],
["setarg", 23, 1, 21, 881, 12],
["setarg", 23, 2, 22, 881, 12],
["invoke", 23, 17, 881, 12],
["jump", "call_done_752", 881, 12],
"record_path_751",
["load_field", 24, 18, "use", 881, 12],
["frame", 25, 24, 2, 881, 12],
["setarg", 25, 0, 18, 881, 12],
["setarg", 25, 1, 1, 881, 12],
["setarg", 25, 2, 16, 881, 12],
["invoke", 25, 17, 881, 12],
"call_done_752",
["return", 17, 881, 12],
["null", 26, 881, 12],
["return", 26, 881, 12]
],
"name": "<anonymous>",
"filename": "internal/engine.cm",
@@ -6427,32 +6439,32 @@
["move", 8, 83, 875, 45],
["function", 86, 56, 876, 13],
["store_field", 6, 86, "use", 876, 3],
["get", 87, 11, 1, 881, 14],
["load_field", 88, 87, "args", 881, 14],
["load_field", 89, 88, "arg", 881, 14],
["store_field", 6, 89, "args", 881, 3],
["get", 90, 63, 1, 882, 14],
["store_field", 6, 90, "log", 882, 3],
["get", 91, 68, 1, 884, 30],
["get", 93, 20, 1, 884, 21],
["is_proxy", 94, 93, 884, 21],
["jump_false", 94, "record_path_751", 884, 21],
["null", 95, 884, 21],
["access", 96, "slurp", 884, 21],
["array", 97, 1, 91, 884, 21],
["frame", 98, 93, 2, 884, 21],
["setarg", 98, 0, 95, 884, 21],
["setarg", 98, 1, 96, 884, 21],
["setarg", 98, 2, 97, 884, 21],
["invoke", 98, 92, 884, 21],
["jump", "call_done_752", 884, 21],
"record_path_751",
["load_field", 99, 93, "slurp", 884, 21],
["frame", 100, 99, 1, 884, 21],
["setarg", 100, 0, 93, 884, 21],
["setarg", 100, 1, 91, 884, 21],
["invoke", 100, 92, 884, 21],
"call_done_752",
["get", 87, 11, 1, 883, 14],
["load_field", 88, 87, "args", 883, 14],
["load_field", 89, 88, "arg", 883, 14],
["store_field", 6, 89, "args", 883, 3],
["get", 90, 63, 1, 884, 14],
["store_field", 6, 90, "log", 884, 3],
["get", 91, 68, 1, 886, 30],
["get", 93, 20, 1, 886, 21],
["is_proxy", 94, 93, 886, 21],
["jump_false", 94, "record_path_753", 886, 21],
["null", 95, 886, 21],
["access", 96, "slurp", 886, 21],
["array", 97, 1, 91, 886, 21],
["frame", 98, 93, 2, 886, 21],
["setarg", 98, 0, 95, 886, 21],
["setarg", 98, 1, 96, 886, 21],
["setarg", 98, 2, 97, 886, 21],
["invoke", 98, 92, 886, 21],
["jump", "call_done_754", 886, 21],
"record_path_753",
["load_field", 99, 93, "slurp", 886, 21],
["frame", 100, 99, 1, 886, 21],
["setarg", 100, 0, 93, 886, 21],
["setarg", 100, 1, 91, 886, 21],
["invoke", 100, 92, 886, 21],
"call_done_754",
[
"access",
102,
@@ -6461,16 +6473,16 @@
"kind": "name",
"make": "intrinsic"
},
884,
886,
16
],
["frame", 103, 102, 1, 884, 16],
["null", 104, 884, 16],
["setarg", 103, 0, 104, 884, 16],
["setarg", 103, 1, 92, 884, 16],
["invoke", 103, 101, 884, 16],
["move", 4, 101, 884, 16],
["get", 105, 68, 1, 885, 29],
["frame", 103, 102, 1, 886, 16],
["null", 104, 886, 16],
["setarg", 103, 0, 104, 886, 16],
["setarg", 103, 1, 92, 886, 16],
["invoke", 103, 101, 886, 16],
["move", 4, 101, 886, 16],
["get", 105, 68, 1, 887, 29],
[
"access",
107,
@@ -6479,17 +6491,17 @@
"kind": "name",
"make": "intrinsic"
},
885,
887,
13
],
["frame", 108, 107, 2, 885, 13],
["null", 109, 885, 13],
["setarg", 108, 0, 109, 885, 13],
["setarg", 108, 1, 4, 885, 13],
["setarg", 108, 2, 105, 885, 13],
["invoke", 108, 106, 885, 13],
["move", 10, 106, 885, 13],
["get", 110, 46, 1, 886, 24],
["frame", 108, 107, 2, 887, 13],
["null", 109, 887, 13],
["setarg", 108, 0, 109, 887, 13],
["setarg", 108, 1, 4, 887, 13],
["setarg", 108, 2, 105, 887, 13],
["invoke", 108, 106, 887, 13],
["move", 10, 106, 887, 13],
["get", 110, 46, 1, 888, 24],
[
"access",
112,
@@ -6498,44 +6510,44 @@
"kind": "name",
"make": "intrinsic"
},
886,
888,
13
],
["frame", 113, 112, 3, 886, 13],
["null", 114, 886, 13],
["setarg", 113, 0, 114, 886, 13],
["setarg", 113, 1, 110, 886, 13],
["setarg", 113, 2, 10, 886, 13],
["setarg", 113, 3, 6, 886, 13],
["invoke", 113, 111, 886, 13],
["move", 11, 111, 886, 13],
["jump_false", 11, "if_else_753", 887, 7],
["access", 115, "Program must not return anything", 888, 15],
["get", 117, 63, 1, 888, 5],
["is_proxy", 118, 117, 888, 5],
["jump_false", 118, "record_path_755", 888, 5],
["null", 119, 888, 5],
["access", 120, "error", 888, 5],
["array", 121, 1, 115, 888, 5],
["frame", 122, 117, 2, 888, 5],
["setarg", 122, 0, 119, 888, 5],
["setarg", 122, 1, 120, 888, 5],
["setarg", 122, 2, 121, 888, 5],
["invoke", 122, 116, 888, 5],
["jump", "call_done_756", 888, 5],
"record_path_755",
["load_field", 123, 117, "error", 888, 5],
["frame", 124, 123, 1, 888, 5],
["setarg", 124, 0, 117, 888, 5],
["setarg", 124, 1, 115, 888, 5],
["invoke", 124, 116, 888, 5],
"call_done_756",
["disrupt", 889, 5],
["jump", "if_end_754", 889, 5],
"if_else_753",
"if_end_754",
["null", 125, 889, 5],
["return", 125, 889, 5]
["frame", 113, 112, 3, 888, 13],
["null", 114, 888, 13],
["setarg", 113, 0, 114, 888, 13],
["setarg", 113, 1, 110, 888, 13],
["setarg", 113, 2, 10, 888, 13],
["setarg", 113, 3, 6, 888, 13],
["invoke", 113, 111, 888, 13],
["move", 11, 111, 888, 13],
["jump_false", 11, "if_else_755", 889, 7],
["access", 115, "Program must not return anything", 890, 15],
["get", 117, 63, 1, 890, 5],
["is_proxy", 118, 117, 890, 5],
["jump_false", 118, "record_path_757", 890, 5],
["null", 119, 890, 5],
["access", 120, "error", 890, 5],
["array", 121, 1, 115, 890, 5],
["frame", 122, 117, 2, 890, 5],
["setarg", 122, 0, 119, 890, 5],
["setarg", 122, 1, 120, 890, 5],
["setarg", 122, 2, 121, 890, 5],
["invoke", 122, 116, 890, 5],
["jump", "call_done_758", 890, 5],
"record_path_757",
["load_field", 123, 117, "error", 890, 5],
["frame", 124, 123, 1, 890, 5],
["setarg", 124, 0, 117, 890, 5],
["setarg", 124, 1, 115, 890, 5],
["invoke", 124, 116, 890, 5],
"call_done_758",
["disrupt", 891, 5],
["jump", "if_end_756", 891, 5],
"if_else_755",
"if_end_756",
["null", 125, 891, 5],
["return", 125, 891, 5]
],
"name": "<anonymous>",
"filename": "internal/engine.cm",
@@ -7367,7 +7379,7 @@
["move", 69, 324, 736, 15],
"_nop_bl_2",
["jump_true", 69, "if_else_638", 738, 6],
["access", 326, "No program specified. Usage: cell <program.ce> [args...]", 739, 13],
["access", 326, "No program specified. Usage: cell <program> [args...]", 739, 13],
["is_proxy", 328, 63, 739, 3],
["jump_false", 328, "record_path_640", 739, 3],
["null", 329, 739, 3],
@@ -7450,7 +7462,7 @@
["setarg", 359, 2, 357, 829, 5],
["invoke", 359, 358, 829, 5],
["jump_false", 358, "if_else_646", 829, 5],
["array", 361, 2, 46, 46, 1, 1],
["array", 361, 1, 46, 1, 1],
[
"access",
362,
@@ -7462,7 +7474,7 @@
1,
1
],
["access", 363, "error: {0} is a module (.cm), not an actor (.ce). Run it with: cell --core <path> {1}\n", 1, 1],
["access", 363, "error: {0} is a module (.cm), not a program (.ce)\n", 1, 1],
["frame", 365, 362, 2, 1, 1],
["null", 366, 1, 1],
["setarg", 365, 0, 366, 1, 1],
@@ -7915,7 +7927,7 @@
"if_end_695",
["function", 487, 57, 856, 10],
["is_proxy", 489, 2, 856, 1],
["jump_false", 489, "record_path_757", 856, 1],
["jump_false", 489, "record_path_759", 856, 1],
["null", 490, 856, 1],
["access", 491, "clock", 856, 1],
["array", 492, 1, 487, 856, 1],
@@ -7924,14 +7936,14 @@
["setarg", 493, 1, 491, 856, 1],
["setarg", 493, 2, 492, 856, 1],
["invoke", 493, 488, 856, 1],
["jump", "call_done_758", 856, 1],
"record_path_757",
["jump", "call_done_760", 856, 1],
"record_path_759",
["load_field", 494, 2, "clock", 856, 1],
["frame", 495, 494, 1, 856, 1],
["setarg", 495, 0, 2, 856, 1],
["setarg", 495, 1, 487, 856, 1],
["invoke", 495, 488, 856, 1],
"call_done_758",
"call_done_760",
["return", 488, 856, 1]
]
},

View File

@@ -1,5 +1,5 @@
// regen.cm — regenerate .cm.mcode files
// Run with: ./cell --core . regen.cm
// regen.ce — regenerate .mach bytecode files
// Run with: ./cell --core . regen
var fd = use("fd")
var json = use("json")

View File

@@ -277,13 +277,11 @@ static int run_test_suite(size_t heap_size)
static void print_usage(const char *prog)
{
printf("Usage: %s [options] <script> [args...]\n\n", prog);
printf("Run a cell script (.ce actor or .cm module).\n\n");
printf("Usage: %s [options] <program> [args...]\n\n", prog);
printf("Run a cell program (.ce actor).\n\n");
printf("Options:\n");
printf(" --core <path> Set core path directly (overrides CELL_CORE)\n");
printf(" --shop <path> Set shop path (overrides CELL_SHOP)\n");
printf(" --emit-qbe Emit QBE IL (for native compilation)\n");
printf(" --dump-mach Dump MACH bytecode disassembly\n");
printf(" --dev Dev mode (shop=.cell, core=.)\n");
printf(" --test [heap_size] Run C test suite\n");
printf(" -h, --help Show this help message\n");
@@ -316,24 +314,13 @@ int cell_init(int argc, char **argv)
}
/* Default: run script through bootstrap pipeline */
int emit_qbe = 0;
int dump_mach = 0;
int arg_start = 1;
const char *shop_override = NULL;
const char *core_override = NULL;
// Parse flags (order-independent)
while (arg_start < argc && argv[arg_start][0] == '-') {
if (strcmp(argv[arg_start], "--mcode") == 0) {
/* --mcode is now always on; accept and ignore for compat */
arg_start++;
} else if (strcmp(argv[arg_start], "--emit-qbe") == 0) {
emit_qbe = 1;
arg_start++;
} else if (strcmp(argv[arg_start], "--dump-mach") == 0) {
dump_mach = 1;
arg_start++;
} else if (strcmp(argv[arg_start], "--shop") == 0) {
if (strcmp(argv[arg_start], "--shop") == 0) {
if (arg_start + 1 >= argc) {
printf("ERROR: --shop requires a path argument\n");
return 1;
@@ -363,6 +350,11 @@ int cell_init(int argc, char **argv)
}
}
if (arg_start >= argc) {
print_usage(argv[0]);
return 1;
}
if (!find_cell_shop(shop_override, core_override)) return 1;
actor_initialize();
@@ -427,8 +419,9 @@ int cell_init(int argc, char **argv)
JS_SetPropertyStr(ctx, hidden_env, "core_path", JS_NewString(ctx, core_path));
JS_SetPropertyStr(ctx, hidden_env, "shop_path",
shop_path ? JS_NewString(ctx, shop_path) : JS_NULL);
JS_SetPropertyStr(ctx, hidden_env, "emit_qbe", JS_NewBool(ctx, emit_qbe));
JS_SetPropertyStr(ctx, hidden_env, "dump_mach", JS_NewBool(ctx, dump_mach));
/* TODO: remove after next 'make regen' — old bootstrap.mach reads these */
JS_SetPropertyStr(ctx, hidden_env, "emit_qbe", JS_FALSE);
JS_SetPropertyStr(ctx, hidden_env, "dump_mach", JS_FALSE);
JS_SetPropertyStr(ctx, hidden_env, "actorsym", JS_DupValue(ctx, cli_rt->actor_sym_ref.val));
JS_SetPropertyStr(ctx, hidden_env, "json", js_json_use(ctx));
JS_SetPropertyStr(ctx, hidden_env, "nota", js_nota_use(ctx));