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, ()> {
|
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 let Some(ch) = input.chars().next() {
|
||||||
if items.contains(ch) {
|
if items.contains(ch) {
|
||||||
let (_first, rest) = input.split_at(1);
|
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))
|
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
|
/// 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..]))
|
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() {
|
match input.chars().next() {
|
||||||
Some(ch) if ch.is_whitespace() => Ok((ch, &input[1..])),
|
Some(ch) if ch.is_whitespace() => Ok((ch, &input[1..])),
|
||||||
_ => Err(((), input)),
|
_ => Err(((), input)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn literals() {
|
fn primitive_parsers() {
|
||||||
let parser = literal_char('f');
|
let parser = literal_char('f');
|
||||||
assert_eq!(Ok(('f', "unky")), parser.parse("funky"));
|
assert_eq!(Ok(('f', "unky")), parser.parse("funky"));
|
||||||
|
|
||||||
let repr = parser.representation();
|
let repr = parser.representation();
|
||||||
assert!(matches!(repr.production(), EBNF::CharTerminal('f')));
|
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),
|
Nonterminal(String),
|
||||||
CharTerminal(char),
|
CharTerminal(char),
|
||||||
StringTerminal(String),
|
StringTerminal(String),
|
||||||
|
LabeledTerminal(String),
|
||||||
Alternation(Vec<EBNF>),
|
Alternation(Vec<EBNF>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,6 +56,7 @@ impl fmt::Display for EBNF {
|
|||||||
}
|
}
|
||||||
EBNF::Nonterminal(name) => write!(f, "{name}"),
|
EBNF::Nonterminal(name) => write!(f, "{name}"),
|
||||||
EBNF::StringTerminal(term) => write!(f, r#""{term}""#),
|
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('(')
|
literal_char('(')
|
||||||
.ignore_then(
|
.ignore_then(
|
||||||
repeated(parse_expr)
|
repeated(parse_expr)
|
||||||
.separated_by(repeated(whitespace).at_least(1).to(()))
|
.separated_by(repeated(Whitespace).at_least(1).to(()))
|
||||||
.allow_trailing(true),
|
.allow_trailing(true),
|
||||||
)
|
)
|
||||||
.then_ignore(literal_char(')'))
|
.then_ignore(literal_char(')'))
|
||||||
@ -70,7 +70,7 @@ fn test_parse_list() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_sexp(input: &str) -> ParseResult<&str, Expr, ()> {
|
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]
|
#[test]
|
||||||
|
Loading…
Reference in New Issue
Block a user