more reprs
This commit is contained in:
parent
4818b23c3b
commit
9c2228dbff
@ -23,7 +23,7 @@ pub fn literal_char<'a>(expected: char) -> impl Parser<&'a str, char, ()> {
|
||||
}
|
||||
|
||||
pub fn one_of<'a>(items: &'static str) -> impl Parser<&'a str, char, ()> {
|
||||
move |input: &'a str| {
|
||||
(move |input: &'a str| {
|
||||
if let Some(ch) = input.chars().next() {
|
||||
if items.contains(ch) {
|
||||
let (_first, rest) = input.split_at(1);
|
||||
@ -31,7 +31,16 @@ pub fn one_of<'a>(items: &'static str) -> impl Parser<&'a str, char, ()> {
|
||||
}
|
||||
}
|
||||
Err(((), input))
|
||||
}
|
||||
})
|
||||
.to_anno()
|
||||
.with_repr(
|
||||
Representation::new().with_production(EBNF::Alternation(
|
||||
items
|
||||
.chars()
|
||||
.map(|ch| EBNF::CharTerminal(ch))
|
||||
.collect::<Vec<_>>(),
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Parses a standard identifier in a programming language
|
||||
@ -56,23 +65,46 @@ pub fn identifier(input: &str) -> ParseResult<&str, String, ()> {
|
||||
Ok((buf, &input[next_index..]))
|
||||
}
|
||||
|
||||
pub fn whitespace(input: &str) -> ParseResult<&str, char, ()> {
|
||||
pub struct Whitespace;
|
||||
|
||||
impl Parser<&str, char, ()> for Whitespace {
|
||||
fn name(&self) -> Option<String> {
|
||||
Some("whitespace".into())
|
||||
}
|
||||
|
||||
fn representation(&self) -> Representation {
|
||||
Representation::new().with_production(EBNF::LabeledTerminal("whitespace".into()))
|
||||
}
|
||||
|
||||
fn parse<'a>(&self, input: &'a str) -> ParseResult<&'a str, char, ()> {
|
||||
match input.chars().next() {
|
||||
Some(ch) if ch.is_whitespace() => Ok((ch, &input[1..])),
|
||||
_ => Err(((), input)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn literals() {
|
||||
fn primitive_parsers() {
|
||||
let parser = literal_char('f');
|
||||
assert_eq!(Ok(('f', "unky")), parser.parse("funky"));
|
||||
|
||||
let repr = parser.representation();
|
||||
assert!(matches!(repr.production(), EBNF::CharTerminal('f')));
|
||||
|
||||
let parser = one_of("asdf");
|
||||
let production = parser.representation().production();
|
||||
assert!(
|
||||
matches!(production, EBNF::Alternation(v) if matches!(v.as_slice(), [
|
||||
EBNF::CharTerminal('a'),
|
||||
EBNF::CharTerminal('s'),
|
||||
EBNF::CharTerminal('d'),
|
||||
EBNF::CharTerminal('f'),
|
||||
]))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ pub enum EBNF {
|
||||
Nonterminal(String),
|
||||
CharTerminal(char),
|
||||
StringTerminal(String),
|
||||
LabeledTerminal(String),
|
||||
Alternation(Vec<EBNF>),
|
||||
}
|
||||
|
||||
@ -55,6 +56,7 @@ impl fmt::Display for EBNF {
|
||||
}
|
||||
EBNF::Nonterminal(name) => write!(f, "{name}"),
|
||||
EBNF::StringTerminal(term) => write!(f, r#""{term}""#),
|
||||
EBNF::LabeledTerminal(s) => write!(f, "<{s}>"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ fn parse_list(input: &str) -> ParseResult<&str, Expr, ()> {
|
||||
literal_char('(')
|
||||
.ignore_then(
|
||||
repeated(parse_expr)
|
||||
.separated_by(repeated(whitespace).at_least(1).to(()))
|
||||
.separated_by(repeated(Whitespace).at_least(1).to(()))
|
||||
.allow_trailing(true),
|
||||
)
|
||||
.then_ignore(literal_char(')'))
|
||||
@ -70,7 +70,7 @@ fn test_parse_list() {
|
||||
}
|
||||
|
||||
fn parse_sexp(input: &str) -> ParseResult<&str, Expr, ()> {
|
||||
parse_list.surrounded_by(repeated(whitespace)).parse(input)
|
||||
parse_list.surrounded_by(repeated(Whitespace)).parse(input)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
Loading…
Reference in New Issue
Block a user