async_parse_wiki_text/
template.rs

1// Copyright 2018 Fredrik Portström <https://portstrom.com>
2// This is free software distributed under the terms specified in
3// the file LICENSE at the top-level directory of this distribution.
4
5use tokio::task::yield_now;
6
7use crate::state::{State, OpenNode};
8use crate::state::OpenNodeType;
9use crate::{Parameter, Warning, WarningMessage, Node};
10
11
12pub async fn parse_parameter_name_end(state: &mut State) {
13    let stack_length = state.stack.len();
14    if stack_length > 0 {
15        if let OpenNode {
16            type_:
17                OpenNodeType::Template {
18                    name: Some(_),
19                    parameters,
20                },
21            ..
22        } = &mut state.stack[stack_length - 1]
23        {
24            let parameters_length = parameters.len();
25            let name = &mut parameters[parameters_length - 1].name;
26            if name.is_none() {
27                crate::state::flush(
28                    &mut state.nodes,
29                    state.flushed_position,
30                    crate::state::skip_whitespace_backwards(state.wiki_text.clone(), state.scan_position).await,
31                    state.wiki_text.clone(),
32                ).await;
33                state.flushed_position =
34                    crate::state::skip_whitespace_forwards(state.wiki_text.clone(), state.scan_position + 1).await;
35                state.scan_position = state.flushed_position;
36                *name = Some(std::mem::take(&mut state.nodes));
37                return;
38            }
39        }
40    }
41    state.scan_position += 1;
42    yield_now().await;
43}
44
45pub async fn parse_parameter_separator(state: &mut State) {
46    match state.stack.last_mut() {
47        Some(OpenNode {
48            type_: OpenNodeType::Parameter { default, name },
49            ..
50        }) => {
51            if name.is_none() {
52                let position =
53                    crate::state::skip_whitespace_backwards(state.wiki_text.clone(), state.scan_position).await;
54                crate::state::flush(
55                    &mut state.nodes,
56                    state.flushed_position,
57                    position,
58                    state.wiki_text.clone(),
59                ).await;
60                *name = Some(std::mem::take(&mut state.nodes));
61            } else {
62                crate::state::flush(
63                    &mut state.nodes,
64                    state.flushed_position,
65                    state.scan_position,
66                    state.wiki_text.clone(),
67                ).await;
68                *default = Some(std::mem::take(&mut state.nodes));
69                state.warnings.push(Warning {
70                    end: state.scan_position + 1,
71                    message: WarningMessage::UselessTextInParameter,
72                    start: state.scan_position,
73                });
74            }
75            state.scan_position += 1;
76            state.flushed_position = state.scan_position;
77        }
78        _ => unreachable!(),
79    }
80}
81
82pub async fn parse_template_end(state: &mut State) {
83    match state.stack.pop() {
84        Some(OpenNode {
85            nodes,
86            start,
87            type_: OpenNodeType::Parameter { default, name },
88        }) => if state.get_byte(state.scan_position + 2).await == Some(b'}') {
89            if let Some(name) = name {
90                let start_position = state.scan_position;
91                state.flush(start_position).await;
92                let nodes = std::mem::replace(&mut state.nodes, nodes);
93                state.nodes.push(Node::Parameter {
94                    default: Some(default.unwrap_or(nodes)),
95                    end: state.scan_position,
96                    name,
97                    start,
98                });
99            } else {
100                let start_position = state.skip_whitespace_backwards(state.scan_position).await;
101                state.flush(start_position).await;
102                let nodes = std::mem::replace(&mut state.nodes, nodes);
103                state.nodes.push(Node::Parameter {
104                    default: None,
105                    end: state.scan_position,
106                    name: nodes,
107                    start,
108                });
109            }
110            state.scan_position += 3;
111            state.flushed_position = state.scan_position;
112        } else {
113            state.warnings.push(Warning {
114                end: state.scan_position + 2,
115                message: WarningMessage::UnexpectedEndTagRewinding,
116                start: state.scan_position,
117            });
118            state.rewind(nodes, start);
119        },
120        Some(OpenNode {
121            nodes,
122            start,
123            type_:
124                OpenNodeType::Template {
125                    name,
126                    mut parameters,
127                },
128        }) => {
129            let position = state.skip_whitespace_backwards(state.scan_position).await;
130            state.flush(position).await;
131            state.scan_position += 2;
132            state.flushed_position = state.scan_position;
133            let name = match name {
134                None => std::mem::replace(&mut state.nodes, nodes),
135                Some(name) => {
136                    let parameters_length = parameters.len();
137                    let parameter = &mut parameters[parameters_length - 1];
138                    parameter.end = position;
139                    parameter.value = std::mem::replace(&mut state.nodes, nodes);
140                    name
141                }
142            };
143            state.nodes.push(Node::Template {
144                end: state.scan_position,
145                name,
146                parameters,
147                start,
148            });
149        }
150        Some(OpenNode { nodes, start, .. }) => {
151            state.warnings.push(Warning {
152                end: state.scan_position + 2,
153                message: WarningMessage::UnexpectedEndTagRewinding,
154                start: state.scan_position,
155            });
156            state.rewind(nodes, start);
157        }
158        _ => {
159            state.warnings.push(Warning {
160                end: state.scan_position + 2,
161                message: WarningMessage::UnexpectedEndTag,
162                start: state.scan_position,
163            });
164            state.scan_position += 2;
165        }
166    }
167}
168
169pub async fn parse_template_separator(state: &mut State) {
170    match state.stack.last_mut() {
171        Some(OpenNode {
172            type_: OpenNodeType::Template { name, parameters },
173            ..
174        }) => {
175            let position = crate::state::skip_whitespace_backwards(state.wiki_text.clone(), state.scan_position).await;
176            crate::state::flush(
177                &mut state.nodes,
178                state.flushed_position,
179                position,
180                state.wiki_text.clone(),
181            ).await;
182            state.flushed_position =
183                crate::state::skip_whitespace_forwards(state.wiki_text.clone(), state.scan_position + 1).await;
184            state.scan_position = state.flushed_position;
185            if name.is_none() {
186                *name = Some(std::mem::take(&mut state.nodes));
187            } else {
188                let parameters_length = parameters.len();
189                let parameter = &mut parameters[parameters_length - 1];
190                parameter.end = position;
191                parameter.value = std::mem::take(&mut state.nodes);
192            }
193            parameters.push(Parameter {
194                end: 0,
195                name: None,
196                start: state.scan_position,
197                value: vec![],
198            });
199        }
200        _ => unreachable!(),
201    }
202    yield_now().await;
203}
204
205pub async fn parse_template_start(state: &mut State) {
206    let scan_position = state.scan_position;
207    if state.get_byte(state.scan_position + 2).await == Some(b'{') {
208        let position = state.skip_whitespace_forwards(scan_position + 3).await;
209        state.push_open_node(
210            OpenNodeType::Parameter {
211                default: None,
212                name: None,
213            },
214            position,
215        ).await;
216    } else {
217        let position = state.skip_whitespace_forwards(scan_position + 2).await;
218        state.push_open_node(
219            OpenNodeType::Template {
220                name: None,
221                parameters: vec![],
222            },
223            position,
224        ).await;
225    }
226}