Trait arithmetic_parser::grammars::ParseLiteral

source ·
pub trait ParseLiteral: 'static {
    type Lit: Clone + Debug;

    // Required method
    fn parse_literal(input: InputSpan<'_>) -> NomResult<'_, Self::Lit>;
}
Expand description

Encapsulates parsing literals in a grammar.

§Examples

If your grammar does not need to support type annotations, you can define a ParseLiteral impl and wrap it into Untyped to get a Grammar / Parse:

use arithmetic_parser::{
    grammars::{Features, ParseLiteral, Parse, Untyped},
    ErrorKind, InputSpan, NomResult,
};

/// Grammar that parses `u64` numbers.
#[derive(Debug)]
struct IntegerGrammar;

impl ParseLiteral for IntegerGrammar {
    type Lit = u64;

    // We use the `nom` crate to construct necessary parsers.
    fn parse_literal(input: InputSpan<'_>) -> NomResult<'_, Self::Lit> {
        use nom::{character::complete::digit1, combinator::map_res};
        let parser = |s: InputSpan<'_>| {
            s.fragment().parse().map_err(ErrorKind::literal)
        };
        map_res(digit1, parser)(input)
    }
}

// Here's how a grammar can be used.
let program = "
    x = 1 + 2 * 3 + sin(a^3 / b^2);
    some_function = |a, b| (a + b, a - b);
    other_function = |x| {
        r = min(rand(), 0);
        r * x
    };
    (y, z) = some_function({ x = x - 1; x }, x);
    other_function(y - z)
";
let parsed = Untyped::<IntegerGrammar>::parse_statements(program)?;
println!("{:#?}", parsed);

Required Associated Types§

source

type Lit: Clone + Debug

Type of the literal used in the grammar.

Required Methods§

source

fn parse_literal(input: InputSpan<'_>) -> NomResult<'_, Self::Lit>

Attempts to parse a literal.

Literals should follow these rules:

  • A literal must be distinguished from other constructs, in particular, variable identifiers.
  • If a literal may end with . and methods are enabled in Parse::FEATURES, care should be taken for cases when . is a part of a call, rather than a part of a literal. For example, a parser for real-valued literals should interpret 1.abs() as a call of the abs method on receiver 1, rather than 1. followed by ineligible abs().

If a literal may start with - or ! (in general, unary ops), these ops will be consumed as a part of the literal, rather than Expr::Unary, unless the literal is followed by an eligible higher-priority operation (i.e., a method call) and the literal without a preceding unary op is still eligible. That is, if -1 and 1 are both valid literals, then -1.abs() will be parsed as negation applied to 1.abs(). On the other hand, if !foo! is a valid literal, but foo! isn’t, !foo!.bar() will be parsed as method bar() called on !foo!.

§Return value

The output should follow nom conventions on errors / failures.

Object Safety§

This trait is not object safe.

Implementors§