inline: replace Delim by Opener
no need to have a delimiter for closer, only opener needs to be stored in stack
This commit is contained in:
parent
ed5aed3759
commit
66d821f03e
1 changed files with 89 additions and 78 deletions
167
src/inline.rs
167
src/inline.rs
|
@ -176,7 +176,7 @@ pub struct VerbatimState {
|
||||||
pub struct Parser<I: Iterator + Clone> {
|
pub struct Parser<I: Iterator + Clone> {
|
||||||
input: Input<I>,
|
input: Input<I>,
|
||||||
/// Stack with kind and index of _potential_ openers for containers.
|
/// Stack with kind and index of _potential_ openers for containers.
|
||||||
openers: Vec<(Delim, usize)>,
|
openers: Vec<(Opener, usize)>,
|
||||||
/// Buffer queue for next events. Events are buffered until no modifications due to future
|
/// Buffer queue for next events. Events are buffered until no modifications due to future
|
||||||
/// characters are needed.
|
/// characters are needed.
|
||||||
events: std::collections::VecDeque<Event>,
|
events: std::collections::VecDeque<Event>,
|
||||||
|
@ -468,33 +468,28 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_container(&mut self, first: &lex::Token) -> Option<()> {
|
fn parse_container(&mut self, first: &lex::Token) -> Option<()> {
|
||||||
let (delim, dir) = Delim::from_token(first)?;
|
|
||||||
|
|
||||||
self.openers
|
self.openers
|
||||||
.iter()
|
.iter()
|
||||||
.rposition(|(d, _)| delim.closes(*d))
|
.rposition(|(o, _)| o.closed_by(first.kind))
|
||||||
.and_then(|o| {
|
.and_then(|o| {
|
||||||
if matches!(dir, Dir::Open) {
|
let (opener, e) = self.openers[o];
|
||||||
|
let e_attr = e;
|
||||||
|
let e_opener = e + 1;
|
||||||
|
|
||||||
|
if e_opener == self.events.len() - 1 {
|
||||||
|
// empty container
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let whitespace_after = self.events.back().map_or(false, |ev| {
|
let whitespace_after = self.events.back().map_or(false, |ev| {
|
||||||
matches!(ev.kind, EventKind::Whitespace | EventKind::Atom(Softbreak))
|
matches!(ev.kind, EventKind::Whitespace | EventKind::Atom(Softbreak))
|
||||||
});
|
});
|
||||||
if matches!(dir, Dir::Both) && whitespace_after {
|
if opener.bidirectional() && whitespace_after {
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (d, e) = self.openers[o];
|
|
||||||
let e_attr = e;
|
|
||||||
let e_opener = e + 1;
|
|
||||||
if e_opener == self.events.len() - 1 {
|
|
||||||
// empty container
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let inner_span = self.events[e_opener].span.between(self.input.span);
|
let inner_span = self.events[e_opener].span.between(self.input.span);
|
||||||
self.openers.drain(o..);
|
self.openers.drain(o..);
|
||||||
let mut closed = match DelimEventKind::from(d) {
|
let mut closed = match DelimEventKind::from(opener) {
|
||||||
DelimEventKind::Container(cont) => {
|
DelimEventKind::Container(cont) => {
|
||||||
self.events[e_opener].kind = EventKind::Enter(cont);
|
self.events[e_opener].kind = EventKind::Enter(cont);
|
||||||
self.push(EventKind::Exit(cont))
|
self.push(EventKind::Exit(cont))
|
||||||
|
@ -538,10 +533,8 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
|
||||||
closed
|
closed
|
||||||
})
|
})
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
if matches!(dir, Dir::Close) {
|
let opener = Opener::from_token(first.kind)?;
|
||||||
return None;
|
if opener.bidirectional()
|
||||||
}
|
|
||||||
if matches!(dir, Dir::Both)
|
|
||||||
&& self
|
&& self
|
||||||
.input
|
.input
|
||||||
.peek()
|
.peek()
|
||||||
|
@ -549,7 +542,7 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if matches!(delim, Delim::SingleQuoted | Delim::DoubleQuoted)
|
if matches!(opener, Opener::SingleQuoted | Opener::DoubleQuoted)
|
||||||
&& self
|
&& self
|
||||||
.events
|
.events
|
||||||
.back()
|
.back()
|
||||||
|
@ -557,19 +550,19 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
self.openers.push((delim, self.events.len()));
|
self.openers.push((opener, self.events.len()));
|
||||||
// push dummy event in case attributes are encountered after closing delimiter
|
// push dummy event in case attributes are encountered after closing delimiter
|
||||||
self.push_sp(
|
self.push_sp(
|
||||||
EventKind::Placeholder,
|
EventKind::Placeholder,
|
||||||
Span::empty_at(self.input.span.start()),
|
Span::empty_at(self.input.span.start()),
|
||||||
);
|
);
|
||||||
// use non-opener for now, replace if closed later
|
// use non-opener for now, replace if closed later
|
||||||
self.push(match delim {
|
self.push(match opener {
|
||||||
Delim::SingleQuoted => EventKind::Atom(Quote {
|
Opener::SingleQuoted => EventKind::Atom(Quote {
|
||||||
ty: QuoteType::Single,
|
ty: QuoteType::Single,
|
||||||
left: false,
|
left: false,
|
||||||
}),
|
}),
|
||||||
Delim::DoubleQuoted => EventKind::Atom(Quote {
|
Opener::DoubleQuoted => EventKind::Atom(Quote {
|
||||||
ty: QuoteType::Double,
|
ty: QuoteType::Double,
|
||||||
left: true,
|
left: true,
|
||||||
}),
|
}),
|
||||||
|
@ -691,7 +684,7 @@ enum SpanType {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
enum Delim {
|
enum Opener {
|
||||||
Span(SpanType),
|
Span(SpanType),
|
||||||
Strong(Directionality),
|
Strong(Directionality),
|
||||||
Emphasis(Directionality),
|
Emphasis(Directionality),
|
||||||
|
@ -704,54 +697,72 @@ enum Delim {
|
||||||
DoubleQuoted,
|
DoubleQuoted,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
impl Opener {
|
||||||
enum Dir {
|
fn from_token(kind: lex::Kind) -> Option<Self> {
|
||||||
Open,
|
|
||||||
Close,
|
|
||||||
Both,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Delim {
|
|
||||||
fn from_token(token: &lex::Token) -> Option<(Self, Dir)> {
|
|
||||||
use Delim::*;
|
|
||||||
use Dir::{Both, Close, Open};
|
|
||||||
use Directionality::{Bi, Uni};
|
use Directionality::{Bi, Uni};
|
||||||
|
use Opener::*;
|
||||||
use SpanType::{General, Image};
|
use SpanType::{General, Image};
|
||||||
|
|
||||||
match token.kind {
|
match kind {
|
||||||
lex::Kind::Sym(Symbol::Asterisk) => Some((Strong(Bi), Both)),
|
lex::Kind::Sym(Symbol::Asterisk) => Some(Strong(Bi)),
|
||||||
lex::Kind::Sym(Symbol::Underscore) => Some((Emphasis(Bi), Both)),
|
lex::Kind::Sym(Symbol::Underscore) => Some(Emphasis(Bi)),
|
||||||
lex::Kind::Sym(Symbol::Caret) => Some((Superscript(Bi), Both)),
|
lex::Kind::Sym(Symbol::Caret) => Some(Superscript(Bi)),
|
||||||
lex::Kind::Sym(Symbol::Tilde) => Some((Subscript(Bi), Both)),
|
lex::Kind::Sym(Symbol::Tilde) => Some(Subscript(Bi)),
|
||||||
lex::Kind::Sym(Symbol::Quote1) => Some((SingleQuoted, Both)),
|
lex::Kind::Sym(Symbol::Quote1) => Some(SingleQuoted),
|
||||||
lex::Kind::Sym(Symbol::Quote2) => Some((DoubleQuoted, Both)),
|
lex::Kind::Sym(Symbol::Quote2) => Some(DoubleQuoted),
|
||||||
lex::Kind::Sym(Symbol::ExclaimBracket) => Some((Span(Image), Open)),
|
lex::Kind::Sym(Symbol::ExclaimBracket) => Some(Span(Image)),
|
||||||
lex::Kind::Open(Delimiter::Bracket) => Some((Span(General), Open)),
|
lex::Kind::Open(Delimiter::Bracket) => Some(Span(General)),
|
||||||
lex::Kind::Close(Delimiter::Bracket) => Some((Span(General), Close)),
|
lex::Kind::Open(Delimiter::BraceAsterisk) => Some(Strong(Uni)),
|
||||||
lex::Kind::Open(Delimiter::BraceAsterisk) => Some((Strong(Uni), Open)),
|
lex::Kind::Open(Delimiter::BraceUnderscore) => Some(Emphasis(Uni)),
|
||||||
lex::Kind::Close(Delimiter::BraceAsterisk) => Some((Strong(Uni), Close)),
|
lex::Kind::Open(Delimiter::BraceCaret) => Some(Superscript(Uni)),
|
||||||
lex::Kind::Open(Delimiter::BraceUnderscore) => Some((Emphasis(Uni), Open)),
|
lex::Kind::Open(Delimiter::BraceTilde) => Some(Subscript(Uni)),
|
||||||
lex::Kind::Close(Delimiter::BraceUnderscore) => Some((Emphasis(Uni), Close)),
|
lex::Kind::Open(Delimiter::BraceEqual) => Some(Mark),
|
||||||
lex::Kind::Open(Delimiter::BraceCaret) => Some((Superscript(Uni), Open)),
|
lex::Kind::Open(Delimiter::BraceHyphen) => Some(Delete),
|
||||||
lex::Kind::Close(Delimiter::BraceCaret) => Some((Superscript(Uni), Close)),
|
lex::Kind::Open(Delimiter::BracePlus) => Some(Insert),
|
||||||
lex::Kind::Open(Delimiter::BraceTilde) => Some((Subscript(Uni), Open)),
|
lex::Kind::Open(Delimiter::BraceQuote1) => Some(SingleQuoted),
|
||||||
lex::Kind::Close(Delimiter::BraceTilde) => Some((Subscript(Uni), Close)),
|
lex::Kind::Open(Delimiter::BraceQuote2) => Some(DoubleQuoted),
|
||||||
lex::Kind::Open(Delimiter::BraceEqual) => Some((Mark, Open)),
|
|
||||||
lex::Kind::Close(Delimiter::BraceEqual) => Some((Mark, Close)),
|
|
||||||
lex::Kind::Open(Delimiter::BraceHyphen) => Some((Delete, Open)),
|
|
||||||
lex::Kind::Close(Delimiter::BraceHyphen) => Some((Delete, Close)),
|
|
||||||
lex::Kind::Open(Delimiter::BracePlus) => Some((Insert, Open)),
|
|
||||||
lex::Kind::Close(Delimiter::BracePlus) => Some((Insert, Close)),
|
|
||||||
lex::Kind::Open(Delimiter::BraceQuote1) => Some((SingleQuoted, Open)),
|
|
||||||
lex::Kind::Close(Delimiter::BraceQuote1) => Some((SingleQuoted, Close)),
|
|
||||||
lex::Kind::Open(Delimiter::BraceQuote2) => Some((DoubleQuoted, Open)),
|
|
||||||
lex::Kind::Close(Delimiter::BraceQuote2) => Some((DoubleQuoted, Close)),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn closes(self, opener: Delim) -> bool {
|
fn closed_by(&self, kind: lex::Kind) -> bool {
|
||||||
self == opener || matches!((opener, self), (Delim::Span(..), Delim::Span(..)))
|
use Directionality::{Bi, Uni};
|
||||||
|
use Opener::*;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Span(..) => matches!(kind, lex::Kind::Close(Delimiter::Bracket)),
|
||||||
|
Strong(Bi) => matches!(kind, lex::Kind::Sym(Symbol::Asterisk)),
|
||||||
|
Strong(Uni) => matches!(kind, lex::Kind::Close(Delimiter::BraceAsterisk)),
|
||||||
|
Emphasis(Bi) => matches!(kind, lex::Kind::Sym(Symbol::Underscore)),
|
||||||
|
Emphasis(Uni) => matches!(kind, lex::Kind::Close(Delimiter::BraceUnderscore)),
|
||||||
|
Superscript(Bi) => matches!(kind, lex::Kind::Sym(Symbol::Caret)),
|
||||||
|
Superscript(Uni) => matches!(kind, lex::Kind::Close(Delimiter::BraceCaret)),
|
||||||
|
Subscript(Bi) => matches!(kind, lex::Kind::Sym(Symbol::Tilde)),
|
||||||
|
Subscript(Uni) => matches!(kind, lex::Kind::Close(Delimiter::BraceTilde)),
|
||||||
|
Mark => matches!(kind, lex::Kind::Close(Delimiter::BraceEqual)),
|
||||||
|
Delete => matches!(kind, lex::Kind::Close(Delimiter::BraceHyphen)),
|
||||||
|
Insert => matches!(kind, lex::Kind::Close(Delimiter::BracePlus)),
|
||||||
|
SingleQuoted => matches!(
|
||||||
|
kind,
|
||||||
|
lex::Kind::Sym(Symbol::Quote1) | lex::Kind::Close(Delimiter::BraceQuote1)
|
||||||
|
),
|
||||||
|
DoubleQuoted => matches!(
|
||||||
|
kind,
|
||||||
|
lex::Kind::Sym(Symbol::Quote2) | lex::Kind::Close(Delimiter::BraceQuote2)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bidirectional(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
Opener::Strong(Directionality::Bi)
|
||||||
|
| Opener::Emphasis(Directionality::Bi)
|
||||||
|
| Opener::Superscript(Directionality::Bi)
|
||||||
|
| Opener::Subscript(Directionality::Bi)
|
||||||
|
| Opener::SingleQuoted
|
||||||
|
| Opener::DoubleQuoted
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,19 +772,19 @@ enum DelimEventKind {
|
||||||
Quote(QuoteType),
|
Quote(QuoteType),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Delim> for DelimEventKind {
|
impl From<Opener> for DelimEventKind {
|
||||||
fn from(d: Delim) -> Self {
|
fn from(d: Opener) -> Self {
|
||||||
match d {
|
match d {
|
||||||
Delim::Span(ty) => Self::Span(ty),
|
Opener::Span(ty) => Self::Span(ty),
|
||||||
Delim::Strong(..) => Self::Container(Strong),
|
Opener::Strong(..) => Self::Container(Strong),
|
||||||
Delim::Emphasis(..) => Self::Container(Emphasis),
|
Opener::Emphasis(..) => Self::Container(Emphasis),
|
||||||
Delim::Superscript(..) => Self::Container(Superscript),
|
Opener::Superscript(..) => Self::Container(Superscript),
|
||||||
Delim::Subscript(..) => Self::Container(Subscript),
|
Opener::Subscript(..) => Self::Container(Subscript),
|
||||||
Delim::Mark => Self::Container(Mark),
|
Opener::Mark => Self::Container(Mark),
|
||||||
Delim::Delete => Self::Container(Delete),
|
Opener::Delete => Self::Container(Delete),
|
||||||
Delim::Insert => Self::Container(Insert),
|
Opener::Insert => Self::Container(Insert),
|
||||||
Delim::SingleQuoted => Self::Quote(QuoteType::Single),
|
Opener::SingleQuoted => Self::Quote(QuoteType::Single),
|
||||||
Delim::DoubleQuoted => Self::Quote(QuoteType::Double),
|
Opener::DoubleQuoted => Self::Quote(QuoteType::Double),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue