1use once_cell::sync::Lazy;
2use pest::{
3 iterators::Pair,
4 pratt_parser::{Assoc, Op, PrattParser},
5};
6
7use super::{
8 Array, BinaryExpr, Block, Boolean, Character, FnDef, Ident, If, Integer, Position, PostfixExpr,
9 PrefixExpr, Rule, Str,
10};
11
12#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
13pub enum Expression<T> {
14 If(If<T>),
15 Binary(BinaryExpr<T>),
16 Prefix(PrefixExpr<T>),
17 Postfix(PostfixExpr<T>),
18 Integer(Integer<T>),
19 Character(Character<T>),
20 Ident(Ident<T>),
21 Str(Str<T>),
22 FnDef(FnDef<T>),
23 Block(Block<T>),
24 Boolean(Boolean<T>),
25 Array(Array<T>),
26}
27
28static PRATT_PARSER: Lazy<PrattParser<Rule>> = Lazy::new(|| {
29 PrattParser::new()
30 .op(Op::infix(Rule::lessThan, Assoc::Left)
31 | Op::infix(Rule::greaterThan, Assoc::Left)
32 | Op::infix(Rule::equal, Assoc::Left))
33 .op(Op::infix(Rule::plus, Assoc::Left) | Op::infix(Rule::minus, Assoc::Left))
34 .op(Op::infix(Rule::times, Assoc::Left) | Op::infix(Rule::dividedBy, Assoc::Left))
35 .op(Op::prefix(Rule::unaryMinus) | Op::prefix(Rule::not))
36 .op(Op::postfix(Rule::call))
37 .op(Op::postfix(Rule::indexing))
38});
39
40impl Expression<()> {
41 pub fn from_pair(pair: Pair<Rule>, file: &str) -> Expression<()> {
42 PRATT_PARSER
43 .map_primary(|primary| match primary.as_rule() {
44 Rule::expr => Expression::from_pair(primary, file),
45 Rule::decimalNumber | Rule::hexNumber => {
46 Expression::Integer(Integer::from_pair(primary, file))
47 }
48 Rule::character => Expression::Character(Character::from_pair(primary, file)),
49 Rule::ident => Expression::Ident(Ident::from_pair(primary, file)),
50 Rule::string => Expression::Str(Str::from_pair(primary, file)),
51 Rule::fnDef => Expression::FnDef(FnDef::from_pair(primary, file)),
52 Rule::ifStmt => Expression::If(If::from_pair(primary, file)),
53 Rule::block => Expression::Block(Block::from_pair(primary, file)),
54 Rule::boolean => Expression::Boolean(Boolean::from_pair(primary, file)),
55 Rule::array => Expression::Array(Array::from_pair(primary, file)),
56 rule => unreachable!("Unexpected rule {:?} while parsing primary", rule),
57 })
58 .map_prefix(|op, rhs| Expression::Prefix(PrefixExpr::from_op_rhs(op, rhs, file)))
59 .map_postfix(|lhs, op| Expression::Postfix(PostfixExpr::from_lhs_op(lhs, op, file)))
60 .map_infix(|lhs, op, rhs| {
61 Expression::Binary(BinaryExpr::from_lhs_op_rhs(lhs, op, rhs, file))
62 })
63 .parse(pair.into_inner())
64 }
65}
66
67impl<T> Expression<T>
68where
69 T: Clone,
70{
71 pub fn position(&self) -> Position {
72 match self {
73 Expression::If(If { position, .. })
74 | Expression::Binary(BinaryExpr { position, .. })
75 | Expression::Prefix(PrefixExpr { position, .. })
76 | Expression::Postfix(PostfixExpr { position, .. })
77 | Expression::Integer(Integer { position, .. })
78 | Expression::Character(Character { position, .. })
79 | Expression::Ident(Ident { position, .. })
80 | Expression::Str(Str { position, .. })
81 | Expression::FnDef(FnDef { position, .. })
82 | Expression::Block(Block { position, .. })
83 | Expression::Boolean(Boolean { position, .. })
84 | Expression::Array(Array { position, .. }) => position.to_owned(),
85 }
86 }
87
88 pub fn info(&self) -> T {
89 match self {
90 Expression::If(If { info, .. })
91 | Expression::Binary(BinaryExpr { info, .. })
92 | Expression::Prefix(PrefixExpr { info, .. })
93 | Expression::Postfix(PostfixExpr { info, .. })
94 | Expression::Integer(Integer { info, .. })
95 | Expression::Character(Character { info, .. })
96 | Expression::Ident(Ident { info, .. })
97 | Expression::Str(Str { info, .. })
98 | Expression::FnDef(FnDef { info, .. })
99 | Expression::Block(Block { info, .. })
100 | Expression::Boolean(Boolean { info, .. })
101 | Expression::Array(Array { info, .. }) => info.clone(),
102 }
103 }
104}