arithmetic_parser/
lib.rs

1//! Parser for arithmetic expressions with flexible definition of literals and support
2//! of type annotations.
3//!
4//! Overall, parsed grammars are similar to Rust syntax,
5//! [with a few notable differences](#differences-with-rust).
6//!
7//! # Supported syntax features
8//!
9//! - **Variables.** A variable name is defined similar to Rust and other programming languages,
10//!   as a sequence of alphanumeric chars and underscores that does not start with a digit.
11//! - **Literals.** The parser for literals is user-provided, thus allowing to apply the library
12//!   to different domains (e.g., finite group arithmetic).
13//! - `//` and `/* .. */` **comments**.
14//! - Basic **arithmetic operations**: `+`, `-` (binary and unary), `*`, `/`, `^` (power).
15//!   The parser outputs AST with nodes organized according to the operation priority.
16//! - **Function calls**: `foo(1.0, x)`.
17//! - **Parentheses** which predictably influence operation priority.
18//!
19//! The parser supports both complete and streaming (incomplete) modes; the latter is useful
20//! for REPLs and similar applications.
21//!
22//! ## Optional syntax features
23//!
24//! These features can be switched on or off when defining a [`Parse`](grammars::Parse) impl
25//! by declaring the corresponding [`Features`](grammars::Features).
26//!
27//! - **Tuples.** A tuple is two or more elements separated by commas, such as `(x, y)`
28//!   or `(1, 2 * x)`. Tuples are parsed both as lvalues and rvalues.
29//! - **Tuple destructuring.** Using a tuple as an lvalue, for example, `(x, y, z) = foo`.
30//!   The "rest" syntax is also supported, either named or unnamed: `(head, ...tail) = foo`,
31//!   `(a, ..., b, c) = foo`.
32//! - **Function definitions.** A definition looks like a closure definition in Rust, e.g.,
33//!   `|x| x - 10` or `|x, y| { z = max(x, y); (z - x, z - y) }`. A definition may be
34//!   assigned to a variable (which is the way to define named functions).
35//! - **Destructuring for function args.** Similar to tuple destructuring, it is possible to
36//!   destructure and group args in function definitions, for example, `|(x, y), ...zs| { }`.
37//! - **Blocks.** A block is several `;`-delimited statements enclosed in `{}` braces,
38//!   e.g, `{ z = max(x, y); (z - x, z - y) }`. The blocks can be used in all contexts
39//!   instead of a simple expression; for example, `min({ z = 5; z - 1 }, 3)`.
40//! - **Objects.** Object is a mapping of string fields to values. Objects are defined via
41//!   *object expressions*, which look similar to struct initialization in Rust or object
42//!   initialization in JavaScript; for example, `#{ x: 1, y }`. (Note the `#` char at the start
43//!   of the block; it is used to distinguish object expressions from blocks.)
44//! - **Methods.** Method call is a function call separated from the receiver with a `.` char;
45//!   for example, `foo.bar(2, x)`.
46//! - **Type annotations.** A type annotation in the form `var: Type` can be present
47//!   in the lvalues or in the function argument definitions. The parser for type annotations
48//!   is user-defined.
49//! - **Boolean operations**: `==`, `!=`, `&&`, `||`, `!`.
50//! - **Order comparisons,** that is, `>`, `<`, `>=`, and `<=` boolean ops.
51//!
52//! ## Differences with Rust
53//!
54//! *(within shared syntax constructs; of course, Rust is much more expressive)*
55//!
56//! - No keyword for assigning a variable (i.e., no `let` / `let mut`). There are no
57//!   keywords in general.
58//! - Functions are only defined via the closure syntax.
59//! - There is "rest" destructuting for tuples and function arguments.
60//! - Type annotations are placed within tuple elements, for example, `(x: Num, _) = y`.
61//! - Object expressions are enclosed in `#{ ... }`, similarly to [Rhai](https://rhai.rs/).
62//!
63//! # Crate features
64//!
65//! - `std`. Enables support of types from `std`, such as the `Error` trait, and propagates
66//!   to dependencies.
67//! - `num-complex`. Implements [`NumLiteral`](crate::grammars::NumLiteral) for floating-point
68//!   complex numbers (`Complex32` and `Complex64`).
69//! - `num-bigint`. Implements [`NumLiteral`](crate::grammars::NumLiteral) for `BigInt` and
70//!   `BigUint` from the `num-bigint` crate.
71//!
72//! # Examples
73//!
74//! Using a grammar for arithmetic on real values.
75//!
76//! ```
77//! # use assert_matches::assert_matches;
78//! use arithmetic_parser::{
79//!     grammars::{F32Grammar, Parse, Untyped},
80//!     NomResult, Statement, Expr, FnDefinition, LvalueLen,
81//! };
82//!
83//! const PROGRAM: &str = r#"
84//!     // This is a comment.
85//!     x = 1 + 2.5 * 3 + sin(a^3 / b^2 /* another comment */);
86//!     // Function declarations have syntax similar to Rust closures.
87//!     some_function = |a, b| (a + b, a - b);
88//!     other_function = |x| {
89//!         r = min(rand(), 0.5);
90//!         r * x
91//!     };
92//!     // Tuples and blocks are supported and have a similar syntax to Rust.
93//!     (y, z) = some_function({ x = x - 0.5; x }, x);
94//!     other_function(y - z)
95//! "#;
96//!
97//! # fn main() -> anyhow::Result<()> {
98//! let block = Untyped::<F32Grammar>::parse_statements(PROGRAM)?;
99//! // First statement is an assignment.
100//! assert_matches!(
101//!     block.statements[0].extra,
102//!     Statement::Assignment { ref lhs, .. } if *lhs.fragment() == "x"
103//! );
104//! // The RHS of the second statement is a function.
105//! let some_function = match &block.statements[1].extra {
106//!     Statement::Assignment { rhs, .. } => &rhs.extra,
107//!     _ => panic!("Unexpected parsing result"),
108//! };
109//! // This function has a single argument and a single statement in the body.
110//! assert_matches!(
111//!     some_function,
112//!     Expr::FnDefinition(FnDefinition { ref args, ref body, .. })
113//!         if args.extra.len() == LvalueLen::Exact(2)
114//!             && body.statements.is_empty()
115//!             && body.return_value.is_some()
116//! );
117//! # Ok(())
118//! # }
119//! ```
120
121#![cfg_attr(not(feature = "std"), no_std)]
122#![doc(html_root_url = "https://docs.rs/arithmetic-parser/0.3.0")]
123#![warn(missing_docs, missing_debug_implementations)]
124#![warn(clippy::all, clippy::pedantic)]
125#![allow(
126    clippy::missing_errors_doc,
127    clippy::must_use_candidate,
128    clippy::module_name_repetitions
129)]
130
131// Polyfill for `alloc` types.
132mod alloc {
133    #[cfg(not(feature = "std"))]
134    extern crate alloc;
135
136    #[cfg(not(feature = "std"))]
137    pub use alloc::{borrow::ToOwned, boxed::Box, format, string::String, vec, vec::Vec};
138    #[cfg(feature = "std")]
139    pub use std::{borrow::ToOwned, boxed::Box, format, string::String, vec, vec::Vec};
140}
141
142pub use crate::{
143    error::{Context, Error, ErrorKind, SpannedError, UnsupportedType},
144    ops::{BinaryOp, Op, OpPriority, UnaryOp},
145    parser::is_valid_variable_name,
146    spans::{
147        with_span, CodeFragment, InputSpan, LocatedSpan, MaybeSpanned, NomResult, Spanned,
148        StripCode, StripResultExt,
149    },
150};
151
152use core::fmt;
153
154use crate::{
155    alloc::{vec, Box, Vec},
156    grammars::Grammar,
157};
158
159mod error;
160pub mod grammars;
161mod ops;
162mod parser;
163mod spans;
164
165/// Object expression, such as `#{ x, y: x + 2 }`.
166#[derive(Debug)]
167#[non_exhaustive]
168pub struct ObjectExpr<'a, T: Grammar<'a>> {
169    /// Fields. Each field is the field name and an optional expression (that is, parts
170    /// before and after the colon char `:`, respectively).
171    pub fields: Vec<(Spanned<'a>, Option<SpannedExpr<'a, T>>)>,
172}
173
174impl<'a, T: Grammar<'a>> Clone for ObjectExpr<'a, T> {
175    fn clone(&self) -> Self {
176        Self {
177            fields: self.fields.clone(),
178        }
179    }
180}
181
182impl<'a, T: Grammar<'a>> PartialEq for ObjectExpr<'a, T> {
183    fn eq(&self, other: &Self) -> bool {
184        self.fields == other.fields
185    }
186}
187
188/// Arithmetic expression with an abstract types for type annotations and literals.
189#[derive(Debug)]
190#[non_exhaustive]
191pub enum Expr<'a, T: Grammar<'a>> {
192    /// Variable use, e.g., `x`.
193    Variable,
194
195    /// Literal (semantic depends on `T`).
196    Literal(T::Lit),
197
198    /// Function definition, e.g., `|x, y| { x + y }`.
199    FnDefinition(FnDefinition<'a, T>),
200
201    /// Type cast, e.g., `x as Bool`.
202    TypeCast {
203        /// Value being cast, e.g., `x` in `x as Bool`.
204        value: Box<SpannedExpr<'a, T>>,
205        /// Type annotation for the case, e.g., `Bool` in `x as Bool`.
206        ty: Spanned<'a, T::Type>,
207    },
208
209    /// Function call, e.g., `foo(x, y)` or `|x| { x + 5 }(3)`.
210    Function {
211        /// Function value. In the simplest case, this is a variable, but may also be another
212        /// kind of expression, such as `|x| { x + 5 }` in `|x| { x + 5 }(3)`.
213        name: Box<SpannedExpr<'a, T>>,
214        /// Function arguments.
215        args: Vec<SpannedExpr<'a, T>>,
216    },
217
218    /// Field access, e.g., `foo.bar`.
219    FieldAccess {
220        /// Name of the called method, e.g. `bar` in `foo.bar`.
221        name: Spanned<'a>,
222        /// Receiver of the call, e.g., `foo` in `foo.bar(x, 5)`.
223        receiver: Box<SpannedExpr<'a, T>>,
224    },
225
226    /// Method call, e.g., `foo.bar(x, 5)`.
227    Method {
228        /// Name of the called method, e.g. `bar` in `foo.bar(x, 5)`.
229        name: Spanned<'a>,
230        /// Receiver of the call, e.g., `foo` in `foo.bar(x, 5)`.
231        receiver: Box<SpannedExpr<'a, T>>,
232        /// Arguments; e.g., `x, 5` in `foo.bar(x, 5)`.
233        args: Vec<SpannedExpr<'a, T>>,
234    },
235
236    /// Unary operation, e.g., `-x`.
237    Unary {
238        /// Operator.
239        op: Spanned<'a, UnaryOp>,
240        /// Inner expression.
241        inner: Box<SpannedExpr<'a, T>>,
242    },
243
244    /// Binary operation, e.g., `x + 1`.
245    Binary {
246        /// LHS of the operation.
247        lhs: Box<SpannedExpr<'a, T>>,
248        /// Operator.
249        op: Spanned<'a, BinaryOp>,
250        /// RHS of the operation.
251        rhs: Box<SpannedExpr<'a, T>>,
252    },
253
254    /// Tuple expression, e.g., `(x, y + z)`.
255    Tuple(Vec<SpannedExpr<'a, T>>),
256
257    /// Block expression, e.g., `{ x = 3; x + y }`.
258    Block(Block<'a, T>),
259
260    /// Object expression, e.g., `#{ x, y: x + 2 }`.
261    Object(ObjectExpr<'a, T>),
262}
263
264impl<'a, T: Grammar<'a>> Expr<'a, T> {
265    /// Returns LHS of the binary expression. If this is not a binary expression, returns `None`.
266    pub fn binary_lhs(&self) -> Option<&SpannedExpr<'a, T>> {
267        match self {
268            Expr::Binary { ref lhs, .. } => Some(lhs),
269            _ => None,
270        }
271    }
272
273    /// Returns RHS of the binary expression. If this is not a binary expression, returns `None`.
274    pub fn binary_rhs(&self) -> Option<&SpannedExpr<'a, T>> {
275        match self {
276            Expr::Binary { ref rhs, .. } => Some(rhs),
277            _ => None,
278        }
279    }
280
281    /// Returns the type of this expression.
282    pub fn ty(&self) -> ExprType {
283        match self {
284            Self::Variable => ExprType::Variable,
285            Self::Literal(_) => ExprType::Literal,
286            Self::FnDefinition(_) => ExprType::FnDefinition,
287            Self::TypeCast { .. } => ExprType::Cast,
288            Self::Tuple(_) => ExprType::Tuple,
289            Self::Object(_) => ExprType::Object,
290            Self::Block(_) => ExprType::Block,
291            Self::Function { .. } => ExprType::Function,
292            Self::FieldAccess { .. } => ExprType::FieldAccess,
293            Self::Method { .. } => ExprType::Method,
294            Self::Unary { .. } => ExprType::Unary,
295            Self::Binary { .. } => ExprType::Binary,
296        }
297    }
298}
299
300impl<'a, T: Grammar<'a>> Clone for Expr<'a, T> {
301    fn clone(&self) -> Self {
302        match self {
303            Self::Variable => Self::Variable,
304            Self::Literal(lit) => Self::Literal(lit.clone()),
305            Self::FnDefinition(function) => Self::FnDefinition(function.clone()),
306            Self::TypeCast { value, ty } => Self::TypeCast {
307                value: value.clone(),
308                ty: ty.clone(),
309            },
310            Self::Tuple(tuple) => Self::Tuple(tuple.clone()),
311            Self::Object(statements) => Self::Object(statements.clone()),
312            Self::Block(block) => Self::Block(block.clone()),
313            Self::Function { name, args } => Self::Function {
314                name: name.clone(),
315                args: args.clone(),
316            },
317            Self::FieldAccess { name, receiver } => Self::FieldAccess {
318                name: *name,
319                receiver: receiver.clone(),
320            },
321            Self::Method {
322                name,
323                receiver,
324                args,
325            } => Self::Method {
326                name: *name,
327                receiver: receiver.clone(),
328                args: args.clone(),
329            },
330            Self::Unary { op, inner } => Self::Unary {
331                op: *op,
332                inner: inner.clone(),
333            },
334            Self::Binary { op, lhs, rhs } => Self::Binary {
335                op: *op,
336                lhs: lhs.clone(),
337                rhs: rhs.clone(),
338            },
339        }
340    }
341}
342
343impl<'a, T> PartialEq for Expr<'a, T>
344where
345    T: Grammar<'a>,
346    T::Lit: PartialEq,
347    T::Type: PartialEq,
348{
349    fn eq(&self, other: &Self) -> bool {
350        match (self, other) {
351            (Self::Variable, Self::Variable) => true,
352            (Self::Literal(this), Self::Literal(that)) => this == that,
353            (Self::FnDefinition(this), Self::FnDefinition(that)) => this == that,
354
355            (
356                Self::TypeCast { value, ty },
357                Self::TypeCast {
358                    value: other_value,
359                    ty: other_ty,
360                },
361            ) => value == other_value && ty == other_ty,
362
363            (Self::Tuple(this), Self::Tuple(that)) => this == that,
364            (Self::Object(this), Self::Object(that)) => this == that,
365            (Self::Block(this), Self::Block(that)) => this == that,
366
367            (
368                Self::Function { name, args },
369                Self::Function {
370                    name: that_name,
371                    args: that_args,
372                },
373            ) => name == that_name && args == that_args,
374
375            (
376                Self::FieldAccess { name, receiver },
377                Self::FieldAccess {
378                    name: that_name,
379                    receiver: that_receiver,
380                },
381            ) => name == that_name && receiver == that_receiver,
382
383            (
384                Self::Method {
385                    name,
386                    receiver,
387                    args,
388                },
389                Self::Method {
390                    name: that_name,
391                    receiver: that_receiver,
392                    args: that_args,
393                },
394            ) => name == that_name && receiver == that_receiver && args == that_args,
395
396            (
397                Self::Unary { op, inner },
398                Self::Unary {
399                    op: that_op,
400                    inner: that_inner,
401                },
402            ) => op == that_op && inner == that_inner,
403
404            (
405                Self::Binary { lhs, op, rhs },
406                Self::Binary {
407                    lhs: that_lhs,
408                    op: that_op,
409                    rhs: that_rhs,
410                },
411            ) => op == that_op && lhs == that_lhs && rhs == that_rhs,
412
413            _ => false,
414        }
415    }
416}
417
418/// `Expr` with the associated type and code span.
419pub type SpannedExpr<'a, T> = Spanned<'a, Expr<'a, T>>;
420
421/// Type of an `Expr`.
422#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
423#[non_exhaustive]
424pub enum ExprType {
425    /// Variable use, e.g., `x`.
426    Variable,
427    /// Literal (semantic depends on the grammar).
428    Literal,
429    /// Function definition, e.g., `|x, y| { x + y }`.
430    FnDefinition,
431    /// Cast, e.g., `x as Bool`.
432    Cast,
433    /// Function call, e.g., `foo(x, y)` or `|x| { x + 5 }(3)`.
434    Function,
435    /// Field access, e.g., `foo.bar`.
436    FieldAccess,
437    /// Method call, e.g., `foo.bar(x, 5)`.
438    Method,
439    /// Unary operation, e.g., `-x`.
440    Unary,
441    /// Binary operation, e.g., `x + 1`.
442    Binary,
443    /// Tuple expression, e.g., `(x, y + z)`.
444    Tuple,
445    /// Object expression, e.g., `#{ x = 1; y = x + 2; }`.
446    Object,
447    /// Block expression, e.g., `{ x = 3; x + y }`.
448    Block,
449}
450
451impl fmt::Display for ExprType {
452    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
453        formatter.write_str(match self {
454            Self::Variable => "variable",
455            Self::Literal => "literal",
456            Self::FnDefinition => "function definition",
457            Self::Cast => "type cast",
458            Self::Function => "function call",
459            Self::FieldAccess => "field access",
460            Self::Method => "method call",
461            Self::Unary => "unary operation",
462            Self::Binary => "binary operation",
463            Self::Tuple => "tuple",
464            Self::Object => "object",
465            Self::Block => "block",
466        })
467    }
468}
469
470/// Length of an assigned lvalue.
471#[derive(Debug, Clone, Copy, PartialEq)]
472#[non_exhaustive]
473pub enum LvalueLen {
474    /// Exact length.
475    Exact(usize),
476    /// Minimum length.
477    AtLeast(usize),
478}
479
480impl LvalueLen {
481    /// Checks if this length matches the provided length of the rvalue.
482    pub fn matches(self, value: usize) -> bool {
483        match self {
484            Self::Exact(len) => value == len,
485            Self::AtLeast(len) => value >= len,
486        }
487    }
488}
489
490impl fmt::Display for LvalueLen {
491    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
492        match self {
493            Self::Exact(len) => write!(formatter, "{}", len),
494            Self::AtLeast(len) => write!(formatter, "at least {}", len),
495        }
496    }
497}
498
499impl From<usize> for LvalueLen {
500    fn from(value: usize) -> Self {
501        Self::Exact(value)
502    }
503}
504
505/// Tuple destructuring, such as `(a, b, ..., c)`.
506#[derive(Debug, Clone, PartialEq)]
507pub struct Destructure<'a, T> {
508    /// Start part of the destructuring, e.g, `a` and `b` in `(a, b, ..., c)`.
509    pub start: Vec<SpannedLvalue<'a, T>>,
510    /// Middle part of the destructuring, e.g., `rest` in `(a, b, ...rest, _)`.
511    pub middle: Option<Spanned<'a, DestructureRest<'a, T>>>,
512    /// End part of the destructuring, e.g., `c` in `(a, b, ..., c)`.
513    pub end: Vec<SpannedLvalue<'a, T>>,
514}
515
516impl<T> Destructure<'_, T> {
517    /// Returns the length of destructured elements.
518    pub fn len(&self) -> LvalueLen {
519        if self.middle.is_some() {
520            LvalueLen::AtLeast(self.start.len() + self.end.len())
521        } else {
522            LvalueLen::Exact(self.start.len())
523        }
524    }
525
526    /// Checks if the destructuring is empty.
527    pub fn is_empty(&self) -> bool {
528        self.start.is_empty()
529    }
530}
531
532/// Rest syntax, such as `...rest` in `(a, ...rest, b)`.
533#[derive(Debug, Clone, PartialEq)]
534pub enum DestructureRest<'a, T> {
535    /// Unnamed rest syntax, i.e., `...`.
536    Unnamed,
537    /// Named rest syntax, e.g., `...rest`.
538    Named {
539        /// Variable span, e.g., `rest`.
540        variable: Spanned<'a>,
541        /// Type annotation of the value.
542        ty: Option<Spanned<'a, T>>,
543    },
544}
545
546impl<'a, T> DestructureRest<'a, T> {
547    /// Tries to convert this rest declaration into an lvalue. Return `None` if the rest declaration
548    /// is unnamed.
549    pub fn to_lvalue(&self) -> Option<SpannedLvalue<'a, T>> {
550        match self {
551            Self::Named { variable, .. } => {
552                Some(variable.copy_with_extra(Lvalue::Variable { ty: None }))
553            }
554            _ => None,
555        }
556    }
557}
558
559/// Object destructuring, such as `{ x, y: new_y }`.
560#[derive(Debug, Clone, PartialEq)]
561#[non_exhaustive]
562pub struct ObjectDestructure<'a, T> {
563    /// Fields mentioned in the destructuring.
564    pub fields: Vec<ObjectDestructureField<'a, T>>,
565}
566
567/// Single field in [`ObjectDestructure`], such as `x` and `y: new_y` in `{ x, y: new_y }`.
568///
569/// In addition to the "ordinary" `field: lvalue` syntax for a field with binding,
570/// an alternative one is supported: `field -> lvalue`. This makes the case
571/// of a field with type annotation easier to recognize (for humans); `field -> lvalue: Type` is
572/// arguably more readable than `field: lvalue: Type` (although the latter is still valid syntax).
573#[derive(Debug, Clone, PartialEq)]
574pub struct ObjectDestructureField<'a, T> {
575    /// Field name, such as `xs` in `xs: (x, ...tail)`.
576    pub field_name: Spanned<'a>,
577    /// Binding for the field, such as `(x, ...tail)` in `xs: (x, ...tail)`.
578    pub binding: Option<SpannedLvalue<'a, T>>,
579}
580
581/// Assignable value.
582#[derive(Debug, Clone, PartialEq)]
583#[non_exhaustive]
584pub enum Lvalue<'a, T> {
585    /// Simple variable, e.g., `x`.
586    Variable {
587        /// Type annotation of the value.
588        ty: Option<Spanned<'a, T>>,
589    },
590    /// Tuple destructuring, e.g., `(x, y)`.
591    Tuple(Destructure<'a, T>),
592    /// Object destructuring, e.g., `{ x, y }`.
593    Object(ObjectDestructure<'a, T>),
594}
595
596impl<T> Lvalue<'_, T> {
597    /// Returns type of this lvalue.
598    pub fn ty(&self) -> LvalueType {
599        match self {
600            Self::Variable { .. } => LvalueType::Variable,
601            Self::Tuple(_) => LvalueType::Tuple,
602            Self::Object(_) => LvalueType::Object,
603        }
604    }
605}
606
607/// [`Lvalue`] with the associated code span.
608pub type SpannedLvalue<'a, T> = Spanned<'a, Lvalue<'a, T>>;
609
610/// Type of an [`Lvalue`].
611#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
612#[non_exhaustive]
613pub enum LvalueType {
614    /// Simple variable, e.g., `x`.
615    Variable,
616    /// Tuple destructuring, e.g., `(x, y)`.
617    Tuple,
618    /// Object destructuring, e.g., `{ x, y }`.
619    Object,
620}
621
622impl fmt::Display for LvalueType {
623    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
624        formatter.write_str(match self {
625            Self::Variable => "simple variable",
626            Self::Tuple => "tuple destructuring",
627            Self::Object => "object destructuring",
628        })
629    }
630}
631
632/// Statement: an expression or a variable assignment.
633#[derive(Debug)]
634#[non_exhaustive]
635pub enum Statement<'a, T: Grammar<'a>> {
636    /// Expression, e.g., `x + (1, 2)`.
637    Expr(SpannedExpr<'a, T>),
638
639    /// Assigment, e.g., `(x, y) = (5, 8)`.
640    Assignment {
641        /// LHS of the assignment.
642        lhs: SpannedLvalue<'a, T::Type>,
643        /// RHS of the assignment.
644        rhs: Box<SpannedExpr<'a, T>>,
645    },
646}
647
648impl<'a, T: Grammar<'a>> Statement<'a, T> {
649    /// Returns the type of this statement.
650    pub fn ty(&self) -> StatementType {
651        match self {
652            Self::Expr(_) => StatementType::Expr,
653            Self::Assignment { .. } => StatementType::Assignment,
654        }
655    }
656}
657
658impl<'a, T: Grammar<'a>> Clone for Statement<'a, T> {
659    fn clone(&self) -> Self {
660        match self {
661            Self::Expr(expr) => Self::Expr(expr.clone()),
662            Self::Assignment { lhs, rhs } => Self::Assignment {
663                lhs: lhs.clone(),
664                rhs: rhs.clone(),
665            },
666        }
667    }
668}
669
670impl<'a, T> PartialEq for Statement<'a, T>
671where
672    T: Grammar<'a>,
673    T::Lit: PartialEq,
674    T::Type: PartialEq,
675{
676    fn eq(&self, other: &Self) -> bool {
677        match (self, other) {
678            (Self::Expr(this), Self::Expr(that)) => this == that,
679
680            (
681                Self::Assignment { lhs, rhs },
682                Self::Assignment {
683                    lhs: that_lhs,
684                    rhs: that_rhs,
685                },
686            ) => lhs == that_lhs && rhs == that_rhs,
687
688            _ => false,
689        }
690    }
691}
692
693/// Statement with the associated code span.
694pub type SpannedStatement<'a, T> = Spanned<'a, Statement<'a, T>>;
695
696/// Type of a [`Statement`].
697#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
698#[non_exhaustive]
699pub enum StatementType {
700    /// Expression, e.g., `x + (1, 2)`.
701    Expr,
702    /// Assigment, e.g., `(x, y) = (5, 8)`.
703    Assignment,
704}
705
706impl fmt::Display for StatementType {
707    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
708        formatter.write_str(match self {
709            Self::Expr => "expression",
710            Self::Assignment => "variable assignment",
711        })
712    }
713}
714
715/// Block of statements.
716///
717/// A block may end with a return expression, e.g., `{ x = 1; x }`.
718#[derive(Debug)]
719#[non_exhaustive]
720pub struct Block<'a, T: Grammar<'a>> {
721    /// Statements in the block.
722    pub statements: Vec<SpannedStatement<'a, T>>,
723    /// The last statement in the block which is returned from the block.
724    pub return_value: Option<Box<SpannedExpr<'a, T>>>,
725}
726
727impl<'a, T: Grammar<'a>> Clone for Block<'a, T> {
728    fn clone(&self) -> Self {
729        Self {
730            statements: self.statements.clone(),
731            return_value: self.return_value.clone(),
732        }
733    }
734}
735
736impl<'a, T> PartialEq for Block<'a, T>
737where
738    T: Grammar<'a>,
739    T::Lit: PartialEq,
740    T::Type: PartialEq,
741{
742    fn eq(&self, other: &Self) -> bool {
743        self.return_value == other.return_value && self.statements == other.statements
744    }
745}
746
747impl<'a, T: Grammar<'a>> Block<'a, T> {
748    /// Creates an empty block.
749    pub fn empty() -> Self {
750        Self {
751            statements: vec![],
752            return_value: None,
753        }
754    }
755}
756
757/// Function definition, e.g., `|x, y| x + y`.
758///
759/// A function definition consists of a list of arguments and the function body.
760#[derive(Debug)]
761#[non_exhaustive]
762pub struct FnDefinition<'a, T: Grammar<'a>> {
763    /// Function arguments, e.g., `x, y`.
764    pub args: Spanned<'a, Destructure<'a, T::Type>>,
765    /// Function body, e.g., `x + y`.
766    pub body: Block<'a, T>,
767}
768
769impl<'a, T: Grammar<'a>> Clone for FnDefinition<'a, T> {
770    fn clone(&self) -> Self {
771        Self {
772            args: self.args.clone(),
773            body: self.body.clone(),
774        }
775    }
776}
777
778impl<'a, T> PartialEq for FnDefinition<'a, T>
779where
780    T: Grammar<'a>,
781    T::Lit: PartialEq,
782    T::Type: PartialEq,
783{
784    fn eq(&self, other: &Self) -> bool {
785        self.args == other.args && self.body == other.body
786    }
787}