bracket/parser/
mod.rs

1//! Convert the lexer token stream to AST nodes.
2use crate::{
3    error::{Error, ErrorInfo, SyntaxError},
4    lexer::{self, lex, Lexer, Token},
5    parser::{
6        ast::{Block, CallTarget, Document, Element, Lines, Node, Text},
7        call::CallParseContext,
8    },
9    SyntaxResult,
10};
11use std::ops::Range;
12
13/// Default file name.
14pub(crate) const UNKNOWN: &str = "unknown";
15
16pub mod ast;
17mod block;
18mod call;
19pub mod iter;
20mod link;
21pub(crate) mod path;
22mod string;
23
24/// Set the file name used in error messages.
25///
26/// It is also possible to set the line and byte offsets if your template
27/// is being extracted from a larger document.
28#[derive(Debug)]
29pub struct ParserOptions {
30    /// The name of a file for the template source being parsed.
31    pub file_name: String,
32    /// A line offset into the file for error reporting,
33    /// the first line has index zero.
34    pub line_offset: usize,
35    /// Byte offset into the source file.
36    pub byte_offset: usize,
37}
38
39impl ParserOptions {
40    /// Create parser options using the given `file_name`.
41    pub fn new(
42        file_name: String,
43        line_offset: usize,
44        byte_offset: usize,
45    ) -> Self {
46        Self {
47            file_name,
48            line_offset,
49            byte_offset,
50        }
51    }
52}
53
54impl Default for ParserOptions {
55    fn default() -> Self {
56        Self {
57            file_name: UNKNOWN.to_string(),
58            line_offset: 0,
59            byte_offset: 0,
60        }
61    }
62}
63
64#[derive(Debug)]
65pub(crate) struct ParseState {
66    file_name: String,
67    line: usize,
68    byte: usize,
69}
70
71impl ParseState {
72    /// Create a parser state with an unknown file name.
73    pub fn new() -> Self {
74        Self {
75            file_name: UNKNOWN.to_string(),
76            line: 0,
77            byte: 0,
78        }
79    }
80
81    pub fn file_name(&self) -> &str {
82        &self.file_name
83    }
84
85    pub fn line(&self) -> &usize {
86        &self.line
87    }
88
89    pub fn line_mut(&mut self) -> &mut usize {
90        &mut self.line
91    }
92
93    pub fn byte(&self) -> &usize {
94        &self.byte
95    }
96
97    pub fn byte_mut(&mut self) -> &mut usize {
98        &mut self.byte
99    }
100
101    /// Get an initial line range for this parse state.
102    pub fn line_range(&self) -> Range<usize> {
103        self.line.clone()..self.line.clone() + 1
104    }
105}
106
107impl From<&ParserOptions> for ParseState {
108    fn from(opts: &ParserOptions) -> Self {
109        Self {
110            file_name: opts.file_name.clone(),
111            line: opts.line_offset.clone(),
112            byte: opts.byte_offset.clone(),
113        }
114    }
115}
116
117/// Convert a lexer token stream to AST nodes.
118///
119/// The `Parser` is an `Iterator` that yields `Node`:
120///
121/// ```ignore
122/// let content = "A {{var}} template.";
123/// let parser = Parser::new(content, Default::default());
124/// for node in parser {
125///     println!("{:#?}", node.unwrap());
126/// }
127/// ```
128pub struct Parser<'source> {
129    source: &'source str,
130    lexer: Lexer<'source>,
131    state: ParseState,
132    stack: Vec<(&'source str, Block<'source>)>,
133    next_token: Option<Token>,
134    errors: Option<&'source mut Vec<Error>>,
135}
136
137impl<'source> Parser<'source> {
138    /// Create a new Parser for the given source template.
139    ///
140    /// This will prepare a lexer and initial state for the iterator.
141    pub fn new(source: &'source str, options: ParserOptions) -> Self {
142        let lexer = lex(source);
143        let state = ParseState::from(&options);
144        Self {
145            source,
146            lexer,
147            state,
148            stack: vec![],
149            next_token: None,
150            errors: None,
151        }
152    }
153
154    /// Set a list of errors that this parser should add
155    /// compile time syntax errors to.
156    ///
157    /// Changes the behavior of this parser to be infallible to
158    /// support a *lint* operation.
159    pub fn set_errors(&mut self, errors: &'source mut Vec<Error>) {
160        self.errors = Some(errors);
161    }
162
163    /// Parse the entire document into a node tree.
164    ///
165    /// This iterates the parser until completion and adds
166    /// each node to a `Document` node which is returned.
167    pub fn parse(&mut self) -> SyntaxResult<Node<'source>> {
168        let mut doc = Document(&self.source, vec![]);
169        for node in self {
170            let node = node?;
171            doc.nodes_mut().push(node);
172        }
173        Ok(Node::Document(doc))
174    }
175
176    /// Yield the next token accounting for text normalization which
177    /// saves the next token for further processing.
178    fn token(&mut self) -> Option<Token> {
179        if let Some(t) = self.next_token.take() {
180            self.next_token = None;
181            Some(t)
182        } else {
183            self.lexer.next()
184        }
185    }
186
187    /// Consume tokens and yield nodes.
188    ///
189    /// Decoupled from the iterator `next()` implementation as it needs to
190    /// greedily consume tokens and advance again when entering block scopes.
191    fn advance(&mut self, next: Token) -> SyntaxResult<Option<Node<'source>>> {
192        if next.is_newline() {
193            *self.state.line_mut() += 1;
194        }
195
196        // Normalize consecutive text nodes
197        if next.is_text() {
198            let mut line_range = self.state.line_range();
199            let (span, next) = block::until(
200                &mut self.lexer,
201                &mut self.state,
202                next.span().clone(),
203                &|t: &Token| !t.is_text(),
204            );
205            self.next_token = next;
206            line_range.end = self.state.line() + 1;
207            return Ok(Some(Node::Text(Text::new(
208                self.source,
209                span,
210                line_range,
211            ))));
212        }
213
214        //println!("Advance token {:?}", &next);
215
216        match next {
217            Token::Block(lex, mut span) => match lex {
218                lexer::Block::StartRawBlock => {
219                    return block::raw(
220                        self.source,
221                        &mut self.lexer,
222                        &mut self.state,
223                        span,
224                    )
225                    .map(Some);
226                }
227                lexer::Block::StartRawComment => {
228                    return block::raw_comment(
229                        self.source,
230                        &mut self.lexer,
231                        &mut self.state,
232                        span,
233                    )
234                    .map(Some);
235                }
236                lexer::Block::StartRawStatement => {
237                    return block::raw_statement(
238                        self.source,
239                        &mut self.lexer,
240                        &mut self.state,
241                        span,
242                    )
243                    .map(Some);
244                }
245                lexer::Block::StartComment => {
246                    return block::comment(
247                        self.source,
248                        &mut self.lexer,
249                        &mut self.state,
250                        span,
251                    )
252                    .map(Some);
253                }
254                lexer::Block::StartBlockScope => {
255                    let block = block::scope(
256                        self.source,
257                        &mut self.lexer,
258                        &mut self.state,
259                        span,
260                    )?;
261
262                    let name = block.name().ok_or_else(|| {
263                        *self.state.byte_mut() =
264                            block.call().target().span().start;
265                        SyntaxError::BlockName(
266                            ErrorInfo::from((self.source, &mut self.state))
267                                .into(),
268                        )
269                    })?;
270
271                    match block.call().target() {
272                        CallTarget::Path(ref _path) => {}
273                        CallTarget::SubExpr(_) => {
274                            if !block.call().is_partial() {
275                                return Err(SyntaxError::BlockTargetSubExpr(
276                                    ErrorInfo::from((
277                                        self.source,
278                                        &mut self.state,
279                                    ))
280                                    .into(),
281                                ));
282                            }
283                        }
284                    }
285
286                    self.stack.push((name, block));
287
288                    while let Some(t) = self.token() {
289                        match self.advance(t) {
290                            Ok(mut node) => {
291                                if node.is_none() || self.stack.is_empty() {
292                                    return Ok(node);
293                                } else {
294                                    let (_, current) =
295                                        self.stack.last_mut().unwrap();
296
297                                    if let Some(node) = node.take() {
298                                        match node {
299                                            // NOTE: The push() implementation on Block
300                                            // NOTE: will add to the last conditional if
301                                            // NOTE: any conditions are present.
302                                            Node::Statement(call) => {
303                                                if call.is_conditional() {
304                                                    let mut condition =
305                                                        Block::new(
306                                                            self.source,
307                                                            call.open_span()
308                                                                .clone(),
309                                                            false,
310                                                            self.state
311                                                                .line_range(),
312                                                        );
313                                                    condition.set_call(call);
314                                                    current.add_condition(
315                                                        condition,
316                                                    );
317                                                } else {
318                                                    current.push(
319                                                        Node::Statement(call),
320                                                    );
321                                                }
322                                            }
323                                            _ => {
324                                                current.push(node);
325                                            }
326                                        }
327                                    }
328                                }
329                            }
330                            Err(e) => return Err(e),
331                        }
332                    }
333                }
334                lexer::Block::EndBlockScope => {
335                    // Need a temp block to parse the call parameters so we
336                    // can match the tag end name
337                    let temp = block::scope(
338                        self.source,
339                        &mut self.lexer,
340                        &mut self.state,
341                        span.clone(),
342                    )?;
343
344                    if self.stack.is_empty() {
345                        let notes = if let Some(close) = temp.name() {
346                            vec![format!("perhaps open the block '{}'", close)]
347                        } else {
348                            vec![]
349                        };
350
351                        *self.state.byte_mut() = span.start;
352
353                        return Err(SyntaxError::BlockNotOpen(
354                            ErrorInfo::from((
355                                self.source,
356                                &mut self.state,
357                                notes,
358                            ))
359                            .into(),
360                        ));
361                    }
362
363                    let (open_name, mut block) = self.stack.pop().unwrap();
364
365                    if let Some(close_name) = temp.name() {
366                        if open_name != close_name {
367                            let notes = vec![format!(
368                                "opening name is '{}'",
369                                open_name
370                            )];
371                            return Err(SyntaxError::TagNameMismatch(
372                                ErrorInfo::from((
373                                    self.source,
374                                    &mut self.state,
375                                    notes,
376                                ))
377                                .into(),
378                            ));
379                        }
380
381                        // Update span for entire close tag: `{{/name}}`!
382                        if temp.call().is_closed() {
383                            let end_tag_close = temp.call().span();
384                            span.end = end_tag_close.end;
385                        }
386                        block.exit(span);
387
388                        block.lines_end(self.state.line());
389
390                        return Ok(Some(Node::Block(block)));
391                    } else {
392                        return Err(SyntaxError::ExpectedIdentifier(
393                            ErrorInfo::from((self.source, &mut self.state))
394                                .into(),
395                        ));
396                    }
397                }
398                lexer::Block::StartStatement => {
399                    let context = if self.stack.is_empty() {
400                        CallParseContext::Statement
401                    } else {
402                        CallParseContext::ScopeStatement
403                    };
404                    let call = call::parse(
405                        self.source,
406                        &mut self.lexer,
407                        &mut self.state,
408                        span,
409                        context,
410                    )?;
411                    return Ok(Some(Node::Statement(call)));
412                }
413
414                lexer::Block::StartLink => {
415                    let link = link::parse(
416                        self.source,
417                        &mut self.lexer,
418                        &mut self.state,
419                        span,
420                    )?;
421                    return Ok(Some(Node::Link(link)));
422                }
423                _ => {}
424            },
425            Token::Link(_, _) => {}
426            Token::RawComment(_, _) => {}
427            Token::RawStatement(_, _) => {}
428            Token::Comment(_, _) => {}
429            Token::Parameters(_, _) => {}
430            Token::Array(_, _) => {}
431            Token::DoubleQuoteString(_, _) => {}
432            Token::SingleQuoteString(_, _) => {}
433        }
434
435        Ok(None)
436    }
437}
438
439impl<'source> Iterator for Parser<'source> {
440    type Item = SyntaxResult<Node<'source>>;
441
442    fn next(&mut self) -> Option<Self::Item> {
443        if let Some(t) = self.token() {
444            match self.advance(t) {
445                Ok(node) => return node.map(Ok),
446                Err(e) => {
447                    if let Some(ref mut errors) = self.errors.as_mut() {
448                        errors.push(Error::from(e));
449                        // Consume tokens until we reach the top-level lexer mode
450                        self.next_token = self.lexer.until_mode();
451                        // NOTE: Try to advance to the next node or error
452                        // NOTE: when collecting errors
453                        return self.next();
454                    } else {
455                        return Some(Err(e));
456                    }
457                }
458            }
459        }
460        None
461    }
462}