add -e flag
This commit is contained in:
@@ -435,6 +435,12 @@ if (args != null && (_init == null || !_init.program)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -e flag: eval script string directly
|
||||||
|
var _eval_script = (_init != null && _init.eval_script) ? _init.eval_script : null
|
||||||
|
if (_eval_script && !_init.program) {
|
||||||
|
_init.program = "-e"
|
||||||
|
}
|
||||||
|
|
||||||
use_cache['core/internal/os'] = os
|
use_cache['core/internal/os'] = os
|
||||||
|
|
||||||
// Extra env properties added as engine initializes (log, runtime fns, etc.)
|
// Extra env properties added as engine initializes (log, runtime fns, etc.)
|
||||||
@@ -1426,6 +1432,47 @@ function enet_check()
|
|||||||
// Finally, run the program
|
// Finally, run the program
|
||||||
actor_mod.setname(_cell.args.program)
|
actor_mod.setname(_cell.args.program)
|
||||||
|
|
||||||
|
if (_eval_script) {
|
||||||
|
// -e flag: compile and run inline script
|
||||||
|
$_.clock(_ => {
|
||||||
|
var env = {}
|
||||||
|
arrfor(array(runtime_env), function(k) { env[k] = runtime_env[k] })
|
||||||
|
env.use = function(path) {
|
||||||
|
var ck = 'core/' + path
|
||||||
|
var _use_core_result = null
|
||||||
|
var _use_core_ok = false
|
||||||
|
if (use_cache[ck]) return use_cache[ck]
|
||||||
|
var _try_core = function() {
|
||||||
|
_use_core_result = use_core(path)
|
||||||
|
_use_core_ok = true
|
||||||
|
} disruption {}
|
||||||
|
_try_core()
|
||||||
|
if (_use_core_ok && _use_core_result) return _use_core_result
|
||||||
|
var _shop_use = function() {
|
||||||
|
return shop.use(path, null)
|
||||||
|
} disruption {
|
||||||
|
log.error(`use('${path}') failed`)
|
||||||
|
disrupt
|
||||||
|
}
|
||||||
|
return _shop_use()
|
||||||
|
}
|
||||||
|
env.args = _cell.args.arg
|
||||||
|
env.log = log
|
||||||
|
env = stone(env)
|
||||||
|
|
||||||
|
var ast = analyze(_eval_script, "-e")
|
||||||
|
var val = null
|
||||||
|
var _compile = function() {
|
||||||
|
var mach_blob = compile_user_blob("-e", ast, null)
|
||||||
|
val = mach_load(mach_blob, env)
|
||||||
|
} disruption {
|
||||||
|
os.exit(1)
|
||||||
|
}
|
||||||
|
_compile()
|
||||||
|
})
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
var prog = _cell.args.program
|
var prog = _cell.args.program
|
||||||
if (ends_with(prog, '.cm')) {
|
if (ends_with(prog, '.cm')) {
|
||||||
os.print(`error: ${prog} is a module (.cm), not a program (.ce)\n`)
|
os.print(`error: ${prog} is a module (.cm), not a program (.ce)\n`)
|
||||||
@@ -1562,18 +1609,23 @@ $_.clock(_ => {
|
|||||||
var script = null
|
var script = null
|
||||||
var ast = null
|
var ast = null
|
||||||
var mach_blob = null
|
var mach_blob = null
|
||||||
if (cached_path && fd.is_file(cached_path)) {
|
var _compile = function() {
|
||||||
val = mach_load(fd.slurp(cached_path), env)
|
if (cached_path && fd.is_file(cached_path)) {
|
||||||
} else {
|
val = mach_load(fd.slurp(cached_path), env)
|
||||||
script = text(source_blob)
|
} else {
|
||||||
ast = analyze(script, prog_path)
|
script = text(source_blob)
|
||||||
mach_blob = compile_user_blob(prog, ast, pkg)
|
ast = analyze(script, prog_path)
|
||||||
if (cached_path) {
|
mach_blob = compile_user_blob(prog, ast, pkg)
|
||||||
ensure_build_dir()
|
if (cached_path) {
|
||||||
fd.slurpwrite(cached_path, mach_blob)
|
ensure_build_dir()
|
||||||
|
fd.slurpwrite(cached_path, mach_blob)
|
||||||
|
}
|
||||||
|
val = mach_load(mach_blob, env)
|
||||||
}
|
}
|
||||||
val = mach_load(mach_blob, env)
|
} disruption {
|
||||||
|
os.exit(1)
|
||||||
}
|
}
|
||||||
|
_compile()
|
||||||
if (val) {
|
if (val) {
|
||||||
log.error('Program must not return anything')
|
log.error('Program must not return anything')
|
||||||
disrupt
|
disrupt
|
||||||
|
|||||||
@@ -455,6 +455,7 @@ static void print_usage(const char *prog)
|
|||||||
printf(" --native Use AOT native code instead of bytecode\n");
|
printf(" --native Use AOT native code instead of bytecode\n");
|
||||||
printf(" --heap <size> Initial heap size (e.g. 256MB, 1GB)\n");
|
printf(" --heap <size> Initial heap size (e.g. 256MB, 1GB)\n");
|
||||||
printf(" --test [heap_size] Run C test suite\n");
|
printf(" --test [heap_size] Run C test suite\n");
|
||||||
|
printf(" -e <code> Evaluate code string as a program\n");
|
||||||
printf(" -h, --help Show this help message\n");
|
printf(" -h, --help Show this help message\n");
|
||||||
printf("\nEnvironment:\n");
|
printf("\nEnvironment:\n");
|
||||||
printf(" CELL_CORE Core path (default: <shop>/packages/core)\n");
|
printf(" CELL_CORE Core path (default: <shop>/packages/core)\n");
|
||||||
@@ -490,6 +491,7 @@ int cell_init(int argc, char **argv)
|
|||||||
size_t heap_size = 1024 * 1024; /* 1MB default */
|
size_t heap_size = 1024 * 1024; /* 1MB default */
|
||||||
const char *shop_override = NULL;
|
const char *shop_override = NULL;
|
||||||
const char *core_override = NULL;
|
const char *core_override = NULL;
|
||||||
|
const char *eval_script = NULL;
|
||||||
|
|
||||||
// Parse flags (order-independent)
|
// Parse flags (order-independent)
|
||||||
while (arg_start < argc && argv[arg_start][0] == '-') {
|
while (arg_start < argc && argv[arg_start][0] == '-') {
|
||||||
@@ -536,12 +538,19 @@ int cell_init(int argc, char **argv)
|
|||||||
} else if (strcmp(argv[arg_start], "--no-warn") == 0) {
|
} else if (strcmp(argv[arg_start], "--no-warn") == 0) {
|
||||||
warn_mode = 0;
|
warn_mode = 0;
|
||||||
arg_start++;
|
arg_start++;
|
||||||
|
} else if (strcmp(argv[arg_start], "-e") == 0) {
|
||||||
|
if (arg_start + 1 >= argc) {
|
||||||
|
printf("ERROR: -e requires a code string argument\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
eval_script = argv[arg_start + 1];
|
||||||
|
arg_start += 2;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg_start >= argc) {
|
if (arg_start >= argc && !eval_script) {
|
||||||
print_usage(argv[0]);
|
print_usage(argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -675,7 +684,7 @@ int cell_init(int argc, char **argv)
|
|||||||
JS_SetPropertyStr(ctx, env_ref.val, "actorsym", JS_DupValue(ctx, cli_rt->actor_sym_ref.val));
|
JS_SetPropertyStr(ctx, env_ref.val, "actorsym", JS_DupValue(ctx, cli_rt->actor_sym_ref.val));
|
||||||
tmp = js_core_json_use(ctx);
|
tmp = js_core_json_use(ctx);
|
||||||
JS_SetPropertyStr(ctx, env_ref.val, "json", tmp);
|
JS_SetPropertyStr(ctx, env_ref.val, "json", tmp);
|
||||||
if (native_mode || !warn_mode) {
|
if (native_mode || !warn_mode || eval_script) {
|
||||||
JSGCRef init_ref;
|
JSGCRef init_ref;
|
||||||
JS_AddGCRef(ctx, &init_ref);
|
JS_AddGCRef(ctx, &init_ref);
|
||||||
init_ref.val = JS_NewObject(ctx);
|
init_ref.val = JS_NewObject(ctx);
|
||||||
@@ -683,6 +692,10 @@ int cell_init(int argc, char **argv)
|
|||||||
JS_SetPropertyStr(ctx, init_ref.val, "native_mode", JS_NewBool(ctx, 1));
|
JS_SetPropertyStr(ctx, init_ref.val, "native_mode", JS_NewBool(ctx, 1));
|
||||||
if (!warn_mode)
|
if (!warn_mode)
|
||||||
JS_SetPropertyStr(ctx, init_ref.val, "no_warn", JS_NewBool(ctx, 1));
|
JS_SetPropertyStr(ctx, init_ref.val, "no_warn", JS_NewBool(ctx, 1));
|
||||||
|
if (eval_script) {
|
||||||
|
JSValue es = JS_NewString(ctx, eval_script);
|
||||||
|
JS_SetPropertyStr(ctx, init_ref.val, "eval_script", es);
|
||||||
|
}
|
||||||
JS_SetPropertyStr(ctx, env_ref.val, "init", init_ref.val);
|
JS_SetPropertyStr(ctx, env_ref.val, "init", init_ref.val);
|
||||||
JS_DeleteGCRef(ctx, &init_ref);
|
JS_DeleteGCRef(ctx, &init_ref);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
38
vm_suite.ce
38
vm_suite.ce
@@ -7434,11 +7434,39 @@ run("disruption propagation - runtime error direct vs nested", function() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// BUG: invoking a non-function (e.g. `var x = 42; x()`) crashes the VM
|
run("disruption propagation - invoke non-function at runtime", function() {
|
||||||
// instead of cleanly disrupting. The compiler warns "invoking int — will
|
// Use an array to hide the type from the compiler so it can't
|
||||||
// always disrupt" but the generated code causes a hard crash that kills
|
// statically prove the invoke will fail. This tests the VM's
|
||||||
// the entire actor, bypassing disruption handlers.
|
// MACH_FRAME runtime check, not the compile-time diagnostic.
|
||||||
// Cannot add a runtime test for this without crashing the suite.
|
var vals = [42, null, "hello", true]
|
||||||
|
var i = 0
|
||||||
|
var count = 0
|
||||||
|
for (i = 0; i < length(vals); i++) {
|
||||||
|
if (should_disrupt(function() { vals[i]() })) {
|
||||||
|
count = count + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq(count, 4, "all non-function values should disrupt when invoked")
|
||||||
|
})
|
||||||
|
|
||||||
|
run("disruption propagation - invoke non-function direct handler", function() {
|
||||||
|
// Same test but with a direct disruption handler to verify consistency.
|
||||||
|
var vals = [42, null, "hello", true]
|
||||||
|
var i = 0
|
||||||
|
var count = 0
|
||||||
|
var caught = false
|
||||||
|
var try_call = function() {
|
||||||
|
vals[i]()
|
||||||
|
} disruption {
|
||||||
|
caught = true
|
||||||
|
}
|
||||||
|
for (i = 0; i < length(vals); i++) {
|
||||||
|
caught = false
|
||||||
|
try_call()
|
||||||
|
if (caught) count = count + 1
|
||||||
|
}
|
||||||
|
assert_eq(count, 4, "all non-function values should disrupt with direct handler")
|
||||||
|
})
|
||||||
|
|
||||||
run("disruption propagation - comparison error direct vs nested", function() {
|
run("disruption propagation - comparison error direct vs nested", function() {
|
||||||
var via_should = should_disrupt(function() {
|
var via_should = should_disrupt(function() {
|
||||||
|
|||||||
Reference in New Issue
Block a user