streamlined cell running
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
// Hidden vars (os, args) come from env
|
// Hidden vars (os, args, core_path) come from env
|
||||||
// args[0] = script filename, args[1..] = user args
|
// args[0] = script name, args[1..] = user args
|
||||||
var load_internal = os.load_internal
|
var load_internal = os.load_internal
|
||||||
function use_embed(name) {
|
function use_embed(name) {
|
||||||
return load_internal("js_" + name + "_use")
|
return load_internal("js_" + name + "_use")
|
||||||
@@ -13,23 +13,76 @@ use_cache['fd'] = fd
|
|||||||
use_cache['os'] = os
|
use_cache['os'] = os
|
||||||
use_cache['json'] = json
|
use_cache['json'] = json
|
||||||
|
|
||||||
function use(path) {
|
// Bootstrap: load tokenize.cm and parse.cm via C pipeline (mach_eval)
|
||||||
|
function use_basic(path) {
|
||||||
if (use_cache[path])
|
if (use_cache[path])
|
||||||
return use_cache[path];
|
return use_cache[path]
|
||||||
|
var result = use_embed(replace(path, '/', '_'))
|
||||||
|
use_cache[path] = result
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
var tok_path = core_path + "/tokenize.cm"
|
||||||
|
var par_path = core_path + "/parse.cm"
|
||||||
|
var tokenize_mod = mach_eval("tokenize", text(fd.slurp(tok_path)), {use: use_basic})
|
||||||
|
var parse_mod = mach_eval("parse", text(fd.slurp(par_path)), {use: use_basic})
|
||||||
|
|
||||||
|
// analyze: tokenize + parse, check for errors
|
||||||
|
function analyze(src, filename) {
|
||||||
|
var tok_result = tokenize_mod(src, filename)
|
||||||
|
var ast = parse_mod(tok_result.tokens, src, filename)
|
||||||
|
var _i = 0
|
||||||
|
var prev_line = -1
|
||||||
|
var prev_msg = null
|
||||||
|
var e = null
|
||||||
|
var msg = null
|
||||||
|
var line = null
|
||||||
|
var col = null
|
||||||
|
var has_errors = ast.errors != null && length(ast.errors) > 0
|
||||||
|
if (has_errors) {
|
||||||
|
while (_i < length(ast.errors)) {
|
||||||
|
e = ast.errors[_i]
|
||||||
|
msg = e.message
|
||||||
|
line = e.line
|
||||||
|
col = e.column
|
||||||
|
if (msg != prev_msg || line != prev_line) {
|
||||||
|
if (line != null && col != null) {
|
||||||
|
print(`${filename}:${text(line)}:${text(col)}: error: ${msg}`)
|
||||||
|
} else {
|
||||||
|
print(`${filename}: error: ${msg}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev_line = line
|
||||||
|
prev_msg = msg
|
||||||
|
_i = _i + 1
|
||||||
|
}
|
||||||
|
disrupt
|
||||||
|
}
|
||||||
|
return ast
|
||||||
|
}
|
||||||
|
|
||||||
|
// use() with ƿit pipeline for .cm modules
|
||||||
|
function use(path) {
|
||||||
var file_path = path + '.cm'
|
var file_path = path + '.cm'
|
||||||
var script = null
|
var script = null
|
||||||
|
var ast = null
|
||||||
var result = null
|
var result = null
|
||||||
var exports = null
|
if (use_cache[path])
|
||||||
|
return use_cache[path]
|
||||||
|
|
||||||
|
// Check CWD first, then core_path
|
||||||
|
if (!fd.is_file(file_path))
|
||||||
|
file_path = core_path + '/' + path + '.cm'
|
||||||
|
|
||||||
if (fd.is_file(file_path)) {
|
if (fd.is_file(file_path)) {
|
||||||
script = text(fd.slurp(file_path))
|
script = text(fd.slurp(file_path))
|
||||||
result = mach_eval(path, script, {use: use})
|
ast = analyze(script, file_path)
|
||||||
|
result = mach_eval_ast(path, json.encode(ast), {use: use})
|
||||||
use_cache[path] = result
|
use_cache[path] = result
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try embedded C module
|
// Fallback to embedded C module
|
||||||
result = use_embed(replace(path, '/', '_'))
|
result = use_embed(replace(path, '/', '_'))
|
||||||
use_cache[path] = result
|
use_cache[path] = result
|
||||||
return result
|
return result
|
||||||
@@ -37,14 +90,19 @@ function use(path) {
|
|||||||
|
|
||||||
// Load and run the user's program
|
// Load and run the user's program
|
||||||
var program = args[0]
|
var program = args[0]
|
||||||
|
var script_file = program
|
||||||
|
|
||||||
|
// Add .ce extension if not already present
|
||||||
|
if (!ends_with(script_file, '.ce') && !ends_with(script_file, '.cm'))
|
||||||
|
script_file = program + '.ce'
|
||||||
|
|
||||||
var user_args = []
|
var user_args = []
|
||||||
var _i = 1
|
var _j = 1
|
||||||
while (_i < length(args)) {
|
while (_j < length(args)) {
|
||||||
push(user_args, args[_i])
|
push(user_args, args[_j])
|
||||||
_i = _i + 1
|
_j = _j + 1
|
||||||
}
|
}
|
||||||
var blob = fd.slurp(program)
|
|
||||||
stone(blob)
|
var script = text(fd.slurp(script_file))
|
||||||
var script = text(blob)
|
var ast = analyze(script, script_file)
|
||||||
mach_eval(program, script, {use: use, args: user_args, json: json})
|
mach_eval_ast(program, json.encode(ast), {use: use, args: user_args, json: json})
|
||||||
|
|||||||
5
parse.ce
5
parse.ce
@@ -1,7 +1,8 @@
|
|||||||
|
var fd = use("fd")
|
||||||
var tokenize = use("tokenize")
|
var tokenize = use("tokenize")
|
||||||
var parse = use("parse")
|
var parse = use("parse")
|
||||||
var src = args[0]
|
var filename = args[0]
|
||||||
var filename = length(args) > 1 ? args[1] : "<stdin>"
|
var src = text(fd.slurp(filename))
|
||||||
var result = tokenize(src, filename)
|
var result = tokenize(src, filename)
|
||||||
var ast = parse(result.tokens, src, filename)
|
var ast = parse(result.tokens, src, filename)
|
||||||
print(json.encode(ast))
|
print(json.encode(ast))
|
||||||
|
|||||||
@@ -650,6 +650,7 @@ int cell_init(int argc, char **argv)
|
|||||||
|
|
||||||
JSValue hidden_env = JS_NewObject(ctx);
|
JSValue hidden_env = JS_NewObject(ctx);
|
||||||
JS_SetPropertyStr(ctx, hidden_env, "os", js_os_use(ctx));
|
JS_SetPropertyStr(ctx, hidden_env, "os", js_os_use(ctx));
|
||||||
|
JS_SetPropertyStr(ctx, hidden_env, "core_path", JS_NewString(ctx, core_path));
|
||||||
JSValue args_arr = JS_NewArray(ctx);
|
JSValue args_arr = JS_NewArray(ctx);
|
||||||
for (int i = 2; i < argc; i++) {
|
for (int i = 2; i < argc; i++) {
|
||||||
JSValue str = JS_NewString(ctx, argv[i]);
|
JSValue str = JS_NewString(ctx, argv[i]);
|
||||||
@@ -679,41 +680,72 @@ int cell_init(int argc, char **argv)
|
|||||||
return exit_code;
|
return exit_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
int script_start = 1;
|
/* Default: run script through mach-run bootstrap pipeline */
|
||||||
|
if (!find_cell_shop()) return 1;
|
||||||
|
|
||||||
/* Find the cell shop at ~/.cell */
|
size_t boot_size;
|
||||||
int found = find_cell_shop();
|
char *boot_data = load_core_file("internal/bootstrap.cm", &boot_size);
|
||||||
if (!found) {
|
if (!boot_data) {
|
||||||
|
printf("ERROR: Could not load internal/bootstrap.cm from %s\n", core_path);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create the initial actor from the command line */
|
cJSON *boot_ast = JS_ASTTree(boot_data, boot_size, "internal/bootstrap.cm");
|
||||||
int actor_argc = argc - script_start;
|
free(boot_data);
|
||||||
char **actor_argv = argv + script_start;
|
if (!boot_ast) {
|
||||||
|
printf("Failed to parse internal/bootstrap.cm\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
WotaBuffer startwota;
|
if (print_tree_errors(boot_ast)) {
|
||||||
wota_buffer_init(&startwota, 5);
|
cJSON_Delete(boot_ast);
|
||||||
wota_write_record(&startwota, 2);
|
return 1;
|
||||||
wota_write_text(&startwota, "program");
|
}
|
||||||
wota_write_text(&startwota, actor_argv[0]);
|
|
||||||
wota_write_text(&startwota, "arg");
|
|
||||||
wota_write_array(&startwota, actor_argc - 1);
|
|
||||||
for (int i = 1; i < actor_argc; i++)
|
|
||||||
wota_write_text(&startwota, actor_argv[i]);
|
|
||||||
|
|
||||||
/* Initialize synchronization primitives */
|
|
||||||
actor_initialize();
|
|
||||||
|
|
||||||
root_cell = create_actor(startwota.data);
|
|
||||||
#ifndef TARGET_PLAYDATE
|
|
||||||
signal(SIGINT, signal_handler);
|
|
||||||
signal(SIGTERM, signal_handler);
|
|
||||||
signal(SIGSEGV, signal_handler);
|
|
||||||
signal(SIGABRT, signal_handler);
|
|
||||||
#endif
|
|
||||||
actor_loop();
|
|
||||||
|
|
||||||
return 0;
|
JSRuntime *rt = JS_NewRuntime();
|
||||||
|
if (!rt) {
|
||||||
|
printf("Failed to create JS runtime\n");
|
||||||
|
cJSON_Delete(boot_ast);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
JSContext *ctx = JS_NewContextWithHeapSize(rt, 16 * 1024 * 1024);
|
||||||
|
if (!ctx) {
|
||||||
|
printf("Failed to create JS context\n");
|
||||||
|
cJSON_Delete(boot_ast); JS_FreeRuntime(rt);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, "core_path", JS_NewString(ctx, core_path));
|
||||||
|
JSValue args_arr = JS_NewArray(ctx);
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
JSValue str = JS_NewString(ctx, argv[i]);
|
||||||
|
JS_ArrayPush(ctx, &args_arr, str);
|
||||||
|
}
|
||||||
|
JS_SetPropertyStr(ctx, hidden_env, "args", args_arr);
|
||||||
|
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)) {
|
||||||
|
JS_GetException(ctx);
|
||||||
|
exit_code = 1;
|
||||||
|
} else if (!JS_IsNull(result)) {
|
||||||
|
const char *str = JS_ToCString(ctx, result);
|
||||||
|
if (str) {
|
||||||
|
printf("%s\n", str);
|
||||||
|
JS_FreeCString(ctx, str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_FreeContext(ctx);
|
||||||
|
JS_FreeRuntime(rt);
|
||||||
|
return exit_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
int JS_ArrayLength(JSContext *js, JSValue a)
|
int JS_ArrayLength(JSContext *js, JSValue a)
|
||||||
|
|||||||
@@ -10434,6 +10434,39 @@ static JSValue js_mach_eval (JSContext *ctx, JSValue this_val, int argc, JSValue
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* mach_eval_ast(name, ast_json, env?) - compile pre-parsed AST and run */
|
||||||
|
static JSValue js_mach_eval_ast (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
|
||||||
|
if (argc < 2 || !JS_IsText (argv[0]) || !JS_IsText (argv[1]))
|
||||||
|
return JS_ThrowTypeError (ctx, "mach_eval_ast requires (name, ast_json) text arguments");
|
||||||
|
|
||||||
|
const char *name = JS_ToCString (ctx, argv[0]);
|
||||||
|
if (!name) return JS_EXCEPTION;
|
||||||
|
|
||||||
|
const char *json_str = JS_ToCString (ctx, argv[1]);
|
||||||
|
if (!json_str) {
|
||||||
|
JS_FreeCString (ctx, name);
|
||||||
|
return JS_EXCEPTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON *ast = cJSON_Parse (json_str);
|
||||||
|
JS_FreeCString (ctx, json_str);
|
||||||
|
|
||||||
|
if (!ast) {
|
||||||
|
JS_FreeCString (ctx, name);
|
||||||
|
return JS_ThrowSyntaxError (ctx, "mach_eval_ast: failed to parse AST JSON");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the filename on the AST root */
|
||||||
|
cJSON_DeleteItemFromObjectCaseSensitive (ast, "filename");
|
||||||
|
cJSON_AddStringToObject (ast, "filename", name);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/* ============================================================================
|
/* ============================================================================
|
||||||
* stone() function - deep freeze with blob support
|
* stone() function - deep freeze with blob support
|
||||||
* ============================================================================
|
* ============================================================================
|
||||||
@@ -11527,6 +11560,7 @@ static void JS_AddIntrinsicBaseObjects (JSContext *ctx) {
|
|||||||
/* Core functions - using GC-safe helper */
|
/* Core functions - using GC-safe helper */
|
||||||
js_set_global_cfunc(ctx, "eval", js_cell_eval, 2);
|
js_set_global_cfunc(ctx, "eval", js_cell_eval, 2);
|
||||||
js_set_global_cfunc(ctx, "mach_eval", js_mach_eval, 3);
|
js_set_global_cfunc(ctx, "mach_eval", js_mach_eval, 3);
|
||||||
|
js_set_global_cfunc(ctx, "mach_eval_ast", js_mach_eval_ast, 3);
|
||||||
js_set_global_cfunc(ctx, "stone", js_cell_stone, 1);
|
js_set_global_cfunc(ctx, "stone", js_cell_stone, 1);
|
||||||
js_set_global_cfunc(ctx, "length", js_cell_length, 1);
|
js_set_global_cfunc(ctx, "length", js_cell_length, 1);
|
||||||
js_set_global_cfunc(ctx, "call", js_cell_call, 3);
|
js_set_global_cfunc(ctx, "call", js_cell_call, 3);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
var fd = use("fd")
|
||||||
var tokenize = use("tokenize")
|
var tokenize = use("tokenize")
|
||||||
var src = args[0]
|
var filename = args[0]
|
||||||
var filename = length(args) > 1 ? args[1] : "<stdin>"
|
var src = text(fd.slurp(filename))
|
||||||
var result = tokenize(src, filename)
|
var result = tokenize(src, filename)
|
||||||
print(json.encode({filename: result.filename, tokens: result.tokens}))
|
print(json.encode({filename: result.filename, tokens: result.tokens}))
|
||||||
|
|||||||
Reference in New Issue
Block a user