Skip to content

Commit ace5ccd

Browse files
committed
feat: add WXML AST helpers
1 parent 4b4da3d commit ace5ccd

File tree

3 files changed

+151
-81
lines changed

3 files changed

+151
-81
lines changed
Lines changed: 120 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,136 @@
11
use super::tag::{Element, ElementKind, Node};
22

3-
pub struct ChildrenIter<'a> {
4-
parent: &'a Element,
5-
cur: usize,
6-
cur_branch: usize,
7-
}
8-
9-
impl<'a> ChildrenIter<'a> {
10-
pub(super) fn new(parent: &'a Element) -> Self {
11-
Self {
12-
parent,
13-
cur: 0,
14-
cur_branch: 0,
3+
macro_rules! iter {
4+
($t:ident, $($mut_t:tt)*) => {
5+
pub struct $t<'a> {
6+
parent: &'a $($mut_t)* Element,
7+
cur: usize,
8+
cur_branch: usize,
159
}
16-
}
17-
}
18-
19-
impl<'a> Iterator for ChildrenIter<'a> {
20-
type Item = &'a Node;
21-
22-
fn next(&mut self) -> Option<Self::Item> {
23-
match &self.parent.kind {
24-
ElementKind::Normal { children, .. }
25-
| ElementKind::Pure { children, .. }
26-
| ElementKind::For { children, .. } => {
27-
let ret = children.get(self.cur);
28-
if ret.is_some() {
29-
self.cur += 1;
10+
11+
impl<'a> $t<'a> {
12+
pub(super) fn new(parent: &'a $($mut_t)* Element) -> Self {
13+
Self {
14+
parent,
15+
cur: 0,
16+
cur_branch: 0,
3017
}
31-
ret
3218
}
33-
ElementKind::If {
34-
branches,
35-
else_branch,
36-
} => {
37-
let ret = loop {
38-
if self.cur_branch >= branches.len() {
39-
if let Some((_, children)) = else_branch {
40-
let ret = children.get(self.cur);
41-
if ret.is_some() {
19+
}
20+
21+
impl<'a> Iterator for $t<'a> {
22+
type Item = &'a $($mut_t)* Node;
23+
24+
fn next(&mut self) -> Option<Self::Item> {
25+
match & $($mut_t)* self.parent.kind {
26+
ElementKind::Normal { children, .. }
27+
| ElementKind::Pure { children, .. }
28+
| ElementKind::For { children, .. } => {
29+
let ret = children.get(self.cur).map(|x| x as *const _);
30+
if let Some(ret) = ret {
31+
self.cur += 1;
32+
// it is safe because the iterator never returns an item twice
33+
Some(unsafe { & $($mut_t)* *(ret as *mut _) })
34+
} else {
35+
None
36+
}
37+
}
38+
ElementKind::If {
39+
branches,
40+
else_branch,
41+
} => {
42+
let ret = loop {
43+
if self.cur_branch >= branches.len() {
44+
if let Some((_, children)) = else_branch {
45+
let ret = children.get(self.cur).map(|x| x as *const _);
46+
if ret.is_some() {
47+
self.cur += 1;
48+
}
49+
break ret;
50+
}
51+
break None;
52+
}
53+
let (_, _, children) = unsafe { branches.get_unchecked(self.cur_branch) };
54+
let ret = children.get(self.cur).map(|x| x as *const _);
55+
if let Some(ret) = ret {
4256
self.cur += 1;
57+
break Some(ret);
4358
}
44-
break ret;
45-
}
46-
break None;
59+
self.cur_branch += 1;
60+
self.cur = 0;
61+
};
62+
// it is safe because the iterator never returns an item twice
63+
ret.map(|ret| unsafe { & $($mut_t)* *(ret as *mut _) })
4764
}
48-
let (_, _, children) = unsafe { branches.get_unchecked(self.cur_branch) };
49-
let ret = children.get(self.cur);
50-
if ret.is_some() {
51-
self.cur += 1;
52-
break ret;
65+
ElementKind::TemplateRef { .. }
66+
| ElementKind::Include { .. }
67+
| ElementKind::Slot { .. } => None,
68+
}
69+
}
70+
71+
fn size_hint(&self) -> (usize, Option<usize>) {
72+
let count = match &self.parent.kind {
73+
ElementKind::Normal { children, .. }
74+
| ElementKind::Pure { children, .. }
75+
| ElementKind::For { children, .. } => children.len(),
76+
ElementKind::If {
77+
branches,
78+
else_branch,
79+
} => {
80+
branches.iter().map(|x| x.2.len()).sum::<usize>()
81+
+ else_branch.iter().map(|x| x.1.len()).sum::<usize>()
5382
}
54-
self.cur_branch += 1;
55-
self.cur = 0;
83+
ElementKind::TemplateRef { .. }
84+
| ElementKind::Include { .. }
85+
| ElementKind::Slot { .. } => 0,
5686
};
57-
ret
87+
(count, Some(count))
5888
}
59-
ElementKind::TemplateRef { .. }
60-
| ElementKind::Include { .. }
61-
| ElementKind::Slot { .. } => None,
6289
}
63-
}
90+
};
91+
}
92+
93+
iter!(ChildrenIter,);
94+
iter!(ChildrenIterMut, mut);
95+
96+
#[cfg(test)]
97+
mod test {
98+
use crate::parse::tag::{Node, Value};
6499

65-
fn size_hint(&self) -> (usize, Option<usize>) {
66-
let count = match &self.parent.kind {
67-
ElementKind::Normal { children, .. }
68-
| ElementKind::Pure { children, .. }
69-
| ElementKind::For { children, .. } => children.len(),
70-
ElementKind::If {
71-
branches,
72-
else_branch,
73-
} => {
74-
branches.iter().map(|x| x.2.len()).sum::<usize>()
75-
+ else_branch.iter().map(|x| x.1.len()).sum::<usize>()
100+
#[test]
101+
fn iter_children() {
102+
const SRC: &'static str = r#"
103+
<div>
104+
<div>A</div>
105+
<block wx:for="123">B</block>
106+
<block wx:if="1">C</block>
107+
<block wx:elif="2">D</block>
108+
<block wx:elif="3">E</block>
109+
<block>F</block>
110+
</div>
111+
"#;
112+
let (mut template, _) = crate::parse::parse("TEST", SRC);
113+
fn rec(node: &mut Node, visited: &mut String) {
114+
if let Node::Text(v) = node {
115+
let Value::Static { value, .. } = v else { unreachable!() };
116+
visited.push_str(&value);
117+
*value = "".into();
76118
}
77-
ElementKind::TemplateRef { .. }
78-
| ElementKind::Include { .. }
79-
| ElementKind::Slot { .. } => 0,
80-
};
81-
(count, Some(count))
119+
if let Node::Element(elem) = node {
120+
for child in elem.iter_children_mut() {
121+
rec(child, visited);
122+
}
123+
}
124+
}
125+
let mut visited = String::new();
126+
for node in &mut template.content {
127+
rec(node, &mut visited);
128+
}
129+
assert_eq!(visited, "ABCDEF");
130+
let mut visited = String::new();
131+
for node in &mut template.content {
132+
rec(node, &mut visited);
133+
}
134+
assert_eq!(visited, "");
82135
}
83136
}

glass-easel-template-compiler/src/parse/mod.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ impl<'s> ParseState<'s> {
154154
}
155155

156156
/// Try parse with `f` , reverting the state if it returns `None` .
157-
pub fn try_parse<T>(&mut self, f: impl FnOnce(&mut Self) -> Option<T>) -> Option<T> {
157+
pub(crate) fn try_parse<T>(&mut self, f: impl FnOnce(&mut Self) -> Option<T>) -> Option<T> {
158158
let prev = self.cur_index;
159159
let prev_line = self.line;
160160
let prev_utf16_col = self.utf16_col;
@@ -184,7 +184,7 @@ impl<'s> ParseState<'s> {
184184
}
185185
}
186186

187-
pub fn skip_until_before(&mut self, until: &str) -> Option<&'s str> {
187+
pub(crate) fn skip_until_before(&mut self, until: &str) -> Option<&'s str> {
188188
let s = self.cur_str();
189189
if let Some(index) = s.find(until) {
190190
let ret = &s[..index];
@@ -196,22 +196,22 @@ impl<'s> ParseState<'s> {
196196
}
197197
}
198198

199-
pub fn skip_until_after(&mut self, until: &str) -> Option<&'s str> {
199+
pub(crate) fn skip_until_after(&mut self, until: &str) -> Option<&'s str> {
200200
let ret = self.skip_until_before(until);
201201
if ret.is_some() {
202202
self.skip_bytes(until.len());
203203
}
204204
ret
205205
}
206206

207-
pub fn peek_chars(&mut self) -> impl 's + Iterator<Item = char> {
207+
pub(crate) fn peek_chars(&mut self) -> impl 's + Iterator<Item = char> {
208208
if let Some(f) = self.auto_skip_whitespace.as_ref() {
209209
f(self);
210210
}
211211
self.cur_str().chars()
212212
}
213213

214-
pub fn peek_n<const N: usize>(&mut self) -> Option<[char; N]> {
214+
pub(crate) fn peek_n<const N: usize>(&mut self) -> Option<[char; N]> {
215215
let mut ret: [char; N] = ['\x00'; N];
216216
let mut iter = self.peek_chars();
217217
for i in 0..N {
@@ -220,15 +220,15 @@ impl<'s> ParseState<'s> {
220220
Some(ret)
221221
}
222222

223-
pub fn peek<const I: usize>(&mut self) -> Option<char> {
223+
pub(crate) fn peek<const I: usize>(&mut self) -> Option<char> {
224224
let mut iter = self.peek_chars();
225225
for _ in 0..I {
226226
iter.next()?;
227227
}
228228
iter.next()
229229
}
230230

231-
pub fn peek_str(&mut self, s: &str) -> bool {
231+
pub(crate) fn peek_str(&mut self, s: &str) -> bool {
232232
if let Some(f) = self.auto_skip_whitespace.as_ref() {
233233
f(self);
234234
}
@@ -279,7 +279,7 @@ impl<'s> ParseState<'s> {
279279
}
280280

281281
/// Consume the specified string if it matches the peek of the input.
282-
pub fn consume_str(&mut self, s: &str) -> Option<Range<Position>> {
282+
pub(crate) fn consume_str(&mut self, s: &str) -> Option<Range<Position>> {
283283
self.consume_str_except_followed(s, [])
284284
}
285285

@@ -301,7 +301,7 @@ impl<'s> ParseState<'s> {
301301
}
302302
}
303303

304-
pub fn next(&mut self) -> Option<char> {
304+
pub(crate) fn next(&mut self) -> Option<char> {
305305
if let Some(f) = self.auto_skip_whitespace.as_ref() {
306306
f(self);
307307
}
@@ -320,7 +320,7 @@ impl<'s> ParseState<'s> {
320320
Some(ret)
321321
}
322322

323-
pub fn skip_whitespace(&mut self) -> Option<Range<Position>> {
323+
pub(crate) fn skip_whitespace(&mut self) -> Option<Range<Position>> {
324324
let mut start_pos = None;
325325
let s = self.cur_str();
326326
let mut i = s.char_indices();
@@ -370,17 +370,17 @@ impl<'s> ParseState<'s> {
370370
///
371371
/// Panics if the start or the end is not at a character boundary.
372372
///
373-
pub fn code_slice(&self, range: Range<usize>) -> &'s str {
373+
pub(crate) fn code_slice(&self, range: Range<usize>) -> &'s str {
374374
&self.whole_str[range]
375375
}
376376

377377
/// Get the current UTF-8 byte index in the input.
378-
pub fn cur_index(&self) -> usize {
378+
pub(crate) fn cur_index(&self) -> usize {
379379
self.cur_index as usize
380380
}
381381

382382
/// Get the current position.
383-
pub fn position(&self) -> Position {
383+
pub(crate) fn position(&self) -> Position {
384384
Position {
385385
line: self.line,
386386
utf16_col: self.utf16_col,

glass-easel-template-compiler/src/parse/tag.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,12 @@ pub struct Comment {
273273
pub location: Range<Position>,
274274
}
275275

276+
impl Comment {
277+
pub fn new(content: &str, location: Range<Position>) -> Self {
278+
Self { content: content.to_string(), location }
279+
}
280+
}
281+
276282
#[derive(Debug, Clone)]
277283
#[non_exhaustive]
278284
pub struct UnknownMetaTag {
@@ -492,6 +498,10 @@ impl Element {
492498
super::iter::ChildrenIter::new(self)
493499
}
494500

501+
pub fn iter_children_mut(&mut self) -> super::iter::ChildrenIterMut {
502+
super::iter::ChildrenIterMut::new(self)
503+
}
504+
495505
pub fn slot_value_refs(&self) -> Option<impl Iterator<Item = &StaticAttribute>> {
496506
match &self.kind {
497507
ElementKind::Normal { common, .. } | ElementKind::Slot { common, .. } => {
@@ -3109,7 +3119,7 @@ impl TemplateStructure for Value {
31093119
}
31103120

31113121
impl Value {
3112-
fn new_empty(pos: Position) -> Self {
3122+
pub fn new_empty(pos: Position) -> Self {
31133123
Self::Static {
31143124
value: CompactString::new_inline(""),
31153125
location: pos..pos,
@@ -3124,6 +3134,13 @@ impl Value {
31243134
}
31253135
}
31263136

3137+
pub fn new_expression(
3138+
expression: Box<Expression>,
3139+
double_brace_location: (Range<Position>, Range<Position>),
3140+
) -> Self {
3141+
Self::Dynamic { expression, double_brace_location, binding_map_keys: None }
3142+
}
3143+
31273144
fn parse_data_binding(ps: &mut ParseState, is_template_data: bool) -> Option<Self> {
31283145
let Some(double_brace_left) = ps.consume_str("{{") else {
31293146
return None;

0 commit comments

Comments
 (0)