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,
name: tag_name, bits: vec![],
bits, })));
children, return Ok(Node::Django(DjangoNode::Tag(TagNode::Block {
branches, name: tag_name,
} bits,
} else { children,
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: Positive
- Django:
Tag:
Branch:
name: elif
bits:
- x
- "<"
- "0"
children: []
- Text: Negative
- Django:
Tag:
Branch:
name: else
bits: []
children: []
- Text: Zero - Text: Zero
branches: - Django:
- Block: Tag:
name: elif Closing:
bits: name: endif
- elif bits: []
children:
- Text: Positive
- Block:
name: else
bits:
- else
children:
- Text: Negative

View file

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

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,79 +6,104 @@ 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: children:
- Django:
Variable:
bits:
- user
- name
filters:
- name: title
arguments: []
- name: default
arguments:
- "'Guest'"
- Django:
Tag:
Block:
name: for
bits:
- for
- group
- in
- user.groups
children:
- Django:
Tag:
Block:
name: if
bits:
- if
- forloop.first
children:
- Text: (
- Django:
Tag:
Closing:
name: endif
bits: []
- Django:
Variable:
bits:
- group
- name
filters: []
- Django:
Tag:
Block:
name: if
bits:
- if
- not
- forloop.last
children:
- Text: ", "
- Django:
Tag:
Closing:
name: endif
bits: []
- Django:
Tag:
Block:
name: if
bits:
- if
- forloop.last
children:
- 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 - Text: Guest
branches: - Django:
- Block: Tag:
name: else Closing:
bits: name: endif
- else bits: []
children:
- Django:
Variable:
bits:
- user
- name
filters:
- name: title
arguments: []
- name: default
arguments:
- "'Guest'"
- Django:
Tag:
Branching:
name: for
bits:
- for
- group
- in
- user.groups
children:
- Text: (no groups)
branches:
- Block:
name: empty
bits:
- empty
children:
- Django:
Tag:
Block:
name: if
bits:
- if
- forloop.first
children:
- Text: (
- Django:
Variable:
bits:
- group
- name
filters: []
- Django:
Tag:
Block:
name: if
bits:
- if
- not
- forloop.last
children:
- Text: ", "
- Django:
Tag:
Block:
name: if
bits:
- if
- forloop.last
children:
- Text: )
- 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,27 +94,37 @@ nodes:
- Text: "!" - Text: "!"
- Django: - Django:
Tag: Tag:
Branching: Block:
name: if name: if
bits: bits:
- if - if
- user.is_staff - user.is_staff
children: children:
- Html:
Element:
tag_name: span
attributes: {}
children:
- Text: Admin
- Django:
Tag:
Branch:
name: else
bits: []
children: []
- Html: - Html:
Element: Element:
tag_name: span tag_name: span
attributes: {} attributes: {}
children: children:
- Text: User - Text: User
branches: - Django:
- Block: Tag:
name: else Closing:
bits: name: endif
- else bits: []
children: - Django:
- Html: Tag:
Element: Closing:
tag_name: span name: endif
attributes: {} bits: []
children:
- Text: Admin

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; }"