Merge branch 'mcode' into newsyn
This commit is contained in:
213
source/cell.c
213
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 = "<eval>";
|
||||
|
||||
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 = "<eval>";
|
||||
|
||||
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);
|
||||
|
||||
@@ -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 */
|
||||
@@ -32594,7 +32594,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;
|
||||
|
||||
@@ -32633,7 +32633,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 */
|
||||
@@ -33189,7 +33189,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 */
|
||||
@@ -33937,7 +33937,7 @@ done:
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Register VM Public API
|
||||
MACH Public API
|
||||
============================================================ */
|
||||
|
||||
/* Print a single constant pool value for dump output */
|
||||
@@ -34275,25 +34275,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 */
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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), "<test>");
|
||||
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), "<test>");
|
||||
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), "<test>");
|
||||
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), "<test>");
|
||||
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), "<test>");
|
||||
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), "<test>");
|
||||
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), "<test>");
|
||||
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), "<test>");
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user