arithmetic-parser 0.2.0-beta.1

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

Flexible Arithmetic Parser

Build Status License: Apache-2.0 rust 1.41.0+ required

Links: Docs.rs crate docs (master) changelog

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.
  • Order comparisons, that is, >, <, >=, and <= boolean ops. (The reason is that these ops do not make sense for some grammars, such as for modular arithmetic.)

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.