aboutsummaryrefslogtreecommitdiffstats
path: root/src/construct/code_fenced.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/construct/code_fenced.rs170
1 files changed, 83 insertions, 87 deletions
diff --git a/src/construct/code_fenced.rs b/src/construct/code_fenced.rs
index c4c3e86..a22a0f9 100644
--- a/src/construct/code_fenced.rs
+++ b/src/construct/code_fenced.rs
@@ -110,18 +110,6 @@ use crate::token::Token;
use crate::tokenizer::{ContentType, State, Tokenizer};
use crate::util::slice::{Position, Slice};
-/// State needed to parse code (fenced).
-#[derive(Debug, Clone)]
-struct Info {
- /// Number of markers on the opening fence sequence.
- size: usize,
- /// Number of tabs or spaces of indentation before the opening fence
- /// sequence.
- prefix: usize,
- /// Marker of fences (`u8`).
- marker: u8,
-}
-
/// Start of fenced code.
///
/// ```markdown
@@ -173,15 +161,10 @@ fn before_sequence_open(tokenizer: &mut Tokenizer) -> State {
}
if let Some(b'`' | b'~') = tokenizer.current {
+ tokenizer.tokenize_state.marker = tokenizer.current.unwrap();
+ tokenizer.tokenize_state.prefix = prefix;
tokenizer.enter(Token::CodeFencedFenceSequence);
- sequence_open(
- tokenizer,
- Info {
- prefix,
- size: 0,
- marker: tokenizer.current.unwrap(),
- },
- )
+ sequence_open(tokenizer)
} else {
State::Nok
}
@@ -195,20 +178,23 @@ fn before_sequence_open(tokenizer: &mut Tokenizer) -> State {
/// | console.log(1)
/// | ~~~
/// ```
-fn sequence_open(tokenizer: &mut Tokenizer, mut info: Info) -> State {
+fn sequence_open(tokenizer: &mut Tokenizer) -> State {
match tokenizer.current {
- Some(b'`' | b'~') if tokenizer.current.unwrap() == info.marker => {
+ Some(b'`' | b'~') if tokenizer.current.unwrap() == tokenizer.tokenize_state.marker => {
+ tokenizer.tokenize_state.size += 1;
tokenizer.consume();
- State::Fn(Box::new(|t| {
- info.size += 1;
- sequence_open(t, info)
- }))
+ State::Fn(Box::new(sequence_open))
}
- _ if info.size >= CODE_FENCED_SEQUENCE_SIZE_MIN => {
+ _ if tokenizer.tokenize_state.size >= CODE_FENCED_SEQUENCE_SIZE_MIN => {
tokenizer.exit(Token::CodeFencedFenceSequence);
- tokenizer.attempt_opt(space_or_tab(), |t| info_before(t, info))(tokenizer)
+ tokenizer.attempt_opt(space_or_tab(), info_before)(tokenizer)
+ }
+ _ => {
+ tokenizer.tokenize_state.marker = 0;
+ tokenizer.tokenize_state.prefix = 0;
+ tokenizer.tokenize_state.size = 0;
+ State::Nok
}
- _ => State::Nok,
}
}
@@ -220,18 +206,18 @@ fn sequence_open(tokenizer: &mut Tokenizer, mut info: Info) -> State {
/// | console.log(1)
/// | ~~~
/// ```
-fn info_before(tokenizer: &mut Tokenizer, info: Info) -> State {
+fn info_before(tokenizer: &mut Tokenizer) -> State {
match tokenizer.current {
None | Some(b'\n') => {
tokenizer.exit(Token::CodeFencedFence);
// Do not form containers.
tokenizer.concrete = true;
- at_break(tokenizer, info)
+ at_break(tokenizer)
}
_ => {
tokenizer.enter(Token::CodeFencedFenceInfo);
tokenizer.enter_with_content(Token::Data, Some(ContentType::String));
- info_inside(tokenizer, info)
+ info_inside(tokenizer)
}
}
}
@@ -244,7 +230,7 @@ fn info_before(tokenizer: &mut Tokenizer, info: Info) -> State {
/// | console.log(1)
/// | ~~~
/// ```
-fn info_inside(tokenizer: &mut Tokenizer, info: Info) -> State {
+fn info_inside(tokenizer: &mut Tokenizer) -> State {
match tokenizer.current {
None | Some(b'\n') => {
tokenizer.exit(Token::Data);
@@ -252,17 +238,23 @@ fn info_inside(tokenizer: &mut Tokenizer, info: Info) -> State {
tokenizer.exit(Token::CodeFencedFence);
// Do not form containers.
tokenizer.concrete = true;
- at_break(tokenizer, info)
+ at_break(tokenizer)
}
Some(b'\t' | b' ') => {
tokenizer.exit(Token::Data);
tokenizer.exit(Token::CodeFencedFenceInfo);
- tokenizer.attempt_opt(space_or_tab(), |t| meta_before(t, info))(tokenizer)
+ tokenizer.attempt_opt(space_or_tab(), meta_before)(tokenizer)
+ }
+ Some(b'`') if tokenizer.tokenize_state.marker == b'`' => {
+ tokenizer.concrete = false;
+ tokenizer.tokenize_state.marker = 0;
+ tokenizer.tokenize_state.prefix = 0;
+ tokenizer.tokenize_state.size = 0;
+ State::Nok
}
- Some(b'`') if info.marker == b'`' => State::Nok,
Some(_) => {
tokenizer.consume();
- State::Fn(Box::new(|t| info_inside(t, info)))
+ State::Fn(Box::new(info_inside))
}
}
}
@@ -275,18 +267,18 @@ fn info_inside(tokenizer: &mut Tokenizer, info: Info) -> State {
/// | console.log(1)
/// | ~~~
/// ```
-fn meta_before(tokenizer: &mut Tokenizer, info: Info) -> State {
+fn meta_before(tokenizer: &mut Tokenizer) -> State {
match tokenizer.current {
None | Some(b'\n') => {
tokenizer.exit(Token::CodeFencedFence);
// Do not form containers.
tokenizer.concrete = true;
- at_break(tokenizer, info)
+ at_break(tokenizer)
}
_ => {
tokenizer.enter(Token::CodeFencedFenceMeta);
tokenizer.enter_with_content(Token::Data, Some(ContentType::String));
- meta(tokenizer, info)
+ meta(tokenizer)
}
}
}
@@ -299,7 +291,7 @@ fn meta_before(tokenizer: &mut Tokenizer, info: Info) -> State {
/// | console.log(1)
/// | ~~~
/// ```
-fn meta(tokenizer: &mut Tokenizer, info: Info) -> State {
+fn meta(tokenizer: &mut Tokenizer) -> State {
match tokenizer.current {
None | Some(b'\n') => {
tokenizer.exit(Token::Data);
@@ -307,12 +299,18 @@ fn meta(tokenizer: &mut Tokenizer, info: Info) -> State {
tokenizer.exit(Token::CodeFencedFence);
// Do not form containers.
tokenizer.concrete = true;
- at_break(tokenizer, info)
+ at_break(tokenizer)
+ }
+ Some(b'`') if tokenizer.tokenize_state.marker == b'`' => {
+ tokenizer.concrete = false;
+ tokenizer.tokenize_state.marker = 0;
+ tokenizer.tokenize_state.prefix = 0;
+ tokenizer.tokenize_state.size = 0;
+ State::Nok
}
- Some(b'`') if info.marker == b'`' => State::Nok,
_ => {
tokenizer.consume();
- State::Fn(Box::new(|t| meta(t, info)))
+ State::Fn(Box::new(meta))
}
}
}
@@ -326,13 +324,9 @@ fn meta(tokenizer: &mut Tokenizer, info: Info) -> State {
/// ^
/// | ~~~
/// ```
-fn at_break(tokenizer: &mut Tokenizer, info: Info) -> State {
+fn at_break(tokenizer: &mut Tokenizer) -> State {
tokenizer.check(partial_non_lazy_continuation, |ok| {
- if ok {
- Box::new(move |t| at_non_lazy_break(t, info))
- } else {
- Box::new(after)
- }
+ Box::new(if ok { at_non_lazy_break } else { after })
})(tokenizer)
}
@@ -345,19 +339,10 @@ fn at_break(tokenizer: &mut Tokenizer, info: Info) -> State {
/// ^
/// | ~~~
/// ```
-fn at_non_lazy_break(tokenizer: &mut Tokenizer, info: Info) -> State {
- let clone = info.clone();
-
- tokenizer.attempt(
- |t| close_begin(t, info),
- |ok| {
- if ok {
- Box::new(after)
- } else {
- Box::new(|t| content_before(t, clone))
- }
- },
- )(tokenizer)
+fn at_non_lazy_break(tokenizer: &mut Tokenizer) -> State {
+ tokenizer.attempt(close_begin, |ok| {
+ Box::new(if ok { after } else { content_before })
+ })(tokenizer)
}
/// Before a closing fence, at the line ending.
@@ -368,13 +353,13 @@ fn at_non_lazy_break(tokenizer: &mut Tokenizer, info: Info) -> State {
/// ^
/// | ~~~
/// ```
-fn close_begin(tokenizer: &mut Tokenizer, info: Info) -> State {
+fn close_begin(tokenizer: &mut Tokenizer) -> State {
match tokenizer.current {
Some(b'\n') => {
tokenizer.enter(Token::LineEnding);
tokenizer.consume();
tokenizer.exit(Token::LineEnding);
- State::Fn(Box::new(|t| close_start(t, info)))
+ State::Fn(Box::new(close_start))
}
_ => unreachable!("expected eol"),
}
@@ -388,7 +373,7 @@ fn close_begin(tokenizer: &mut Tokenizer, info: Info) -> State {
/// > | ~~~
/// ^
/// ```
-fn close_start(tokenizer: &mut Tokenizer, info: Info) -> State {
+fn close_start(tokenizer: &mut Tokenizer) -> State {
tokenizer.enter(Token::CodeFencedFence);
tokenizer.go(
space_or_tab_min_max(
@@ -399,7 +384,7 @@ fn close_start(tokenizer: &mut Tokenizer, info: Info) -> State {
usize::MAX
},
),
- |t| close_before(t, info),
+ close_before,
)(tokenizer)
}
@@ -411,11 +396,11 @@ fn close_start(tokenizer: &mut Tokenizer, info: Info) -> State {
/// > | ~~~
/// ^
/// ```
-fn close_before(tokenizer: &mut Tokenizer, info: Info) -> State {
+fn close_before(tokenizer: &mut Tokenizer) -> State {
match tokenizer.current {
- Some(b'`' | b'~') if tokenizer.current.unwrap() == info.marker => {
+ Some(b'`' | b'~') if tokenizer.current.unwrap() == tokenizer.tokenize_state.marker => {
tokenizer.enter(Token::CodeFencedFenceSequence);
- close_sequence(tokenizer, info, 0)
+ close_sequence(tokenizer)
}
_ => State::Nok,
}
@@ -429,17 +414,24 @@ fn close_before(tokenizer: &mut Tokenizer, info: Info) -> State {
/// > | ~~~
/// ^
/// ```
-fn close_sequence(tokenizer: &mut Tokenizer, info: Info, size: usize) -> State {
+fn close_sequence(tokenizer: &mut Tokenizer) -> State {
match tokenizer.current {
- Some(b'`' | b'~') if tokenizer.current.unwrap() == info.marker => {
+ Some(b'`' | b'~') if tokenizer.current.unwrap() == tokenizer.tokenize_state.marker => {
+ tokenizer.tokenize_state.size_other += 1;
tokenizer.consume();
- State::Fn(Box::new(move |t| close_sequence(t, info, size + 1)))
+ State::Fn(Box::new(close_sequence))
}
- _ if size >= CODE_FENCED_SEQUENCE_SIZE_MIN && size >= info.size => {
+ _ if tokenizer.tokenize_state.size_other >= CODE_FENCED_SEQUENCE_SIZE_MIN
+ && tokenizer.tokenize_state.size_other >= tokenizer.tokenize_state.size =>
+ {
+ tokenizer.tokenize_state.size_other = 0;
tokenizer.exit(Token::CodeFencedFenceSequence);
tokenizer.attempt_opt(space_or_tab(), close_sequence_after)(tokenizer)
}
- _ => State::Nok,
+ _ => {
+ tokenizer.tokenize_state.size_other = 0;
+ State::Nok
+ }
}
}
@@ -469,11 +461,11 @@ fn close_sequence_after(tokenizer: &mut Tokenizer) -> State {
/// ^
/// | ~~~
/// ```
-fn content_before(tokenizer: &mut Tokenizer, info: Info) -> State {
+fn content_before(tokenizer: &mut Tokenizer) -> State {
tokenizer.enter(Token::LineEnding);
tokenizer.consume();
tokenizer.exit(Token::LineEnding);
- State::Fn(Box::new(|t| content_start(t, info)))
+ State::Fn(Box::new(content_start))
}
/// Before code content, definitely not before a closing fence.
///
@@ -483,10 +475,11 @@ fn content_before(tokenizer: &mut Tokenizer, info: Info) -> State {
/// ^
/// | ~~~
/// ```
-fn content_start(tokenizer: &mut Tokenizer, info: Info) -> State {
- tokenizer.go(space_or_tab_min_max(0, info.prefix), |t| {
- content_begin(t, info)
- })(tokenizer)
+fn content_start(tokenizer: &mut Tokenizer) -> State {
+ tokenizer.go(
+ space_or_tab_min_max(0, tokenizer.tokenize_state.prefix),
+ content_begin,
+ )(tokenizer)
}
/// Before code content, after a prefix.
@@ -497,12 +490,12 @@ fn content_start(tokenizer: &mut Tokenizer, info: Info) -> State {
/// ^
/// | ~~~
/// ```
-fn content_begin(tokenizer: &mut Tokenizer, info: Info) -> State {
+fn content_begin(tokenizer: &mut Tokenizer) -> State {
match tokenizer.current {
- None | Some(b'\n') => at_break(tokenizer, info),
+ None | Some(b'\n') => at_break(tokenizer),
_ => {
tokenizer.enter(Token::CodeFlowChunk);
- content_continue(tokenizer, info)
+ content_continue(tokenizer)
}
}
}
@@ -515,15 +508,15 @@ fn content_begin(tokenizer: &mut Tokenizer, info: Info) -> State {
/// ^^^^^^^^^^^^^^
/// | ~~~
/// ```
-fn content_continue(tokenizer: &mut Tokenizer, info: Info) -> State {
+fn content_continue(tokenizer: &mut Tokenizer) -> State {
match tokenizer.current {
None | Some(b'\n') => {
tokenizer.exit(Token::CodeFlowChunk);
- at_break(tokenizer, info)
+ at_break(tokenizer)
}
_ => {
tokenizer.consume();
- State::Fn(Box::new(|t| content_continue(t, info)))
+ State::Fn(Box::new(content_continue))
}
}
}
@@ -538,6 +531,9 @@ fn content_continue(tokenizer: &mut Tokenizer, info: Info) -> State {
/// ```
fn after(tokenizer: &mut Tokenizer) -> State {
tokenizer.exit(Token::CodeFenced);
+ tokenizer.tokenize_state.marker = 0;
+ tokenizer.tokenize_state.prefix = 0;
+ tokenizer.tokenize_state.size = 0;
// Feel free to interrupt.
tokenizer.interrupt = false;
// No longer concrete.