Skip to content
Merged
49 changes: 48 additions & 1 deletion src/analyzer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1299,7 +1299,7 @@ impl Analyzer {

Statement::PatternDefinition {
name,
pattern: _,
pattern,
line,
column,
} => {
Expand All @@ -1315,6 +1315,9 @@ impl Analyzer {
if let Err(e) = self.current_scope.define(pattern_symbol) {
self.errors.push(e);
}

// Analyze the pattern expression to catch undefined list references
self.analyze_pattern_expression(pattern, *line, *column);
Comment on lines +1318 to +1320

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

analyze_pattern_expression is now responsible for catching undefined list references in patterns, but there’s no unit test exercising the new failure mode (e.g., a pattern referencing an undefined list name). Adding an analyzer-level test would help prevent regressions in this semantic check.

Copilot uses AI. Check for mistakes.
}

Statement::ListenStatement {
Expand Down Expand Up @@ -1559,6 +1562,50 @@ impl Analyzer {
}
}

fn analyze_pattern_expression(
&mut self,
pattern: &crate::parser::ast::PatternExpression,
line: usize,
column: usize,
) {
use crate::parser::ast::PatternExpression;
match pattern {
PatternExpression::Literal(_)
| PatternExpression::CharacterClass(_)
| PatternExpression::Anchor(_)
| PatternExpression::Backreference(_) => {}
PatternExpression::Quantified { pattern: inner, .. } => {
self.analyze_pattern_expression(inner, line, column);
}
PatternExpression::Sequence(patterns) | PatternExpression::Alternative(patterns) => {
for inner in patterns {
self.analyze_pattern_expression(inner, line, column);
}
}
PatternExpression::Capture { pattern: inner, .. } => {
self.analyze_pattern_expression(inner, line, column);
}
PatternExpression::Lookahead(inner)
| PatternExpression::NegativeLookahead(inner)
| PatternExpression::Lookbehind(inner)
| PatternExpression::NegativeLookbehind(inner) => {
self.analyze_pattern_expression(inner, line, column);
}
PatternExpression::ListReference(name) => {
// Same check as Expression::Variable to ensure it exists
if self.current_scope.resolve(name).is_none()
&& !self.action_parameters.contains(name)
{
self.errors.push(SemanticError {
message: format!("Undefined list reference '{name}' in pattern"),
line,
column,
});
}
}
}
}

fn analyze_action_body(&mut self, statement: &Statement) {
if let Statement::ActionDefinition {
parameters, body, ..
Expand Down
Loading