Compare commits
3 Commits
af2d296f40
...
8cf98d8a9e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cf98d8a9e | ||
|
|
3c38e828e5 | ||
|
|
0a45394689 |
153
source/cell.c
153
source/cell.c
@@ -399,33 +399,15 @@ int cell_init(int argc, char **argv)
|
||||
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 *json = JS_AST(ctx, script, strlen(script), filename);
|
||||
char *json = JS_AST(script, strlen(script), filename);
|
||||
if (json) {
|
||||
int has_errors = print_json_errors(json);
|
||||
printf("%s\n", json);
|
||||
free(json);
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
free(allocated_script);
|
||||
return has_errors ? 1 : 0;
|
||||
} else {
|
||||
printf("Failed to parse AST\n");
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
free(allocated_script);
|
||||
return 1;
|
||||
}
|
||||
@@ -460,33 +442,15 @@ int cell_init(int argc, char **argv)
|
||||
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 *json = JS_Tokenize(ctx, script, strlen(script), filename);
|
||||
char *json = JS_Tokenize(script, strlen(script), filename);
|
||||
if (json) {
|
||||
int has_errors = print_json_errors(json);
|
||||
printf("%s\n", json);
|
||||
free(json);
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
free(allocated_script);
|
||||
return has_errors ? 1 : 0;
|
||||
} else {
|
||||
printf("Failed to tokenize\n");
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
free(allocated_script);
|
||||
return 1;
|
||||
}
|
||||
@@ -521,51 +485,31 @@ int cell_init(int argc, char **argv)
|
||||
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);
|
||||
char *ast_json = JS_AST(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);
|
||||
char *mcode_json = JS_Mcode(ast_json);
|
||||
free(ast_json);
|
||||
|
||||
if (!mcode_json) {
|
||||
printf("Failed to generate MCODE\n");
|
||||
JS_FreeContext(ctx); JS_FreeRuntime(rt); free(allocated_script);
|
||||
free(allocated_script);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("%s\n", mcode_json);
|
||||
free(mcode_json);
|
||||
|
||||
JS_FreeContext(ctx);
|
||||
JS_FreeRuntime(rt);
|
||||
free(allocated_script);
|
||||
return 0;
|
||||
}
|
||||
@@ -592,40 +536,35 @@ int cell_init(int argc, char **argv)
|
||||
script = (char *)script_or_file;
|
||||
}
|
||||
|
||||
JSRuntime *rt = JS_NewRuntime();
|
||||
if (!rt) { printf("Failed to create JS runtime\n"); free(allocated_script); return 1; }
|
||||
/* Use a parser context (small heap) for AST + MCODE generation */
|
||||
JSContext *parse_ctx = JS_NewContext(rt);
|
||||
if (!parse_ctx) { printf("Failed to create JS context\n"); JS_FreeRuntime(rt); free(allocated_script); return 1; }
|
||||
|
||||
char *ast_json = JS_AST(parse_ctx, script, strlen(script), filename);
|
||||
char *ast_json = JS_AST(script, strlen(script), filename);
|
||||
if (!ast_json) {
|
||||
printf("Failed to parse AST\n");
|
||||
JS_FreeContext(parse_ctx); JS_FreeRuntime(rt); free(allocated_script);
|
||||
free(allocated_script);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (print_json_errors(ast_json)) {
|
||||
free(ast_json); JS_FreeContext(parse_ctx); JS_FreeRuntime(rt); free(allocated_script);
|
||||
free(ast_json); free(allocated_script);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *mcode_json = JS_Mcode(parse_ctx, ast_json);
|
||||
char *mcode_json = JS_Mcode(ast_json);
|
||||
free(ast_json);
|
||||
JS_FreeContext(parse_ctx);
|
||||
|
||||
if (!mcode_json) {
|
||||
printf("Failed to generate MCODE\n");
|
||||
JS_FreeRuntime(rt); free(allocated_script);
|
||||
free(allocated_script);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (print_json_errors(mcode_json)) {
|
||||
free(mcode_json); JS_FreeRuntime(rt); free(allocated_script);
|
||||
free(mcode_json); free(allocated_script);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Use a larger heap context for execution */
|
||||
JSRuntime *rt = JS_NewRuntime();
|
||||
if (!rt) { printf("Failed to create JS runtime\n"); free(mcode_json); free(allocated_script); return 1; }
|
||||
JSContext *ctx = JS_NewContextWithHeapSize(rt, 64 * 1024);
|
||||
if (!ctx) { printf("Failed to create execution context\n"); free(mcode_json); JS_FreeRuntime(rt); free(allocated_script); return 1; }
|
||||
|
||||
@@ -676,37 +615,32 @@ int cell_init(int argc, char **argv)
|
||||
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);
|
||||
char *ast_json = JS_AST(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;
|
||||
}
|
||||
|
||||
JSRuntime *rt = JS_NewRuntime();
|
||||
if (!rt) {
|
||||
printf("Failed to create JS runtime\n");
|
||||
free(ast_json); free(allocated_script);
|
||||
return 1;
|
||||
}
|
||||
JSContext *ctx = JS_NewContext(rt);
|
||||
if (!ctx) {
|
||||
printf("Failed to create JS context\n");
|
||||
free(ast_json); JS_FreeRuntime(rt); free(allocated_script);
|
||||
return 1;
|
||||
}
|
||||
|
||||
JS_DumpMach(ctx, ast_json, JS_NULL);
|
||||
free(ast_json);
|
||||
|
||||
@@ -745,37 +679,32 @@ int cell_init(int argc, char **argv)
|
||||
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);
|
||||
char *ast_json = JS_AST(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;
|
||||
}
|
||||
|
||||
JSRuntime *rt = JS_NewRuntime();
|
||||
if (!rt) {
|
||||
printf("Failed to create JS runtime\n");
|
||||
free(ast_json); free(allocated_script);
|
||||
return 1;
|
||||
}
|
||||
JSContext *ctx = JS_NewContext(rt);
|
||||
if (!ctx) {
|
||||
printf("Failed to create JS context\n");
|
||||
free(ast_json); JS_FreeRuntime(rt); free(allocated_script);
|
||||
return 1;
|
||||
}
|
||||
|
||||
JSValue result = JS_RunMach(ctx, ast_json, JS_NULL);
|
||||
free(ast_json);
|
||||
|
||||
|
||||
398
source/quickjs.c
398
source/quickjs.c
@@ -27857,7 +27857,6 @@ JSValue js_math_cycles_use (JSContext *ctx) {
|
||||
============================================================ */
|
||||
|
||||
typedef struct ASTParseState {
|
||||
JSContext *ctx;
|
||||
const char *filename;
|
||||
const uint8_t *buf_start;
|
||||
const uint8_t *buf_ptr;
|
||||
@@ -27870,23 +27869,42 @@ typedef struct ASTParseState {
|
||||
int has_error;
|
||||
union {
|
||||
struct {
|
||||
JSValue str;
|
||||
const char *str;
|
||||
size_t len;
|
||||
} str;
|
||||
struct {
|
||||
JSValue val;
|
||||
double val;
|
||||
} num;
|
||||
struct {
|
||||
JSValue str;
|
||||
const char *str;
|
||||
size_t len;
|
||||
BOOL has_escape;
|
||||
BOOL is_reserved;
|
||||
} ident;
|
||||
struct {
|
||||
JSValue body;
|
||||
JSValue flags;
|
||||
const char *body;
|
||||
size_t body_len;
|
||||
const char *flags;
|
||||
size_t flags_len;
|
||||
} regexp;
|
||||
} token_u;
|
||||
} ASTParseState;
|
||||
|
||||
/* Add a length-delimited string to a cJSON object (source pointers aren't null-terminated) */
|
||||
static void cjson_add_strn (cJSON *obj, const char *key, const char *str, size_t len) {
|
||||
char *tmp = sys_malloc (len + 1);
|
||||
memcpy (tmp, str, len);
|
||||
tmp[len] = '\0';
|
||||
cJSON_AddStringToObject (obj, key, tmp);
|
||||
sys_free (tmp);
|
||||
}
|
||||
|
||||
/* Compare a length-delimited token string against a null-terminated literal */
|
||||
static inline BOOL tok_eq (const char *str, size_t len, const char *lit) {
|
||||
size_t ll = strlen (lit);
|
||||
return len == ll && memcmp (str, lit, ll) == 0;
|
||||
}
|
||||
|
||||
static cJSON *ast_parse_expr (ASTParseState *s);
|
||||
static cJSON *ast_parse_assign_expr (ASTParseState *s);
|
||||
static cJSON *ast_parse_statement (ASTParseState *s);
|
||||
@@ -28046,7 +28064,8 @@ redo:
|
||||
}
|
||||
p++;
|
||||
s->token_val = TOK_TEMPLATE;
|
||||
s->token_u.str.str = JS_NewStringLen (s->ctx, (const char *)(start + 1), p - start - 2);
|
||||
s->token_u.str.str = (const char *)(start + 1);
|
||||
s->token_u.str.len = p - start - 2;
|
||||
} break;
|
||||
case '\'':
|
||||
case '\"': {
|
||||
@@ -28065,7 +28084,8 @@ redo:
|
||||
p++;
|
||||
/* Store the string content without quotes */
|
||||
s->token_val = TOK_STRING;
|
||||
s->token_u.str.str = JS_NewStringLen (s->ctx, (const char *)(start + 1), p - start - 2);
|
||||
s->token_u.str.str = (const char *)(start + 1);
|
||||
s->token_u.str.len = p - start - 2;
|
||||
} break;
|
||||
case '\r':
|
||||
if (p[1] == '\n') p++;
|
||||
@@ -28137,7 +28157,8 @@ redo:
|
||||
}
|
||||
}
|
||||
size_t len = p - start;
|
||||
s->token_u.ident.str = JS_NewStringLen (s->ctx, (const char *)start, len);
|
||||
s->token_u.ident.str = (const char *)start;
|
||||
s->token_u.ident.len = len;
|
||||
s->token_u.ident.has_escape = ident_has_escape;
|
||||
s->token_u.ident.is_reserved = FALSE;
|
||||
s->token_val = TOK_IDENT;
|
||||
@@ -28222,7 +28243,7 @@ redo:
|
||||
numstr[p - start] = '\0';
|
||||
double val = strtod (numstr, NULL);
|
||||
sys_free (numstr);
|
||||
s->token_u.num.val = JS_NewFloat64 (s->ctx, val);
|
||||
s->token_u.num.val = val;
|
||||
} break;
|
||||
case '*':
|
||||
if (p[1] == '=') { p += 2; s->token_val = TOK_MUL_ASSIGN; }
|
||||
@@ -28357,11 +28378,13 @@ static int tokenize_next (ASTParseState *s) {
|
||||
if (p >= s->buf_end) {
|
||||
ast_error (s, start, "unterminated template literal");
|
||||
s->token_val = TOK_ERROR;
|
||||
s->token_u.str.str = JS_NewStringLen (s->ctx, (const char *)(start + 1), p - start - 1);
|
||||
s->token_u.str.str = (const char *)(start + 1);
|
||||
s->token_u.str.len = p - start - 1;
|
||||
} else {
|
||||
p++;
|
||||
s->token_val = TOK_TEMPLATE;
|
||||
s->token_u.str.str = JS_NewStringLen (s->ctx, (const char *)(start + 1), p - start - 2);
|
||||
s->token_u.str.str = (const char *)(start + 1);
|
||||
s->token_u.str.len = p - start - 2;
|
||||
}
|
||||
} break;
|
||||
case '\'':
|
||||
@@ -28376,11 +28399,13 @@ static int tokenize_next (ASTParseState *s) {
|
||||
if (p >= s->buf_end) {
|
||||
ast_error (s, start, "unterminated string literal");
|
||||
s->token_val = TOK_ERROR;
|
||||
s->token_u.str.str = JS_NewStringLen (s->ctx, (const char *)(start + 1), p - start - 1);
|
||||
s->token_u.str.str = (const char *)(start + 1);
|
||||
s->token_u.str.len = p - start - 1;
|
||||
} else {
|
||||
p++;
|
||||
s->token_val = TOK_STRING;
|
||||
s->token_u.str.str = JS_NewStringLen (s->ctx, (const char *)(start + 1), p - start - 2);
|
||||
s->token_u.str.str = (const char *)(start + 1);
|
||||
s->token_u.str.len = p - start - 2;
|
||||
}
|
||||
} break;
|
||||
case '\r':
|
||||
@@ -28460,7 +28485,8 @@ static int tokenize_next (ASTParseState *s) {
|
||||
}
|
||||
}
|
||||
size_t len = p - start;
|
||||
s->token_u.ident.str = JS_NewStringLen (s->ctx, (const char *)start, len);
|
||||
s->token_u.ident.str = (const char *)start;
|
||||
s->token_u.ident.len = len;
|
||||
s->token_u.ident.has_escape = ident_has_escape;
|
||||
s->token_u.ident.is_reserved = FALSE;
|
||||
s->token_val = TOK_IDENT;
|
||||
@@ -28544,7 +28570,7 @@ static int tokenize_next (ASTParseState *s) {
|
||||
numstr[p - start] = '\0';
|
||||
double val = strtod (numstr, NULL);
|
||||
sys_free (numstr);
|
||||
s->token_u.num.val = JS_NewFloat64 (s->ctx, val);
|
||||
s->token_u.num.val = val;
|
||||
} break;
|
||||
case '*':
|
||||
if (p[1] == '=') { p += 2; s->token_val = TOK_MUL_ASSIGN; }
|
||||
@@ -28639,10 +28665,7 @@ static cJSON *ast_parse_primary (ASTParseState *s) {
|
||||
switch (s->token_val) {
|
||||
case TOK_NUMBER: {
|
||||
node = ast_node (s, "number", start);
|
||||
double d = JS_VALUE_GET_FLOAT64 (s->token_u.num.val);
|
||||
if (JS_VALUE_GET_TAG (s->token_u.num.val) == JS_TAG_INT) {
|
||||
d = JS_VALUE_GET_INT (s->token_u.num.val);
|
||||
}
|
||||
double d = s->token_u.num.val;
|
||||
/* Store original text representation */
|
||||
size_t len = s->buf_ptr - start;
|
||||
char *text = sys_malloc (len + 1);
|
||||
@@ -28657,9 +28680,7 @@ static cJSON *ast_parse_primary (ASTParseState *s) {
|
||||
|
||||
case TOK_STRING: {
|
||||
node = ast_node (s, "text", start);
|
||||
const char *str = JS_ToCString (s->ctx, s->token_u.str.str);
|
||||
cJSON_AddStringToObject (node, "value", str ? str : "");
|
||||
JS_FreeCString (s->ctx, str);
|
||||
cjson_add_strn (node, "value", s->token_u.str.str, s->token_u.str.len);
|
||||
ast_node_end (s, node, s->buf_ptr);
|
||||
ast_next_token (s);
|
||||
} break;
|
||||
@@ -28681,9 +28702,7 @@ static cJSON *ast_parse_primary (ASTParseState *s) {
|
||||
if (!has_expr) {
|
||||
/* Simple template — unchanged behavior */
|
||||
node = ast_node (s, "text", start);
|
||||
const char *str = JS_ToCString (s->ctx, s->token_u.str.str);
|
||||
cJSON_AddStringToObject (node, "value", str ? str : "");
|
||||
JS_FreeCString (s->ctx, str);
|
||||
cjson_add_strn (node, "value", s->token_u.str.str, s->token_u.str.len);
|
||||
ast_node_end (s, node, s->buf_ptr);
|
||||
ast_next_token (s);
|
||||
} else {
|
||||
@@ -28747,9 +28766,7 @@ static cJSON *ast_parse_primary (ASTParseState *s) {
|
||||
node = ast_parse_arrow_function (s);
|
||||
} else {
|
||||
node = ast_node (s, "name", start);
|
||||
const char *str = JS_ToCString (s->ctx, s->token_u.ident.str);
|
||||
cJSON_AddStringToObject (node, "name", str ? str : "");
|
||||
JS_FreeCString (s->ctx, str);
|
||||
cjson_add_strn (node, "name", s->token_u.ident.str, s->token_u.ident.len);
|
||||
ast_node_end (s, node, s->buf_ptr);
|
||||
ast_next_token (s);
|
||||
}
|
||||
@@ -28845,9 +28862,7 @@ static cJSON *ast_parse_primary (ASTParseState *s) {
|
||||
while (s->token_val != ')' && s->token_val != TOK_EOF) {
|
||||
if (s->token_val == TOK_IDENT) {
|
||||
cJSON *param = ast_node (s, "name", s->token_ptr);
|
||||
const char *str = JS_ToCString (s->ctx, s->token_u.ident.str);
|
||||
cJSON_AddStringToObject (param, "name", str ? str : "");
|
||||
JS_FreeCString (s->ctx, str);
|
||||
cjson_add_strn (param, "name", s->token_u.ident.str, s->token_u.ident.len);
|
||||
ast_node_end (s, param, s->buf_ptr);
|
||||
ast_next_token (s);
|
||||
if (s->token_val == '=' || s->token_val == '|') {
|
||||
@@ -28994,9 +29009,7 @@ static cJSON *ast_parse_postfix (ASTParseState *s) {
|
||||
cJSON *new_node = ast_node (s, ".", start);
|
||||
cJSON_AddItemToObject (new_node, "left", node);
|
||||
if (s->token_val == TOK_IDENT) {
|
||||
const char *str = JS_ToCString (s->ctx, s->token_u.ident.str);
|
||||
cJSON_AddStringToObject (new_node, "right", str ? str : "");
|
||||
JS_FreeCString (s->ctx, str);
|
||||
cjson_add_strn (new_node, "right", s->token_u.ident.str, s->token_u.ident.len);
|
||||
ast_next_token (s);
|
||||
} else {
|
||||
ast_error (s, s->token_ptr, "expected property name after '.'");
|
||||
@@ -29079,9 +29092,7 @@ static cJSON *ast_parse_postfix (ASTParseState *s) {
|
||||
/* Optional property access: o?.a */
|
||||
cJSON *new_node = ast_node (s, "?.", start);
|
||||
cJSON_AddItemToObject (new_node, "left", node);
|
||||
const char *str = JS_ToCString (s->ctx, s->token_u.ident.str);
|
||||
cJSON_AddStringToObject (new_node, "right", str ? str : "");
|
||||
JS_FreeCString (s->ctx, str);
|
||||
cjson_add_strn (new_node, "right", s->token_u.ident.str, s->token_u.ident.len);
|
||||
ast_next_token (s);
|
||||
ast_node_end (s, new_node, s->buf_ptr);
|
||||
node = new_node;
|
||||
@@ -29363,9 +29374,7 @@ static cJSON *ast_parse_function_inner (ASTParseState *s, BOOL is_expr) {
|
||||
|
||||
/* Optional function name */
|
||||
if (s->token_val == TOK_IDENT) {
|
||||
const char *str = JS_ToCString (s->ctx, s->token_u.ident.str);
|
||||
cJSON_AddStringToObject (node, "name", str ? str : "");
|
||||
JS_FreeCString (s->ctx, str);
|
||||
cjson_add_strn (node, "name", s->token_u.ident.str, s->token_u.ident.len);
|
||||
ast_next_token (s);
|
||||
}
|
||||
|
||||
@@ -29377,18 +29386,22 @@ static cJSON *ast_parse_function_inner (ASTParseState *s, BOOL is_expr) {
|
||||
if (s->token_val == TOK_IDENT) {
|
||||
const uint8_t *param_ptr = s->token_ptr;
|
||||
cJSON *param = ast_node (s, "name", param_ptr);
|
||||
const char *str = JS_ToCString (s->ctx, s->token_u.ident.str);
|
||||
cJSON_AddStringToObject (param, "name", str ? str : "");
|
||||
cjson_add_strn (param, "name", s->token_u.ident.str, s->token_u.ident.len);
|
||||
/* Check for duplicate parameter name */
|
||||
{
|
||||
char *tmp_name = sys_malloc (s->token_u.ident.len + 1);
|
||||
memcpy (tmp_name, s->token_u.ident.str, s->token_u.ident.len);
|
||||
tmp_name[s->token_u.ident.len] = '\0';
|
||||
cJSON *prev;
|
||||
cJSON_ArrayForEach (prev, params) {
|
||||
const char *prev_name = cJSON_GetStringValue (cJSON_GetObjectItem (prev, "name"));
|
||||
if (prev_name && str && strcmp (prev_name, str) == 0) {
|
||||
ast_error (s, param_ptr, "duplicate parameter name '%s'", str);
|
||||
if (prev_name && strcmp (prev_name, tmp_name) == 0) {
|
||||
ast_error (s, param_ptr, "duplicate parameter name '%s'", tmp_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
JS_FreeCString (s->ctx, str);
|
||||
sys_free (tmp_name);
|
||||
}
|
||||
ast_node_end (s, param, s->buf_ptr);
|
||||
ast_next_token (s);
|
||||
if (s->token_val == '=' || s->token_val == '|') {
|
||||
@@ -29448,9 +29461,7 @@ static cJSON *ast_parse_arrow_function (ASTParseState *s) {
|
||||
if (s->token_val == TOK_IDENT) {
|
||||
/* Single parameter without parens: x => ... */
|
||||
cJSON *param = ast_node (s, "name", s->token_ptr);
|
||||
const char *str = JS_ToCString (s->ctx, s->token_u.ident.str);
|
||||
cJSON_AddStringToObject (param, "name", str ? str : "");
|
||||
JS_FreeCString (s->ctx, str);
|
||||
cjson_add_strn (param, "name", s->token_u.ident.str, s->token_u.ident.len);
|
||||
ast_node_end (s, param, s->buf_ptr);
|
||||
cJSON_AddItemToArray (params, param);
|
||||
ast_next_token (s);
|
||||
@@ -29461,18 +29472,22 @@ static cJSON *ast_parse_arrow_function (ASTParseState *s) {
|
||||
if (s->token_val == TOK_IDENT) {
|
||||
const uint8_t *param_ptr = s->token_ptr;
|
||||
cJSON *param = ast_node (s, "name", param_ptr);
|
||||
const char *str = JS_ToCString (s->ctx, s->token_u.ident.str);
|
||||
cJSON_AddStringToObject (param, "name", str ? str : "");
|
||||
cjson_add_strn (param, "name", s->token_u.ident.str, s->token_u.ident.len);
|
||||
/* Check for duplicate parameter name */
|
||||
{
|
||||
char *tmp_name = sys_malloc (s->token_u.ident.len + 1);
|
||||
memcpy (tmp_name, s->token_u.ident.str, s->token_u.ident.len);
|
||||
tmp_name[s->token_u.ident.len] = '\0';
|
||||
cJSON *prev;
|
||||
cJSON_ArrayForEach (prev, params) {
|
||||
const char *prev_name = cJSON_GetStringValue (cJSON_GetObjectItem (prev, "name"));
|
||||
if (prev_name && str && strcmp (prev_name, str) == 0) {
|
||||
ast_error (s, param_ptr, "duplicate parameter name '%s'", str);
|
||||
if (prev_name && strcmp (prev_name, tmp_name) == 0) {
|
||||
ast_error (s, param_ptr, "duplicate parameter name '%s'", tmp_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
JS_FreeCString (s->ctx, str);
|
||||
sys_free (tmp_name);
|
||||
}
|
||||
ast_node_end (s, param, s->buf_ptr);
|
||||
ast_next_token (s);
|
||||
|
||||
@@ -29587,8 +29602,11 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
|
||||
const uint8_t *var_ptr = s->token_ptr;
|
||||
node = ast_node (s, kind_name, start);
|
||||
cJSON *left = ast_node (s, "name", s->token_ptr);
|
||||
const char *str = JS_ToCString (s->ctx, s->token_u.ident.str);
|
||||
cJSON_AddStringToObject (left, "name", str ? str : "");
|
||||
cjson_add_strn (left, "name", s->token_u.ident.str, s->token_u.ident.len);
|
||||
/* Save name for potential error message */
|
||||
char *var_name = sys_malloc (s->token_u.ident.len + 1);
|
||||
memcpy (var_name, s->token_u.ident.str, s->token_u.ident.len);
|
||||
var_name[s->token_u.ident.len] = '\0';
|
||||
ast_node_end (s, left, s->buf_ptr);
|
||||
cJSON_AddItemToObject (node, "left", left);
|
||||
ast_next_token (s);
|
||||
@@ -29602,9 +29620,9 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
|
||||
cJSON_AddBoolToObject (node, "pop", 1);
|
||||
} else if (is_def) {
|
||||
/* def (constant) requires initializer */
|
||||
ast_error (s, var_ptr, "missing initializer for constant '%s'", str);
|
||||
ast_error (s, var_ptr, "missing initializer for constant '%s'", var_name);
|
||||
}
|
||||
JS_FreeCString (s->ctx, str);
|
||||
sys_free (var_name);
|
||||
ast_node_end (s, node, s->buf_ptr);
|
||||
cJSON_AddItemToArray (decls, node);
|
||||
decl_count++;
|
||||
@@ -29772,9 +29790,7 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
|
||||
node = ast_node (s, "break", start);
|
||||
ast_next_token (s);
|
||||
if (s->token_val == TOK_IDENT && !s->got_lf) {
|
||||
const char *str = JS_ToCString (s->ctx, s->token_u.ident.str);
|
||||
cJSON_AddStringToObject (node, "name", str ? str : "");
|
||||
JS_FreeCString (s->ctx, str);
|
||||
cjson_add_strn (node, "name", s->token_u.ident.str, s->token_u.ident.len);
|
||||
ast_next_token (s);
|
||||
}
|
||||
ast_expect_semi (s);
|
||||
@@ -29785,9 +29801,7 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
|
||||
node = ast_node (s, "continue", start);
|
||||
ast_next_token (s);
|
||||
if (s->token_val == TOK_IDENT && !s->got_lf) {
|
||||
const char *str = JS_ToCString (s->ctx, s->token_u.ident.str);
|
||||
cJSON_AddStringToObject (node, "name", str ? str : "");
|
||||
JS_FreeCString (s->ctx, str);
|
||||
cjson_add_strn (node, "name", s->token_u.ident.str, s->token_u.ident.len);
|
||||
ast_next_token (s);
|
||||
}
|
||||
ast_expect_semi (s);
|
||||
@@ -29816,9 +29830,7 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
|
||||
if (s->token_val == '(') {
|
||||
ast_next_token (s);
|
||||
if (s->token_val == TOK_IDENT) {
|
||||
const char *str = JS_ToCString (s->ctx, s->token_u.ident.str);
|
||||
cJSON_AddStringToObject (catch_node, "name", str ? str : "");
|
||||
JS_FreeCString (s->ctx, str);
|
||||
cjson_add_strn (catch_node, "name", s->token_u.ident.str, s->token_u.ident.len);
|
||||
ast_next_token (s);
|
||||
}
|
||||
if (s->token_val == ')') ast_next_token (s);
|
||||
@@ -29864,9 +29876,7 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
|
||||
if (p < s->buf_end && *p == ':') {
|
||||
/* Labeled statement */
|
||||
node = ast_node (s, "label", start);
|
||||
const char *str = JS_ToCString (s->ctx, s->token_u.ident.str);
|
||||
cJSON_AddStringToObject (node, "name", str ? str : "");
|
||||
JS_FreeCString (s->ctx, str);
|
||||
cjson_add_strn (node, "name", s->token_u.ident.str, s->token_u.ident.len);
|
||||
ast_next_token (s); /* skip identifier */
|
||||
ast_next_token (s); /* skip colon */
|
||||
cJSON *stmt = ast_parse_statement (s);
|
||||
@@ -30540,11 +30550,10 @@ static void ast_semantic_check (cJSON *ast, cJSON **errors_out,
|
||||
*intrinsics_out = intr_arr;
|
||||
}
|
||||
|
||||
char *JS_AST (JSContext *ctx, const char *source, size_t len, const char *filename) {
|
||||
char *JS_AST (const char *source, size_t len, const char *filename) {
|
||||
ASTParseState s;
|
||||
memset (&s, 0, sizeof (s));
|
||||
|
||||
s.ctx = ctx;
|
||||
s.filename = filename;
|
||||
s.buf_start = (const uint8_t *)source;
|
||||
s.buf_ptr = (const uint8_t *)source;
|
||||
@@ -30628,22 +30637,15 @@ static cJSON *build_token_object (ASTParseState *s) {
|
||||
cJSON_AddStringToObject (tok, "value", text);
|
||||
sys_free (text);
|
||||
/* Store parsed number */
|
||||
double d = JS_VALUE_GET_FLOAT64 (s->token_u.num.val);
|
||||
if (JS_VALUE_GET_TAG (s->token_u.num.val) == JS_TAG_INT) {
|
||||
d = JS_VALUE_GET_INT (s->token_u.num.val);
|
||||
}
|
||||
double d = s->token_u.num.val;
|
||||
cJSON_AddNumberToObject (tok, "number", d);
|
||||
} break;
|
||||
case TOK_STRING:
|
||||
case TOK_TEMPLATE: {
|
||||
const char *str = JS_ToCString (s->ctx, s->token_u.str.str);
|
||||
cJSON_AddStringToObject (tok, "value", str ? str : "");
|
||||
JS_FreeCString (s->ctx, str);
|
||||
cjson_add_strn (tok, "value", s->token_u.str.str, s->token_u.str.len);
|
||||
} break;
|
||||
case TOK_IDENT: {
|
||||
const char *str = JS_ToCString (s->ctx, s->token_u.ident.str);
|
||||
cJSON_AddStringToObject (tok, "value", str ? str : "");
|
||||
JS_FreeCString (s->ctx, str);
|
||||
cjson_add_strn (tok, "value", s->token_u.ident.str, s->token_u.ident.len);
|
||||
} break;
|
||||
case TOK_ERROR: {
|
||||
/* Store the raw source text as value */
|
||||
@@ -30673,11 +30675,10 @@ static cJSON *build_token_object (ASTParseState *s) {
|
||||
return tok;
|
||||
}
|
||||
|
||||
char *JS_Tokenize (JSContext *ctx, const char *source, size_t len, const char *filename) {
|
||||
char *JS_Tokenize (const char *source, size_t len, const char *filename) {
|
||||
ASTParseState s;
|
||||
memset (&s, 0, sizeof (s));
|
||||
|
||||
s.ctx = ctx;
|
||||
s.filename = filename;
|
||||
s.buf_start = (const uint8_t *)source;
|
||||
s.buf_ptr = (const uint8_t *)source;
|
||||
@@ -30731,23 +30732,52 @@ typedef struct MachVarInfo {
|
||||
int is_closure; /* 1 if captured by a nested function */
|
||||
} MachVarInfo;
|
||||
|
||||
/* ---- Compile-time constant pool entry ---- */
|
||||
/* Stores raw data during compilation; converted to JSValues when loading into context */
|
||||
typedef enum { MACH_CP_INT, MACH_CP_FLOAT, MACH_CP_STR } MachCPType;
|
||||
typedef struct {
|
||||
MachCPType type;
|
||||
union {
|
||||
int32_t ival; /* integer constant */
|
||||
double fval; /* float constant */
|
||||
char *str; /* owned C string */
|
||||
};
|
||||
} MachCPoolEntry;
|
||||
|
||||
/* ---- Compiled output (context-free) ---- */
|
||||
typedef struct MachCode {
|
||||
uint16_t arity;
|
||||
uint16_t nr_close_slots;
|
||||
uint16_t nr_slots;
|
||||
uint16_t entry_point;
|
||||
|
||||
uint32_t cpool_count;
|
||||
MachCPoolEntry *cpool;
|
||||
|
||||
uint32_t instr_count;
|
||||
MachInstr32 *instructions;
|
||||
|
||||
uint32_t func_count;
|
||||
struct MachCode **functions;
|
||||
|
||||
char *name; /* owned C string, or NULL */
|
||||
} MachCode;
|
||||
|
||||
/* ---- Compiler state ---- */
|
||||
|
||||
typedef struct MachCompState {
|
||||
JSContext *ctx;
|
||||
|
||||
/* Instruction buffer (growable) */
|
||||
MachInstr32 *code;
|
||||
int code_count;
|
||||
int code_capacity;
|
||||
|
||||
/* Constant pool */
|
||||
JSValue *cpool;
|
||||
/* Constant pool (raw entries, no GC objects) */
|
||||
MachCPoolEntry *cpool;
|
||||
int cpool_count;
|
||||
int cpool_capacity;
|
||||
|
||||
/* Nested functions */
|
||||
JSCodeRegister **functions;
|
||||
MachCode **functions;
|
||||
int func_count;
|
||||
int func_capacity;
|
||||
|
||||
@@ -30810,56 +30840,77 @@ static void mach_free_reg_to(MachCompState *cs, int saved) {
|
||||
cs->freereg = saved;
|
||||
}
|
||||
|
||||
/* Add a constant to the pool, return its index */
|
||||
static int mach_cpool_add(MachCompState *cs, JSValue val) {
|
||||
/* Check for duplicates (simple linear scan) */
|
||||
/* Add an integer constant to the pool, return its index */
|
||||
static int mach_cpool_add_int(MachCompState *cs, int32_t val) {
|
||||
for (int i = 0; i < cs->cpool_count; i++) {
|
||||
JSValue existing = cs->cpool[i];
|
||||
/* Compare by tag and value */
|
||||
if (JS_IsInt(val) && JS_IsInt(existing)) {
|
||||
if (JS_VALUE_GET_INT(val) == JS_VALUE_GET_INT(existing))
|
||||
return i;
|
||||
} else if (JS_VALUE_IS_TEXT(val) && JS_VALUE_IS_TEXT(existing)) {
|
||||
const char *a = JS_ToCString(cs->ctx, val);
|
||||
const char *b = JS_ToCString(cs->ctx, existing);
|
||||
int eq = a && b && strcmp(a, b) == 0;
|
||||
JS_FreeCString(cs->ctx, a);
|
||||
JS_FreeCString(cs->ctx, b);
|
||||
if (eq) return i;
|
||||
MachCPoolEntry *e = &cs->cpool[i];
|
||||
if (e->type == MACH_CP_INT && e->ival == val) return i;
|
||||
}
|
||||
}
|
||||
|
||||
if (cs->cpool_count >= cs->cpool_capacity) {
|
||||
int new_cap = cs->cpool_capacity ? cs->cpool_capacity * 2 : 16;
|
||||
cs->cpool = sys_realloc(cs->cpool, new_cap * sizeof(JSValue));
|
||||
cs->cpool = sys_realloc(cs->cpool, new_cap * sizeof(MachCPoolEntry));
|
||||
cs->cpool_capacity = new_cap;
|
||||
}
|
||||
cs->cpool[cs->cpool_count] = val;
|
||||
cs->cpool[cs->cpool_count] = (MachCPoolEntry){ .type = MACH_CP_INT, .ival = val };
|
||||
return cs->cpool_count++;
|
||||
}
|
||||
|
||||
/* Add a float constant to the pool, return its index */
|
||||
static int mach_cpool_add_float(MachCompState *cs, double val) {
|
||||
for (int i = 0; i < cs->cpool_count; i++) {
|
||||
MachCPoolEntry *e = &cs->cpool[i];
|
||||
if (e->type == MACH_CP_FLOAT && e->fval == val) return i;
|
||||
}
|
||||
if (cs->cpool_count >= cs->cpool_capacity) {
|
||||
int new_cap = cs->cpool_capacity ? cs->cpool_capacity * 2 : 16;
|
||||
cs->cpool = sys_realloc(cs->cpool, new_cap * sizeof(MachCPoolEntry));
|
||||
cs->cpool_capacity = new_cap;
|
||||
}
|
||||
cs->cpool[cs->cpool_count] = (MachCPoolEntry){ .type = MACH_CP_FLOAT, .fval = val };
|
||||
return cs->cpool_count++;
|
||||
}
|
||||
|
||||
/* Add a string constant, return its cpool index */
|
||||
static int mach_cpool_add_str(MachCompState *cs, const char *str) {
|
||||
/* Check for existing identical string first (before allocating) */
|
||||
/* Check for existing identical string */
|
||||
for (int i = 0; i < cs->cpool_count; i++) {
|
||||
JSValue existing = cs->cpool[i];
|
||||
if (JS_VALUE_IS_TEXT(existing)) {
|
||||
const char *s = JS_ToCString(cs->ctx, existing);
|
||||
int eq = s && strcmp(s, str) == 0;
|
||||
JS_FreeCString(cs->ctx, s);
|
||||
if (eq) return i;
|
||||
MachCPoolEntry *e = &cs->cpool[i];
|
||||
if (e->type == MACH_CP_STR && strcmp(e->str, str) == 0)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
JSValue val = JS_NewString(cs->ctx, str);
|
||||
if (cs->cpool_count >= cs->cpool_capacity) {
|
||||
int new_cap = cs->cpool_capacity ? cs->cpool_capacity * 2 : 16;
|
||||
cs->cpool = sys_realloc(cs->cpool, new_cap * sizeof(JSValue));
|
||||
cs->cpool = sys_realloc(cs->cpool, new_cap * sizeof(MachCPoolEntry));
|
||||
cs->cpool_capacity = new_cap;
|
||||
}
|
||||
cs->cpool[cs->cpool_count] = val;
|
||||
char *dup = sys_malloc(strlen(str) + 1);
|
||||
memcpy(dup, str, strlen(str) + 1);
|
||||
cs->cpool[cs->cpool_count] = (MachCPoolEntry){ .type = MACH_CP_STR, .str = dup };
|
||||
return cs->cpool_count++;
|
||||
}
|
||||
|
||||
/* Convert compile-time cpool entries to JSValue array for JSCodeRegister.
|
||||
Caller takes ownership of the returned array. Frees the raw entries.
|
||||
Strings are interned into stone memory (no GC allocation). */
|
||||
static JSValue *mach_materialize_cpool(JSContext *ctx, MachCPoolEntry *entries, int count) {
|
||||
if (count == 0) { sys_free(entries); return NULL; }
|
||||
JSValue *cpool = js_malloc_rt(count * sizeof(JSValue));
|
||||
for (int i = 0; i < count; i++) {
|
||||
switch (entries[i].type) {
|
||||
case MACH_CP_INT:
|
||||
cpool[i] = JS_NewInt32(ctx, entries[i].ival);
|
||||
break;
|
||||
case MACH_CP_FLOAT:
|
||||
cpool[i] = JS_NewFloat64(ctx, entries[i].fval);
|
||||
break;
|
||||
case MACH_CP_STR:
|
||||
cpool[i] = js_key_new(ctx, entries[i].str);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cpool;
|
||||
}
|
||||
|
||||
/* Add a variable */
|
||||
static void mach_add_var(MachCompState *cs, const char *name, int slot, int is_const) {
|
||||
if (cs->var_count >= cs->var_capacity) {
|
||||
@@ -30885,10 +30936,10 @@ static int mach_find_var(MachCompState *cs, const char *name) {
|
||||
}
|
||||
|
||||
/* Add a nested function, return its index */
|
||||
static int mach_add_function(MachCompState *cs, JSCodeRegister *fn) {
|
||||
static int mach_add_function(MachCompState *cs, MachCode *fn) {
|
||||
if (cs->func_count >= cs->func_capacity) {
|
||||
int new_cap = cs->func_capacity ? cs->func_capacity * 2 : 4;
|
||||
cs->functions = sys_realloc(cs->functions, new_cap * sizeof(JSCodeRegister*));
|
||||
cs->functions = sys_realloc(cs->functions, new_cap * sizeof(MachCode*));
|
||||
cs->func_capacity = new_cap;
|
||||
}
|
||||
cs->functions[cs->func_count] = fn;
|
||||
@@ -30957,12 +31008,11 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
mach_emit(cs, MACH_AsBx(MACH_LOADI, dest, (int16_t)ival));
|
||||
} else {
|
||||
/* Large number: use constant pool */
|
||||
JSValue val;
|
||||
int ki;
|
||||
if (dval == (double)(int32_t)dval)
|
||||
val = JS_NewInt32(cs->ctx, (int32_t)dval);
|
||||
ki = mach_cpool_add_int(cs, (int32_t)dval);
|
||||
else
|
||||
val = JS_NewFloat64(cs->ctx, dval);
|
||||
int ki = mach_cpool_add(cs, val);
|
||||
ki = mach_cpool_add_float(cs, dval);
|
||||
mach_emit(cs, MACH_ABx(MACH_LOADK, dest, ki));
|
||||
}
|
||||
} else {
|
||||
@@ -31398,7 +31448,6 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
if (dest < 0) dest = mach_reserve_reg(cs);
|
||||
/* Compile nested function */
|
||||
MachCompState child = {0};
|
||||
child.ctx = cs->ctx;
|
||||
child.parent = cs;
|
||||
child.scopes = cs->scopes;
|
||||
child.freereg = 1; /* slot 0 = this */
|
||||
@@ -31441,10 +31490,11 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
/* Implicit return null */
|
||||
mach_emit(&child, MACH_ABC(MACH_RETNIL, 0, 0, 0));
|
||||
|
||||
/* Build JSCodeRegister for the child function */
|
||||
/* Build MachCode for the child function */
|
||||
cJSON *fn_scope = mach_find_scope_record(cs->scopes, child.function_nr);
|
||||
cJSON *fn_ncs = fn_scope ? cJSON_GetObjectItem(fn_scope, "nr_close_slots") : NULL;
|
||||
JSCodeRegister *fn_code = js_mallocz_rt(sizeof(JSCodeRegister));
|
||||
MachCode *fn_code = sys_malloc(sizeof(MachCode));
|
||||
memset(fn_code, 0, sizeof(MachCode));
|
||||
fn_code->arity = nparams;
|
||||
fn_code->nr_slots = child.maxreg;
|
||||
fn_code->nr_close_slots = fn_ncs ? (int)cJSON_GetNumberValue(fn_ncs) : 0;
|
||||
@@ -31458,10 +31508,11 @@ static int mach_compile_expr(MachCompState *cs, cJSON *node, int dest) {
|
||||
|
||||
cJSON *fname = cJSON_GetObjectItem(node, "name");
|
||||
if (fname && cJSON_IsString(fname)) {
|
||||
fn_code->name = JS_NewString(cs->ctx, cJSON_GetStringValue(fname));
|
||||
fn_code->name = JS_CellStone(cs->ctx, fn_code->name);
|
||||
const char *ns = cJSON_GetStringValue(fname);
|
||||
fn_code->name = sys_malloc(strlen(ns) + 1);
|
||||
strcpy(fn_code->name, ns);
|
||||
} else {
|
||||
fn_code->name = JS_NULL;
|
||||
fn_code->name = NULL;
|
||||
}
|
||||
|
||||
/* Free child var table (not code/cpool, those are owned by fn_code now) */
|
||||
@@ -31734,7 +31785,7 @@ static void mach_link_code(JSContext *ctx, JSCodeRegister *code, JSValue env) {
|
||||
|
||||
/* ---- Top-level compiler ---- */
|
||||
|
||||
static JSCodeRegister *mach_compile_program(MachCompState *cs, cJSON *ast, JSValue env) {
|
||||
static MachCode *mach_compile_program(MachCompState *cs, cJSON *ast) {
|
||||
cJSON *stmts = cJSON_GetObjectItem(ast, "statements");
|
||||
if (!stmts || !cJSON_IsArray(stmts)) return NULL;
|
||||
|
||||
@@ -31758,8 +31809,9 @@ static JSCodeRegister *mach_compile_program(MachCompState *cs, cJSON *ast, JSVal
|
||||
cJSON *prog_scope = mach_find_scope_record(cs->scopes, 0);
|
||||
cJSON *ncs_node = prog_scope ? cJSON_GetObjectItem(prog_scope, "nr_close_slots") : NULL;
|
||||
|
||||
/* Build JSCodeRegister */
|
||||
JSCodeRegister *code = js_mallocz_rt(sizeof(JSCodeRegister));
|
||||
/* Build MachCode */
|
||||
MachCode *code = sys_malloc(sizeof(MachCode));
|
||||
memset(code, 0, sizeof(MachCode));
|
||||
code->arity = 0;
|
||||
code->nr_slots = cs->maxreg;
|
||||
code->nr_close_slots = ncs_node ? (int)cJSON_GetNumberValue(ncs_node) : 0;
|
||||
@@ -31770,27 +31822,23 @@ static JSCodeRegister *mach_compile_program(MachCompState *cs, cJSON *ast, JSVal
|
||||
code->cpool = cs->cpool;
|
||||
code->func_count = cs->func_count;
|
||||
code->functions = cs->functions;
|
||||
code->name = JS_NULL;
|
||||
code->name = NULL;
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
/* Public API: compile AST JSON to JSCodeRegister */
|
||||
JSCodeRegister *JS_CompileMach(JSContext *ctx, const char *ast_json, JSValue env) {
|
||||
/* Public API: compile AST JSON to MachCode (context-free) */
|
||||
MachCode *JS_CompileMach(const char *ast_json) {
|
||||
cJSON *ast = cJSON_Parse(ast_json);
|
||||
if (!ast) return NULL;
|
||||
|
||||
MachCompState cs = {0};
|
||||
cs.ctx = ctx;
|
||||
cs.freereg = 1; /* slot 0 = this */
|
||||
cs.maxreg = 1;
|
||||
|
||||
JSCodeRegister *code = mach_compile_program(&cs, ast, env);
|
||||
MachCode *code = mach_compile_program(&cs, ast);
|
||||
|
||||
/* Link: resolve GETNAME to GETINTRINSIC/GETENV */
|
||||
if (code) mach_link_code(ctx, code, env);
|
||||
|
||||
/* Free var table (code/cpool/functions are owned by JSCodeRegister now) */
|
||||
/* Free var table (code/cpool/functions are owned by MachCode now) */
|
||||
for (int i = 0; i < cs.var_count; i++)
|
||||
sys_free(cs.vars[i].name);
|
||||
sys_free(cs.vars);
|
||||
@@ -31799,6 +31847,55 @@ JSCodeRegister *JS_CompileMach(JSContext *ctx, const char *ast_json, JSValue env
|
||||
return code;
|
||||
}
|
||||
|
||||
/* Free a MachCode tree (compiled but not yet loaded) */
|
||||
void JS_FreeMachCode(MachCode *mc) {
|
||||
if (!mc) return;
|
||||
sys_free(mc->instructions);
|
||||
for (uint32_t i = 0; i < mc->cpool_count; i++) {
|
||||
if (mc->cpool[i].type == MACH_CP_STR)
|
||||
sys_free(mc->cpool[i].str);
|
||||
}
|
||||
sys_free(mc->cpool);
|
||||
for (uint32_t i = 0; i < mc->func_count; i++)
|
||||
JS_FreeMachCode(mc->functions[i]);
|
||||
sys_free(mc->functions);
|
||||
sys_free(mc->name);
|
||||
sys_free(mc);
|
||||
}
|
||||
|
||||
/* Load a MachCode into a JSCodeRegister (materializes JSValues, needs ctx) */
|
||||
JSCodeRegister *JS_LoadMachCode(JSContext *ctx, MachCode *mc, JSValue env) {
|
||||
JSCodeRegister *code = js_mallocz_rt(sizeof(JSCodeRegister));
|
||||
code->arity = mc->arity;
|
||||
code->nr_close_slots = mc->nr_close_slots;
|
||||
code->nr_slots = mc->nr_slots;
|
||||
code->entry_point = mc->entry_point;
|
||||
code->instr_count = mc->instr_count;
|
||||
code->instructions = mc->instructions; /* transfer ownership */
|
||||
|
||||
/* Materialize cpool: raw -> JSValue */
|
||||
code->cpool_count = mc->cpool_count;
|
||||
code->cpool = mach_materialize_cpool(ctx, mc->cpool, mc->cpool_count);
|
||||
|
||||
/* Recursively load nested functions */
|
||||
code->func_count = mc->func_count;
|
||||
if (mc->func_count > 0) {
|
||||
code->functions = js_malloc_rt(mc->func_count * sizeof(JSCodeRegister *));
|
||||
for (uint32_t i = 0; i < mc->func_count; i++)
|
||||
code->functions[i] = JS_LoadMachCode(ctx, mc->functions[i], env);
|
||||
} else {
|
||||
code->functions = NULL;
|
||||
}
|
||||
|
||||
/* Intern function name */
|
||||
code->name = mc->name ? js_key_new(ctx, mc->name) : JS_NULL;
|
||||
|
||||
/* Link: resolve GETNAME to GETENV/GETINTRINSIC */
|
||||
mach_link_code(ctx, code, env);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
/* Free a JSCodeRegister and all nested functions */
|
||||
static void js_free_code_register(JSCodeRegister *code) {
|
||||
if (!code) return;
|
||||
@@ -32439,7 +32536,6 @@ done:
|
||||
============================================================ */
|
||||
|
||||
typedef struct MachGenState {
|
||||
JSContext *ctx;
|
||||
cJSON *instructions;
|
||||
cJSON *data;
|
||||
cJSON *functions;
|
||||
@@ -33591,7 +33687,6 @@ static void mach_gen_statement (MachGenState *s, cJSON *stmt) {
|
||||
|
||||
static cJSON *mach_gen_function (MachGenState *parent, cJSON *func_node) {
|
||||
MachGenState s = {0};
|
||||
s.ctx = parent->ctx;
|
||||
s.instructions = cJSON_CreateArray ();
|
||||
s.data = parent->data;
|
||||
s.functions = parent->functions;
|
||||
@@ -33813,12 +33908,11 @@ static cJSON *mach_gen_program (MachGenState *s, cJSON *ast) {
|
||||
return result;
|
||||
}
|
||||
|
||||
char *JS_Mcode (JSContext *ctx, const char *ast_json) {
|
||||
char *JS_Mcode (const char *ast_json) {
|
||||
cJSON *ast = cJSON_Parse (ast_json);
|
||||
if (!ast) return NULL;
|
||||
|
||||
MachGenState s = {0};
|
||||
s.ctx = ctx;
|
||||
s.instructions = cJSON_CreateArray ();
|
||||
s.errors = NULL;
|
||||
s.has_error = 0;
|
||||
@@ -35008,12 +35102,13 @@ static void dump_register_code(JSContext *ctx, JSCodeRegister *code, int indent)
|
||||
|
||||
/* Dump MACH bytecode to stdout for debugging. Takes AST JSON. */
|
||||
void JS_DumpMach(JSContext *ctx, const char *ast_json, JSValue env) {
|
||||
JSCodeRegister *code = JS_CompileMach(ctx, ast_json, env);
|
||||
if (!code) {
|
||||
MachCode *mc = JS_CompileMach(ast_json);
|
||||
if (!mc) {
|
||||
printf("=== MACH Bytecode ===\nFailed to compile\n=== End MACH Bytecode ===\n");
|
||||
return;
|
||||
}
|
||||
|
||||
JSCodeRegister *code = JS_LoadMachCode(ctx, mc, env);
|
||||
printf("=== MACH Bytecode ===\n");
|
||||
dump_register_code(ctx, code, 0);
|
||||
printf("=== End MACH Bytecode ===\n");
|
||||
@@ -35021,11 +35116,12 @@ void JS_DumpMach(JSContext *ctx, const char *ast_json, JSValue env) {
|
||||
|
||||
/* Compile and execute MACH bytecode. Takes AST JSON. */
|
||||
JSValue JS_RunMach(JSContext *ctx, const char *ast_json, JSValue env) {
|
||||
JSCodeRegister *code = JS_CompileMach(ctx, ast_json, env);
|
||||
if (!code) {
|
||||
MachCode *mc = JS_CompileMach(ast_json);
|
||||
if (!mc) {
|
||||
return JS_ThrowSyntaxError(ctx, "failed to compile AST to MACH bytecode");
|
||||
}
|
||||
|
||||
JSCodeRegister *code = JS_LoadMachCode(ctx, mc, env);
|
||||
JSValue result = JS_CallRegisterVM(ctx, code, ctx->global_obj, 0, NULL, env, JS_NULL);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1219,29 +1219,42 @@ CellModule *cell_module_from_bytecode (JSContext *ctx, JSFunctionBytecode *main_
|
||||
CellModule *JS_CompileModule (JSContext *ctx, const char *input, size_t input_len, const char *filename);
|
||||
|
||||
/* Parse source code and return AST as JSON string.
|
||||
Returns malloc'd JSON string (caller must free), or NULL on error. */
|
||||
char *JS_AST (JSContext *ctx, const char *source, size_t len, const char *filename);
|
||||
Returns malloc'd JSON string (caller must free), or NULL on error.
|
||||
No JSContext needed — pure string transformation. */
|
||||
char *JS_AST (const char *source, size_t len, const char *filename);
|
||||
|
||||
/* Tokenize source code and return token array as JSON string.
|
||||
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);
|
||||
Returns malloc'd JSON string (caller must free), or NULL on error.
|
||||
No JSContext needed — pure string transformation. */
|
||||
char *JS_Tokenize (const char *source, size_t len, const char *filename);
|
||||
|
||||
/* Compile AST JSON directly to register bytecode.
|
||||
Returns JSCodeRegister* (caller should not free — managed by context), or NULL on error. */
|
||||
struct JSCodeRegister *JS_CompileMach(JSContext *ctx, const char *ast_json, JSValue env);
|
||||
/* Compiled bytecode (context-free, serializable) */
|
||||
typedef struct MachCode MachCode;
|
||||
|
||||
/* Compile AST JSON to context-free MachCode.
|
||||
Returns MachCode* (caller must free with JS_FreeMachCode), or NULL on error. */
|
||||
MachCode *JS_CompileMach(const char *ast_json);
|
||||
|
||||
/* Free a compiled MachCode tree. */
|
||||
void JS_FreeMachCode(MachCode *mc);
|
||||
|
||||
/* Load compiled MachCode into a JSContext, materializing JSValues.
|
||||
Returns JSCodeRegister* linked and ready for execution. */
|
||||
struct JSCodeRegister *JS_LoadMachCode(JSContext *ctx, MachCode *mc, JSValue env);
|
||||
|
||||
/* Dump MACH bytecode to stdout for debugging. Takes AST JSON.
|
||||
Internally generates MCODE and links to binary bytecode. */
|
||||
Internally compiles, loads, and dumps 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.
|
||||
Internally compiles, loads, and executes.
|
||||
Returns result of execution, or JS_EXCEPTION on error. */
|
||||
JSValue JS_RunMach (JSContext *ctx, const char *ast_json, JSValue env);
|
||||
|
||||
/* Compile AST JSON to MCODE JSON (string-based IR).
|
||||
Returns malloc'd JSON string, or NULL on error. Caller must free. */
|
||||
char *JS_Mcode (JSContext *ctx, const char *ast_json);
|
||||
Returns malloc'd JSON string, or NULL on error. Caller must free.
|
||||
No JSContext needed — pure string transformation. */
|
||||
char *JS_Mcode (const char *ast_json);
|
||||
|
||||
/* Parse and execute MCODE JSON directly via the MCODE interpreter.
|
||||
Returns result of execution, or JS_EXCEPTION on error. */
|
||||
|
||||
@@ -2190,7 +2190,7 @@ TEST(cell_module_string_constant) {
|
||||
|
||||
TEST(tokenize_unterminated_string) {
|
||||
const char *src = "var x = \"hello";
|
||||
char *json = JS_Tokenize(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_Tokenize(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_Tokenize returned NULL");
|
||||
ASSERT_ERROR_MSG_CONTAINS(json, "unterminated string");
|
||||
free(json);
|
||||
@@ -2199,7 +2199,7 @@ TEST(tokenize_unterminated_string) {
|
||||
|
||||
TEST(tokenize_unterminated_template) {
|
||||
const char *src = "var x = `hello";
|
||||
char *json = JS_Tokenize(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_Tokenize(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_Tokenize returned NULL");
|
||||
ASSERT_ERROR_MSG_CONTAINS(json, "unterminated template");
|
||||
free(json);
|
||||
@@ -2208,7 +2208,7 @@ TEST(tokenize_unterminated_template) {
|
||||
|
||||
TEST(tokenize_unterminated_block_comment) {
|
||||
const char *src = "var x /* comment";
|
||||
char *json = JS_Tokenize(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_Tokenize(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_Tokenize returned NULL");
|
||||
ASSERT_ERROR_MSG_CONTAINS(json, "unterminated block comment");
|
||||
free(json);
|
||||
@@ -2217,7 +2217,7 @@ TEST(tokenize_unterminated_block_comment) {
|
||||
|
||||
TEST(tokenize_malformed_hex) {
|
||||
const char *src = "var x = 0x";
|
||||
char *json = JS_Tokenize(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_Tokenize(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_Tokenize returned NULL");
|
||||
ASSERT_ERROR_MSG_CONTAINS(json, "malformed hex");
|
||||
free(json);
|
||||
@@ -2226,7 +2226,7 @@ TEST(tokenize_malformed_hex) {
|
||||
|
||||
TEST(tokenize_malformed_binary) {
|
||||
const char *src = "var x = 0b";
|
||||
char *json = JS_Tokenize(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_Tokenize(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_Tokenize returned NULL");
|
||||
ASSERT_ERROR_MSG_CONTAINS(json, "malformed binary");
|
||||
free(json);
|
||||
@@ -2235,7 +2235,7 @@ TEST(tokenize_malformed_binary) {
|
||||
|
||||
TEST(tokenize_malformed_exponent) {
|
||||
const char *src = "var x = 1e+";
|
||||
char *json = JS_Tokenize(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_Tokenize(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_Tokenize returned NULL");
|
||||
ASSERT_ERROR_MSG_CONTAINS(json, "no digits after exponent");
|
||||
free(json);
|
||||
@@ -2244,7 +2244,7 @@ TEST(tokenize_malformed_exponent) {
|
||||
|
||||
TEST(tokenize_valid_no_errors) {
|
||||
const char *src = "var x = 42";
|
||||
char *json = JS_Tokenize(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_Tokenize(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_Tokenize returned NULL");
|
||||
ASSERT_NO_ERRORS(json);
|
||||
free(json);
|
||||
@@ -2257,7 +2257,7 @@ TEST(tokenize_valid_no_errors) {
|
||||
|
||||
TEST(ast_missing_identifier_after_var) {
|
||||
const char *src = "var = 1";
|
||||
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_AST(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||
ASSERT_ERROR_MSG_CONTAINS(json, "expected identifier");
|
||||
free(json);
|
||||
@@ -2266,7 +2266,7 @@ TEST(ast_missing_identifier_after_var) {
|
||||
|
||||
TEST(ast_missing_initializer_def) {
|
||||
const char *src = "def x";
|
||||
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_AST(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||
ASSERT_ERROR_MSG_CONTAINS(json, "missing initializer");
|
||||
free(json);
|
||||
@@ -2275,7 +2275,7 @@ TEST(ast_missing_initializer_def) {
|
||||
|
||||
TEST(ast_recovery_continues_after_error) {
|
||||
const char *src = "var = 1; var y = 2";
|
||||
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_AST(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||
ASSERT_HAS_ERRORS(json, 1);
|
||||
/* Check that 'y' statement is present in the AST */
|
||||
@@ -2286,7 +2286,7 @@ TEST(ast_recovery_continues_after_error) {
|
||||
|
||||
TEST(ast_valid_no_errors) {
|
||||
const char *src = "var x = 1; var y = 2";
|
||||
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_AST(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||
ASSERT_NO_ERRORS(json);
|
||||
free(json);
|
||||
@@ -2299,7 +2299,7 @@ TEST(ast_valid_no_errors) {
|
||||
|
||||
TEST(ast_sem_assign_to_const) {
|
||||
const char *src = "def x = 5; x = 3";
|
||||
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_AST(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||
ASSERT_ERROR_MSG_CONTAINS(json, "cannot assign to constant");
|
||||
free(json);
|
||||
@@ -2308,7 +2308,7 @@ TEST(ast_sem_assign_to_const) {
|
||||
|
||||
TEST(ast_sem_assign_to_arg) {
|
||||
const char *src = "function(x) { x = 5; }";
|
||||
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_AST(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||
ASSERT_ERROR_MSG_CONTAINS(json, "cannot assign to constant");
|
||||
free(json);
|
||||
@@ -2317,7 +2317,7 @@ TEST(ast_sem_assign_to_arg) {
|
||||
|
||||
TEST(ast_sem_redeclare_const) {
|
||||
const char *src = "def x = 1; def x = 2";
|
||||
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_AST(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||
ASSERT_ERROR_MSG_CONTAINS(json, "cannot redeclare constant");
|
||||
free(json);
|
||||
@@ -2326,7 +2326,7 @@ TEST(ast_sem_redeclare_const) {
|
||||
|
||||
TEST(ast_sem_break_outside_loop) {
|
||||
const char *src = "break";
|
||||
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_AST(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||
ASSERT_ERROR_MSG_CONTAINS(json, "outside of loop");
|
||||
free(json);
|
||||
@@ -2335,7 +2335,7 @@ TEST(ast_sem_break_outside_loop) {
|
||||
|
||||
TEST(ast_sem_continue_outside_loop) {
|
||||
const char *src = "continue";
|
||||
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_AST(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||
ASSERT_ERROR_MSG_CONTAINS(json, "outside of loop");
|
||||
free(json);
|
||||
@@ -2344,7 +2344,7 @@ TEST(ast_sem_continue_outside_loop) {
|
||||
|
||||
TEST(ast_sem_break_inside_loop_ok) {
|
||||
const char *src = "while (true) { break; }";
|
||||
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_AST(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||
ASSERT_NO_ERRORS(json);
|
||||
free(json);
|
||||
@@ -2353,7 +2353,7 @@ TEST(ast_sem_break_inside_loop_ok) {
|
||||
|
||||
TEST(ast_sem_increment_const) {
|
||||
const char *src = "def x = 1; x++";
|
||||
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_AST(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||
ASSERT_ERROR_MSG_CONTAINS(json, "cannot assign to constant");
|
||||
free(json);
|
||||
@@ -2362,7 +2362,7 @@ TEST(ast_sem_increment_const) {
|
||||
|
||||
TEST(ast_sem_shadow_var_ok) {
|
||||
const char *src = "var array = []; array";
|
||||
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_AST(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||
ASSERT_NO_ERRORS(json);
|
||||
free(json);
|
||||
@@ -2371,7 +2371,7 @@ TEST(ast_sem_shadow_var_ok) {
|
||||
|
||||
TEST(ast_sem_var_assign_ok) {
|
||||
const char *src = "var x = 1; x = x + 1";
|
||||
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_AST(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||
ASSERT_NO_ERRORS(json);
|
||||
free(json);
|
||||
@@ -2380,7 +2380,7 @@ TEST(ast_sem_var_assign_ok) {
|
||||
|
||||
TEST(ast_sem_nested_function_scope) {
|
||||
const char *src = "var x = 1; function f(x) { return x + 1; }";
|
||||
char *json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||
char *json = JS_AST(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(json != NULL, "JS_AST returned NULL");
|
||||
ASSERT_NO_ERRORS(json);
|
||||
free(json);
|
||||
@@ -2393,21 +2393,23 @@ TEST(ast_sem_nested_function_scope) {
|
||||
|
||||
TEST(mach_compile_basic) {
|
||||
const char *src = "var x = 1; x = x + 1";
|
||||
char *ast_json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||
char *ast_json = JS_AST(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(ast_json != NULL, "JS_AST returned NULL");
|
||||
struct JSCodeRegister *code = JS_CompileMach(ctx, ast_json, JS_NULL);
|
||||
MachCode *mc = JS_CompileMach(ast_json);
|
||||
free(ast_json);
|
||||
ASSERT_MSG(code != NULL, "JS_CompileMach returned NULL");
|
||||
ASSERT_MSG(mc != NULL, "JS_CompileMach returned NULL");
|
||||
JS_FreeMachCode(mc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(mach_compile_function) {
|
||||
const char *src = "function f(x) { return x + 1 }";
|
||||
char *ast_json = JS_AST(ctx, src, strlen(src), "<test>");
|
||||
char *ast_json = JS_AST(src, strlen(src), "<test>");
|
||||
ASSERT_MSG(ast_json != NULL, "JS_AST returned NULL");
|
||||
struct JSCodeRegister *code = JS_CompileMach(ctx, ast_json, JS_NULL);
|
||||
MachCode *mc = JS_CompileMach(ast_json);
|
||||
free(ast_json);
|
||||
ASSERT_MSG(code != NULL, "JS_CompileMach returned NULL");
|
||||
ASSERT_MSG(mc != NULL, "JS_CompileMach returned NULL");
|
||||
JS_FreeMachCode(mc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user