diff --git a/dump_mcode.cm b/dump_mcode.cm new file mode 100644 index 00000000..291b6e46 --- /dev/null +++ b/dump_mcode.cm @@ -0,0 +1,20 @@ +var fd = use("fd") +var json = use("json") +var tokenize = use("tokenize") +var parse = use("parse") +var fold = use("fold") +var mcode = use("mcode") +var streamline = use("streamline") + +var name = args[0] +var src = text(fd.slurp(name)) +var tok = tokenize(src, name) +var ast = parse(tok.tokens, src, name, tokenize) +var folded = fold(ast) +var compiled = mcode(folded) +var optimized = streamline(compiled) +var out = json.encode(optimized) +var f = fd.open("/tmp/mcode_dump.json", "w") +fd.write(f, out) +fd.close(f) +print("wrote /tmp/mcode_dump.json") diff --git a/fold.mach b/fold.mach index 3b4ec013..f637ed3b 100644 Binary files a/fold.mach and b/fold.mach differ diff --git a/fold_new.mach b/fold_new.mach new file mode 100644 index 00000000..54952d4c Binary files /dev/null and b/fold_new.mach differ diff --git a/internal/bootstrap.cm b/internal/bootstrap.cm index 09fb543f..0f8ef0cb 100644 --- a/internal/bootstrap.cm +++ b/internal/bootstrap.cm @@ -1,5 +1,5 @@ // Hidden vars come from env: -// CLI mode (cell_init): os, args, core_path, shop_path, use_mcode +// CLI mode (cell_init): os, args, core_path, shop_path, emit_qbe // 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 @@ -24,7 +24,7 @@ function use_basic(path) { return result } -// Load a module from .mach bytecode, falling back to .ast.json +// Load a module from .mach bytecode (bootstrap modules have no source fallback) function boot_load(name, env) { var mach_path = core_path + '/' + name + ".mach" var data = null @@ -32,9 +32,8 @@ function boot_load(name, env) { data = fd.slurp(mach_path) return mach_load(data, env) } - var ast_path = core_path + '/' + name + ".ast.json" - data = text(fd.slurp(ast_path)) - return mach_eval_ast(name, data, env) + print("error: missing bootstrap bytecode: " + mach_path + "\n") + disrupt } var boot_env = {use: use_basic} @@ -45,14 +44,11 @@ use_cache['tokenize'] = tokenize_mod use_cache['parse'] = parse_mod use_cache['fold'] = fold_mod -// Optionally load mcode compiler module -var mcode_mod = null +// Always load mcode compiler module +var mcode_mod = boot_load("mcode", boot_env) +use_cache['mcode'] = mcode_mod var streamline_mod = null var qbe_emit_mod = null -if (use_mcode) { - mcode_mod = boot_load("mcode", boot_env) - use_cache['mcode'] = mcode_mod -} // Warn if any .cm source is newer than its .mach bytecode function check_mach_stale() { @@ -134,6 +130,8 @@ function load_module(name, env) { var src_path = null var src = null var ast = null + var compiled = null + var optimized = null if (fd.is_file(mach_path)) { data = fd.slurp(mach_path) return mach_load(data, env) @@ -141,38 +139,33 @@ function load_module(name, env) { src_path = core_path + '/' + name + ".cm" src = text(fd.slurp(src_path)) ast = analyze(src, src_path) - return mach_eval_ast(name, json.encode(ast), env) + compiled = mcode_mod(ast) + optimized = streamline_mod(compiled) + return mach_eval_mcode(name, json.encode(optimized), env) } // Load optimization pipeline modules (needs analyze to be defined) var qbe_macros = null -if (use_mcode) { - 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 - } +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 either mcode or mach pipeline +// Run AST through mcode pipeline → register VM function run_ast(name, ast, env) { - var compiled = null - var optimized = null + var compiled = mcode_mod(ast) + var optimized = streamline_mod(compiled) var qbe_il = null - if (use_mcode) { - compiled = mcode_mod(ast) - optimized = streamline_mod(compiled) - if (emit_qbe) { - qbe_il = qbe_emit_mod(optimized, qbe_macros) - print(qbe_il) - return null - } - return mcode_run(name, json.encode(optimized), env) + if (emit_qbe) { + qbe_il = qbe_emit_mod(optimized, qbe_macros) + print(qbe_il) + return null } - return mach_eval_ast(name, json.encode(ast), env) + return mach_eval_mcode(name, json.encode(optimized), env) } // use() with ƿit pipeline for .cm modules diff --git a/internal/bootstrap.mach b/internal/bootstrap.mach index f2696e69..f025bb52 100644 Binary files a/internal/bootstrap.mach and b/internal/bootstrap.mach differ diff --git a/internal/engine.mach b/internal/engine.mach index 3ec759ec..8fc4257b 100644 Binary files a/internal/engine.mach and b/internal/engine.mach differ diff --git a/mcode.mach b/mcode.mach index f5227053..3584d85c 100644 Binary files a/mcode.mach and b/mcode.mach differ diff --git a/meson.build b/meson.build index fbc7f88d..f7ceed8a 100644 --- a/meson.build +++ b/meson.build @@ -46,7 +46,6 @@ src += [ # core 'miniz.c', 'runtime.c', 'mach.c', - 'mcode.c', 'libregexp.c', 'libunicode.c', 'cutils.c', 'dtoa.c' ] diff --git a/parse.cm b/parse.cm index 00bb5bf8..037d0b0f 100644 --- a/parse.cm +++ b/parse.cm @@ -65,7 +65,7 @@ var parse = function(tokens, src, filename, tokenizer) { var errors = [] var error_count = 0 - var function_nr = 1 + var fn_counter = 1 var ast_node = function(kind, token) { return { @@ -422,8 +422,8 @@ var parse = function(tokens, src, filename, tokenizer) { _control_depth = meth_old_cd _control_type = meth_old_ct _expecting_body = meth_old_eb - fn.function_nr = function_nr - function_nr = function_nr + 1 + fn.function_nr = fn_counter + fn_counter = fn_counter + 1 ast_node_end(fn) pair.right = fn } else if (is_ident && (tok.kind == "," || tok.kind == "}")) { @@ -918,8 +918,8 @@ var parse = function(tokens, src, filename, tokenizer) { _control_depth = old_cd _control_type = old_ct _expecting_body = old_eb - node.function_nr = function_nr - function_nr = function_nr + 1 + node.function_nr = fn_counter + fn_counter = fn_counter + 1 ast_node_end(node) return node } @@ -1008,8 +1008,8 @@ var parse = function(tokens, src, filename, tokenizer) { _control_depth = old_cd _control_type = old_ct _expecting_body = old_eb - node.function_nr = function_nr - function_nr = function_nr + 1 + node.function_nr = fn_counter + fn_counter = fn_counter + 1 ast_node_end(node) return node } diff --git a/parse.mach b/parse.mach index 1da26295..e2202fe5 100644 Binary files a/parse.mach and b/parse.mach differ diff --git a/qbe.mach b/qbe.mach index fd0219c9..ba12ea90 100644 Binary files a/qbe.mach and b/qbe.mach differ diff --git a/qbe_emit.cm b/qbe_emit.cm index 9134baee..38b7e7d1 100644 --- a/qbe_emit.cm +++ b/qbe_emit.cm @@ -405,7 +405,7 @@ var qbe_emit = function(ir, qbe) { else if (op == "le_float") fop_id = 3 else if (op == "gt_float") fop_id = 4 else if (op == "ge_float") fop_id = 5 - emit(qbe.cmp_float != null ? cmp_float(p, "%ctx", s(a2), s(a3), fop_id) : ` %${p} =l call $qbe_float_cmp(l %ctx, w ${text(fop_id)}, l ${s(a2)}, l ${s(a3)})`) + emit(qbe.cmp_float != null ? qbe.cmp_float(p, "%ctx", s(a2), s(a3), fop_id) : ` %${p} =l call $qbe_float_cmp(l %ctx, w ${text(fop_id)}, l ${s(a2)}, l ${s(a3)})`) emit(` ${s(a1)} =l copy %${p}`) wb(a1) continue diff --git a/qbe_emit.mach b/qbe_emit.mach index 0c87d508..fb19e2c4 100644 Binary files a/qbe_emit.mach and b/qbe_emit.mach differ diff --git a/regen.cm b/regen.cm index df227202..2abaeee2 100644 --- a/regen.cm +++ b/regen.cm @@ -6,6 +6,8 @@ var json = use("json") var tokenize = use("tokenize") var parse = use("parse") var fold = use("fold") +var mcode = use("mcode") +var streamline = use("streamline") var files = [ {src: "tokenize.cm", name: "tokenize", out: "tokenize.mach"}, @@ -25,21 +27,49 @@ var src = null var tok_result = null var ast = null var folded = null -var ast_json = null +var compiled = null +var optimized = null +var mcode_json = null var bytecode = null var f = null +var errs = null +var ei = 0 +var e = null +var had_errors = false while (i < length(files)) { entry = files[i] src = text(fd.slurp(entry.src)) tok_result = tokenize(src, entry.src) ast = parse(tok_result.tokens, src, entry.src, tokenize) + // Check for parse/semantic errors + errs = ast.errors + if (errs != null && length(errs) > 0) { + ei = 0 + while (ei < length(errs)) { + e = errs[ei] + if (e.line != null) { + print(`${entry.src}:${text(e.line)}:${text(e.column)}: error: ${e.message}`) + } else { + print(`${entry.src}: error: ${e.message}`) + } + ei = ei + 1 + } + had_errors = true + i = i + 1 + continue + } folded = fold(ast) - ast_json = json.encode(folded) - bytecode = mach_compile_ast(entry.name, ast_json) + compiled = mcode(folded) + optimized = streamline(compiled) + mcode_json = json.encode(optimized) + bytecode = mach_compile_mcode_bin(entry.name, mcode_json) f = fd.open(entry.out, "w") fd.write(f, bytecode) fd.close(f) print(`wrote ${entry.out}`) i = i + 1 } +if (had_errors) { + print("regen aborted: fix errors above") +} diff --git a/source/cell.c b/source/cell.c index e1a9e073..1c14d76b 100644 --- a/source/cell.c +++ b/source/cell.c @@ -12,7 +12,6 @@ #include "cJSON.h" #define BOOTSTRAP_MACH "internal/bootstrap.mach" -#define BOOTSTRAP_AST "internal/bootstrap.ast.json" #define BOOTSTRAP_SRC "internal/bootstrap.cm" #define CELL_SHOP_DIR ".cell" #define CELL_CORE_DIR "packages/core" @@ -179,14 +178,9 @@ void script_startup(cell_rt *prt) cell_rt *crt = JS_GetContextOpaque(js); JS_FreeValue(js, js_blob_use(js)); - // Load pre-compiled bootstrap bytecode (.mach), fall back to AST JSON + // Load pre-compiled bootstrap bytecode (.mach) size_t boot_size; - int boot_is_bin = 1; char *boot_data = load_core_file(BOOTSTRAP_MACH, &boot_size); - if (!boot_data) { - boot_is_bin = 0; - boot_data = load_core_file(BOOTSTRAP_AST, &boot_size); - } if (!boot_data) { printf("ERROR: Could not load bootstrap from %s!\n", core_path); return; @@ -211,9 +205,8 @@ void script_startup(cell_rt *prt) JS_SetPropertyStr(js, hidden_env, "init", JS_NULL); } - // Set args and use_mcode to null/false for actor spawn (not CLI mode) + // Set args to null for actor spawn (not CLI mode) JS_SetPropertyStr(js, hidden_env, "args", JS_NULL); - JS_SetPropertyStr(js, hidden_env, "use_mcode", JS_NewBool(js, 0)); if (core_path) JS_SetPropertyStr(js, hidden_env, "core_path", JS_NewString(js, core_path)); @@ -225,17 +218,8 @@ void script_startup(cell_rt *prt) // Run through MACH VM crt->state = ACTOR_RUNNING; - JSValue v; - if (boot_is_bin) { - v = JS_RunMachBin(js, (const uint8_t *)boot_data, boot_size, hidden_env); - free(boot_data); - } else { - cJSON *ast = cJSON_Parse(boot_data); - free(boot_data); - if (!ast) { printf("ERROR: Failed to parse bootstrap AST\n"); return; } - v = JS_RunMachTree(js, ast, hidden_env); - cJSON_Delete(ast); - } + JSValue v = JS_RunMachBin(js, (const uint8_t *)boot_data, boot_size, hidden_env); + free(boot_data); uncaught_exception(js, v); crt->state = ACTOR_IDLE; set_actor_state(crt); @@ -290,7 +274,7 @@ static void print_usage(const char *prog) printf("Options:\n"); printf(" --core Set core path directly (overrides CELL_CORE)\n"); printf(" --shop Set shop path (overrides CELL_SHOP)\n"); - printf(" --mcode