y_lang/ast/
expression.rs

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}