push/pop syntax
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user