push/pop syntax

This commit is contained in:
2026-02-05 20:39:53 -06:00
parent 97a003e025
commit 91761c03e6

View File

@@ -29038,6 +29038,8 @@ static cJSON *ast_parse_postfix (ASTParseState *s) {
cJSON_AddStringToObject (new_node, "right", str ? str : "");
JS_FreeCString (s->ctx, str);
ast_next_token (s);
} else {
ast_error (s, s->token_ptr, "expected property name after '.'");
}
ast_node_end (s, new_node, s->buf_ptr);
node = new_node;
@@ -29045,9 +29047,14 @@ static cJSON *ast_parse_postfix (ASTParseState *s) {
ast_next_token (s);
cJSON *new_node = ast_node (s, "[", start);
cJSON_AddItemToObject (new_node, "left", node);
cJSON *index = ast_parse_assign_expr (s);
cJSON_AddItemToObject (new_node, "right", index);
if (s->token_val == ']') ast_next_token (s);
if (s->token_val == ']') {
ast_next_token (s);
} else {
cJSON *index = ast_parse_assign_expr (s);
cJSON_AddItemToObject (new_node, "right", index);
if (s->token_val == ']') ast_next_token (s);
else ast_error (s, s->token_ptr, "expected ']'");
}
ast_node_end (s, new_node, s->buf_ptr);
node = new_node;
} else if (s->token_val == '(') {
@@ -29062,6 +29069,7 @@ static cJSON *ast_parse_postfix (ASTParseState *s) {
else break;
}
if (s->token_val == ')') ast_next_token (s);
else ast_error (s, s->token_ptr, "unterminated argument list, expected ')'");
ast_node_end (s, new_node, s->buf_ptr);
node = new_node;
} else if (s->token_val == TOK_INC) {
@@ -29088,6 +29096,7 @@ static cJSON *ast_parse_postfix (ASTParseState *s) {
cJSON *index = ast_parse_assign_expr (s);
cJSON_AddItemToObject (new_node, "right", index);
if (s->token_val == ']') ast_next_token (s);
else ast_error (s, s->token_ptr, "expected ']'");
ast_node_end (s, new_node, s->buf_ptr);
node = new_node;
} else if (s->token_val == '(') {
@@ -29103,6 +29112,7 @@ static cJSON *ast_parse_postfix (ASTParseState *s) {
else break;
}
if (s->token_val == ')') ast_next_token (s);
else ast_error (s, s->token_ptr, "unterminated argument list, expected ')'");
ast_node_end (s, new_node, s->buf_ptr);
node = new_node;
} else if (s->token_val == TOK_IDENT) {
@@ -29301,6 +29311,7 @@ static cJSON *ast_parse_ternary (ASTParseState *s) {
ast_next_token (s);
cJSON *then_expr = ast_parse_expr (s);
if (s->token_val == ':') ast_next_token (s);
else ast_error (s, s->token_ptr, "expected ':' in ternary expression");
cJSON *else_expr = ast_parse_expr (s);
cJSON *node = ast_node (s, "then", start);
@@ -29360,6 +29371,15 @@ static cJSON *ast_parse_assign (ASTParseState *s) {
cJSON *node = ast_node (s, kind, start);
cJSON_AddItemToObject (node, "left", left);
cJSON_AddItemToObject (node, "right", right);
/* Check for push/pop bracket syntax */
const char *left_kind = cJSON_GetStringValue (cJSON_GetObjectItem (left, "kind"));
if (left_kind && strcmp (left_kind, "[") == 0 && !cJSON_GetObjectItem (left, "right"))
cJSON_AddBoolToObject (node, "push", 1);
const char *right_kind = cJSON_GetStringValue (cJSON_GetObjectItem (right, "kind"));
if (right_kind && strcmp (right_kind, "[") == 0 && !cJSON_GetObjectItem (right, "right"))
cJSON_AddBoolToObject (node, "pop", 1);
ast_node_end (s, node, s->buf_ptr);
return node;
}
@@ -29423,9 +29443,19 @@ static cJSON *ast_parse_function_inner (ASTParseState *s, BOOL is_expr) {
ast_next_token (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 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 : "");
/* Check for duplicate parameter name */
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);
break;
}
}
JS_FreeCString (s->ctx, str);
ast_node_end (s, param, s->buf_ptr);
ast_next_token (s);
@@ -29497,9 +29527,19 @@ static cJSON *ast_parse_arrow_function (ASTParseState *s) {
ast_next_token (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 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 : "");
/* Check for duplicate parameter name */
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);
break;
}
}
JS_FreeCString (s->ctx, str);
ast_node_end (s, param, s->buf_ptr);
ast_next_token (s);
@@ -29554,6 +29594,12 @@ static cJSON *ast_parse_arrow_function (ASTParseState *s) {
return node;
}
static void ast_expect_semi (ASTParseState *s) {
if (s->token_val == ';') { ast_next_token (s); return; }
if (s->token_val == TOK_EOF || s->token_val == '}' || s->got_lf) return;
ast_error (s, s->token_ptr, "expecting ';'");
}
/* Skip tokens until a statement sync point to recover from errors */
static void ast_sync_to_statement (ASTParseState *s) {
while (s->token_val != TOK_EOF) {
@@ -29616,6 +29662,9 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
ast_next_token (s);
cJSON *right = ast_parse_expr (s);
cJSON_AddItemToObject (node, "right", right);
const char *right_kind = cJSON_GetStringValue (cJSON_GetObjectItem (right, "kind"));
if (right_kind && strcmp (right_kind, "[") == 0 && !cJSON_GetObjectItem (right, "right"))
cJSON_AddBoolToObject (node, "pop", 1);
} else if (is_def) {
/* def (constant) requires initializer */
ast_error (s, var_ptr, "missing initializer for constant '%s'", str);
@@ -29630,13 +29679,14 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
break;
}
}
if (s->token_val == ';') ast_next_token (s);
ast_expect_semi (s);
} break;
case TOK_IF: {
node = ast_node (s, "if", start);
ast_next_token (s);
if (s->token_val == '(') ast_next_token (s);
else ast_error (s, s->token_ptr, "expected '(' before condition");
cJSON *cond = ast_parse_expr (s);
cJSON_AddItemToObject (node, "expression", cond);
if (s->token_val == ')') ast_next_token (s);
@@ -29667,6 +29717,7 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
node = ast_node (s, "while", start);
ast_next_token (s);
if (s->token_val == '(') ast_next_token (s);
else ast_error (s, s->token_ptr, "expected '(' before condition");
cJSON *cond = ast_parse_expr (s);
cJSON_AddItemToObject (node, "expression", cond);
if (s->token_val == ')') ast_next_token (s);
@@ -29689,11 +29740,12 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
if (s->token_val == TOK_WHILE) ast_next_token (s);
else ast_error (s, s->token_ptr, "expected 'while' after do body");
if (s->token_val == '(') ast_next_token (s);
else ast_error (s, s->token_ptr, "expected '(' before condition");
cJSON *cond = ast_parse_expr (s);
cJSON_AddItemToObject (node, "expression", cond);
if (s->token_val == ')') ast_next_token (s);
else ast_error (s, s->token_ptr, "expected ')' after do-while condition");
if (s->token_val == ';') ast_next_token (s);
ast_expect_semi (s);
ast_node_end (s, node, s->buf_ptr);
} break;
@@ -29701,6 +29753,7 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
node = ast_node (s, "for", start);
ast_next_token (s);
if (s->token_val == '(') ast_next_token (s);
else ast_error (s, s->token_ptr, "expected '(' after for");
/* Init */
if (s->token_val != ';') {
@@ -29744,7 +29797,7 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
cJSON *expr = ast_parse_expr (s);
cJSON_AddItemToObject (node, "expression", expr);
}
if (s->token_val == ';') ast_next_token (s);
ast_expect_semi (s);
ast_node_end (s, node, s->buf_ptr);
} break;
@@ -29755,16 +29808,19 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
cJSON *expr = ast_parse_expr (s);
cJSON_AddItemToObject (node, "expression", expr);
}
if (s->token_val == ';') ast_next_token (s);
ast_expect_semi (s);
ast_node_end (s, node, s->buf_ptr);
} break;
case TOK_THROW: {
node = ast_node (s, "throw", start);
ast_next_token (s);
if (s->got_lf) {
ast_error (s, s->token_ptr, "line terminator not allowed after throw");
}
cJSON *expr = ast_parse_expr (s);
cJSON_AddItemToObject (node, "expression", expr);
if (s->token_val == ';') ast_next_token (s);
ast_expect_semi (s);
ast_node_end (s, node, s->buf_ptr);
} break;
@@ -29777,7 +29833,7 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
JS_FreeCString (s->ctx, str);
ast_next_token (s);
}
if (s->token_val == ';') ast_next_token (s);
ast_expect_semi (s);
ast_node_end (s, node, s->buf_ptr);
} break;
@@ -29790,7 +29846,7 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
JS_FreeCString (s->ctx, str);
ast_next_token (s);
}
if (s->token_val == ';') ast_next_token (s);
ast_expect_semi (s);
ast_node_end (s, node, s->buf_ptr);
} break;
@@ -29798,6 +29854,7 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
node = ast_node (s, "switch", start);
ast_next_token (s);
if (s->token_val == '(') ast_next_token (s);
else ast_error (s, s->token_ptr, "expected '(' before switch expression");
cJSON *expr = ast_parse_expr (s);
cJSON_AddItemToObject (node, "expression", expr);
if (s->token_val == ')') ast_next_token (s);
@@ -29805,6 +29862,7 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
cJSON *cases = cJSON_AddArrayToObject (node, "cases");
if (s->token_val == '{') {
int has_default = 0;
ast_next_token (s);
while (s->token_val != '}' && s->token_val != TOK_EOF) {
if (s->token_val == TOK_CASE) {
@@ -29813,6 +29871,7 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
cJSON *case_expr = ast_parse_expr (s);
cJSON_AddItemToObject (case_node, "expression", case_expr);
if (s->token_val == ':') ast_next_token (s);
else ast_error (s, s->token_ptr, "expected ':' after case expression");
cJSON *case_stmts = cJSON_AddArrayToObject (case_node, "statements");
while (s->token_val != TOK_CASE && s->token_val != TOK_DEFAULT &&
s->token_val != '}' && s->token_val != TOK_EOF) {
@@ -29827,9 +29886,13 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
ast_node_end (s, case_node, s->buf_ptr);
cJSON_AddItemToArray (cases, case_node);
} else if (s->token_val == TOK_DEFAULT) {
if (has_default)
ast_error (s, s->token_ptr, "more than one default clause in switch");
has_default = 1;
cJSON *default_node = ast_node (s, "default", s->token_ptr);
ast_next_token (s);
if (s->token_val == ':') ast_next_token (s);
else ast_error (s, s->token_ptr, "expected ':' after default");
cJSON *default_stmts = cJSON_AddArrayToObject (default_node, "statements");
while (s->token_val != TOK_CASE && s->token_val != '}' && s->token_val != TOK_EOF) {
const uint8_t *before = s->token_ptr;
@@ -29847,6 +29910,8 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
}
}
if (s->token_val == '}') ast_next_token (s);
} else {
ast_error (s, s->token_ptr, "expected '{' after switch");
}
ast_node_end (s, node, s->buf_ptr);
} break;
@@ -29860,8 +29925,13 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
cJSON *stmts = ast_parse_block_statements (s);
cJSON_AddItemToObject (node, "statements", stmts);
if (s->token_val == '}') ast_next_token (s);
} else {
ast_error (s, s->token_ptr, "expected '{' for try block");
}
if (s->token_val != TOK_CATCH && s->token_val != TOK_FINALLY)
ast_error (s, s->token_ptr, "expected 'catch' or 'finally' after try block");
if (s->token_val == TOK_CATCH) {
cJSON *catch_node = ast_node (s, "catch", s->token_ptr);
ast_next_token (s);
@@ -29932,7 +30002,7 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
cJSON_AddItemToObject (node, "expression", expr);
ast_node_end (s, node, s->buf_ptr);
}
if (s->token_val == ';') ast_next_token (s);
ast_expect_semi (s);
}
} break;
@@ -29947,7 +30017,7 @@ static cJSON *ast_parse_statement (ASTParseState *s) {
ast_error (s, start, "unexpected token");
return NULL; /* caller syncs */
}
if (s->token_val == ';') ast_next_token (s);
ast_expect_semi (s);
} break;
}