rustbasic_core/template/
parser.rs1use super::lexer::Token;
2
3#[derive(Debug, Clone, PartialEq)]
4pub enum Expr {
5 Path(Vec<String>),
6 StringLiteral(String),
7 NumberLiteral(f64),
8 BooleanLiteral(bool),
9 Comparison {
10 left: Box<Expr>,
11 op: String,
12 right: Box<Expr>,
13 },
14 Filter {
15 expr: Box<Expr>,
16 filter_name: String,
17 args: Vec<Expr>,
18 },
19}
20
21#[derive(Debug, Clone, PartialEq)]
22pub enum Node {
23 Text(String),
24 Variable(Expr),
25 If {
26 condition: Expr,
27 then_branch: Vec<Node>,
28 else_branch: Option<Vec<Node>>,
29 },
30 For {
31 item: String,
32 iterator: Expr,
33 body: Vec<Node>,
34 },
35}
36
37pub struct Parser {
38 tokens: Vec<Token>,
39 pos: usize,
40}
41
42impl Parser {
43 pub fn new(tokens: Vec<Token>) -> Self {
44 Self { tokens, pos: 0 }
45 }
46
47 fn peek(&self) -> Option<Token> {
48 if self.pos < self.tokens.len() {
49 Some(self.tokens[self.pos].clone())
50 } else {
51 None
52 }
53 }
54
55 fn advance(&mut self) -> Option<Token> {
56 if self.pos < self.tokens.len() {
57 let t = &self.tokens[self.pos];
58 self.pos += 1;
59 Some(t.clone())
60 } else {
61 None
62 }
63 }
64
65 fn expect(&mut self, token: Token) -> Result<(), String> {
66 if let Some(t) = self.peek() {
67 if t == token {
68 self.advance();
69 Ok(())
70 } else {
71 Err(format!("Expected token {:?}, found {:?}", token, t))
72 }
73 } else {
74 Err(format!("Expected token {:?}, reached EOF", token))
75 }
76 }
77
78 pub fn parse(&mut self) -> Result<Vec<Node>, String> {
79 let mut nodes = Vec::new();
80 while self.pos < self.tokens.len() {
81 if let Some(token) = self.peek() {
82 match token {
83 Token::Text(text) => {
84 nodes.push(Node::Text(text));
85 self.advance();
86 }
87 Token::VariableStart => {
88 self.advance(); let expr = self.parse_expr()?;
90 self.expect(Token::VariableEnd)?;
91 nodes.push(Node::Variable(expr));
92 }
93 Token::BlockStart => {
94 self.advance(); let node = self.parse_block()?;
96 nodes.push(node);
97 }
98 _ => {
99 return Err(format!("Unexpected token in template body: {:?}", token));
100 }
101 }
102 }
103 }
104 Ok(nodes)
105 }
106
107 fn parse_block(&mut self) -> Result<Node, String> {
108 if let Some(Token::Identifier(keyword)) = self.peek() {
109 match keyword.as_str() {
110 "if" => {
111 self.advance(); let condition = self.parse_expr()?;
113 self.expect(Token::BlockEnd)?;
114
115 let mut then_branch = Vec::new();
116 let mut else_branch = None;
117
118 while self.pos < self.tokens.len() {
119 if let Some(Token::BlockStart) = self.peek()
120 && let Some(Token::Identifier(ident)) = self.tokens.get(self.pos + 1) {
121 if ident == "else" {
122 self.advance(); self.advance(); self.expect(Token::BlockEnd)?;
125
126 let mut else_nodes = Vec::new();
127 while self.pos < self.tokens.len() {
128 if let Some(Token::BlockStart) = self.peek()
129 && let Some(Token::Identifier(inner_ident)) = self.tokens.get(self.pos + 1)
130 && inner_ident == "endif" {
131 break;
132 }
133 if let Some(Token::Text(text)) = self.peek() {
134 else_nodes.push(Node::Text(text));
135 self.advance();
136 } else if let Some(Token::VariableStart) = self.peek() {
137 self.advance();
138 let expr = self.parse_expr()?;
139 self.expect(Token::VariableEnd)?;
140 else_nodes.push(Node::Variable(expr));
141 } else if let Some(Token::BlockStart) = self.peek() {
142 self.advance();
143 else_nodes.push(self.parse_block()?);
144 }
145 }
146 else_branch = Some(else_nodes);
147 continue;
148 } else if ident == "endif" {
149 self.advance(); self.advance(); self.expect(Token::BlockEnd)?;
152 break;
153 }
154 }
155
156 if let Some(Token::Text(text)) = self.peek() {
157 then_branch.push(Node::Text(text));
158 self.advance();
159 } else if let Some(Token::VariableStart) = self.peek() {
160 self.advance();
161 let expr = self.parse_expr()?;
162 self.expect(Token::VariableEnd)?;
163 then_branch.push(Node::Variable(expr));
164 } else if let Some(Token::BlockStart) = self.peek() {
165 self.advance();
166 then_branch.push(self.parse_block()?);
167 }
168 }
169
170 Ok(Node::If {
171 condition,
172 then_branch,
173 else_branch,
174 })
175 }
176 "for" => {
177 self.advance(); let item = if let Some(Token::Identifier(name)) = self.advance() {
179 name
180 } else {
181 return Err("Expected item identifier in for loop".to_string());
182 };
183
184 if let Some(Token::Identifier(keyword_in)) = self.advance() {
185 if keyword_in != "in" {
186 return Err(format!("Expected 'in', found '{}'", keyword_in));
187 }
188 } else {
189 return Err("Expected 'in' keyword in for loop".to_string());
190 }
191
192 let iterator = self.parse_expr()?;
193 self.expect(Token::BlockEnd)?;
194
195 let mut body = Vec::new();
196 while self.pos < self.tokens.len() {
197 if let Some(Token::BlockStart) = self.peek()
198 && let Some(Token::Identifier(ident)) = self.tokens.get(self.pos + 1)
199 && ident == "endfor" {
200 self.advance(); self.advance(); self.expect(Token::BlockEnd)?;
203 break;
204 }
205
206 if let Some(Token::Text(text)) = self.peek() {
207 body.push(Node::Text(text));
208 self.advance();
209 } else if let Some(Token::VariableStart) = self.peek() {
210 self.advance();
211 let expr = self.parse_expr()?;
212 self.expect(Token::VariableEnd)?;
213 body.push(Node::Variable(expr));
214 } else if let Some(Token::BlockStart) = self.peek() {
215 self.advance();
216 body.push(self.parse_block()?);
217 }
218 }
219
220 Ok(Node::For {
221 item,
222 iterator,
223 body,
224 })
225 }
226 other => Err(format!("Unknown block keyword: {}", other)),
227 }
228 } else {
229 Err("Expected keyword at start of block statement".to_string())
230 }
231 }
232
233 fn parse_expr(&mut self) -> Result<Expr, String> {
234 let mut left = self.parse_comparison_expr()?;
235
236 while let Some(Token::Operator(op)) = self.peek() {
237 if op == "|" {
238 self.advance(); if let Some(Token::Identifier(filter_name)) = self.advance() {
240 let mut args = Vec::new();
241 if let Some(Token::Operator(paren)) = self.peek()
242 && paren == "(" {
243 self.advance(); while self.pos < self.tokens.len() {
245 if let Some(Token::Operator(close_paren)) = self.peek()
246 && close_paren == ")" {
247 self.advance(); break;
249 }
250 args.push(self.parse_expr()?);
251 if let Some(Token::Comma) = self.peek() {
252 self.advance();
253 }
254 }
255 }
256 left = Expr::Filter {
257 expr: Box::new(left),
258 filter_name,
259 args,
260 };
261 } else {
262 return Err("Expected filter name after '|'".to_string());
263 }
264 } else {
265 break;
266 }
267 }
268
269 Ok(left)
270 }
271
272 fn parse_comparison_expr(&mut self) -> Result<Expr, String> {
273 let left = self.parse_primary_expr()?;
274
275 if let Some(Token::Operator(op)) = self.peek()
276 && (op == "==" || op == "!=" || op == "<" || op == ">" || op == "<=" || op == ">=") {
277 self.advance(); let right = self.parse_primary_expr()?;
279 return Ok(Expr::Comparison {
280 left: Box::new(left),
281 op,
282 right: Box::new(right),
283 });
284 }
285
286 Ok(left)
287 }
288
289 fn parse_primary_expr(&mut self) -> Result<Expr, String> {
290 if let Some(token) = self.peek() {
291 match token {
292 Token::StringLiteral(s) => {
293 self.advance();
294 Ok(Expr::StringLiteral(s))
295 }
296 Token::NumberLiteral(n) => {
297 self.advance();
298 Ok(Expr::NumberLiteral(n))
299 }
300 Token::Identifier(s) if s == "true" => {
301 self.advance();
302 Ok(Expr::BooleanLiteral(true))
303 }
304 Token::Identifier(s) if s == "false" => {
305 self.advance();
306 Ok(Expr::BooleanLiteral(false))
307 }
308 Token::Identifier(first_name) => {
309 self.advance();
310 let mut path = vec![first_name];
311 while let Some(Token::Dot) = self.peek() {
312 self.advance(); if let Some(Token::Identifier(field)) = self.advance() {
314 path.push(field);
315 } else {
316 return Err("Expected identifier after '.'".to_string());
317 }
318 }
319 Ok(Expr::Path(path))
320 }
321 other => Err(format!("Expected primary expression, found {:?}", other)),
322 }
323 } else {
324 Err("Expected primary expression, reached EOF".to_string())
325 }
326 }
327}