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}