diff options
Diffstat (limited to 'js/scripting-lang/baba-yaga-c/src/parser.c')
-rw-r--r-- | js/scripting-lang/baba-yaga-c/src/parser.c | 281 |
1 files changed, 221 insertions, 60 deletions
diff --git a/js/scripting-lang/baba-yaga-c/src/parser.c b/js/scripting-lang/baba-yaga-c/src/parser.c index b7d8752..6c94913 100644 --- a/js/scripting-lang/baba-yaga-c/src/parser.c +++ b/js/scripting-lang/baba-yaga-c/src/parser.c @@ -889,22 +889,86 @@ static ASTNode* parser_parse_primary(Parser* parser) { ASTNode* value = NULL; /* Check if this is a key-value pair (any token: value) */ - if ((parser_peek(parser)->type == TOKEN_IDENTIFIER || - parser_peek(parser)->type == TOKEN_NUMBER || - parser_peek(parser)->type == TOKEN_BOOLEAN || - parser_peek(parser)->type == TOKEN_STRING) && - !parser_is_at_end(parser) && - parser_peek_next(parser)->type == TOKEN_COLON) { + + /* Check if this is a key-value pair */ + bool is_key_value_pair = false; + + if (parser_peek(parser)->type == TOKEN_LPAREN) { + /* For expression keys, we need to look ahead to find the colon */ + int look_ahead = parser->current; + int paren_count = 0; + bool found_colon = false; + + while (look_ahead < parser->token_count) { + Token* token = parser->tokens[look_ahead]; + if (token->type == TOKEN_LPAREN) { + paren_count++; + } else if (token->type == TOKEN_RPAREN) { + paren_count--; + if (paren_count == 0) { + /* We've found the closing parenthesis, check if next is colon */ + if (look_ahead + 1 < parser->token_count && + parser->tokens[look_ahead + 1]->type == TOKEN_COLON) { + found_colon = true; + } + break; + } + } else if (token->type == TOKEN_COMMA || token->type == TOKEN_RBRACE) { + /* Stop looking if we hit table boundaries */ + break; + } + look_ahead++; + } + is_key_value_pair = found_colon; + } else { + /* For literal keys, check if next token is colon */ + is_key_value_pair = (parser_peek(parser)->type == TOKEN_IDENTIFIER || + parser_peek(parser)->type == TOKEN_NUMBER || + parser_peek(parser)->type == TOKEN_BOOLEAN || + parser_peek(parser)->type == TOKEN_STRING) && + !parser_is_at_end(parser) && + parser_peek_next(parser)->type == TOKEN_COLON; + } + + if (is_key_value_pair) { /* Parse key-value pair */ - Token* key_token = parser_advance(parser); /* Consume the key token */ - if (key_token == NULL) { - /* Cleanup on error */ - for (int i = 0; i < element_count; i++) { - ast_destroy_node(elements[i]); + ASTNode* key_node = NULL; + Token* key_token = NULL; + + if (parser_peek(parser)->type == TOKEN_LPAREN) { + /* Parse expression key */ + key_node = parser_parse_expression(parser); + if (key_node == NULL) { + /* Cleanup on error */ + for (int i = 0; i < element_count; i++) { + ast_destroy_node(elements[i]); + } + free(elements); + return NULL; + } + /* Create a dummy token for line/column info */ + key_token = parser_peek(parser); + if (key_token == NULL) { + /* Cleanup on error */ + for (int i = 0; i < element_count; i++) { + ast_destroy_node(elements[i]); + } + free(elements); + ast_destroy_node(key_node); + return NULL; + } + } else { + /* Parse literal key */ + key_token = parser_advance(parser); /* Consume the key token */ + if (key_token == NULL) { + /* Cleanup on error */ + for (int i = 0; i < element_count; i++) { + ast_destroy_node(elements[i]); + } + free(elements); + return NULL; } - free(elements); - return NULL; } /* Consume colon */ @@ -975,32 +1039,40 @@ static ASTNode* parser_parse_primary(Parser* parser) { return NULL; } - /* Create key value based on token type */ - Value key_value; - if (key_token->type == TOKEN_IDENTIFIER) { - key_value = baba_yaga_value_string(key_token->lexeme); - } else if (key_token->type == TOKEN_NUMBER) { - key_value = baba_yaga_value_number(key_token->literal.number); - } else if (key_token->type == TOKEN_BOOLEAN) { - key_value = baba_yaga_value_boolean(key_token->literal.boolean); - } else if (key_token->type == TOKEN_STRING) { - key_value = baba_yaga_value_string(key_token->lexeme); + /* Create key value based on token type or expression */ + ASTNode* key_arg = NULL; + if (key_node != NULL) { + /* Expression key - use the parsed AST node */ + key_arg = key_node; } else { - /* Cleanup on error */ - for (int i = 0; i < element_count; i++) { - ast_destroy_node(elements[i]); + /* Literal key - create literal value from token */ + Value key_value; + if (key_token->type == TOKEN_IDENTIFIER) { + key_value = baba_yaga_value_string(key_token->lexeme); + } else if (key_token->type == TOKEN_NUMBER) { + key_value = baba_yaga_value_number(key_token->literal.number); + } else if (key_token->type == TOKEN_BOOLEAN) { + key_value = baba_yaga_value_boolean(key_token->literal.boolean); + } else if (key_token->type == TOKEN_STRING) { + key_value = baba_yaga_value_string(key_token->lexeme); + } else { + /* Cleanup on error */ + for (int i = 0; i < element_count; i++) { + ast_destroy_node(elements[i]); + } + free(elements); + free(entry_args); + ast_destroy_node(value); + return NULL; } - free(elements); - free(entry_args); - ast_destroy_node(value); - return NULL; + key_arg = ast_literal_node(key_value, key_token->line, key_token->column); } - entry_args[0] = ast_literal_node(key_value, key_token->line, key_token->column); + entry_args[0] = key_arg; entry_args[1] = value; - ASTNode* key_node = ast_identifier_node("table_entry", key_token->line, key_token->column); - if (key_node == NULL) { + ASTNode* table_entry_node = ast_identifier_node("table_entry", key_token->line, key_token->column); + if (table_entry_node == NULL) { /* Cleanup on error */ for (int i = 0; i < element_count; i++) { ast_destroy_node(elements[i]); @@ -1008,10 +1080,13 @@ static ASTNode* parser_parse_primary(Parser* parser) { free(elements); free(entry_args); ast_destroy_node(value); + if (key_node != NULL) { + ast_destroy_node(key_node); + } return NULL; } - ASTNode* entry_node = ast_function_call_node(key_node, entry_args, 2, key_token->line, key_token->column); + ASTNode* entry_node = ast_function_call_node(table_entry_node, entry_args, 2, key_token->line, key_token->column); if (entry_node == NULL) { /* Cleanup on error */ for (int i = 0; i < element_count; i++) { @@ -1019,8 +1094,11 @@ static ASTNode* parser_parse_primary(Parser* parser) { } free(elements); free(entry_args); - ast_destroy_node(key_node); + ast_destroy_node(table_entry_node); ast_destroy_node(value); + if (key_node != NULL) { + ast_destroy_node(key_node); + } return NULL; } @@ -2492,7 +2570,7 @@ static ASTNode* parser_parse_when_expression(Parser* parser) { int look_ahead = parser->current; int identifier_count = 0; - /* Count consecutive identifiers before 'is' */ + /* Count consecutive identifiers or expressions before 'is' */ while (look_ahead < parser->token_count) { Token* token = parser->tokens[look_ahead]; if (token->type == TOKEN_KEYWORD_IS) { @@ -2500,8 +2578,25 @@ static ASTNode* parser_parse_when_expression(Parser* parser) { } if (token->type == TOKEN_IDENTIFIER) { identifier_count++; + } else if (token->type == TOKEN_LPAREN) { + /* Expression in parentheses - count as one parameter */ + identifier_count++; + /* Skip to closing parenthesis */ + int paren_count = 1; + look_ahead++; + while (look_ahead < parser->token_count && paren_count > 0) { + Token* next_token = parser->tokens[look_ahead]; + if (next_token->type == TOKEN_LPAREN) { + paren_count++; + } else if (next_token->type == TOKEN_RPAREN) { + paren_count--; + } + look_ahead++; + } + /* Continue from the position after the closing parenthesis */ + continue; } else { - /* If we hit anything other than an identifier, it's not multi-parameter */ + /* If we hit anything other than an identifier or expression, it's not multi-parameter */ identifier_count = 0; break; } @@ -2515,17 +2610,44 @@ static ASTNode* parser_parse_when_expression(Parser* parser) { ASTNode* test; if (is_multi_param) { - /* Parse as sequence of identifiers */ + /* Parse as sequence of identifiers or expressions */ ASTNode** identifiers = malloc(identifier_count * sizeof(ASTNode*)); if (!identifiers) return NULL; for (int i = 0; i < identifier_count; i++) { - Token* id_token = parser_advance(parser); - identifiers[i] = ast_identifier_node(id_token->lexeme, id_token->line, id_token->column); + Token* current_token = parser_peek(parser); + if (current_token->type == TOKEN_LPAREN) { + /* Expression in parentheses - parse the expression */ + identifiers[i] = parser_parse_expression(parser); + if (identifiers[i] == NULL) { + /* Cleanup on error */ + for (int j = 0; j < i; j++) { + ast_destroy_node(identifiers[j]); + } + free(identifiers); + return NULL; + } + } else { + /* Identifier - parse as identifier */ + Token* id_token = parser_advance(parser); + identifiers[i] = ast_identifier_node(id_token->lexeme, id_token->line, id_token->column); + } } /* Create a sequence node for the identifiers */ test = ast_sequence_node(identifiers, identifier_count, when_token->line, when_token->column); + + /* Ensure we're positioned at the 'is' token */ + if (parser->current < parser->token_count && + parser->tokens[parser->current]->type != TOKEN_KEYWORD_IS) { + /* We're not at the 'is' token - find it */ + for (int j = parser->current; j < parser->token_count; j++) { + if (parser->tokens[j]->type == TOKEN_KEYWORD_IS) { + parser->current = j; + break; + } + } + } } else { /* Parse as single expression */ test = parser_parse_expression(parser); @@ -2638,7 +2760,8 @@ static ASTNode* parser_parse_when_pattern(Parser* parser) { int look_ahead = parser->current; int literal_count = 0; - /* Count consecutive literals before 'then' */ + /* Count consecutive literals or expressions before 'then' */ + DEBUG_DEBUG("Multi-parameter detection: starting at token %d", look_ahead); while (look_ahead < parser->token_count) { Token* token = parser->tokens[look_ahead]; if (token->type == TOKEN_KEYWORD_THEN) { @@ -2649,6 +2772,25 @@ static ASTNode* parser_parse_when_pattern(Parser* parser) { token->type == TOKEN_STRING || (token->type == TOKEN_IDENTIFIER && token->lexeme && strcmp(token->lexeme, "_") == 0)) { literal_count++; + } else if (token->type == TOKEN_LPAREN) { + /* Expression in parentheses - count as one pattern */ + DEBUG_DEBUG("Multi-parameter detection: found TOKEN_LPAREN at token %d", look_ahead); + literal_count++; + /* Skip to closing parenthesis */ + int paren_count = 1; + look_ahead++; + while (look_ahead < parser->token_count && paren_count > 0) { + Token* next_token = parser->tokens[look_ahead]; + if (next_token->type == TOKEN_LPAREN) { + paren_count++; + } else if (next_token->type == TOKEN_RPAREN) { + paren_count--; + } + look_ahead++; + } + DEBUG_DEBUG("Multi-parameter detection: finished expression, literal_count=%d, look_ahead=%d", literal_count, look_ahead); + /* Continue from the position after the closing parenthesis */ + continue; } else if (token->type == TOKEN_OP_EQUALS || token->type == TOKEN_OP_NOT_EQUALS || token->type == TOKEN_OP_LESS || @@ -2658,8 +2800,11 @@ static ASTNode* parser_parse_when_pattern(Parser* parser) { /* If we hit a comparison operator, it's not multi-parameter */ literal_count = 0; break; + } else if (token->type == TOKEN_SEMICOLON) { + /* If we hit a semicolon, stop looking */ + break; } else { - /* If we hit anything other than a literal, it's not multi-parameter */ + /* If we hit anything other than a literal or expression, it's not multi-parameter */ literal_count = 0; break; } @@ -2667,6 +2812,7 @@ static ASTNode* parser_parse_when_pattern(Parser* parser) { } /* If we have multiple literals followed by 'then', it's multi-parameter */ + DEBUG_DEBUG("Multi-parameter detection: final literal_count=%d, is_multi_param=%s", literal_count, literal_count > 1 ? "true" : "false"); if (literal_count > 1) { is_multi_param = true; } @@ -2678,26 +2824,41 @@ static ASTNode* parser_parse_when_pattern(Parser* parser) { if (!literals) return NULL; for (int i = 0; i < literal_count; i++) { - Token* lit_token = parser_advance(parser); - if (lit_token->type == TOKEN_IDENTIFIER && lit_token->lexeme && strcmp(lit_token->lexeme, "_") == 0) { - /* Wildcard pattern - treat as literal in multi-parameter context */ - literals[i] = ast_literal_node(baba_yaga_value_string("_"), lit_token->line, lit_token->column); - } else if (lit_token->type == TOKEN_IDENTIFIER) { - /* Identifier pattern */ - literals[i] = ast_identifier_node(lit_token->lexeme, lit_token->line, lit_token->column); - } else if (lit_token->type == TOKEN_NUMBER) { - /* Number pattern */ - literals[i] = ast_literal_node(baba_yaga_value_number(lit_token->literal.number), lit_token->line, lit_token->column); - } else if (lit_token->type == TOKEN_STRING) { - /* String pattern */ - literals[i] = ast_literal_node(baba_yaga_value_string(lit_token->lexeme), lit_token->line, lit_token->column); + Token* current_token = parser_peek(parser); + if (current_token->type == TOKEN_LPAREN) { + /* Expression pattern - parse the expression */ + literals[i] = parser_parse_expression(parser); + if (literals[i] == NULL) { + /* Cleanup on error */ + for (int j = 0; j < i; j++) { + ast_destroy_node(literals[j]); + } + free(literals); + return NULL; + } } else { - /* Cleanup on error */ - for (int j = 0; j < i; j++) { - ast_destroy_node(literals[j]); + /* Literal pattern */ + Token* lit_token = parser_advance(parser); + if (lit_token->type == TOKEN_IDENTIFIER && lit_token->lexeme && strcmp(lit_token->lexeme, "_") == 0) { + /* Wildcard pattern - treat as literal in multi-parameter context */ + literals[i] = ast_literal_node(baba_yaga_value_string("_"), lit_token->line, lit_token->column); + } else if (lit_token->type == TOKEN_IDENTIFIER) { + /* Identifier pattern */ + literals[i] = ast_identifier_node(lit_token->lexeme, lit_token->line, lit_token->column); + } else if (lit_token->type == TOKEN_NUMBER) { + /* Number pattern */ + literals[i] = ast_literal_node(baba_yaga_value_number(lit_token->literal.number), lit_token->line, lit_token->column); + } else if (lit_token->type == TOKEN_STRING) { + /* String pattern */ + literals[i] = ast_literal_node(baba_yaga_value_string(lit_token->lexeme), lit_token->line, lit_token->column); + } else { + /* Cleanup on error */ + for (int j = 0; j < i; j++) { + ast_destroy_node(literals[j]); + } + free(literals); + return NULL; } - free(literals); - return NULL; } } |