Adapted parser and ast with grammar

This commit is contained in:
2026-05-17 02:30:03 +02:00
parent 020eebdaba
commit 50c98cf5f7
2 changed files with 119 additions and 69 deletions
+37 -36
View File
@@ -487,25 +487,11 @@ postfix = {
// PREFIX EXPRESSIONS
// ------------------------------------------------------
deref_px = {
"*"
}
mut_ref_px = {
"&" ~ mutable
}
ref_px = {
"&"
}
new_px = {
"new"
}
not_px = {
"!"
}
deref_px = { "*" }
mut_ref_px = { "&" ~ mutable }
ref_px = { "&" }
new_px = { "new" }
not_px = { "!" }
prefix = {
deref_px
@@ -516,30 +502,45 @@ prefix = {
}
// ------------------------------------------------------
// OPERATORS
// OPERATORS (Named individually for Pratt Parser configuration)
// ------------------------------------------------------
bin_op = {
"<="
| ">="
| "=="
| "!="
| "&&"
| "||"
| "+"
| "-"
| "*"
| "/"
| "%"
| "<"
| ">"
lte = { "<=" }
gte = { ">=" }
eq = { "==" }
neq = { "!=" }
and = { "&&" }
or = { "||" }
add = { "+" }
sub = { "-" }
mul = { "*" }
div = { "/" }
rem = { "%" }
lt = { "<" }
gt = { ">" }
bin_op = _{
lte
| gte
| eq
| neq
| and
| or
| add
| sub
| mul
| div
| rem
| lt
| gt
}
// ------------------------------------------------------
// EXPRESSIONS
// ------------------------------------------------------
// Top-level entry point for expressions
expr = { term ~ (bin_op ~ term)* }
// A term is anything that acts as a single unit in an operation
term = _{ prefix* ~ primary ~ postfix* }
// A term handles your Prefix and Postfix combinations around a core Primary
term = { prefix* ~ primary ~ postfix* }
+82 -33
View File
@@ -2,37 +2,107 @@ use crate::{
Rule,
ast::*,
ast_expr,
error::{AstError, GetLength, IntoErr, collect_recovered, collect_recovered_map},
error::{AstError, AstResult, GetLength, IntoErr, collect_recovered, collect_recovered_map},
};
use pest::pratt_parser::PrattParser;
use std::sync::OnceLock;
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Expression {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
let inner = pair.clone().into_inner();
match rule {
// 1. The top level expressions are now processed via the Pratt Parser
Rule::expr => {
let prefixes = inner
.next()
.map(|p| collect_recovered::<Prefix, Prefix>(p.into_inner()))
.unwrap_or_else(|| Ok(Vec::new()));
static PRATT_PARSER: OnceLock<PrattParser<Rule>> = OnceLock::new();
let pratt = PRATT_PARSER.get_or_init(|| {
use Rule::*;
use pest::pratt_parser::{Assoc::*, Op};
let exp = Expression::try_from(inner.next().unwrap());
// Precedence defined from lowest to highest
PrattParser::new()
.op(Op::infix(or, Left))
.op(Op::infix(and, Left))
.op(Op::infix(eq, Left)
| Op::infix(neq, Left)
| Op::infix(lt, Left)
| Op::infix(gt, Left)
| Op::infix(lte, Left)
| Op::infix(gte, Left))
.op(Op::infix(add, Left) | Op::infix(sub, Left))
.op(Op::infix(mul, Left) | Op::infix(div, Left) | Op::infix(rem, Left))
});
if inner.len() > 0 || prefixes.len() > 0 {
pratt
.map_primary(|primary_pair| {
// Elements handled by map_primary are either sub-expressions or 'term' rules
Expression::try_from(primary_pair)
})
.map_infix(|lhs, op, rhs| {
let bin_op = match op.as_rule() {
Rule::lte => BinaryOp::LessThanOrEqual,
Rule::gte => BinaryOp::GreaterThanOrEqual,
Rule::eq => BinaryOp::Equal,
Rule::neq => BinaryOp::NotEqual,
Rule::and => BinaryOp::And,
Rule::or => BinaryOp::Or,
Rule::add => BinaryOp::Plus,
Rule::sub => BinaryOp::Minus,
Rule::mul => BinaryOp::Multiply,
Rule::div => BinaryOp::Divide,
Rule::rem => BinaryOp::Modulo,
Rule::lt => BinaryOp::LessThan,
Rule::gt => BinaryOp::GreaterThan,
_ => return AstError::bug_unimplemented(op),
};
ast_expr!(Expression::Binary {
lhs: lhs.map(Box::new),
op: Ok(bin_op) as AstResult<'_, BinaryOp>,
rhs: rhs.map(Box::new),
})
})
.parse(inner)
}
// 2. The single unit 'term' replaces the old flat 'expr' layout
Rule::term => {
let mut prefix_pairs = Vec::new();
let mut primary_pair = None;
let mut postfix_pairs = Vec::new();
// Sort out flat layout components
for p in inner {
match p.as_rule() {
Rule::prefix => prefix_pairs.push(p),
Rule::primary => primary_pair = Some(p),
Rule::postfix => postfix_pairs.push(p),
_ => {}
}
}
let prefixes = collect_recovered::<Prefix, Prefix>(prefix_pairs.into_iter());
let exp = Expression::try_from(
primary_pair.expect("Term must contain a primary expression"),
);
let postfixes = collect_recovered::<Postfix, Postfix>(postfix_pairs.into_iter());
// Employs your exact original logic using the GetLength trait
if postfixes.len() > 0 || prefixes.len() > 0 {
ast_expr!(Expression::Fix {
initial: exp.map(Box::new),
prefixes: prefixes,
postfixes: collect_recovered(inner),
postfixes: postfixes,
})
} else {
exp
}
}
Rule::primary => inner.next().unwrap().try_into(),
Rule::primary => pair.into_inner().next().unwrap().try_into(),
Rule::static_path => ast_expr!(Expression::Path(pair.try_into())),
Rule::literal => ast_expr!(Expression::Literal(pair.try_into())),
@@ -86,31 +156,10 @@ impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Postfix {
ast_expr!(Postfix::Index(Expression::try_from(inner.next().unwrap())))
}
Rule::binary_px => {
let op_pair = inner.next().unwrap();
let op = match op_pair.as_str() {
"+" => BinaryOp::Plus,
"-" => BinaryOp::Minus,
"*" => BinaryOp::Multiply,
"/" => BinaryOp::Divide,
"%" => BinaryOp::Modulo,
"==" => BinaryOp::Equal,
"!=" => BinaryOp::NotEqual,
"<" => BinaryOp::LessThan,
">" => BinaryOp::GreaterThan,
"<=" => BinaryOp::LessThanOrEqual,
">=" => BinaryOp::GreaterThanOrEqual,
"&&" => BinaryOp::And,
"||" => BinaryOp::Or,
_ => return AstError::bug_unimplemented(op_pair),
};
Ok(Postfix::Binary(op, inner.next().unwrap().try_into().get()?))
}
Rule::macro_call_px => Ok(Postfix::MacroCall(inner.as_str().to_string())),
// Note: Rule::binary_px has been completely decoupled from postfix rules
// as it is now safely managed inside the top-level Pratt execution above.
_ => AstError::bug_unimplemented(pair),
}
}