From ae44ce7b4b264919d7b6451eb63812f27ba837e2 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Fri, 6 Feb 2026 01:56:26 -0600 Subject: [PATCH] mcode and mach --- source/cell.c | 213 ++++++++++++++++++++--------------------------- source/quickjs.c | 48 +++++++---- source/quickjs.h | 19 ++--- source/suite.c | 32 +++---- 4 files changed, 143 insertions(+), 169 deletions(-) diff --git a/source/cell.c b/source/cell.c index 45cbcc78..e30bd151 100644 --- a/source/cell.c +++ b/source/cell.c @@ -492,7 +492,90 @@ int cell_init(int argc, char **argv) } } - /* Check for --mach flag to output machine code JSON */ + /* Check for --mcode flag to output MCODE JSON IR */ + if (argc >= 3 && strcmp(argv[1], "--mcode") == 0) { + const char *script_or_file = argv[2]; + char *script = NULL; + char *allocated_script = NULL; + const char *filename = ""; + + 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; + } + + JSRuntime *rt = JS_NewRuntime(); + if (!rt) { + printf("Failed to create JS runtime\n"); + free(allocated_script); + return 1; + } + JSContext *ctx = JS_NewContext(rt); + if (!ctx) { + printf("Failed to create JS context\n"); + JS_FreeRuntime(rt); + free(allocated_script); + return 1; + } + + char *ast_json = JS_AST(ctx, script, strlen(script), filename); + if (!ast_json) { + printf("Failed to parse AST\n"); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + free(allocated_script); + return 1; + } + + if (print_json_errors(ast_json)) { + free(ast_json); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + free(allocated_script); + return 1; + } + + char *mcode_json = JS_Mcode(ctx, ast_json); + free(ast_json); + + if (mcode_json) { + if (print_json_errors(mcode_json)) { + free(mcode_json); + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + free(allocated_script); + return 1; + } + printf("%s\n", mcode_json); + free(mcode_json); + } else { + printf("Failed to generate MCODE\n"); + } + + JS_FreeContext(ctx); + JS_FreeRuntime(rt); + free(allocated_script); + return mcode_json ? 0 : 1; + } + + /* Check for --mach flag to dump MACH bytecode */ if (argc >= 3 && strcmp(argv[1], "--mach") == 0) { const char *script_or_file = argv[2]; char *script = NULL; @@ -552,113 +635,16 @@ int cell_init(int argc, char **argv) return 1; } - char *mach_json = JS_Mach(ctx, ast_json); + JS_DumpMach(ctx, ast_json, JS_NULL); free(ast_json); - if (mach_json) { - if (print_json_errors(mach_json)) { - free(mach_json); - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - free(allocated_script); - return 1; - } - printf("%s\n", mach_json); - free(mach_json); - } else { - printf("Failed to generate machine code\n"); - } - JS_FreeContext(ctx); JS_FreeRuntime(rt); free(allocated_script); - return mach_json ? 0 : 1; + return 0; } - /* Check for --vmcode flag to dump linked register VM bytecode */ - if (argc >= 3 && strcmp(argv[1], "--vmcode") == 0) { - const char *script_or_file = argv[2]; - char *script = NULL; - char *allocated_script = NULL; - const char *filename = ""; - - 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; - } - - JSRuntime *rt = JS_NewRuntime(); - if (!rt) { - printf("Failed to create JS runtime\n"); - free(allocated_script); - return 1; - } - JSContext *ctx = JS_NewContext(rt); - if (!ctx) { - printf("Failed to create JS context\n"); - JS_FreeRuntime(rt); - free(allocated_script); - return 1; - } - - char *ast_json = JS_AST(ctx, script, strlen(script), filename); - if (!ast_json) { - printf("Failed to parse AST\n"); - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - free(allocated_script); - return 1; - } - - if (print_json_errors(ast_json)) { - free(ast_json); - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - free(allocated_script); - return 1; - } - - char *mach_json = JS_Mach(ctx, ast_json); - free(ast_json); - - if (mach_json) { - if (print_json_errors(mach_json)) { - free(mach_json); - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - free(allocated_script); - return 1; - } - JS_DumpRegisterMach(ctx, mach_json, JS_NULL); - free(mach_json); - } else { - printf("Failed to generate machine code\n"); - } - - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - free(allocated_script); - return mach_json ? 0 : 1; - } - - /* Check for --mach-run flag to generate and run machine code through register VM */ + /* 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; @@ -701,7 +687,6 @@ int cell_init(int argc, char **argv) return 1; } - /* Parse to AST */ char *ast_json = JS_AST(ctx, script, strlen(script), filename); if (!ast_json) { printf("Failed to parse AST\n"); @@ -719,30 +704,9 @@ int cell_init(int argc, char **argv) return 1; } - /* Generate machine code */ - char *mach_json = JS_Mach(ctx, ast_json); + JSValue result = JS_RunMach(ctx, ast_json, JS_NULL); free(ast_json); - if (!mach_json) { - printf("Failed to generate machine code\n"); - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - free(allocated_script); - return 1; - } - - if (print_json_errors(mach_json)) { - free(mach_json); - JS_FreeContext(ctx); - JS_FreeRuntime(rt); - free(allocated_script); - return 1; - } - - /* Execute through register VM */ - JSValue result = JS_IntegrateRegister(ctx, mach_json, JS_NULL); - free(mach_json); - int exit_code = 0; if (JS_IsException(result)) { JSValue exc = JS_GetException(ctx); @@ -753,7 +717,6 @@ int cell_init(int argc, char **argv) } exit_code = 1; } else if (!JS_IsNull(result)) { - /* Print result */ const char *str = JS_ToCString(ctx, result); if (str) { printf("%s\n", str); diff --git a/source/quickjs.c b/source/quickjs.c index ef41f96b..f336becf 100644 --- a/source/quickjs.c +++ b/source/quickjs.c @@ -453,7 +453,7 @@ typedef struct JSFrameRegister { Register-Based VM Data Structures ============================================================ */ -/* Machine code opcode enum - matches instruction names from JS_Mach output */ +/* Machine code opcode enum - matches instruction names from JS_Mcode output */ typedef enum MachOpcode { MACH_OP_NOP = 0, /* Constants */ @@ -30741,7 +30741,7 @@ char *JS_Tokenize (JSContext *ctx, const char *source, size_t len, const char *f } /* ============================================================ - Register-Based Machine Code Generator + MCODE Generator — AST to JSON IR ============================================================ */ /* Variable kinds */ @@ -32582,7 +32582,7 @@ static cJSON *mach_gen_program (MachGenState *s, cJSON *ast) { return result; } -char *JS_Mach (JSContext *ctx, const char *ast_json) { +char *JS_Mcode (JSContext *ctx, const char *ast_json) { cJSON *ast = cJSON_Parse (ast_json); if (!ast) return NULL; @@ -32621,7 +32621,7 @@ char *JS_Mach (JSContext *ctx, const char *ast_json) { } /* ============================================================ - Register VM Linker - converts JSON machine code to JSCodeRegister + MACH Linker — MCODE to binary bytecode ============================================================ */ /* Opcode name to MachOpcode mapping */ @@ -33177,7 +33177,7 @@ static JSCodeRegister *js_link_mach(JSContext *ctx, const char *mach_json, JSVal } /* ============================================================ - Register VM Execution Engine + MACH VM — register-based bytecode interpreter ============================================================ */ /* Allocate a JSFrameRegister on the GC heap */ @@ -33925,7 +33925,7 @@ done: } /* ============================================================ - Register VM Public API + MACH Public API ============================================================ */ /* Print a single constant pool value for dump output */ @@ -34263,25 +34263,37 @@ static void dump_register_code(JSContext *ctx, JSCodeRegister *code, int indent) } } -/* Dump linked register VM bytecode */ -void JS_DumpRegisterMach(JSContext *ctx, const char *mach_json, JSValue env) { - JSCodeRegister *code = js_link_mach(ctx, mach_json, env); - if (!code) { - printf("=== Register VM Bytecode ===\nFailed to link machine code\n=== End Register VM Bytecode ===\n"); +/* Dump MACH bytecode to stdout for debugging. Takes AST JSON. */ +void JS_DumpMach(JSContext *ctx, const char *ast_json, JSValue env) { + char *mcode_json = JS_Mcode(ctx, ast_json); + if (!mcode_json) { + printf("=== MACH Bytecode ===\nFailed to generate MCODE\n=== End MACH Bytecode ===\n"); return; } - printf("=== Register VM Bytecode ===\n"); + JSCodeRegister *code = js_link_mach(ctx, mcode_json, env); + sys_free(mcode_json); + if (!code) { + printf("=== MACH Bytecode ===\nFailed to link MCODE\n=== End MACH Bytecode ===\n"); + return; + } + + printf("=== MACH Bytecode ===\n"); dump_register_code(ctx, code, 0); - printf("=== End Register VM Bytecode ===\n"); + printf("=== End MACH Bytecode ===\n"); } -/* Link and execute register-based machine code */ -JSValue JS_IntegrateRegister(JSContext *ctx, const char *mach_json, JSValue env) { - /* Link the machine code */ - JSCodeRegister *code = js_link_mach(ctx, mach_json, env); +/* Compile and execute MACH bytecode. Takes AST JSON. */ +JSValue JS_RunMach(JSContext *ctx, const char *ast_json, JSValue env) { + char *mcode_json = JS_Mcode(ctx, ast_json); + if (!mcode_json) { + return JS_ThrowSyntaxError(ctx, "failed to generate MCODE from AST"); + } + + JSCodeRegister *code = js_link_mach(ctx, mcode_json, env); + sys_free(mcode_json); if (!code) { - return JS_ThrowSyntaxError(ctx, "failed to link machine code"); + return JS_ThrowSyntaxError(ctx, "failed to link MCODE to MACH bytecode"); } /* Execute the main code */ diff --git a/source/quickjs.h b/source/quickjs.h index d304e578..66641f30 100644 --- a/source/quickjs.h +++ b/source/quickjs.h @@ -1226,19 +1226,18 @@ char *JS_AST (JSContext *ctx, const char *source, size_t len, const char *filena Returns malloc'd JSON string (caller must free), or NULL on error. */ char *JS_Tokenize (JSContext *ctx, const char *source, size_t len, const char *filename); -/* Generate register-based machine code from AST JSON. +/* Generate MCODE (JSON IR) from AST JSON. Returns malloc'd JSON string (caller must free), or NULL on error. */ -char *JS_Mach (JSContext *ctx, const char *ast_json); +char *JS_Mcode (JSContext *ctx, const char *ast_json); -/* Link and execute register-based machine code. - mach_json: JSON output from JS_Mach - env: stone record for external variable resolution (or JS_NULL) +/* Dump MACH bytecode to stdout for debugging. Takes AST JSON. + Internally generates MCODE and links to binary bytecode. */ +void JS_DumpMach (JSContext *ctx, const char *ast_json, JSValue env); + +/* Compile and execute MACH bytecode. Takes AST JSON. + Internally generates MCODE and links to binary bytecode. Returns result of execution, or JS_EXCEPTION on error. */ -JSValue JS_IntegrateRegister (JSContext *ctx, const char *mach_json, JSValue env); - -/* Dump linked register VM bytecode to stdout for debugging. - Links mach_json and prints the resulting bytecode with resolved labels. */ -void JS_DumpRegisterMach (JSContext *ctx, const char *mach_json, JSValue env); +JSValue JS_RunMach (JSContext *ctx, const char *ast_json, JSValue env); /* Integrate a CellModule with an environment and execute. Returns callable function value, or JS_EXCEPTION on error. */ diff --git a/source/suite.c b/source/suite.c index c345b919..40b0f103 100644 --- a/source/suite.c +++ b/source/suite.c @@ -2395,9 +2395,9 @@ TEST(mach_assign_to_const) { const char *src = "def x = 1; x = 2"; char *ast_json = JS_AST(ctx, src, strlen(src), ""); ASSERT_MSG(ast_json != NULL, "JS_AST returned NULL"); - char *mach_json = JS_Mach(ctx, ast_json); + char *mach_json = JS_Mcode(ctx, ast_json); free(ast_json); - ASSERT_MSG(mach_json != NULL, "JS_Mach returned NULL"); + ASSERT_MSG(mach_json != NULL, "JS_Mcode returned NULL"); ASSERT_ERROR_MSG_CONTAINS(mach_json, "cannot assign to constant"); free(mach_json); return 1; @@ -2407,9 +2407,9 @@ TEST(mach_assign_to_arg) { const char *src = "function f(x) { x = 5 }"; char *ast_json = JS_AST(ctx, src, strlen(src), ""); ASSERT_MSG(ast_json != NULL, "JS_AST returned NULL"); - char *mach_json = JS_Mach(ctx, ast_json); + char *mach_json = JS_Mcode(ctx, ast_json); free(ast_json); - ASSERT_MSG(mach_json != NULL, "JS_Mach returned NULL"); + ASSERT_MSG(mach_json != NULL, "JS_Mcode returned NULL"); ASSERT_ERROR_MSG_CONTAINS(mach_json, "cannot assign to function argument"); free(mach_json); return 1; @@ -2419,9 +2419,9 @@ TEST(mach_redeclare_const) { const char *src = "def x = 1; def x = 2"; char *ast_json = JS_AST(ctx, src, strlen(src), ""); ASSERT_MSG(ast_json != NULL, "JS_AST returned NULL"); - char *mach_json = JS_Mach(ctx, ast_json); + char *mach_json = JS_Mcode(ctx, ast_json); free(ast_json); - ASSERT_MSG(mach_json != NULL, "JS_Mach returned NULL"); + ASSERT_MSG(mach_json != NULL, "JS_Mcode returned NULL"); ASSERT_ERROR_MSG_CONTAINS(mach_json, "cannot redeclare constant"); free(mach_json); return 1; @@ -2431,9 +2431,9 @@ TEST(mach_break_outside_loop) { const char *src = "break"; char *ast_json = JS_AST(ctx, src, strlen(src), ""); ASSERT_MSG(ast_json != NULL, "JS_AST returned NULL"); - char *mach_json = JS_Mach(ctx, ast_json); + char *mach_json = JS_Mcode(ctx, ast_json); free(ast_json); - ASSERT_MSG(mach_json != NULL, "JS_Mach returned NULL"); + ASSERT_MSG(mach_json != NULL, "JS_Mcode returned NULL"); ASSERT_ERROR_MSG_CONTAINS(mach_json, "outside of loop"); free(mach_json); return 1; @@ -2443,9 +2443,9 @@ TEST(mach_continue_outside_loop) { const char *src = "continue"; char *ast_json = JS_AST(ctx, src, strlen(src), ""); ASSERT_MSG(ast_json != NULL, "JS_AST returned NULL"); - char *mach_json = JS_Mach(ctx, ast_json); + char *mach_json = JS_Mcode(ctx, ast_json); free(ast_json); - ASSERT_MSG(mach_json != NULL, "JS_Mach returned NULL"); + ASSERT_MSG(mach_json != NULL, "JS_Mcode returned NULL"); ASSERT_ERROR_MSG_CONTAINS(mach_json, "outside of loop"); free(mach_json); return 1; @@ -2455,9 +2455,9 @@ TEST(mach_assign_unbound_var) { const char *src = "x = 42"; char *ast_json = JS_AST(ctx, src, strlen(src), ""); ASSERT_MSG(ast_json != NULL, "JS_AST returned NULL"); - char *mach_json = JS_Mach(ctx, ast_json); + char *mach_json = JS_Mcode(ctx, ast_json); free(ast_json); - ASSERT_MSG(mach_json != NULL, "JS_Mach returned NULL"); + ASSERT_MSG(mach_json != NULL, "JS_Mcode returned NULL"); ASSERT_ERROR_MSG_CONTAINS(mach_json, "not declared"); free(mach_json); return 1; @@ -2467,9 +2467,9 @@ TEST(mach_shadow_is_ok) { const char *src = "var array = []; array"; char *ast_json = JS_AST(ctx, src, strlen(src), ""); ASSERT_MSG(ast_json != NULL, "JS_AST returned NULL"); - char *mach_json = JS_Mach(ctx, ast_json); + char *mach_json = JS_Mcode(ctx, ast_json); free(ast_json); - ASSERT_MSG(mach_json != NULL, "JS_Mach returned NULL"); + ASSERT_MSG(mach_json != NULL, "JS_Mcode returned NULL"); ASSERT_NO_ERRORS(mach_json); free(mach_json); return 1; @@ -2479,9 +2479,9 @@ TEST(mach_valid_no_errors) { const char *src = "var x = 1; x = x + 1"; char *ast_json = JS_AST(ctx, src, strlen(src), ""); ASSERT_MSG(ast_json != NULL, "JS_AST returned NULL"); - char *mach_json = JS_Mach(ctx, ast_json); + char *mach_json = JS_Mcode(ctx, ast_json); free(ast_json); - ASSERT_MSG(mach_json != NULL, "JS_Mach returned NULL"); + ASSERT_MSG(mach_json != NULL, "JS_Mcode returned NULL"); ASSERT_NO_ERRORS(mach_json); free(mach_json); return 1;