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 { fn representation(&self) -> Representation {
let at_least = self.at_least.unwrap_or(0); let at_least = self.at_least.unwrap_or(0);
let at_most = self.at_most.unwrap_or(u32::MAX); //TODO flesh this out better
let production = EBNF::Repeated(Box::new(self.inner_parser.representation().production())); 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) Representation::new().with_production(production)
} }
} }
@ -204,6 +208,19 @@ where
Ok((results, input)) 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> 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> pub fn map<P, F, I, O1, O2, E>(parser: P, map_fn: F) -> impl Parser<I, O2, E>
where where
P: Parser<I, O1, E>, P: Parser<I, O1, E>,
F: Fn(O1) -> O2, F: Fn(O1) -> O2,
{ {
move |input| { let production = parser.representation().production();
(move |input| {
parser parser
.parse(input) .parse(input)
.map(|(result, rest)| (map_fn(result), rest)) .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), StringTerminal(String),
LabeledTerminal(String), LabeledTerminal(String),
Alternation(Vec<EBNF>), 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 { impl fmt::Display for EBNF {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { 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::CharTerminal(ch) => write!(f, "'{ch}'"),
EBNF::Alternation(items) => { EBNF::Alternation(items) => {
for item in intersperse_option(items.iter()) { for item in intersperse_option(items.iter()) {
@ -58,7 +78,27 @@ 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}>"), 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 = parser.parse("bongo bongo bongo bongo");
let output = output.unwrap(); let output = output.unwrap();
assert_eq!(output.0, vec!["bongo", "bongo", "bongo", "bongo"]); assert_eq!(output.0, vec!["bongo", "bongo", "bongo", "bongo"]);
assert_eq!(parser.representation().show(), r#"["bongo" ' '+]*"#);
let bongos = repeated(literal("bongo")); let bongos = repeated(literal("bongo"));
let output = bongos.parse("tra la la").unwrap(); let output = bongos.parse("tra la la").unwrap();
assert_eq!(output.0.len(), 0); assert_eq!(output.0.len(), 0);
assert_eq!(output.1, "tra la la"); assert_eq!(output.1, "tra la la");
assert_eq!(bongos.representation().show(), r#""bongo"*"#);
} }
#[test] #[test]