add closing tag and adjust branching strat

This commit is contained in:
Josh Thomas 2025-01-04 15:32:04 -06:00
parent 0ea2dea1a9
commit ec05c62c2a
11 changed files with 213 additions and 215 deletions

View file

@ -63,8 +63,8 @@ pub enum TagNode {
#[derive(Clone, Debug, Serialize)] #[derive(Clone, Debug, Serialize)]
pub struct DjangoFilter { pub struct DjangoFilter {
pub name: String, name: String,
pub arguments: Vec<String>, arguments: Vec<String>,
} }
impl DjangoFilter { impl DjangoFilter {

View file

@ -155,22 +155,28 @@ impl Parser {
let specs = TagSpec::load_builtin_specs().unwrap_or_default(); let specs = TagSpec::load_builtin_specs().unwrap_or_default();
// Check if closing or intermediate tag according to any spec // Check if this is a closing tag
for (_, spec) in specs.iter() { for (_, spec) in specs.iter() {
if Some(&tag_name) == spec.closing.as_ref() { if Some(&tag_name) == spec.closing.as_ref() {
let node = Node::Django(DjangoNode::Tag(TagNode::Closing {
name: tag_name.clone(),
bits: bits[1..].to_vec(),
}));
return Err(ParserError::ErrorSignal(Signal::SpecialTag(tag_name))); return Err(ParserError::ErrorSignal(Signal::SpecialTag(tag_name)));
} }
}
// Check if this is a branch tag according to any spec
for (_, spec) in specs.iter() {
if let Some(intermediates) = &spec.intermediates { if let Some(intermediates) = &spec.intermediates {
if intermediates.contains(&tag_name) { if intermediates.iter().any(|i| i.name == tag_name) {
return Err(ParserError::ErrorSignal(Signal::SpecialTag(tag_name))); return Err(ParserError::ErrorSignal(Signal::SpecialTag(tag_name)));
} }
} }
} }
let tag_spec = specs.get(tag_name.as_str()).cloned(); let tag_spec = specs.get(tag_name.as_str()).cloned();
let mut children = Vec::new(); let mut children = Vec::new();
let mut branches = Vec::new();
while !self.is_at_end() { while !self.is_at_end() {
match self.next_node() { match self.next_node() {
@ -181,40 +187,44 @@ impl Parser {
if let Some(spec) = &tag_spec { if let Some(spec) = &tag_spec {
// Check if closing tag // Check if closing tag
if Some(&tag) == spec.closing.as_ref() { if Some(&tag) == spec.closing.as_ref() {
let tag_node = if !branches.is_empty() { children.push(Node::Django(DjangoNode::Tag(TagNode::Closing {
TagNode::Branching { name: tag,
bits: vec![],
})));
return Ok(Node::Django(DjangoNode::Tag(TagNode::Block {
name: tag_name, name: tag_name,
bits, bits,
children, children,
branches, })));
}
} else {
TagNode::Block {
name: tag_name,
bits,
children,
}
};
return Ok(Node::Django(DjangoNode::Tag(tag_node)));
} }
// Check if intermediate tag // Check if intermediate tag
if let Some(intermediates) = &spec.intermediates { if let Some(intermediates) = &spec.intermediates {
if intermediates.contains(&tag) { if let Some(intermediate) = intermediates.iter().find(|i| i.name == tag) {
branches.push(TagNode::Block { // Create branch node with the current children
name: tag.clone(), let branch_bits = if intermediate.args {
bits: vec![tag.clone()], match &self.tokens[self.current - 1].token_type() {
children, TokenType::DjangoBlock(content) => content
}); .split_whitespace()
children = Vec::new(); .skip(1) // Skip the tag name
.map(|s| s.to_string())
.collect(),
_ => vec![tag.clone()],
}
} else {
vec![]
};
children.push(Node::Django(DjangoNode::Tag(TagNode::Branch {
name: tag,
bits: branch_bits,
children: Vec::new(),
})));
continue; continue;
} }
} }
} }
return Err(ParserError::UnexpectedTag(tag)); return Err(ParserError::UnexpectedTag(tag));
} }
Err(e) => { Err(e) => return Err(e),
return Err(e);
}
} }
} }

View file

@ -5,7 +5,7 @@ expression: ast
nodes: nodes:
- Django: - Django:
Tag: Tag:
Branching: Block:
name: if name: if
bits: bits:
- if - if
@ -13,17 +13,26 @@ nodes:
- ">" - ">"
- "0" - "0"
children: children:
- Text: Zero - Text: Positive
branches: - Django:
- Block: Tag:
Branch:
name: elif name: elif
bits: bits:
- elif - x
children: - "<"
- Text: Positive - "0"
- Block: children: []
name: else
bits:
- else
children:
- Text: Negative - Text: Negative
- Django:
Tag:
Branch:
name: else
bits: []
children: []
- Text: Zero
- Django:
Tag:
Closing:
name: endif
bits: []

View file

@ -5,23 +5,28 @@ expression: ast
nodes: nodes:
- Django: - Django:
Tag: Tag:
Branching: Block:
name: for name: for
bits: bits:
- for - for
- item - item
- in - in
- items - items
children:
- Text: No items
branches:
- Block:
name: empty
bits:
- empty
children: children:
- Django: - Django:
Variable: Variable:
bits: bits:
- item - item
filters: [] filters: []
- Django:
Tag:
Branch:
name: empty
bits: []
children: []
- Text: No items
- Django:
Tag:
Closing:
name: endfor
bits: []

View file

@ -12,3 +12,8 @@ nodes:
- user.is_authenticated - user.is_authenticated
children: children:
- Text: Welcome - Text: Welcome
- Django:
Tag:
Closing:
name: endif
bits: []

View file

@ -6,18 +6,11 @@ nodes:
- Text: "Welcome, " - Text: "Welcome, "
- Django: - Django:
Tag: Tag:
Branching: Block:
name: if name: if
bits: bits:
- if - if
- user.is_authenticated - user.is_authenticated
children:
- Text: Guest
branches:
- Block:
name: else
bits:
- else
children: children:
- Django: - Django:
Variable: Variable:
@ -32,20 +25,13 @@ nodes:
- "'Guest'" - "'Guest'"
- Django: - Django:
Tag: Tag:
Branching: Block:
name: for name: for
bits: bits:
- for - for
- group - group
- in - in
- user.groups - user.groups
children:
- Text: (no groups)
branches:
- Block:
name: empty
bits:
- empty
children: children:
- Django: - Django:
Tag: Tag:
@ -56,6 +42,11 @@ nodes:
- forloop.first - forloop.first
children: children:
- Text: ( - Text: (
- Django:
Tag:
Closing:
name: endif
bits: []
- Django: - Django:
Variable: Variable:
bits: bits:
@ -72,6 +63,11 @@ nodes:
- forloop.last - forloop.last
children: children:
- Text: ", " - Text: ", "
- Django:
Tag:
Closing:
name: endif
bits: []
- Django: - Django:
Tag: Tag:
Block: Block:
@ -81,4 +77,33 @@ nodes:
- forloop.last - forloop.last
children: children:
- Text: ) - Text: )
- Django:
Tag:
Closing:
name: endif
bits: []
- Django:
Tag:
Branch:
name: empty
bits: []
children: []
- Text: (no groups)
- Django:
Tag:
Closing:
name: endfor
bits: []
- Django:
Tag:
Branch:
name: else
bits: []
children: []
- Text: Guest
- Django:
Tag:
Closing:
name: endif
bits: []
- Text: "!" - Text: "!"

View file

@ -27,3 +27,13 @@ nodes:
- item - item
- name - name
filters: [] filters: []
- Django:
Tag:
Closing:
name: endif
bits: []
- Django:
Tag:
Closing:
name: endfor
bits: []

View file

@ -94,7 +94,7 @@ nodes:
- Text: "!" - Text: "!"
- Django: - Django:
Tag: Tag:
Branching: Block:
name: if name: if
bits: bits:
- if - if
@ -105,16 +105,26 @@ nodes:
tag_name: span tag_name: span
attributes: {} attributes: {}
children: children:
- Text: User - Text: Admin
branches: - Django:
- Block: Tag:
Branch:
name: else name: else
bits: bits: []
- else children: []
children:
- Html: - Html:
Element: Element:
tag_name: span tag_name: span
attributes: {} attributes: {}
children: children:
- Text: Admin - Text: User
- Django:
Tag:
Closing:
name: endif
bits: []
- Django:
Tag:
Closing:
name: endif
bits: []

View file

@ -1,53 +0,0 @@
---
source: crates/djls-template-ast/src/parser.rs
expression: ast
---
nodes:
- Html:
Doctype: "!DOCTYPE"
- Html:
Element:
tag_name: html
attributes: {}
children:
- Html:
Element:
tag_name: head
attributes: {}
children:
- Html:
Element:
tag_name: title
attributes: {}
children:
- Text: Test
- Html:
Element:
tag_name: body
attributes: {}
children:
- Html:
Element:
tag_name: h1
attributes: {}
children:
- Text: Hello World
- Html:
Element:
tag_name: p
attributes: {}
children:
- Text: This is a test
- Script:
Element:
attributes: {}
children:
- Text: "console.log(\"Hello World\");"
- Style:
Element:
attributes:
style: Boolean
children:
- Text: "h1 "
- Text: "{"
- Text: "color: red; }"

View file

@ -1,10 +0,0 @@
---
source: crates/djls-template-ast/src/parser.rs
expression: ast
---
nodes:
- Script:
Element:
attributes: {}
children:
- Text: "console.log(\"Hello World\");"

View file

@ -1,13 +0,0 @@
---
source: crates/djls-template-ast/src/parser.rs
expression: ast
---
nodes:
- Style:
Element:
attributes:
style: Boolean
children:
- Text: "h1 "
- Text: "{"
- Text: "color: red; }"