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§
Required Methods§
sourcefn parse_literal(input: InputSpan<'_>) -> NomResult<'_, Self::Lit>
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 inParse::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 interpret1.abs()
as a call of theabs
method on receiver1
, rather than1.
followed by ineligibleabs()
.
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.