[−][src]Crate arithmetic_parser
Parser for arithmetic expressions with flexible definition of literals and support of type annotations.
Overall, parsed grammars are similar to Rust syntax, with a few notable differences.
Supported syntax features
- Variables. A variable name is defined similar to Rust and other programming languages, as a sequence of alphanumeric chars and underscores that does not start with a digit.
- Literals. The parser for literals is user-provided, thus allowing to apply the library to different domains (e.g., finite group arithmetic).
//and/* .. */comments.- Basic arithmetic operations:
+,-(binary and unary),*,/,^(power). The parser outputs AST with nodes organized according to the operation priority. - Function calls:
foo(1.0, x). - Parentheses which predictably influence operation priority.
The parser supports both complete and streaming (incomplete) modes; the latter is useful for REPLs and similar applications.
Optional syntax features
These features can be switched on or off when defining a Parse impl
by declaring the corresponding Features.
- Tuples. A tuple is two or more elements separated by commas, such as
(x, y)or(1, 2 * x). Tuples are parsed both as lvalues and rvalues. - Tuple destructuring. Using a tuple as an lvalue, for example,
(x, y, z) = foo. The "rest" syntax is also supported, either named or unnamed:(head, ...tail) = foo,(a, ..., b, c) = foo. - Function definitions. A definition looks like a closure definition in Rust, e.g.,
|x| x - 10or|x, y| { z = max(x, y); (z - x, z - y) }. A definition may be assigned to a variable (which is the way to define named functions). - Destructuring for function args. Similar to tuple destructuring, it is possible to
destructure and group args in function definitions, for example,
|(x, y), ...zs| { }. - Blocks. A block is several
;-delimited statements enclosed in{}braces, e.g,{ z = max(x, y); (z - x, z - y) }. The blocks can be used in all contexts instead of a simple expression; for example,min({ z = 5; z - 1 }, 3). - Methods. Method call is a function call separated from the receiver with a
.char; for example,foo.bar(2, x). - Type annotations. A type annotation in the form
var: Typecan be present in the lvalues or in the function argument definitions. The parser for type annotations is user-defined. - Boolean operations:
==,!=,&&,||,!. - Order comparisons, that is,
>,<,>=, and<=boolean ops.
Differences with Rust
(within shared syntax constructs; of course, Rust is much more expressive)
- No keyword for assigning a variable (i.e., no
let/let mut). There are no keywords in general. - Functions are only defined via the closure syntax.
- There is "rest" destructuting for tuples and function arguments.
- Type hints are placed within tuple elements, for example,
(x: Num, _) = y.
Crate features
std. Enables support of types fromstd, such as theErrortrait, and propagates to dependencies.num-complex. ImplementsNumLiteralfor floating-point complex numbers (Complex32andComplex64).num-bigint. ImplementsNumLiteralforBigIntandBigUintfrom thenum-bigintcrate.
Examples
Using a grammar for arithmetic on real values.
use arithmetic_parser::{ grammars::{F32Grammar, Parse, Untyped}, NomResult, Statement, Expr, FnDefinition, LvalueLen, }; const PROGRAM: &str = r#" // This is a comment. x = 1 + 2.5 * 3 + sin(a^3 / b^2 /* another comment */); // Function declarations have syntax similar to Rust closures. some_function = |a, b| (a + b, a - b); other_function = |x| { r = min(rand(), 0.5); r * x }; // Tuples and blocks are supported and have a similar syntax to Rust. (y, z) = some_function({ x = x - 0.5; x }, x); other_function(y - z) "#; let block = Untyped::<F32Grammar>::parse_statements(PROGRAM)?; // First statement is an assignment. assert_matches!( block.statements[0].extra, Statement::Assignment { ref lhs, .. } if *lhs.fragment() == "x" ); // The RHS of the second statement is a function. let some_function = match &block.statements[1].extra { Statement::Assignment { rhs, .. } => &rhs.extra, _ => panic!("Unexpected parsing result"), }; // This function has a single argument and a single statement in the body. assert_matches!( some_function, Expr::FnDefinition(FnDefinition { ref args, ref body, .. }) if args.extra.len() == LvalueLen::Exact(2) && body.statements.is_empty() && body.return_value.is_some() );
Modules
| grammars | Grammar functionality and a collection of standard grammars. |
Structs
| Block | Block of statements. |
| Destructure | Tuple destructuring, such as |
| FnDefinition | Function definition, e.g., |
| LocatedSpan | Code span together with information related to where it is located in the code. |
| SpannedError | Parsing error with a generic code span. |
Enums
| BinaryOp | Binary arithmetic operation. |
| CodeFragment | Container for a code fragment that can be in one of the two states: either the code string is retained, or it is stripped away. |
| Context | Parsing context. |
| DestructureRest | Rest syntax, such as |
| ErrorKind | Parsing error kind. |
| Expr | Arithmetic expression with an abstract types for type hints and literals. |
| ExprType | Type of an |
| Lvalue | Assignable value. |
| LvalueLen | Length of an assigned lvalue. |
| LvalueType | Type of an |
| Op | Generic operation, either unary or binary. |
| OpPriority | Priority of an operation. |
| Statement | Statement: an expression or a variable assignment. |
| StatementType | Type of a |
| UnaryOp | Unary operation. |
Traits
| StripCode | Encapsulates stripping references to code fragments. The result can outlive the code. |
| StripResultExt | Helper trait for |
Functions
| is_valid_variable_name | Checks if the provided string is a valid variable name. |
Type Definitions
| Error | Error with code span available as a string reference. |
| InputSpan | Code span. |
| MaybeSpanned | Value with an optional associated code span. |
| NomResult | Parsing outcome generalized by the type returned on success. |
| Spanned | Value with an associated code span. |
| SpannedExpr |
|
| SpannedLvalue |
|
| SpannedStatement | Statement with the associated code span. |