diff options
Diffstat (limited to 'parse_wiki_text/src/template.rs')
-rw-r--r-- | parse_wiki_text/src/template.rs | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/parse_wiki_text/src/template.rs b/parse_wiki_text/src/template.rs new file mode 100644 index 0000000..494644b --- /dev/null +++ b/parse_wiki_text/src/template.rs @@ -0,0 +1,248 @@ +// Copyright 2019 Fredrik Portström <https://portstrom.com> +// This is free software distributed under the terms specified in +// the file LICENSE at the top-level directory of this distribution. + +pub fn parse_parameter_name_end(state: &mut crate::State) { + let stack_length = state.stack.len(); + if stack_length > 0 { + if let crate::OpenNode { + type_: + crate::OpenNodeType::Template { + name: Some(_), + parameters, + }, + .. + } = &mut state.stack[stack_length - 1] + { + let parameters_length = parameters.len(); + let name = &mut parameters[parameters_length - 1].name; + if name.is_none() { + crate::state::flush( + &mut state.nodes, + state.flushed_position, + crate::state::skip_whitespace_backwards(state.wiki_text, state.scan_position), + state.wiki_text, + ); + state.flushed_position = crate::state::skip_whitespace_forwards( + state.wiki_text, + state.scan_position + 1, + ); + state.scan_position = state.flushed_position; + *name = Some(std::mem::replace(&mut state.nodes, vec![])); + return; + } + } + } + state.scan_position += 1; +} + +pub fn parse_parameter_separator(state: &mut crate::State) { + match state.stack.last_mut() { + Some(crate::OpenNode { + type_: crate::OpenNodeType::Parameter { default, name }, + .. + }) => { + if name.is_none() { + let position = + crate::state::skip_whitespace_backwards(state.wiki_text, state.scan_position); + crate::state::flush( + &mut state.nodes, + state.flushed_position, + position, + state.wiki_text, + ); + *name = Some(std::mem::replace(&mut state.nodes, vec![])); + } else { + crate::state::flush( + &mut state.nodes, + state.flushed_position, + state.scan_position, + state.wiki_text, + ); + *default = Some(std::mem::replace(&mut state.nodes, vec![])); + state.warnings.push(crate::Warning { + end: state.scan_position + 1, + message: crate::WarningMessage::UselessTextInParameter, + start: state.scan_position, + }); + } + state.scan_position += 1; + state.flushed_position = state.scan_position; + } + _ => unreachable!(), + } +} + +pub fn parse_template_end(state: &mut crate::State) { + match state.stack.last() { + Some(crate::OpenNode { + type_: crate::OpenNodeType::Parameter { .. }, + .. + }) => match state.stack.pop() { + Some(crate::OpenNode { + nodes, + start, + type_: crate::OpenNodeType::Parameter { default, name }, + }) => { + if state.get_byte(state.scan_position + 2) == Some(b'}') { + if let Some(name) = name { + let start_position = state.scan_position; + state.flush(start_position); + let nodes = std::mem::replace(&mut state.nodes, nodes); + state.nodes.push(crate::Node::Parameter { + default: Some(default.unwrap_or(nodes)), + end: state.scan_position, + name, + start, + }); + } else { + let start_position = state.skip_whitespace_backwards(state.scan_position); + state.flush(start_position); + let nodes = std::mem::replace(&mut state.nodes, nodes); + state.nodes.push(crate::Node::Parameter { + default: None, + end: state.scan_position, + name: nodes, + start, + }); + } + state.scan_position += 3; + state.flushed_position = state.scan_position; + } else { + state.warnings.push(crate::Warning { + end: state.scan_position + 2, + message: crate::WarningMessage::UnexpectedEndTagRewinding, + start: state.scan_position, + }); + state.rewind(nodes, start); + } + } + _ => unreachable!(), + }, + Some(crate::OpenNode { + type_: crate::OpenNodeType::Template { .. }, + .. + }) => match state.stack.pop() { + Some(crate::OpenNode { + nodes, + start, + type_: + crate::OpenNodeType::Template { + name, + mut parameters, + }, + }) => { + let position = state.skip_whitespace_backwards(state.scan_position); + state.flush(position); + state.scan_position += 2; + state.flushed_position = state.scan_position; + let name = match name { + None => std::mem::replace(&mut state.nodes, nodes), + Some(name) => { + let parameters_length = parameters.len(); + let parameter = &mut parameters[parameters_length - 1]; + parameter.end = position; + parameter.value = std::mem::replace(&mut state.nodes, nodes); + name + } + }; + state.nodes.push(crate::Node::Template { + end: state.scan_position, + name, + parameters, + start, + }); + } + _ => unreachable!(), + }, + _ => { + if state + .stack + .iter() + .rev() + .skip(1) + .any(|item| match item.type_ { + crate::OpenNodeType::Parameter { .. } => { + state.get_byte(state.scan_position + 2) == Some(b'}') + } + crate::OpenNodeType::Template { .. } => true, + _ => false, + }) + { + state.warnings.push(crate::Warning { + end: state.scan_position + 2, + message: crate::WarningMessage::UnexpectedEndTagRewinding, + start: state.scan_position, + }); + let open_node = state.stack.pop().unwrap(); + state.rewind(open_node.nodes, open_node.start); + } else { + state.warnings.push(crate::Warning { + end: state.scan_position + 2, + message: crate::WarningMessage::UnexpectedEndTag, + start: state.scan_position, + }); + state.scan_position += 2; + } + } + } +} + +pub fn parse_template_separator(state: &mut crate::State) { + match state.stack.last_mut() { + Some(crate::OpenNode { + type_: crate::OpenNodeType::Template { name, parameters }, + .. + }) => { + let position = + crate::state::skip_whitespace_backwards(state.wiki_text, state.scan_position); + crate::state::flush( + &mut state.nodes, + state.flushed_position, + position, + state.wiki_text, + ); + state.flushed_position = + crate::state::skip_whitespace_forwards(state.wiki_text, state.scan_position + 1); + state.scan_position = state.flushed_position; + if name.is_none() { + *name = Some(std::mem::replace(&mut state.nodes, vec![])); + } else { + let parameters_length = parameters.len(); + let parameter = &mut parameters[parameters_length - 1]; + parameter.end = position; + parameter.value = std::mem::replace(&mut state.nodes, vec![]); + } + parameters.push(crate::Parameter { + end: 0, + name: None, + start: state.scan_position, + value: vec![], + }); + } + _ => unreachable!(), + } +} + +pub fn parse_template_start(state: &mut crate::State) { + let scan_position = state.scan_position; + if state.get_byte(state.scan_position + 2) == Some(b'{') { + let position = state.skip_whitespace_forwards(scan_position + 3); + state.push_open_node( + crate::OpenNodeType::Parameter { + default: None, + name: None, + }, + position, + ); + } else { + let position = state.skip_whitespace_forwards(scan_position + 2); + state.push_open_node( + crate::OpenNodeType::Template { + name: None, + parameters: vec![], + }, + position, + ); + } +} |