summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/codegen/codegen.c123
-rw-r--r--src/parser/parser_stmt.c38
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
{