More representation work

This commit is contained in:
Greg Shuflin 2024-02-02 02:39:50 -08:00
parent e6e1d14eee
commit e47bcbe760
4 changed files with 71 additions and 8 deletions

View File

@ -104,8 +104,12 @@ where
fn representation(&self) -> Representation {
let at_least = self.at_least.unwrap_or(0);
let at_most = self.at_most.unwrap_or(u32::MAX);
let production = EBNF::Repeated(Box::new(self.inner_parser.representation().production()));
//TODO flesh this out better
let _at_most = self.at_most.unwrap_or(u32::MAX);
let production = EBNF::Repeated {
inner: Box::new(self.inner_parser.representation().production()),
more_than_once: at_least >= 1,
};
Representation::new().with_production(production)
}
}
@ -204,6 +208,19 @@ where
Ok((results, input))
}
fn representation(&self) -> Representation {
let inner = &self.inner_repeated.inner_parser;
let at_least = self.inner_repeated.at_least.unwrap_or(0);
let inner_production = inner.representation().production();
let delimiter_production = self.delimiter.representation().production();
let production = EBNF::Repeated {
inner: Box::new(EBNF::Sequence(vec![inner_production, delimiter_production])),
more_than_once: at_least >= 1,
};
Representation::new().with_production(production)
}
}
pub fn optional<I, O, E>(parser: impl Parser<I, O, E>) -> impl Parser<I, Option<O>, E>

View File

@ -1,13 +1,16 @@
use crate::Parser;
use crate::{representation::Representation, Parser, ParserExtension};
pub fn map<P, F, I, O1, O2, E>(parser: P, map_fn: F) -> impl Parser<I, O2, E>
where
P: Parser<I, O1, E>,
F: Fn(O1) -> O2,
{
move |input| {
let production = parser.representation().production();
(move |input| {
parser
.parse(input)
.map(|(result, rest)| (map_fn(result), rest))
}
})
.to_anno()
.with_repr(Representation::new().with_production(production))
}

View File

@ -38,13 +38,33 @@ pub enum EBNF {
StringTerminal(String),
LabeledTerminal(String),
Alternation(Vec<EBNF>),
Repeated(Box<EBNF>),
Sequence(Vec<EBNF>),
Repeated {
inner: Box<EBNF>,
more_than_once: bool,
},
}
impl EBNF {
fn needs_wrapping(&self) -> bool {
match self {
EBNF::None => false,
EBNF::Nonterminal(_) => false,
EBNF::CharTerminal(_) => false,
EBNF::StringTerminal(_) => false,
EBNF::LabeledTerminal(_) => false,
EBNF::Sequence(items) => items.len() > 1,
EBNF::Alternation(_) => true,
EBNF::Repeated { .. } => false,
}
}
}
impl fmt::Display for EBNF {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
EBNF::None => write!(f, "none"),
//TODO should try to show the name if possible
EBNF::None => write!(f, "<no-representation>"),
EBNF::CharTerminal(ch) => write!(f, "'{ch}'"),
EBNF::Alternation(items) => {
for item in intersperse_option(items.iter()) {
@ -58,7 +78,27 @@ impl fmt::Display for EBNF {
EBNF::Nonterminal(name) => write!(f, "{name}"),
EBNF::StringTerminal(term) => write!(f, r#""{term}""#),
EBNF::LabeledTerminal(s) => write!(f, "<{s}>"),
EBNF::Repeated(inner) => write!(f, "[ {inner} ]"),
EBNF::Repeated {
inner,
more_than_once,
} => {
let sigil = if *more_than_once { '+' } else { '*' };
if inner.needs_wrapping() {
write!(f, "[{inner}]{sigil}")
} else {
write!(f, "{inner}{sigil}")
}
}
EBNF::Sequence(items) => {
for item in intersperse_option(items.iter()) {
if let Some(item) = item {
write!(f, "{item}")?;
} else {
write!(f, " ")?;
}
}
write!(f, "")
}
}
}
}

View File

@ -81,11 +81,14 @@ fn test_repeated() {
let output = parser.parse("bongo bongo bongo bongo");
let output = output.unwrap();
assert_eq!(output.0, vec!["bongo", "bongo", "bongo", "bongo"]);
assert_eq!(parser.representation().show(), r#"["bongo" ' '+]*"#);
let bongos = repeated(literal("bongo"));
let output = bongos.parse("tra la la").unwrap();
assert_eq!(output.0.len(), 0);
assert_eq!(output.1, "tra la la");
assert_eq!(bongos.representation().show(), r#""bongo"*"#);
}
#[test]