diff options
| author | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-18 11:32:57 +0000 |
|---|---|---|
| committer | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-18 11:32:57 +0000 |
| commit | 977add96ffb28354e487c6587ae02e2cc82f03ac (patch) | |
| tree | d93229cf7bd8aec3ce5ced504523a7259f3f548d /src | |
| parent | 26d4d700f3b20579e48306b3171eedf1a09b060b (diff) | |
Related to #68
Diffstat (limited to 'src')
| -rw-r--r-- | src/codegen/codegen.c | 123 | ||||
| -rw-r--r-- | src/parser/parser_stmt.c | 38 |
2 files changed, 132 insertions, 29 deletions
diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c index 9539338..644e9f5 100644 --- a/src/codegen/codegen.c +++ b/src/codegen/codegen.c @@ -10,6 +10,104 @@ #include "ast.h" #include "zprep_plugin.h" +// Helper: emit a single pattern condition (either a value, or a range) +static void emit_single_pattern_cond(const char *pat, int id, FILE *out) +{ + // Check for range pattern: "start..end" or "start..=end" + char *range_incl = strstr(pat, "..="); + char *range_excl = strstr(pat, ".."); + + if (range_incl) + { + // Inclusive range: start..=end -> _m_id >= start && _m_id <= end + int start_len = (int)(range_incl - pat); + char *start = xmalloc(start_len + 1); + strncpy(start, pat, start_len); + start[start_len] = 0; + char *end = xstrdup(range_incl + 3); + fprintf(out, "(_m_%d >= %s && _m_%d <= %s)", id, start, id, end); + free(start); + free(end); + } + else if (range_excl) + { + // Exclusive range: start..end -> _m_id >= start && _m_id < end + int start_len = (int)(range_excl - pat); + char *start = xmalloc(start_len + 1); + strncpy(start, pat, start_len); + start[start_len] = 0; + char *end = xstrdup(range_excl + 2); + fprintf(out, "(_m_%d >= %s && _m_%d < %s)", id, start, id, end); + free(start); + free(end); + } + else if (pat[0] == '"') + { + // String pattern + fprintf(out, "strcmp(_m_%d, %s) == 0", id, pat); + } + else if (pat[0] == '\'') + { + // Char literal pattern + fprintf(out, "_m_%d == %s", id, pat); + } + else + { + // Numeric or simple pattern + fprintf(out, "_m_%d == %s", id, pat); + } +} + +// Helper: emit condition for a pattern (may contain OR patterns with '|') +static void emit_pattern_condition(ParserContext *ctx, const char *pattern, int id, FILE *out) +{ + // Check if pattern contains '|' for OR patterns + if (strchr(pattern, '|')) + { + // Split by '|' and emit OR conditions + char *pattern_copy = xstrdup(pattern); + char *saveptr; + char *part = strtok_r(pattern_copy, "|", &saveptr); + int first = 1; + fprintf(out, "("); + while (part) + { + if (!first) + { + fprintf(out, " || "); + } + + // Check if part is an enum variant + EnumVariantReg *reg = find_enum_variant(ctx, part); + if (reg) + { + fprintf(out, "_m_%d.tag == %d", id, reg->tag_id); + } + else + { + emit_single_pattern_cond(part, id, out); + } + first = 0; + part = strtok_r(NULL, "|", &saveptr); + } + fprintf(out, ")"); + free(pattern_copy); + } + else + { + // Single pattern (may be a range) + EnumVariantReg *reg = find_enum_variant(ctx, pattern); + if (reg) + { + fprintf(out, "_m_%d.tag == %d", id, reg->tag_id); + } + else + { + emit_single_pattern_cond(pattern, id, out); + } + } +} + // static function for internal use. static char *g_current_func_ret_type = NULL; static void codegen_match_internal(ParserContext *ctx, ASTNode *node, FILE *out, int use_result) @@ -138,29 +236,8 @@ static void codegen_match_internal(ParserContext *ctx, ASTNode *node, FILE *out, } else { - EnumVariantReg *reg = find_enum_variant(ctx, c->match_case.pattern); - if (reg) - { - fprintf(out, "_m_%d.tag == %d", id, reg->tag_id); - } - else if (c->match_case.pattern[0] == '"') - { - fprintf(out, "strcmp(_m_%d, %s) == 0", id, c->match_case.pattern); - } - else if (isdigit(c->match_case.pattern[0]) || c->match_case.pattern[0] == '-') - { - // Numeric pattern - fprintf(out, "_m_%d == %s", id, c->match_case.pattern); - } - else if (c->match_case.pattern[0] == '\'') - { - // Char literal pattern - fprintf(out, "_m_%d == %s", id, c->match_case.pattern); - } - else - { - fprintf(out, "1"); - } + // Use helper for OR patterns, range patterns, and simple patterns + emit_pattern_condition(ctx, c->match_case.pattern, id, out); } fprintf(out, ") { "); if (c->match_case.binding_name) diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c index bfb45d8..d78a9e8 100644 --- a/src/parser/parser_stmt.c +++ b/src/parser/parser_stmt.c @@ -217,7 +217,11 @@ ASTNode *parse_match(ParserContext *ctx, Lexer *l) break; } - // --- 1. Parse Comma-Separated Patterns --- + // --- 1. Parse Patterns (with OR and range support) --- + // Patterns can be: + // - Single value: 1 + // - OR patterns: 1 || 2 or 1 or 2 + // - Range patterns: 1..5 or 1..=5 char patterns_buf[1024]; patterns_buf[0] = 0; int pattern_count = 0; @@ -238,20 +242,42 @@ ASTNode *parse_match(ParserContext *ctx, Lexer *l) p_str = tmp; } + // Check for range pattern: value..end or value..=end + if (lexer_peek(l).type == TOK_DOTDOT || lexer_peek(l).type == TOK_DOTDOT_EQ) + { + int is_inclusive = (lexer_peek(l).type == TOK_DOTDOT_EQ); + lexer_next(l); // eat .. or ..= + Token end_tok = lexer_next(l); + char *end_str = token_strdup(end_tok); + + // Build range pattern: "start..end" or "start..=end" + char *range_str = xmalloc(strlen(p_str) + strlen(end_str) + 4); + sprintf(range_str, "%s%s%s", p_str, is_inclusive ? "..=" : "..", end_str); + free(p_str); + free(end_str); + p_str = range_str; + } + if (pattern_count > 0) { - strcat(patterns_buf, ","); + strcat(patterns_buf, "|"); } strcat(patterns_buf, p_str); free(p_str); pattern_count++; - Lexer lookahead = *l; - skip_comments(&lookahead); - if (lexer_peek(&lookahead).type == TOK_COMMA) + // Check for OR continuation: ||, 'or', or comma (legacy) + Token next = lexer_peek(l); + skip_comments(l); + int is_or = (next.type == TOK_OR) || + (next.type == TOK_OP && next.len == 2 && next.start[0] == '|' && + next.start[1] == '|') || + (next.type == TOK_COMMA); // Legacy comma support + if (is_or) { - lexer_next(l); // eat comma + lexer_next(l); // eat ||, 'or', or comma skip_comments(l); + continue; } else { |
