wip fix span / typeset precedence
This commit is contained in:
parent
352be02ccf
commit
d8d464902a
3 changed files with 182 additions and 118 deletions
33
src/attr.rs
33
src/attr.rs
|
@ -4,8 +4,13 @@ use crate::Span;
|
|||
|
||||
use State::*;
|
||||
|
||||
pub fn valid<I: Iterator<Item = char>>(chars: I) -> bool {
|
||||
!Parser::new(chars).any(|e| matches!(e, Element::Invalid))
|
||||
pub fn valid<I: Iterator<Item = char>>(chars: I) -> usize {
|
||||
let mut p = Parser::new(chars);
|
||||
if p.any(|e| matches!(e, Element::Invalid)) {
|
||||
0
|
||||
} else {
|
||||
p.pos
|
||||
}
|
||||
}
|
||||
|
||||
// Attributes are relatively rare, we choose to pay 8 bytes always and sometimes an extra
|
||||
|
@ -178,14 +183,7 @@ impl<I: Iterator<Item = char>> Parser<I> {
|
|||
ValueQuoted
|
||||
}
|
||||
}
|
||||
Done => {
|
||||
if c.is_whitespace() {
|
||||
Done
|
||||
} else {
|
||||
Invalid
|
||||
}
|
||||
}
|
||||
Invalid => panic!(),
|
||||
Invalid | Done => panic!(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -193,6 +191,10 @@ impl<I: Iterator<Item = char>> Parser<I> {
|
|||
fn step(&mut self) -> (State, Span) {
|
||||
let start = self.pos.saturating_sub(1);
|
||||
|
||||
if self.state == Done {
|
||||
return (Done, Span::empty_at(start));
|
||||
}
|
||||
|
||||
while let Some(state_next) = self.step_char() {
|
||||
if self.state != state_next {
|
||||
return (
|
||||
|
@ -204,7 +206,7 @@ impl<I: Iterator<Item = char>> Parser<I> {
|
|||
|
||||
(
|
||||
if self.state == Done { Done } else { Invalid },
|
||||
Span::new(start, self.pos),
|
||||
Span::new(start, self.pos - 1),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -325,4 +327,13 @@ mod test {
|
|||
("id", "some_id"),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn valid() {
|
||||
let src0 = "{.class %comment%}";
|
||||
assert_eq!(super::valid(src0.chars()), src0.len());
|
||||
|
||||
let src1 = format!("{} trailing", src0);
|
||||
assert_eq!(super::valid(src1.chars()), src0.len());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -270,7 +270,7 @@ impl BlockParser {
|
|||
))
|
||||
}
|
||||
}
|
||||
'{' => attr::valid(line_t.chars())
|
||||
'{' => (attr::valid(line_t.chars()) == line_t.trim_end().len())
|
||||
.then(|| (Block::Atom(Attributes), Span::by_len(start, line_t.len()))),
|
||||
'|' => (&line_t[line_t.len() - 1..] == "|"
|
||||
&& &line_t[line_t.len() - 2..line_t.len() - 1] != "\\")
|
||||
|
|
219
src/inline.rs
219
src/inline.rs
|
@ -1,3 +1,4 @@
|
|||
use crate::attr;
|
||||
use crate::lex;
|
||||
use crate::Span;
|
||||
|
||||
|
@ -71,10 +72,7 @@ pub struct Parser<I> {
|
|||
/// Span of current event.
|
||||
span: Span,
|
||||
/// Stack with kind and index of _potential_ openers for typesetting containers.
|
||||
typesets: Vec<(Container, usize)>,
|
||||
/// Stack with index of _potential_ span/link openers.
|
||||
spans: Vec<(usize, bool)>,
|
||||
//attributes: Vec<(Span, usize)>,
|
||||
openers: Vec<(Delim, usize)>,
|
||||
/// Buffer queue for next events. Events are buffered until no modifications due to future
|
||||
/// characters are needed.
|
||||
events: std::collections::VecDeque<Event>,
|
||||
|
@ -85,8 +83,7 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
|
|||
Self {
|
||||
lexer: lex::Lexer::new(chars),
|
||||
span: Span::new(0, 0),
|
||||
typesets: Vec::new(),
|
||||
spans: Vec::new(),
|
||||
openers: Vec::new(),
|
||||
events: std::collections::VecDeque::new(),
|
||||
}
|
||||
}
|
||||
|
@ -111,8 +108,7 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
|
|||
self.reset_span();
|
||||
self.eat().map(|first| {
|
||||
self.parse_verbatim(&first)
|
||||
.or_else(|| self.parse_span(&first))
|
||||
.or_else(|| self.parse_typeset(&first))
|
||||
.or_else(|| self.parse_container(&first))
|
||||
.or_else(|| self.parse_atom(&first))
|
||||
.unwrap_or(Event {
|
||||
kind: EventKind::Str,
|
||||
|
@ -212,30 +208,86 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
|
|||
})
|
||||
}
|
||||
|
||||
fn parse_span(&mut self, first: &lex::Token) -> Option<Event> {
|
||||
fn parse_container(&mut self, first: &lex::Token) -> Option<Event> {
|
||||
enum Dir {
|
||||
Open,
|
||||
Close,
|
||||
Both,
|
||||
}
|
||||
|
||||
use Directionality::{Bi, Uni};
|
||||
use SpanType::{General, Image};
|
||||
|
||||
match first.kind {
|
||||
lex::Kind::Sym(Symbol::ExclaimBracket) => Some((true, true)),
|
||||
lex::Kind::Open(Delimiter::Bracket) => Some((true, false)),
|
||||
lex::Kind::Close(Delimiter::Bracket) => Some((false, false)),
|
||||
lex::Kind::Sym(Symbol::Asterisk) => Some((Delim::Strong(Bi), Dir::Both)),
|
||||
lex::Kind::Sym(Symbol::Underscore) => Some((Delim::Emphasis(Bi), Dir::Both)),
|
||||
lex::Kind::Sym(Symbol::Caret) => Some((Delim::Superscript(Bi), Dir::Both)),
|
||||
lex::Kind::Sym(Symbol::Tilde) => Some((Delim::Subscript(Bi), Dir::Both)),
|
||||
lex::Kind::Sym(Symbol::Quote1) => Some((Delim::SingleQuoted, Dir::Both)),
|
||||
lex::Kind::Sym(Symbol::Quote2) => Some((Delim::DoubleQuoted, Dir::Both)),
|
||||
lex::Kind::Sym(Symbol::ExclaimBracket) => Some((Delim::Span(Image), Dir::Open)),
|
||||
lex::Kind::Open(Delimiter::Bracket) => Some((Delim::Span(General), Dir::Open)),
|
||||
lex::Kind::Close(Delimiter::Bracket) => Some((Delim::Span(General), Dir::Close)),
|
||||
lex::Kind::Open(Delimiter::BraceAsterisk) => Some((Delim::Strong(Uni), Dir::Open)),
|
||||
lex::Kind::Close(Delimiter::BraceAsterisk) => Some((Delim::Strong(Uni), Dir::Close)),
|
||||
lex::Kind::Open(Delimiter::BraceUnderscore) => Some((Delim::Emphasis(Uni), Dir::Open)),
|
||||
lex::Kind::Close(Delimiter::BraceUnderscore) => {
|
||||
Some((Delim::Emphasis(Uni), Dir::Close))
|
||||
}
|
||||
lex::Kind::Open(Delimiter::BraceCaret) => Some((Delim::Superscript(Uni), Dir::Open)),
|
||||
lex::Kind::Close(Delimiter::BraceCaret) => Some((Delim::Superscript(Uni), Dir::Close)),
|
||||
lex::Kind::Open(Delimiter::BraceTilde) => Some((Delim::Subscript(Uni), Dir::Open)),
|
||||
lex::Kind::Close(Delimiter::BraceTilde) => Some((Delim::Subscript(Uni), Dir::Close)),
|
||||
lex::Kind::Open(Delimiter::BraceEqual) => Some((Delim::Mark, Dir::Open)),
|
||||
lex::Kind::Close(Delimiter::BraceEqual) => Some((Delim::Mark, Dir::Close)),
|
||||
lex::Kind::Open(Delimiter::BraceHyphen) => Some((Delim::Delete, Dir::Open)),
|
||||
lex::Kind::Close(Delimiter::BraceHyphen) => Some((Delim::Delete, Dir::Close)),
|
||||
lex::Kind::Open(Delimiter::BracePlus) => Some((Delim::Insert, Dir::Open)),
|
||||
lex::Kind::Close(Delimiter::BracePlus) => Some((Delim::Insert, Dir::Close)),
|
||||
_ => None,
|
||||
}
|
||||
.and_then(|(open, img)| {
|
||||
if open {
|
||||
self.spans.push((self.events.len(), img));
|
||||
// use str for now, replace if closed later
|
||||
.map(|(delim, dir)| {
|
||||
self.openers
|
||||
.iter()
|
||||
.rposition(|(d, _)| d.matches(delim))
|
||||
.and_then(|o| {
|
||||
let (d, e) = self.openers[o];
|
||||
if matches!(dir, Dir::Close | Dir::Both) {
|
||||
let e = match Container::try_from(d) {
|
||||
Ok(cont) => {
|
||||
self.events[e].kind = EventKind::Enter(cont);
|
||||
Some(Event {
|
||||
kind: EventKind::Str,
|
||||
kind: EventKind::Exit(cont),
|
||||
span: self.span,
|
||||
})
|
||||
} else if !self.spans.is_empty() {
|
||||
}
|
||||
Err(ty) => self.post_span(ty, e),
|
||||
};
|
||||
self.openers.drain(o..);
|
||||
e
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
self.openers.push((delim, self.events.len()));
|
||||
// use str for now, replace if closed later
|
||||
Event {
|
||||
kind: EventKind::Str,
|
||||
span: self.span,
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn post_span(&mut self, ty: SpanType, opener_event: usize) -> Option<Event> {
|
||||
let mut ahead = self.lexer.inner().clone();
|
||||
let img = self.spans.last().unwrap().1;
|
||||
match ahead.next() {
|
||||
Some(opener @ ('[' | '(')) => {
|
||||
let (closer, kind) = match opener {
|
||||
'[' if img => (']', ReferenceImage),
|
||||
'[' if ty == SpanType::Image => (']', ReferenceImage),
|
||||
'[' => (']', ReferenceLink),
|
||||
'(' if img => (')', InlineImage),
|
||||
'(' if ty == SpanType::Image => (')', InlineImage),
|
||||
'(' => (')', InlineLink),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
@ -253,12 +305,10 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
|
|||
(kind, span)
|
||||
})
|
||||
}
|
||||
Some('{') => todo!(),
|
||||
_ => None,
|
||||
}
|
||||
.map(|(kind, span)| {
|
||||
self.lexer = lex::Lexer::new(ahead);
|
||||
let (opener_event, _) = self.spans.pop().unwrap();
|
||||
self.events[opener_event].kind = EventKind::Enter(kind);
|
||||
self.events[opener_event].span = span;
|
||||
self.span = span.translate(1);
|
||||
|
@ -267,64 +317,6 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
|
|||
span,
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_typeset(&mut self, first: &lex::Token) -> Option<Event> {
|
||||
enum Dir {
|
||||
Open,
|
||||
Close,
|
||||
Both,
|
||||
}
|
||||
|
||||
match first.kind {
|
||||
lex::Kind::Sym(Symbol::Asterisk) => Some((Strong, Dir::Both)),
|
||||
lex::Kind::Sym(Symbol::Underscore) => Some((Emphasis, Dir::Both)),
|
||||
lex::Kind::Sym(Symbol::Caret) => Some((Superscript, Dir::Both)),
|
||||
lex::Kind::Sym(Symbol::Tilde) => Some((Subscript, Dir::Both)),
|
||||
lex::Kind::Sym(Symbol::Quote1) => Some((SingleQuoted, Dir::Both)),
|
||||
lex::Kind::Sym(Symbol::Quote2) => Some((DoubleQuoted, Dir::Both)),
|
||||
lex::Kind::Open(Delimiter::BraceAsterisk) => Some((Strong, Dir::Open)),
|
||||
lex::Kind::Close(Delimiter::BraceAsterisk) => Some((Strong, Dir::Close)),
|
||||
lex::Kind::Open(Delimiter::BraceCaret) => Some((Superscript, Dir::Open)),
|
||||
lex::Kind::Close(Delimiter::BraceCaret) => Some((Superscript, Dir::Close)),
|
||||
lex::Kind::Open(Delimiter::BraceEqual) => Some((Mark, Dir::Open)),
|
||||
lex::Kind::Close(Delimiter::BraceEqual) => Some((Mark, Dir::Close)),
|
||||
lex::Kind::Open(Delimiter::BraceHyphen) => Some((Delete, Dir::Open)),
|
||||
lex::Kind::Close(Delimiter::BraceHyphen) => Some((Delete, Dir::Close)),
|
||||
lex::Kind::Open(Delimiter::BracePlus) => Some((Insert, Dir::Open)),
|
||||
lex::Kind::Close(Delimiter::BracePlus) => Some((Insert, Dir::Close)),
|
||||
lex::Kind::Open(Delimiter::BraceTilde) => Some((Subscript, Dir::Open)),
|
||||
lex::Kind::Close(Delimiter::BraceTilde) => Some((Subscript, Dir::Close)),
|
||||
lex::Kind::Open(Delimiter::BraceUnderscore) => Some((Emphasis, Dir::Open)),
|
||||
lex::Kind::Close(Delimiter::BraceUnderscore) => Some((Emphasis, Dir::Close)),
|
||||
_ => None,
|
||||
}
|
||||
.map(|(cont, dir)| {
|
||||
self.typesets
|
||||
.iter()
|
||||
.rposition(|(c, _)| *c == cont)
|
||||
.and_then(|o| {
|
||||
matches!(dir, Dir::Close | Dir::Both).then(|| {
|
||||
let (_, e) = &mut self.typesets[o];
|
||||
self.events[*e].kind = EventKind::Enter(cont);
|
||||
self.typesets.drain(o..);
|
||||
EventKind::Exit(cont)
|
||||
})
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
self.typesets.push((cont, self.events.len()));
|
||||
// use str for now, replace if closed later
|
||||
EventKind::Str
|
||||
})
|
||||
})
|
||||
.map(|kind| Event {
|
||||
kind,
|
||||
span: self.span,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_atom(&mut self, first: &lex::Token) -> Option<Event> {
|
||||
|
@ -346,13 +338,74 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum Directionality {
|
||||
Uni,
|
||||
Bi,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum SpanType {
|
||||
Image,
|
||||
General,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum Delim {
|
||||
Span(SpanType),
|
||||
Strong(Directionality),
|
||||
Emphasis(Directionality),
|
||||
Superscript(Directionality),
|
||||
Subscript(Directionality),
|
||||
SingleQuoted,
|
||||
DoubleQuoted,
|
||||
Mark,
|
||||
Delete,
|
||||
Insert,
|
||||
}
|
||||
|
||||
impl Delim {
|
||||
fn matches(self, other: Delim) -> bool {
|
||||
match self {
|
||||
Self::Span(..) => matches!(other, Self::Span(..)),
|
||||
Self::Strong(..) => matches!(other, Self::Strong(..)),
|
||||
Self::Emphasis(..) => matches!(other, Self::Emphasis(..)),
|
||||
Self::Superscript(..) => matches!(other, Self::Superscript(..)),
|
||||
Self::Subscript(..) => matches!(other, Self::Subscript(..)),
|
||||
Self::SingleQuoted => matches!(other, Self::SingleQuoted),
|
||||
Self::DoubleQuoted => matches!(other, Self::DoubleQuoted),
|
||||
Self::Mark => matches!(other, Self::Mark),
|
||||
Self::Delete => matches!(other, Self::Delete),
|
||||
Self::Insert => matches!(other, Self::Insert),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Delim> for Container {
|
||||
type Error = SpanType;
|
||||
|
||||
fn try_from(d: Delim) -> Result<Self, Self::Error> {
|
||||
match d {
|
||||
Delim::Span(ty) => Err(ty),
|
||||
Delim::Strong(..) => Ok(Self::Strong),
|
||||
Delim::Emphasis(..) => Ok(Self::Emphasis),
|
||||
Delim::Superscript(..) => Ok(Self::Superscript),
|
||||
Delim::Subscript(..) => Ok(Self::Subscript),
|
||||
Delim::SingleQuoted => Ok(Self::SingleQuoted),
|
||||
Delim::DoubleQuoted => Ok(Self::DoubleQuoted),
|
||||
Delim::Mark => Ok(Self::Mark),
|
||||
Delim::Delete => Ok(Self::Delete),
|
||||
Delim::Insert => Ok(Self::Insert),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Iterator<Item = char> + Clone> Iterator for Parser<I> {
|
||||
type Item = Event;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while self.events.is_empty()
|
||||
|| !self.typesets.is_empty()
|
||||
|| !self.spans.is_empty()
|
||||
|| !self.openers.is_empty()
|
||||
|| self // for merge
|
||||
.events
|
||||
.back()
|
||||
|
|
Loading…
Reference in a new issue