Skip to content

Commit 5dabbf2

Browse files
fix
1 parent dbfdb97 commit 5dabbf2

File tree

1 file changed

+69
-52
lines changed

1 file changed

+69
-52
lines changed

crates/djls-template-ast/src/parser.rs

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,16 @@ use thiserror::Error;
66
pub struct Parser {
77
tokens: TokenStream,
88
current: usize,
9+
ast: Ast,
910
}
1011

1112
impl Parser {
1213
pub fn new(tokens: TokenStream) -> Self {
13-
Parser { tokens, current: 0 }
14+
Parser {
15+
tokens,
16+
current: 0,
17+
ast: Ast::default(),
18+
}
1419
}
1520

1621
pub fn parse(&mut self) -> Result<Ast, ParserError> {
@@ -26,19 +31,19 @@ impl Parser {
2631
}
2732
Err(err) => {
2833
match err {
29-
ParserError::NodeWithError { node, error } => {
30-
ast.add_error(error);
34+
ParserError::Ast(err, Some(node)) => {
3135
ast.add_node(node);
36+
ast.add_error(err);
3237
}
33-
ParserError::Ast(err) => {
38+
ParserError::Ast(err, None) => {
3439
ast.add_error(err);
3540
}
3641
_ => return Err(err),
3742
}
3843

3944
if let Err(e) = self.synchronize() {
4045
match e {
41-
ParserError::Ast(AstError::StreamError(ref kind))
46+
ParserError::Ast(AstError::StreamError(ref kind), _)
4247
if kind == "AtEnd" =>
4348
{
4449
break
@@ -57,7 +62,10 @@ impl Parser {
5762

5863
fn next_node(&mut self) -> Result<Node, ParserError> {
5964
if self.is_at_end() {
60-
return Err(ParserError::Ast(AstError::StreamError("AtEnd".to_string())));
65+
return Err(ParserError::Ast(
66+
AstError::StreamError("AtEnd".to_string()),
67+
None,
68+
));
6169
}
6270

6371
let token = self.peek()?;
@@ -84,7 +92,10 @@ impl Parser {
8492
| TokenType::ScriptTagClose(_)
8593
| TokenType::StyleTagOpen(_)
8694
| TokenType::StyleTagClose(_) => self.parse_text(),
87-
TokenType::Eof => Err(ParserError::Ast(AstError::StreamError("AtEnd".to_string()))),
95+
TokenType::Eof => Err(ParserError::Ast(
96+
AstError::StreamError("AtEnd".to_string()),
97+
None,
98+
)),
8899
}?;
89100
Ok(node)
90101
}
@@ -142,7 +153,7 @@ impl Parser {
142153
Err(ParserError::ErrorSignal(Signal::SpecialTag(tag))) => {
143154
if let Some(spec) = &tag_spec {
144155
// Check if closing tag
145-
if Some(&tag) == spec.closing.as_ref() {
156+
if spec.closing.as_ref().map(|s| s.as_str()) == Some(&tag) {
146157
// If we have a current branch, add it to children
147158
if let Some((name, bits, branch_children)) = current_branch {
148159
children.push(Node::Django(DjangoNode::Tag(TagNode::Branch {
@@ -187,19 +198,15 @@ impl Parser {
187198
}
188199
}
189200
}
190-
// If we get here, it's an unexpected tag - return what we have
191-
// but signal that we hit an error
201+
// If we get here, it's an unexpected tag
192202
let node = Node::Django(DjangoNode::Tag(TagNode::Block {
193-
name: tag_name,
194-
bits,
195-
children,
203+
name: tag_name.clone(),
204+
bits: bits.clone(),
205+
children: children.clone(),
196206
}));
197-
return Err(ParserError::NodeWithError {
198-
node,
199-
error: AstError::UnexpectedTag(tag),
200-
});
207+
return Err(ParserError::Ast(AstError::UnexpectedTag(tag), Some(node)));
201208
}
202-
Err(ParserError::Ast(AstError::StreamError(kind))) if kind == "AtEnd" => {
209+
Err(ParserError::Ast(AstError::StreamError(kind), _)) if kind == "AtEnd" => {
203210
break;
204211
}
205212
Err(e) => return Err(e),
@@ -213,11 +220,10 @@ impl Parser {
213220
}));
214221

215222
if !found_closing_tag {
216-
// Return the node with an unclosed tag error
217-
return Err(ParserError::NodeWithError {
218-
node,
219-
error: AstError::UnclosedTag(tag_name),
220-
});
223+
return Err(ParserError::Ast(
224+
AstError::UnclosedTag(tag_name),
225+
Some(node),
226+
));
221227
}
222228

223229
Ok(node)
@@ -329,22 +335,32 @@ impl Parser {
329335
}
330336

331337
fn synchronize(&mut self) -> Result<(), ParserError> {
332-
let sync_types = [
333-
TokenType::DjangoBlock(String::new()),
334-
TokenType::DjangoVariable(String::new()),
335-
TokenType::Comment(String::new(), String::from("{#"), Some(String::from("#}"))),
336-
TokenType::Eof,
337-
];
338+
let mut depth = 0;
339+
let mut found_django_token = false;
338340

339341
while !self.is_at_end() {
340-
let current = self.peek()?;
341-
342-
for sync_type in &sync_types {
343-
if current.token_type() == sync_type {
344-
return Ok(());
342+
if let TokenType::DjangoBlock(content) = &self.tokens[self.current].token_type() {
343+
let tag = content.split_whitespace().next().unwrap_or("");
344+
if let Some(spec) = TagSpec::load_builtin_specs().unwrap_or_default().get(tag) {
345+
if spec.closing.as_deref() == Some(tag) {
346+
depth -= 1;
347+
if depth <= 0 {
348+
found_django_token = true;
349+
break;
350+
}
351+
} else {
352+
depth += 1;
353+
}
345354
}
346355
}
347-
self.consume()?;
356+
self.current += 1;
357+
}
358+
359+
if !found_django_token {
360+
return Err(ParserError::Ast(
361+
AstError::StreamError("AtEnd".into()),
362+
None,
363+
));
348364
}
349365

350366
Ok(())
@@ -362,47 +378,48 @@ pub enum Signal {
362378

363379
#[derive(Error, Debug)]
364380
pub enum ParserError {
365-
#[error(transparent)]
366-
Ast(#[from] AstError),
367-
#[error("multi-line comment outside of script or style context")]
368-
InvalidMultiLineComment,
381+
#[error("ast error: {0}")]
382+
Ast(AstError, Option<Node>),
369383
#[error("internal signal: {0:?}")]
370384
ErrorSignal(Signal),
371-
#[error("node with error: {node:?}, error: {error}")]
372-
NodeWithError { node: Node, error: AstError },
385+
}
386+
387+
impl From<AstError> for ParserError {
388+
fn from(err: AstError) -> Self {
389+
ParserError::Ast(err, None)
390+
}
373391
}
374392

375393
impl ParserError {
376394
pub fn unclosed_tag(tag: impl Into<String>) -> Self {
377-
Self::Ast(AstError::UnclosedTag(tag.into()))
395+
Self::Ast(AstError::UnclosedTag(tag.into()), None)
378396
}
379397

380398
pub fn unexpected_tag(tag: impl Into<String>) -> Self {
381-
Self::Ast(AstError::UnexpectedTag(tag.into()))
399+
Self::Ast(AstError::UnexpectedTag(tag.into()), None)
382400
}
383401

384402
pub fn invalid_tag(kind: impl Into<String>) -> Self {
385-
Self::Ast(AstError::InvalidTag(kind.into()))
403+
Self::Ast(AstError::InvalidTag(kind.into()), None)
386404
}
387405

388406
pub fn block_error(kind: impl Into<String>, name: impl Into<String>) -> Self {
389-
Self::Ast(AstError::BlockError(kind.into(), name.into()))
407+
Self::Ast(AstError::BlockError(kind.into(), name.into()), None)
390408
}
391409

392410
pub fn stream_error(kind: impl Into<String>) -> Self {
393-
Self::Ast(AstError::StreamError(kind.into()))
411+
Self::Ast(AstError::StreamError(kind.into()), None)
394412
}
395413

396414
pub fn token_error(expected: impl Into<String>, actual: Token) -> Self {
397-
Self::Ast(AstError::TokenError(format!(
398-
"expected {}, got {:?}",
399-
expected.into(),
400-
actual
401-
)))
415+
Self::Ast(
416+
AstError::TokenError(format!("expected {}, got {:?}", expected.into(), actual)),
417+
None,
418+
)
402419
}
403420

404421
pub fn argument_error(kind: impl Into<String>, details: impl Into<String>) -> Self {
405-
Self::Ast(AstError::ArgumentError(kind.into(), details.into()))
422+
Self::Ast(AstError::ArgumentError(kind.into(), details.into()), None)
406423
}
407424
}
408425

0 commit comments

Comments
 (0)