lemma/parser/
rules.rs

1use crate::ast::ExpressionIdGenerator;
2use crate::error::LemmaError;
3use crate::parser::Rule;
4use crate::semantic::*;
5use pest::iterators::Pair;
6
7pub(crate) fn parse_rule_definition(
8    pair: Pair<Rule>,
9    id_gen: &mut ExpressionIdGenerator,
10) -> Result<LemmaRule, LemmaError> {
11    let span = crate::ast::Span::from_pest_span(pair.as_span());
12    let mut rule_name = None;
13    let mut rule_expression = None;
14
15    for inner_pair in pair.into_inner() {
16        match inner_pair.as_rule() {
17            Rule::rule_name => rule_name = Some(inner_pair.as_str().to_string()),
18            Rule::rule_expression => {
19                rule_expression = Some(parse_rule_expression(inner_pair, id_gen)?)
20            }
21            _ => {}
22        }
23    }
24
25    let name = rule_name.ok_or_else(|| {
26        LemmaError::Engine("Grammar error: rule_definition missing rule_name".to_string())
27    })?;
28    let (expression, unless_clauses) = rule_expression.ok_or_else(|| {
29        LemmaError::Engine("Grammar error: rule_definition missing rule_expression".to_string())
30    })?;
31
32    Ok(LemmaRule {
33        name,
34        expression,
35        unless_clauses,
36        span: Some(span),
37    })
38}
39
40fn parse_rule_expression(
41    pair: Pair<Rule>,
42    id_gen: &mut ExpressionIdGenerator,
43) -> Result<(Expression, Vec<UnlessClause>), LemmaError> {
44    let mut expression = None;
45    let mut unless_clauses = Vec::new();
46
47    for inner_pair in pair.into_inner() {
48        match inner_pair.as_rule() {
49            Rule::expression_group => {
50                expression = Some(crate::parser::expressions::parse_or_expression(
51                    inner_pair, id_gen,
52                )?);
53            }
54            Rule::unless_statement => {
55                let unless_clause = parse_unless_statement(inner_pair, id_gen)?;
56                unless_clauses.push(unless_clause);
57            }
58            _ => {}
59        }
60    }
61
62    let expr = expression.ok_or_else(|| {
63        LemmaError::Engine("Grammar error: rule_expression missing expression_group".to_string())
64    })?;
65    Ok((expr, unless_clauses))
66}
67
68fn parse_unless_statement(
69    pair: Pair<Rule>,
70    id_gen: &mut ExpressionIdGenerator,
71) -> Result<UnlessClause, LemmaError> {
72    let span = crate::ast::Span::from_pest_span(pair.as_span());
73    let mut condition = None;
74    let mut result = None;
75
76    for inner_pair in pair.clone().into_inner() {
77        match inner_pair.as_rule() {
78            Rule::expression_group => {
79                if condition.is_none() {
80                    condition = Some(crate::parser::expressions::parse_or_expression(
81                        inner_pair, id_gen,
82                    )?);
83                } else {
84                    result = Some(crate::parser::expressions::parse_or_expression(
85                        inner_pair, id_gen,
86                    )?);
87                }
88            }
89            Rule::veto_expression => {
90                let veto_span = crate::ast::Span::from_pest_span(inner_pair.as_span());
91                // Pest grammar: ^"veto" ~ (SPACE+ ~ string_literal)?
92                // If string_literal child exists, extract the string content (without quotes)
93                let message = inner_pair
94                    .clone()
95                    .into_inner()
96                    .find(|p| p.as_rule() == Rule::string_literal)
97                    .map(|string_pair| {
98                        let content = string_pair.as_str();
99                        content[1..content.len() - 1].to_string()
100                    });
101                let kind = ExpressionKind::Veto(VetoExpression { message });
102                result = Some(Expression::new(kind, Some(veto_span), id_gen.next_id()));
103            }
104            _ => {}
105        }
106    }
107
108    let cond = condition.ok_or_else(|| {
109        LemmaError::Engine("Grammar error: unless_statement missing condition".to_string())
110    })?;
111    let res = result.ok_or_else(|| {
112        LemmaError::Engine("Grammar error: unless_statement missing result".to_string())
113    })?;
114
115    Ok(UnlessClause {
116        condition: cond,
117        result: res,
118        span: Some(span),
119    })
120}