inline cont

This commit is contained in:
Noah Hellman 2022-11-27 23:56:19 +01:00
parent b2bc575e27
commit eaea5cf95c
2 changed files with 61 additions and 69 deletions

View file

@ -57,7 +57,7 @@ pub enum Container {
Delete, Delete,
Emphasis, Emphasis,
Strong, Strong,
//Mark, Mark,
// smart quoting // smart quoting
SingleQuoted, SingleQuoted,
DoubleQuoted, DoubleQuoted,
@ -65,12 +65,18 @@ pub enum Container {
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum Event { pub enum Event {
Enter(Container), Enter(Container, OpenerState),
Exit(Container), Exit(Container),
Atom(Atom), Atom(Atom),
Node(Node), Node(Node),
} }
#[derive(Debug, PartialEq, Eq)]
pub enum OpenerState {
Unclosed,
Closed,
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Dir { pub enum Dir {
Open, Open,
@ -79,9 +85,8 @@ pub enum Dir {
} }
pub struct Parser<'s> { pub struct Parser<'s> {
openers: Vec<Container>, openers: Vec<(Container, usize)>,
close_containers: Option<usize>, events: std::collections::VecDeque<Event>,
next: Option<Event>,
span: Span, span: Span,
lexer: std::iter::Peekable<lex::Lexer<'s>>, lexer: std::iter::Peekable<lex::Lexer<'s>>,
@ -91,8 +96,7 @@ impl<'s> Parser<'s> {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
openers: Vec::new(), openers: Vec::new(),
close_containers: None, events: std::collections::VecDeque::new(),
next: None,
span: Span::new(0, 0), span: Span::new(0, 0),
lexer: lex::Lexer::new("").peekable(), lexer: lex::Lexer::new("").peekable(),
@ -206,8 +210,8 @@ impl<'s> Parser<'s> {
lex::Kind::Close(Delimiter::BraceAsterisk) => Some((Strong, Dir::Close)), lex::Kind::Close(Delimiter::BraceAsterisk) => Some((Strong, Dir::Close)),
lex::Kind::Open(Delimiter::BraceCaret) => Some((Superscript, Dir::Open)), lex::Kind::Open(Delimiter::BraceCaret) => Some((Superscript, Dir::Open)),
lex::Kind::Close(Delimiter::BraceCaret) => Some((Superscript, Dir::Close)), lex::Kind::Close(Delimiter::BraceCaret) => Some((Superscript, Dir::Close)),
//lex::Kind::Open(Delimiter::BraceEqual) => Some((Mark, Dir::Open)), lex::Kind::Open(Delimiter::BraceEqual) => Some((Mark, Dir::Open)),
//lex::Kind::Close(Delimiter::BraceEqual) => Some((Mark, Dir::Close)), lex::Kind::Close(Delimiter::BraceEqual) => Some((Mark, Dir::Close)),
lex::Kind::Open(Delimiter::BraceHyphen) => Some((Delete, Dir::Open)), lex::Kind::Open(Delimiter::BraceHyphen) => Some((Delete, Dir::Open)),
lex::Kind::Close(Delimiter::BraceHyphen) => Some((Delete, Dir::Close)), lex::Kind::Close(Delimiter::BraceHyphen) => Some((Delete, Dir::Close)),
lex::Kind::Open(Delimiter::BracePlus) => Some((Insert, Dir::Open)), lex::Kind::Open(Delimiter::BracePlus) => Some((Insert, Dir::Open)),
@ -218,16 +222,28 @@ impl<'s> Parser<'s> {
lex::Kind::Close(Delimiter::BraceUnderscore) => Some((Emphasis, Dir::Close)), lex::Kind::Close(Delimiter::BraceUnderscore) => Some((Emphasis, Dir::Close)),
_ => None, _ => None,
} }
.and_then(|(cont, dir)| { .map(|(cont_new, dir)| {
if matches!(dir, Dir::Close | Dir::Both) && self.openers.contains(&cont) { self.openers
self.close_containers = self.openers.iter().rposition(|o| *o == cont); .iter()
Some(Event::Exit(self.openers.pop().unwrap())) .rposition(|(c, _)| *c == cont_new)
} else if matches!(dir, Dir::Open | Dir::Both) { .and_then(|o| {
self.openers.push(cont); matches!(dir, Dir::Close | Dir::Both).then(|| {
Some(Event::Enter(cont)) let (cont_open, e) = &mut self.openers[o];
} else { assert_eq!(*cont_open, cont_new);
None if let Event::Enter(cont_ev, state_ev) = &mut self.events[*e] {
} assert_eq!(*cont_ev, cont_new);
*state_ev = OpenerState::Closed;
self.openers.drain(o..);
Event::Exit(cont_new)
} else {
panic!()
}
})
})
.unwrap_or_else(|| {
self.openers.push((cont_new, self.events.len()));
Event::Enter(cont_new, OpenerState::Unclosed)
})
}) })
} }
} }
@ -236,31 +252,16 @@ impl<'s> Iterator for Parser<'s> {
type Item = Event; type Item = Event;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.next.take().or_else(|| { while self.events.is_empty() || !self.openers.is_empty() {
self.close_containers if let Some(ev) = self.parse_event() {
.and_then(|i| { self.events.push_back(ev);
if i < self.openers.len() { } else {
Some(Event::Exit(self.openers.pop().unwrap())) break;
} else { }
self.close_containers = None; }
None
}
})
.or_else(|| {
let mut current = self.parse_event();
if let Some(Event::Node(Node { kind: Str, span })) = &mut current { // TODO merge str/unclosed enters
self.next = self.parse_event(); self.events.pop_front()
while let Some(Event::Node(Node { kind: Str, span: s })) = self.next {
*span = span.union(s);
self.next = self.parse_event();
}
}
current
})
.or_else(|| self.openers.pop().map(Event::Exit))
})
} }
} }
@ -272,6 +273,7 @@ mod test {
use super::Container::*; use super::Container::*;
use super::Event::*; use super::Event::*;
use super::NodeKind::*; use super::NodeKind::*;
use super::OpenerState::*;
macro_rules! test_parse { macro_rules! test_parse {
($($st:ident,)? $src:expr $(,$($token:expr),* $(,)?)?) => { ($($st:ident,)? $src:expr $(,$($token:expr),* $(,)?)?) => {
@ -317,13 +319,13 @@ mod test {
fn container_basic() { fn container_basic() {
test_parse!( test_parse!(
"_abc_", "_abc_",
Enter(Emphasis), Enter(Emphasis, Closed),
Node(Str.span(1, 4)), Node(Str.span(1, 4)),
Exit(Emphasis) Exit(Emphasis)
); );
test_parse!( test_parse!(
"{_abc_}", "{_abc_}",
Enter(Emphasis), Enter(Emphasis, Closed),
Node(Str.span(2, 5)), Node(Str.span(2, 5)),
Exit(Emphasis) Exit(Emphasis)
); );
@ -333,16 +335,16 @@ mod test {
fn container_nest() { fn container_nest() {
test_parse!( test_parse!(
"{_{_abc_}_}", "{_{_abc_}_}",
Enter(Emphasis), Enter(Emphasis, Closed),
Enter(Emphasis), Enter(Emphasis, Closed),
Node(Str.span(4, 7)), Node(Str.span(4, 7)),
Exit(Emphasis), Exit(Emphasis),
Exit(Emphasis) Exit(Emphasis)
); );
test_parse!( test_parse!(
"*_abc_*", "*_abc_*",
Enter(Strong), Enter(Strong, Closed),
Enter(Emphasis), Enter(Emphasis, Closed),
Node(Str.span(2, 5)), Node(Str.span(2, 5)),
Exit(Emphasis), Exit(Emphasis),
Exit(Strong) Exit(Strong)
@ -358,31 +360,22 @@ mod test {
fn container_close_parent() { fn container_close_parent() {
test_parse!( test_parse!(
"{*{_abc*}", "{*{_abc*}",
Enter(Strong), Enter(Strong, Closed),
Enter(Emphasis), Enter(Emphasis, Unclosed),
Node(Str.span(4, 7)), Node(Str.span(4, 7)),
Exit(Emphasis), Exit(Strong),
Exit(Strong)
); );
} }
#[test] #[test]
fn container_close_block() { fn container_close_block() {
test_parse!( test_parse!("{_abc", Enter(Emphasis, Unclosed), Node(Str.span(2, 5)));
"{_abc",
Enter(Emphasis),
Node(Str.span(2, 5)),
Exit(Emphasis)
);
test_parse!( test_parse!(
"{_{*{_abc", "{_{*{_abc",
Enter(Emphasis), Enter(Emphasis, Unclosed),
Enter(Strong), Enter(Strong, Unclosed),
Enter(Emphasis), Enter(Emphasis, Unclosed),
Node(Str.span(6, 9)), Node(Str.span(6, 9)),
Exit(Emphasis),
Exit(Strong),
Exit(Emphasis),
); );
} }
} }

View file

@ -30,7 +30,7 @@ pub enum Delimiter {
Brace, Brace,
BraceAsterisk, BraceAsterisk,
BraceCaret, BraceCaret,
//BraceEqual, BraceEqual,
BraceHyphen, BraceHyphen,
BracePlus, BracePlus,
BraceTilde, BraceTilde,
@ -149,7 +149,7 @@ impl<'s> Lexer<'s> {
let explicit = match self.peek() { let explicit = match self.peek() {
'*' => Some(Open(BraceAsterisk)), '*' => Some(Open(BraceAsterisk)),
'^' => Some(Open(BraceCaret)), '^' => Some(Open(BraceCaret)),
//'=' => Some(Open(BraceEqual)), '=' => Some(Open(BraceEqual)),
'-' => Some(Open(BraceHyphen)), '-' => Some(Open(BraceHyphen)),
'+' => Some(Open(BracePlus)), '+' => Some(Open(BracePlus)),
'~' => Some(Open(BraceTilde)), '~' => Some(Open(BraceTilde)),
@ -165,7 +165,7 @@ impl<'s> Lexer<'s> {
} }
'*' => self.maybe_eat_close_brace(Asterisk, BraceAsterisk), '*' => self.maybe_eat_close_brace(Asterisk, BraceAsterisk),
'^' => self.maybe_eat_close_brace(Caret, BraceCaret), '^' => self.maybe_eat_close_brace(Caret, BraceCaret),
//'=' => self.maybe_eat_close_brace(Equal, BraceEqual), '=' => self.maybe_eat_close_brace(Equal, BraceEqual),
'+' => self.maybe_eat_close_brace(Plus, BracePlus), '+' => self.maybe_eat_close_brace(Plus, BracePlus),
'~' => self.maybe_eat_close_brace(Tilde, BraceTilde), '~' => self.maybe_eat_close_brace(Tilde, BraceTilde),
'_' => self.maybe_eat_close_brace(Underscore, BraceUnderscore), '_' => self.maybe_eat_close_brace(Underscore, BraceUnderscore),
@ -178,7 +178,6 @@ impl<'s> Lexer<'s> {
} }
} }
'=' => Sym(Equal),
'!' => Sym(Exclaim), '!' => Sym(Exclaim),
'%' => Sym(Percentage), '%' => Sym(Percentage),
'<' => Sym(Lt), '<' => Sym(Lt),