diff options
Diffstat (limited to 'src/construct/partial_destination.rs')
-rw-r--r-- | src/construct/partial_destination.rs | 135 |
1 files changed, 82 insertions, 53 deletions
diff --git a/src/construct/partial_destination.rs b/src/construct/partial_destination.rs index 82e83fe..823ce99 100644 --- a/src/construct/partial_destination.rs +++ b/src/construct/partial_destination.rs @@ -40,36 +40,68 @@ //! //! <!-- To do: link label end. --> -// To do: pass token types in. - use crate::tokenizer::{Code, State, StateFnResult, TokenType, Tokenizer}; +/// Configuration. +/// +/// You must pass the token types in that are used. +#[derive(Debug)] +pub struct Options { + /// Token for the whole destination. + pub destination: TokenType, + /// Token for a literal (enclosed) destination. + pub literal: TokenType, + /// Token for a literal marker. + pub marker: TokenType, + /// Token for a raw destination. + pub raw: TokenType, + /// Token for a the string. + pub string: TokenType, +} + +/// State needed to parse destination. +#[derive(Debug)] +struct Info { + /// Paren balance (used in raw). + balance: usize, + /// Configuration. + options: Options, +} + /// Before a destination. /// /// ```markdown /// |<ab> /// |ab /// ``` -pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { +pub fn start(tokenizer: &mut Tokenizer, code: Code, options: Options) -> StateFnResult { + let info = Info { + balance: 0, + options, + }; + match code { Code::Char('<') => { - tokenizer.enter(TokenType::DefinitionDestination); - tokenizer.enter(TokenType::DefinitionDestinationLiteral); - tokenizer.enter(TokenType::DefinitionDestinationLiteralMarker); + tokenizer.enter(info.options.destination.clone()); + tokenizer.enter(info.options.literal.clone()); + tokenizer.enter(info.options.marker.clone()); tokenizer.consume(code); - tokenizer.exit(TokenType::DefinitionDestinationLiteralMarker); - (State::Fn(Box::new(enclosed_before)), None) + tokenizer.exit(info.options.marker.clone()); + ( + State::Fn(Box::new(|t, c| enclosed_before(t, c, info))), + None, + ) } Code::None | Code::CarriageReturnLineFeed | Code::VirtualSpace | Code::Char(' ' | ')') => { (State::Nok, None) } Code::Char(char) if char.is_ascii_control() => (State::Nok, None), Code::Char(_) => { - tokenizer.enter(TokenType::DefinitionDestination); - tokenizer.enter(TokenType::DefinitionDestinationRaw); - tokenizer.enter(TokenType::DefinitionDestinationString); + tokenizer.enter(info.options.destination.clone()); + tokenizer.enter(info.options.raw.clone()); + tokenizer.enter(info.options.string.clone()); tokenizer.enter(TokenType::ChunkString); - raw(tokenizer, code, 0) + raw(tokenizer, code, info) } } } @@ -79,18 +111,18 @@ pub fn start(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { /// ```markdown /// <|ab> /// ``` -fn enclosed_before(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { +fn enclosed_before(tokenizer: &mut Tokenizer, code: Code, info: Info) -> StateFnResult { if let Code::Char('>') = code { - tokenizer.enter(TokenType::DefinitionDestinationLiteralMarker); + tokenizer.enter(info.options.marker.clone()); tokenizer.consume(code); - tokenizer.exit(TokenType::DefinitionDestinationLiteralMarker); - tokenizer.exit(TokenType::DefinitionDestinationLiteral); - tokenizer.exit(TokenType::DefinitionDestination); + tokenizer.exit(info.options.marker.clone()); + tokenizer.exit(info.options.literal.clone()); + tokenizer.exit(info.options.destination); (State::Ok, None) } else { - tokenizer.enter(TokenType::DefinitionDestinationString); + tokenizer.enter(info.options.string.clone()); tokenizer.enter(TokenType::ChunkString); - enclosed(tokenizer, code) + enclosed(tokenizer, code, info) } } @@ -99,23 +131,26 @@ fn enclosed_before(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { /// ```markdown /// <u|rl> /// ``` -fn enclosed(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { +fn enclosed(tokenizer: &mut Tokenizer, code: Code, info: Info) -> StateFnResult { match code { Code::Char('>') => { tokenizer.exit(TokenType::ChunkString); - tokenizer.exit(TokenType::DefinitionDestinationString); - enclosed_before(tokenizer, code) + tokenizer.exit(info.options.string.clone()); + enclosed_before(tokenizer, code, info) } Code::None | Code::CarriageReturnLineFeed | Code::Char('\r' | '\n' | '<') => { (State::Nok, None) } Code::Char('\\') => { tokenizer.consume(code); - (State::Fn(Box::new(enclosed_escape)), None) + ( + State::Fn(Box::new(|t, c| enclosed_escape(t, c, info))), + None, + ) } _ => { tokenizer.consume(code); - (State::Fn(Box::new(enclosed)), None) + (State::Fn(Box::new(|t, c| enclosed(t, c, info))), None) } } } @@ -125,13 +160,13 @@ fn enclosed(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { /// ```markdown /// <a\|>b> /// ``` -fn enclosed_escape(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { +fn enclosed_escape(tokenizer: &mut Tokenizer, code: Code, info: Info) -> StateFnResult { match code { Code::Char('<' | '>' | '\\') => { tokenizer.consume(code); - (State::Fn(Box::new(enclosed)), None) + (State::Fn(Box::new(|t, c| enclosed(t, c, info))), None) } - _ => enclosed(tokenizer, code), + _ => enclosed(tokenizer, code, info), } } @@ -140,48 +175,44 @@ fn enclosed_escape(tokenizer: &mut Tokenizer, code: Code) -> StateFnResult { /// ```markdown /// a|b /// ``` -fn raw(tokenizer: &mut Tokenizer, code: Code, balance: usize) -> StateFnResult { +fn raw(tokenizer: &mut Tokenizer, code: Code, mut info: Info) -> StateFnResult { // To do: configurable. let limit = usize::MAX; match code { Code::Char('(') => { - if balance >= limit { + if info.balance >= limit { (State::Nok, None) } else { tokenizer.consume(code); - ( - State::Fn(Box::new(move |t, c| raw(t, c, balance + 1))), - None, - ) + info.balance += 1; + (State::Fn(Box::new(move |t, c| raw(t, c, info))), None) } } Code::Char(')') => { - if balance == 0 { + if info.balance == 0 { tokenizer.exit(TokenType::ChunkString); - tokenizer.exit(TokenType::DefinitionDestinationString); - tokenizer.exit(TokenType::DefinitionDestinationRaw); - tokenizer.exit(TokenType::DefinitionDestination); + tokenizer.exit(info.options.string.clone()); + tokenizer.exit(info.options.raw.clone()); + tokenizer.exit(info.options.destination); (State::Ok, Some(vec![code])) } else { tokenizer.consume(code); - ( - State::Fn(Box::new(move |t, c| raw(t, c, balance - 1))), - None, - ) + info.balance -= 1; + (State::Fn(Box::new(move |t, c| raw(t, c, info))), None) } } Code::None | Code::CarriageReturnLineFeed | Code::VirtualSpace | Code::Char('\t' | '\r' | '\n' | ' ') => { - if balance > 0 { + if info.balance > 0 { (State::Nok, None) } else { tokenizer.exit(TokenType::ChunkString); - tokenizer.exit(TokenType::DefinitionDestinationString); - tokenizer.exit(TokenType::DefinitionDestinationRaw); - tokenizer.exit(TokenType::DefinitionDestination); + tokenizer.exit(info.options.string.clone()); + tokenizer.exit(info.options.raw.clone()); + tokenizer.exit(info.options.destination); (State::Ok, Some(vec![code])) } } @@ -189,13 +220,13 @@ fn raw(tokenizer: &mut Tokenizer, code: Code, balance: usize) -> StateFnResult { Code::Char('\\') => { tokenizer.consume(code); ( - State::Fn(Box::new(move |t, c| raw_escape(t, c, balance))), + State::Fn(Box::new(move |t, c| raw_escape(t, c, info))), None, ) } Code::Char(_) => { tokenizer.consume(code); - (State::Fn(Box::new(move |t, c| raw(t, c, balance))), None) + (State::Fn(Box::new(move |t, c| raw(t, c, info))), None) } } } @@ -205,15 +236,13 @@ fn raw(tokenizer: &mut Tokenizer, code: Code, balance: usize) -> StateFnResult { /// ```markdown /// a\|)b /// ``` -fn raw_escape(tokenizer: &mut Tokenizer, code: Code, balance: usize) -> StateFnResult { +fn raw_escape(tokenizer: &mut Tokenizer, code: Code, mut info: Info) -> StateFnResult { match code { Code::Char('(' | ')' | '\\') => { tokenizer.consume(code); - ( - State::Fn(Box::new(move |t, c| raw(t, c, balance + 1))), - None, - ) + info.balance += 1; + (State::Fn(Box::new(move |t, c| raw(t, c, info))), None) } - _ => raw(tokenizer, code, balance), + _ => raw(tokenizer, code, info), } } |