Adapted parser and ast with grammar
This commit is contained in:
+37
-36
@@ -487,25 +487,11 @@ postfix = {
|
|||||||
// PREFIX EXPRESSIONS
|
// PREFIX EXPRESSIONS
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
|
|
||||||
deref_px = {
|
deref_px = { "*" }
|
||||||
"*"
|
mut_ref_px = { "&" ~ mutable }
|
||||||
}
|
ref_px = { "&" }
|
||||||
|
new_px = { "new" }
|
||||||
mut_ref_px = {
|
not_px = { "!" }
|
||||||
"&" ~ mutable
|
|
||||||
}
|
|
||||||
|
|
||||||
ref_px = {
|
|
||||||
"&"
|
|
||||||
}
|
|
||||||
|
|
||||||
new_px = {
|
|
||||||
"new"
|
|
||||||
}
|
|
||||||
|
|
||||||
not_px = {
|
|
||||||
"!"
|
|
||||||
}
|
|
||||||
|
|
||||||
prefix = {
|
prefix = {
|
||||||
deref_px
|
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
|
// EXPRESSIONS
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
|
|
||||||
|
// Top-level entry point for expressions
|
||||||
expr = { term ~ (bin_op ~ term)* }
|
expr = { term ~ (bin_op ~ term)* }
|
||||||
|
|
||||||
// A term is anything that acts as a single unit in an operation
|
// A term handles your Prefix and Postfix combinations around a core Primary
|
||||||
term = _{ prefix* ~ primary ~ postfix* }
|
term = { prefix* ~ primary ~ postfix* }
|
||||||
|
|||||||
@@ -2,37 +2,107 @@ use crate::{
|
|||||||
Rule,
|
Rule,
|
||||||
ast::*,
|
ast::*,
|
||||||
ast_expr,
|
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 {
|
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Expression {
|
||||||
type Error = AstError<'a, Self>;
|
type Error = AstError<'a, Self>;
|
||||||
|
|
||||||
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
|
||||||
let rule = pair.as_rule();
|
let rule = pair.as_rule();
|
||||||
let mut inner = pair.clone().into_inner();
|
let inner = pair.clone().into_inner();
|
||||||
|
|
||||||
match rule {
|
match rule {
|
||||||
|
// 1. The top level expressions are now processed via the Pratt Parser
|
||||||
Rule::expr => {
|
Rule::expr => {
|
||||||
let prefixes = inner
|
static PRATT_PARSER: OnceLock<PrattParser<Rule>> = OnceLock::new();
|
||||||
.next()
|
let pratt = PRATT_PARSER.get_or_init(|| {
|
||||||
.map(|p| collect_recovered::<Prefix, Prefix>(p.into_inner()))
|
use Rule::*;
|
||||||
.unwrap_or_else(|| Ok(Vec::new()));
|
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 {
|
ast_expr!(Expression::Fix {
|
||||||
initial: exp.map(Box::new),
|
initial: exp.map(Box::new),
|
||||||
prefixes: prefixes,
|
prefixes: prefixes,
|
||||||
postfixes: collect_recovered(inner),
|
postfixes: postfixes,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
exp
|
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::static_path => ast_expr!(Expression::Path(pair.try_into())),
|
||||||
Rule::literal => ast_expr!(Expression::Literal(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())))
|
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())),
|
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),
|
_ => AstError::bug_unimplemented(pair),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user