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}