about summary refs log tree commit diff stats
path: root/js/scripting-lang/baba-yaga-c/src/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'js/scripting-lang/baba-yaga-c/src/parser.c')
-rw-r--r--js/scripting-lang/baba-yaga-c/src/parser.c281
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;
             }
         }