arithmetic-parser 0.1.0

Parser for arithmetic expressions with flexible literals and type annotations.
Documentation

Flexible Arithmetic Parser

Build Status License: Apache-2.0 rust 1.42.0+ required

Documentation: crate docs (master)

A versatile parser for arithmetic expressions which allows customizing literal definitions, type annotations and several other aspects of parsing.

Supported 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).
  • Python-like comments staring with #.
  • Basic arithmetic operations: +, - (binary and unary), *, /, ^ (power). The parser outputs AST with nodes organized according to the operation priority.
  • Boolean operations: ==, !=, &&, ||, !.
  • 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 Features

These features can be switched on or off when defining a grammar.

  • 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.
  • 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).
  • 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: Type can be present in the lvalues or in the function argument definitions. The parser for type annotations is user-defined.

Code Sample

Here is an example of code parsed with the grammar with real-valued literals and the only supported type Num:

# This is a comment.
x = 1 + 2.5 * 3 + sin(a^3 / b^2);
# Function declarations have syntax similar to Rust closures.
some_function = |a, b: Num| (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: Num) = some_function({ x = x - 0.5; x }, x);
other_function(y - z)

Implementation Details

The parser is based on the nom crate. The core trait of the library, Grammar, is designed in such a way that switching optional features should not induce run-time overhead; the unused parsing code paths should be removed during compilation.

License

Licensed under the Apache-2.0 license.