bootstrap
This commit is contained in:
40
internal/bootstrap.cm
Normal file
40
internal/bootstrap.cm
Normal file
@@ -0,0 +1,40 @@
|
||||
// Hidden vars (os, program) come from env
|
||||
var load_internal = os.load_internal
|
||||
function use_embed(name) {
|
||||
return load_internal("js_" + name + "_use")
|
||||
}
|
||||
|
||||
var fd = use_embed('fd')
|
||||
|
||||
var use_cache = {}
|
||||
use_cache['fd'] = fd
|
||||
use_cache['os'] = os
|
||||
|
||||
function use(path) {
|
||||
if (use_cache[path])
|
||||
return use_cache[path];
|
||||
|
||||
var file_path = path + '.cm'
|
||||
var script = null
|
||||
var result = null
|
||||
var exports = null
|
||||
|
||||
if (fd.is_file(file_path)) {
|
||||
script = text(fd.slurp(file_path))
|
||||
exports = {}
|
||||
mach_eval(path, script, {use: use, exports: exports})
|
||||
use_cache[path] = exports
|
||||
return exports
|
||||
}
|
||||
|
||||
// Try embedded C module
|
||||
result = use_embed(replace(path, '/', '_'))
|
||||
use_cache[path] = result
|
||||
return result
|
||||
}
|
||||
|
||||
// Load and run the user's program
|
||||
var blob = fd.slurp(program)
|
||||
stone(blob)
|
||||
var script = text(blob)
|
||||
mach_eval(program, script, {use: use})
|
||||
@@ -578,7 +578,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
||||
JSValue js_os_use(JSContext *js) {
|
||||
JS_NewClassID(&js_dylib_class_id);
|
||||
JS_NewClass(js, js_dylib_class_id, &js_dylib_class);
|
||||
|
||||
|
||||
JSValue mod = JS_NewObject(js);
|
||||
JS_SetPropertyFunctionList(js,mod,js_os_funcs,countof(js_os_funcs));
|
||||
return mod;
|
||||
|
||||
130
source/cell.c
130
source/cell.c
@@ -558,59 +558,54 @@ int cell_init(int argc, char **argv)
|
||||
|
||||
/* Check for --run-mcode flag to execute via MCODE interpreter */
|
||||
if (argc >= 3 && strcmp(argv[1], "--run-mcode") == 0) {
|
||||
const char *script_or_file = argv[2];
|
||||
char *script = NULL;
|
||||
char *allocated_script = NULL;
|
||||
const char *filename = "<eval>";
|
||||
const char *filename = argv[2];
|
||||
if (!find_cell_shop()) return 1;
|
||||
|
||||
struct stat st;
|
||||
if (stat(script_or_file, &st) == 0 && S_ISREG(st.st_mode)) {
|
||||
FILE *f = fopen(script_or_file, "r");
|
||||
if (!f) { printf("Failed to open file: %s\n", script_or_file); return 1; }
|
||||
allocated_script = malloc(st.st_size + 1);
|
||||
if (!allocated_script) { fclose(f); printf("Failed to allocate memory\n"); return 1; }
|
||||
size_t read_size = fread(allocated_script, 1, st.st_size, f);
|
||||
fclose(f);
|
||||
allocated_script[read_size] = '\0';
|
||||
script = allocated_script;
|
||||
filename = script_or_file;
|
||||
} else {
|
||||
script = (char *)script_or_file;
|
||||
}
|
||||
|
||||
cJSON *ast = JS_ASTTree(script, strlen(script), filename);
|
||||
if (!ast) {
|
||||
printf("Failed to parse AST\n");
|
||||
free(allocated_script);
|
||||
size_t boot_size;
|
||||
char *boot_data = load_core_file("internal/bootstrap.cm", &boot_size);
|
||||
if (!boot_data) {
|
||||
printf("ERROR: Could not load internal/bootstrap.cm from %s\n", core_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (print_tree_errors(ast)) {
|
||||
cJSON_Delete(ast); free(allocated_script);
|
||||
cJSON *boot_ast = JS_ASTTree(boot_data, boot_size, "internal/bootstrap.cm");
|
||||
free(boot_data);
|
||||
if (!boot_ast) {
|
||||
printf("Failed to parse internal/bootstrap.cm\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
cJSON *mcode = JS_McodeTree(ast);
|
||||
cJSON_Delete(ast);
|
||||
if (print_tree_errors(boot_ast)) {
|
||||
cJSON_Delete(boot_ast);
|
||||
return 1;
|
||||
}
|
||||
|
||||
cJSON *mcode = JS_McodeTree(boot_ast);
|
||||
cJSON_Delete(boot_ast);
|
||||
|
||||
if (!mcode) {
|
||||
printf("Failed to generate MCODE\n");
|
||||
free(allocated_script);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (print_tree_errors(mcode)) {
|
||||
cJSON_Delete(mcode); free(allocated_script);
|
||||
cJSON_Delete(mcode);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Use a larger heap context for execution */
|
||||
JSRuntime *rt = JS_NewRuntime();
|
||||
if (!rt) { printf("Failed to create JS runtime\n"); cJSON_Delete(mcode); free(allocated_script); return 1; }
|
||||
JSContext *ctx = JS_NewContextWithHeapSize(rt, 64 * 1024);
|
||||
if (!ctx) { printf("Failed to create execution context\n"); cJSON_Delete(mcode); JS_FreeRuntime(rt); free(allocated_script); return 1; }
|
||||
if (!rt) { printf("Failed to create JS runtime\n"); cJSON_Delete(mcode); return 1; }
|
||||
JSContext *ctx = JS_NewContextWithHeapSize(rt, 256 * 1024);
|
||||
if (!ctx) { printf("Failed to create execution context\n"); cJSON_Delete(mcode); JS_FreeRuntime(rt); return 1; }
|
||||
|
||||
JSValue result = JS_CallMcodeTree(ctx, mcode); /* takes ownership of mcode */
|
||||
JS_FreeValue(ctx, js_blob_use(ctx));
|
||||
|
||||
JSValue hidden_env = JS_NewObject(ctx);
|
||||
JS_SetPropertyStr(ctx, hidden_env, "os", js_os_use(ctx));
|
||||
JS_SetPropertyStr(ctx, hidden_env, "program", JS_NewString(ctx, filename));
|
||||
hidden_env = JS_Stone(ctx, hidden_env);
|
||||
|
||||
JSValue result = JS_CallMcodeTreeEnv(ctx, mcode, hidden_env);
|
||||
|
||||
if (JS_IsException(result)) {
|
||||
JSValue exc = JS_GetException(ctx);
|
||||
@@ -637,7 +632,6 @@ int cell_init(int argc, char **argv)
|
||||
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
free(allocated_script);
|
||||
return JS_IsException(result) ? 1 : 0;
|
||||
}
|
||||
|
||||
@@ -707,61 +701,50 @@ int cell_init(int argc, char **argv)
|
||||
|
||||
/* Check for --mach-run flag to compile and run through MACH VM */
|
||||
if (argc >= 3 && strcmp(argv[1], "--mach-run") == 0) {
|
||||
const char *script_or_file = argv[2];
|
||||
char *script = NULL;
|
||||
char *allocated_script = NULL;
|
||||
const char *filename = "<eval>";
|
||||
const char *filename = argv[2];
|
||||
if (!find_cell_shop()) return 1;
|
||||
|
||||
struct stat st;
|
||||
if (stat(script_or_file, &st) == 0 && S_ISREG(st.st_mode)) {
|
||||
FILE *f = fopen(script_or_file, "r");
|
||||
if (!f) {
|
||||
printf("Failed to open file: %s\n", script_or_file);
|
||||
return 1;
|
||||
}
|
||||
allocated_script = malloc(st.st_size + 1);
|
||||
if (!allocated_script) {
|
||||
fclose(f);
|
||||
printf("Failed to allocate memory for script\n");
|
||||
return 1;
|
||||
}
|
||||
size_t read_size = fread(allocated_script, 1, st.st_size, f);
|
||||
fclose(f);
|
||||
allocated_script[read_size] = '\0';
|
||||
script = allocated_script;
|
||||
filename = script_or_file;
|
||||
} else {
|
||||
script = (char *)script_or_file;
|
||||
}
|
||||
|
||||
cJSON *ast = JS_ASTTree(script, strlen(script), filename);
|
||||
if (!ast) {
|
||||
printf("Failed to parse AST\n");
|
||||
free(allocated_script);
|
||||
size_t boot_size;
|
||||
char *boot_data = load_core_file("internal/bootstrap.cm", &boot_size);
|
||||
if (!boot_data) {
|
||||
printf("ERROR: Could not load internal/bootstrap.cm from %s\n", core_path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (print_tree_errors(ast)) {
|
||||
cJSON_Delete(ast);
|
||||
free(allocated_script);
|
||||
cJSON *boot_ast = JS_ASTTree(boot_data, boot_size, "internal/bootstrap.cm");
|
||||
free(boot_data);
|
||||
if (!boot_ast) {
|
||||
printf("Failed to parse internal/bootstrap.cm\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (print_tree_errors(boot_ast)) {
|
||||
cJSON_Delete(boot_ast);
|
||||
return 1;
|
||||
}
|
||||
|
||||
JSRuntime *rt = JS_NewRuntime();
|
||||
if (!rt) {
|
||||
printf("Failed to create JS runtime\n");
|
||||
cJSON_Delete(ast); free(allocated_script);
|
||||
cJSON_Delete(boot_ast);
|
||||
return 1;
|
||||
}
|
||||
JSContext *ctx = JS_NewContext(rt);
|
||||
JSContext *ctx = JS_NewContextWithHeapSize(rt, 256 * 1024);
|
||||
if (!ctx) {
|
||||
printf("Failed to create JS context\n");
|
||||
cJSON_Delete(ast); JS_FreeRuntime(rt); free(allocated_script);
|
||||
cJSON_Delete(boot_ast); JS_FreeRuntime(rt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
JSValue result = JS_RunMachTree(ctx, ast, JS_NULL);
|
||||
cJSON_Delete(ast);
|
||||
JS_FreeValue(ctx, js_blob_use(ctx));
|
||||
|
||||
JSValue hidden_env = JS_NewObject(ctx);
|
||||
JS_SetPropertyStr(ctx, hidden_env, "os", js_os_use(ctx));
|
||||
JS_SetPropertyStr(ctx, hidden_env, "program", JS_NewString(ctx, filename));
|
||||
hidden_env = JS_Stone(ctx, hidden_env);
|
||||
|
||||
JSValue result = JS_RunMachTree(ctx, boot_ast, hidden_env);
|
||||
cJSON_Delete(boot_ast);
|
||||
|
||||
int exit_code = 0;
|
||||
if (JS_IsException(result)) {
|
||||
@@ -796,7 +779,6 @@ int cell_init(int argc, char **argv)
|
||||
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
free(allocated_script);
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
|
||||
@@ -3444,6 +3444,34 @@ JSValue JS_CallMcodeTree(JSContext *ctx, cJSON *root) {
|
||||
return result;
|
||||
}
|
||||
|
||||
JSValue JS_CallMcodeTreeEnv(JSContext *ctx, cJSON *root, JSValue env) {
|
||||
if (!root) return JS_ThrowSyntaxError(ctx, "invalid MCODE tree");
|
||||
|
||||
cJSON *main_obj = cJSON_GetObjectItemCaseSensitive(root, "main");
|
||||
if (!main_obj) {
|
||||
cJSON_Delete(root);
|
||||
return JS_ThrowSyntaxError(ctx, "MCODE tree missing 'main' section");
|
||||
}
|
||||
|
||||
cJSON *functions = cJSON_GetObjectItemCaseSensitive(root, "functions");
|
||||
|
||||
/* Parse main code */
|
||||
JSMCode *code = jsmcode_parse(main_obj, functions);
|
||||
if (!code) {
|
||||
cJSON_Delete(root);
|
||||
return JS_ThrowInternalError(ctx, "failed to parse MCODE");
|
||||
}
|
||||
code->json_root = root; /* Keep tree alive — instrs point into it */
|
||||
|
||||
/* Execute with global_obj as this, passing env as outer_frame */
|
||||
JSValue result = mcode_exec(ctx, code, ctx->global_obj, 0, NULL, env);
|
||||
|
||||
/* Clear frame ref before freeing mcode — stack trace data is inside code */
|
||||
ctx->reg_current_frame = JS_NULL;
|
||||
jsmcode_free(code);
|
||||
return result;
|
||||
}
|
||||
|
||||
JSValue JS_CallMcode(JSContext *ctx, const char *mcode_json) {
|
||||
cJSON *root = cJSON_Parse(mcode_json);
|
||||
if (!root) return JS_ThrowSyntaxError(ctx, "invalid MCODE JSON");
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
// #define DUMP_ROPE_REBALANCE
|
||||
|
||||
/* test the GC by forcing it before each object allocation */
|
||||
#define FORCE_GC_AT_MALLOC
|
||||
// #define FORCE_GC_AT_MALLOC
|
||||
|
||||
#define POISON_HEAP
|
||||
/* POISON_HEAP: Use ASan's memory poisoning to detect stale pointer access */
|
||||
|
||||
@@ -1268,6 +1268,9 @@ char *JS_Mcode (const char *ast_json);
|
||||
/* Execute MCODE from cJSON tree. Takes ownership of root. */
|
||||
JSValue JS_CallMcodeTree (JSContext *ctx, struct cJSON *root);
|
||||
|
||||
/* Execute MCODE from cJSON tree with hidden env. Takes ownership of root. */
|
||||
JSValue JS_CallMcodeTreeEnv (JSContext *ctx, struct cJSON *root, JSValue env);
|
||||
|
||||
/* Parse and execute MCODE JSON string.
|
||||
Returns result of execution, or JS_EXCEPTION on error. */
|
||||
JSValue JS_CallMcode (JSContext *ctx, const char *mcode_json);
|
||||
|
||||
@@ -10655,7 +10655,8 @@ static JSValue js_mach_eval (JSContext *ctx, JSValue this_val, int argc, JSValue
|
||||
return JS_ThrowSyntaxError (ctx, "mach_eval: failed to parse AST");
|
||||
}
|
||||
|
||||
JSValue result = JS_RunMachTree (ctx, ast, JS_NULL);
|
||||
JSValue env = (argc >= 3 && JS_IsObject (argv[2])) ? argv[2] : JS_NULL;
|
||||
JSValue result = JS_RunMachTree (ctx, ast, env);
|
||||
cJSON_Delete (ast);
|
||||
JS_FreeCString (ctx, name);
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user