Expand description
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 - 10
or|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)
. - Objects. Object is a mapping of string fields to values. Objects are defined via
object expressions, which look similar to struct initialization in Rust or object
initialization in JavaScript; for example,
#{ x: 1, y }
. (Note the#
char at the start of the block; it is used to distinguish object expressions from blocks.) - 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: Type
can 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 annotations are placed within tuple elements, for example,
(x: Num, _) = y
. - Object expressions are enclosed in
#{ ... }
, similarly to Rhai.
§Crate features
std
. Enables support of types fromstd
, such as theError
trait, and propagates to dependencies.num-complex
. ImplementsNumLiteral
for floating-point complex numbers (Complex32
andComplex64
).num-bigint
. ImplementsNumLiteral
forBigInt
andBigUint
from thenum-bigint
crate.
§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
(a, b, ..., c)
. - FnDefinition
- Function definition, e.g.,
|x, y| x + y
. - Located
Span - Code span together with information related to where it is located in the code.
- Object
Destructure - Object destructuring, such as
{ x, y: new_y }
. - Object
Destructure Field - Single field in
ObjectDestructure
, such asx
andy: new_y
in{ x, y: new_y }
. - Object
Expr - Object expression, such as
#{ x, y: x + 2 }
. - Spanned
Error - Parsing error with a generic code span.
Enums§
- Binary
Op - Binary arithmetic operation.
- Code
Fragment - 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.
- Destructure
Rest - Rest syntax, such as
...rest
in(a, ...rest, b)
. - Error
Kind - Parsing error kind.
- Expr
- Arithmetic expression with an abstract types for type annotations and literals.
- Expr
Type - Type of an
Expr
. - Lvalue
- Assignable value.
- Lvalue
Len - Length of an assigned lvalue.
- Lvalue
Type - Type of an
Lvalue
. - Op
- Generic operation, either unary or binary.
- OpPriority
- Priority of an operation.
- Statement
- Statement: an expression or a variable assignment.
- Statement
Type - Type of a
Statement
. - UnaryOp
- Unary operation.
- Unsupported
Type - Description of a construct not supported by a certain module (e.g., interpreter or type inference).
Traits§
- Strip
Code - Encapsulates stripping references to code fragments. The result can outlive the code.
- Strip
Result Ext - Helper trait for
Result
s with the error component that implementsStripCode
.
Functions§
- is_
valid_ variable_ name - Checks if the provided string is a valid variable name.
- with_
span - Wrapper around parsers allowing to capture both their output and the relevant span.
Type Aliases§
- Error
- Error with code span available as a string reference.
- Input
Span - Code span.
- Maybe
Spanned - Value with an optional associated code span.
- NomResult
- Parsing outcome generalized by the type returned on success.
- Spanned
- Value with an associated code span.
- Spanned
Expr Expr
with the associated type and code span.- Spanned
Lvalue Lvalue
with the associated code span.- Spanned
Statement - Statement with the associated code span.