more reprs

This commit is contained in:
Greg Shuflin 2024-01-31 03:13:46 -08:00
parent 4818b23c3b
commit 9c2228dbff
3 changed files with 43 additions and 9 deletions

View File

@ -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'),
]))
);
} }
} }

View File

@ -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}>"),
} }
} }
} }

View File

@ -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]