cas_parser/parser/ast/
expr.rs

1use crate::{
2    parser::{
3        ast::{
4            assign::Assign,
5            binary::Binary,
6            block::Block,
7            call::Call,
8            if_expr::If,
9            literal::Literal,
10            loop_expr::{Break, Continue, Loop},
11            paren::Paren,
12            unary::Unary,
13            while_expr::While,
14        },
15        error::{kind, Error},
16        fmt::Latex,
17        iter::ExprIter,
18        token::{op::Precedence, CloseParen},
19        Parse,
20        Parser,
21    },
22    return_if_ok,
23};
24use std::{fmt, ops::Range};
25
26#[cfg(feature = "serde")]
27use serde::{Deserialize, Serialize};
28
29/// Represents a general expression in CalcScript.
30///
31/// An expression is any valid piece of code that can be evaluated to produce a value. Expressions
32/// can be used as the right-hand side of an assignment, or as the argument to a function call.
33#[derive(Debug, Clone, PartialEq)]
34#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
35pub enum Expr {
36    /// A literal value.
37    Literal(Literal),
38
39    /// A parenthesized expression, such as `(1 + 2)`.
40    Paren(Paren),
41
42    /// A blocked expression, such as `{1 + 2}`.
43    Block(Block),
44
45    /// An if expression, such as `if x > 0 then x else -x`.
46    If(If),
47
48    /// A loop expression, as in `loop { ... }`.
49    Loop(Loop),
50
51    /// A while loop expression, as in `while x > 0 then { ... }`.
52    While(While),
53
54    /// A break expression, used to exit a loop, optionally with a value.
55    Break(Break),
56
57    /// A continue expression, used to skip the rest of a loop iteration.
58    Continue(Continue),
59
60    /// A function call, such as `abs(-1)`.
61    Call(Call),
62
63    /// A unary operation, such as `-1` or `!true`.
64    Unary(Unary),
65
66    /// A binary operation, such as `1 + 2`.
67    Binary(Binary),
68
69    /// An assignment of a variable or function, such as `x = 1` or `f(x) = x^2`.
70    Assign(Assign),
71}
72
73impl Expr {
74    /// Returns the span of the expression.
75    pub fn span(&self) -> Range<usize> {
76        match self {
77            Expr::Literal(literal) => literal.span(),
78            Expr::Paren(paren) => paren.span(),
79            Expr::Block(block) => block.span(),
80            Expr::If(if_expr) => if_expr.span(),
81            Expr::Loop(loop_expr) => loop_expr.span(),
82            Expr::While(while_expr) => while_expr.span(),
83            Expr::Break(break_expr) => break_expr.span(),
84            Expr::Continue(continue_expr) => continue_expr.span(),
85            Expr::Call(call) => call.span(),
86            Expr::Unary(unary) => unary.span(),
87            Expr::Binary(binary) => binary.span(),
88            Expr::Assign(assign) => assign.span(),
89        }
90    }
91
92    /// Returns an iterator that traverses the tree of expressions in left-to-right post-order
93    /// (i.e. depth-first).
94    pub fn post_order_iter(&self) -> ExprIter {
95        ExprIter::new(self)
96    }
97
98    /// If this expression is a [`Expr::Paren`], returns the innermost expression in the
99    /// parenthesized expression. Otherwise, returns `self`.
100    pub fn innermost(&self) -> &Expr {
101        let mut inner = self;
102        while let Expr::Paren(paren) = inner {
103            inner = &paren.expr;
104        }
105        inner
106    }
107}
108
109impl<'source> Parse<'source> for Expr {
110    fn std_parse(
111        input: &mut Parser<'source>,
112        recoverable_errors: &mut Vec<Error>
113    ) -> Result<Self, Vec<Error>> {
114        if input.clone().try_parse::<CloseParen>().is_ok() {
115            return Err(vec![input.error(kind::UnclosedParenthesis { opening: false })]);
116        }
117
118        let _ = return_if_ok!(input.try_parse().map(Self::Assign).forward_errors(recoverable_errors));
119        let lhs = Unary::parse_or_lower(input, recoverable_errors)?;
120        Ok(Binary::parse_expr(input, recoverable_errors, lhs, Precedence::Any)?.0)
121    }
122}
123
124impl std::fmt::Display for Expr {
125    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126        match self {
127            Expr::Literal(literal) => literal.fmt(f),
128            Expr::Paren(paren) => paren.fmt(f),
129            Expr::Block(block) => block.fmt(f),
130            Expr::If(if_expr) => if_expr.fmt(f),
131            Expr::Loop(loop_expr) => loop_expr.fmt(f),
132            Expr::While(while_expr) => while_expr.fmt(f),
133            Expr::Break(break_expr) => break_expr.fmt(f),
134            Expr::Continue(continue_expr) => continue_expr.fmt(f),
135            Expr::Call(call) => call.fmt(f),
136            Expr::Unary(unary) => unary.fmt(f),
137            Expr::Binary(binary) => binary.fmt(f),
138            Expr::Assign(assign) => assign.fmt(f),
139        }
140    }
141}
142
143impl Latex for Expr {
144    fn fmt_latex(&self, f: &mut fmt::Formatter) -> fmt::Result {
145        match self {
146            Expr::Literal(literal) => literal.fmt_latex(f),
147            Expr::Paren(paren) => paren.fmt_latex(f),
148            Expr::Block(block) => block.fmt_latex(f),
149            Expr::If(if_expr) => if_expr.fmt_latex(f),
150            Expr::Loop(loop_expr) => loop_expr.fmt_latex(f),
151            Expr::While(while_expr) => while_expr.fmt_latex(f),
152            Expr::Break(break_expr) => break_expr.fmt_latex(f),
153            Expr::Continue(continue_expr) => continue_expr.fmt_latex(f),
154            Expr::Call(call) => call.fmt_latex(f),
155            Expr::Unary(unary) => unary.fmt_latex(f),
156            Expr::Binary(binary) => binary.fmt_latex(f),
157            Expr::Assign(assign) => assign.fmt_latex(f),
158        }
159    }
160}
161
162/// Represents a primary expression in CalcScript.
163///
164/// Primary expressions are the simplest expressions, and are the building blocks of more complex
165/// expressions. Primary expressions are also self-contained. This means that primary expressions
166/// within a larger expression can be replaced with equivalent, but different kinds of primary
167/// expressions, and the larger expression will still be valid.
168#[derive(Debug, Clone, PartialEq)]
169pub enum Primary {
170    /// A literal value.
171    Literal(Literal),
172
173    /// A parenthesized expression, such as `(1 + 2)`.
174    Paren(Paren),
175
176    /// A blocked expression, such as `{1 + 2}`.
177    Block(Block),
178
179    /// An if expression, such as `if x > 0 then x else -x`.
180    If(If),
181
182    /// A loop expression, as in `loop { ... }`.
183    Loop(Loop),
184
185    /// A while loop expression, as in `while x > 0 then { ... }`.
186    While(While),
187
188    /// A break expression, used to exit a loop, optionally with a value.
189    Break(Break),
190
191    /// A continue expression, used to skip the rest of a loop iteration.
192    Continue(Continue),
193
194    /// A function call, such as `abs(-1)`.
195    Call(Call),
196}
197
198impl Primary {
199    /// Returns the span of the primary expression.
200    pub fn span(&self) -> Range<usize> {
201        match self {
202            Primary::Literal(literal) => literal.span(),
203            Primary::Paren(paren) => paren.span(),
204            Primary::Block(block) => block.span(),
205            Primary::If(if_expr) => if_expr.span(),
206            Primary::Loop(loop_expr) => loop_expr.span(),
207            Primary::While(while_expr) => while_expr.span(),
208            Primary::Break(break_expr) => break_expr.span(),
209            Primary::Continue(continue_expr) => continue_expr.span(),
210            Primary::Call(call) => call.span(),
211        }
212    }
213}
214
215impl<'source> Parse<'source> for Primary {
216    fn std_parse(
217        input: &mut Parser<'source>,
218        recoverable_errors: &mut Vec<Error>
219    ) -> Result<Self, Vec<Error>> {
220        let _ = return_if_ok!(input.try_parse().map(Self::If).forward_errors(recoverable_errors));
221        let _ = return_if_ok!(input.try_parse().map(Self::Loop).forward_errors(recoverable_errors));
222        let _ = return_if_ok!(input.try_parse().map(Self::While).forward_errors(recoverable_errors));
223        let _ = return_if_ok!(input.try_parse().map(Self::Break).forward_errors(recoverable_errors));
224        let _ = return_if_ok!(input.try_parse().map(Self::Continue).forward_errors(recoverable_errors));
225        // function calls can overlap with literals, so we need to try parsing a function call
226        // first
227        let _ = return_if_ok!(input.try_parse().map(Self::Call).forward_errors(recoverable_errors));
228        let _ = return_if_ok!(input.try_parse().map(Self::Literal).forward_errors(recoverable_errors));
229        let _ = return_if_ok!(input.try_parse().map(Self::Paren).forward_errors(recoverable_errors));
230        input.try_parse().map(Self::Block).forward_errors(recoverable_errors)
231    }
232}
233
234impl From<Primary> for Expr {
235    fn from(primary: Primary) -> Self {
236        match primary {
237            Primary::Literal(literal) => Self::Literal(literal),
238            Primary::Paren(paren) => Self::Paren(paren),
239            Primary::Block(block) => Self::Block(block),
240            Primary::If(if_expr) => Self::If(if_expr),
241            Primary::Loop(loop_expr) => Self::Loop(loop_expr),
242            Primary::While(while_expr) => Self::While(while_expr),
243            Primary::Break(break_expr) => Self::Break(break_expr),
244            Primary::Continue(continue_expr) => Self::Continue(continue_expr),
245            Primary::Call(call) => Self::Call(call),
246        }
247    }
248}