1use crate::ast::{ASTNode, BinaryOp, Expr, Program, Property, Statement};
11use crate::token::{Token, TokenType};
12
13pub struct Parser {
15 tokens: Vec<Token>,
16 current: usize,
17}
18
19impl Parser {
20 pub fn new(tokens: Vec<Token>) -> Self {
22 Self { tokens, current: 0 }
23 }
24
25 pub fn parse(&mut self) -> Result<Program, String> {
27 let mut program = Program::new();
28
29 while !self.is_at_end() {
30 if self.match_token(&[TokenType::Newline]) {
32 continue;
33 }
34
35 if self.match_token(&[TokenType::Indent, TokenType::Dedent]) {
37 continue;
38 }
39
40 if self.is_at_end() {
41 break;
42 }
43
44 let node = self.parse_top_level()?;
45 program.add_node(node);
46 }
47
48 Ok(program)
49 }
50
51 fn parse_top_level(&mut self) -> Result<ASTNode, String> {
53 match &self.peek().token_type {
54 TokenType::Fn => self.parse_function(),
55 TokenType::Var => self.parse_variable(),
56 TokenType::Import => self.parse_import(),
57 TokenType::Identifier(_) => self.parse_css_rule(),
58 TokenType::Dot => self.parse_css_rule(),
59 TokenType::At => {
60 self.parse_css_rule()
62 }
63 _ => Err(format!(
64 "Unexpected token at {}:{}: {:?}",
65 self.peek().line,
66 self.peek().column,
67 self.peek().token_type
68 )),
69 }
70 }
71
72 fn parse_function(&mut self) -> Result<ASTNode, String> {
74 self.consume(&TokenType::Fn, "Expected @fn")?;
75
76 let name = self.consume_identifier("Expected function name")?;
77
78 self.consume(&TokenType::LeftParen, "Expected '(' after function name")?;
79
80 let mut params = Vec::new();
81 if !self.check(&TokenType::RightParen) {
82 loop {
83 let param = self.consume_identifier("Expected parameter name")?;
84 params.push(param);
85
86 if !self.match_token(&[TokenType::Comma]) {
87 break;
88 }
89 }
90 }
91
92 self.consume(&TokenType::RightParen, "Expected ')' after parameters")?;
93 self.consume(&TokenType::Colon, "Expected ':' after function signature")?;
94
95 let body = self.parse_block()?;
97
98 Ok(ASTNode::Function { name, params, body })
99 }
100
101 fn parse_variable(&mut self) -> Result<ASTNode, String> {
103 self.consume(&TokenType::Var, "Expected @var")?;
104
105 let name = self.consume_identifier("Expected variable name")?;
106
107 self.consume(&TokenType::Colon, "Expected ':' after variable name")?;
108
109 let value = self.parse_expression()?;
110
111 Ok(ASTNode::Variable { name, value })
112 }
113
114 fn parse_import(&mut self) -> Result<ASTNode, String> {
116 self.consume(&TokenType::Import, "Expected @import")?;
117
118 let path = match &self.peek().token_type {
119 TokenType::String(s) => {
120 let path = s.clone();
121 self.advance();
122 path
123 }
124 _ => return Err(format!("Expected string after @import at {}:{}",
125 self.peek().line, self.peek().column)),
126 };
127
128 Ok(ASTNode::Import { path })
129 }
130
131 fn parse_css_rule(&mut self) -> Result<ASTNode, String> {
133 let selector = self.parse_selector()?;
134
135 self.consume(&TokenType::Colon, "Expected ':' after selector")?;
136
137 let properties = self.parse_properties_block()?;
139
140 Ok(ASTNode::CSSRule { selector, properties })
141 }
142
143 fn parse_selector(&mut self) -> Result<String, String> {
145 let mut selector_parts = Vec::new();
146
147 loop {
148 match &self.peek().token_type {
149 TokenType::Identifier(id) => {
150 selector_parts.push(id.clone());
151 self.advance();
152 }
153 TokenType::Dot => {
154 selector_parts.push(".".to_string());
155 self.advance();
156 }
157 TokenType::At => {
158 selector_parts.push("@".to_string());
159 self.advance();
160 }
161 TokenType::Colon => break,
162 _ => {
163 return Err(format!(
164 "Unexpected token in selector at {}:{}: {:?}",
165 self.peek().line,
166 self.peek().column,
167 self.peek().token_type
168 ))
169 }
170 }
171 }
172
173 if selector_parts.is_empty() {
174 return Err("Empty selector".to_string());
175 }
176
177 Ok(selector_parts.join(""))
178 }
179
180 fn parse_block(&mut self) -> Result<Vec<Statement>, String> {
182 let mut statements = Vec::new();
183
184 self.consume(&TokenType::Indent, "Expected indented block")?;
186
187 while !self.check(&TokenType::Dedent) && !self.is_at_end() {
188 if self.match_token(&[TokenType::Newline]) {
190 continue;
191 }
192
193 if self.check(&TokenType::Dedent) {
194 break;
195 }
196
197 let stmt = self.parse_statement()?;
198 statements.push(stmt);
199 }
200
201 self.consume(&TokenType::Dedent, "Expected dedent after block")?;
202
203 Ok(statements)
204 }
205
206 fn parse_statement(&mut self) -> Result<Statement, String> {
208 match &self.peek().token_type {
209 TokenType::Return => {
210 self.advance();
211 let expr = self.parse_expression()?;
212 Ok(Statement::Return(expr))
213 }
214 TokenType::Identifier(name) => {
215 let name = name.clone();
216 self.advance();
217
218 if self.match_token(&[TokenType::Assign]) {
219 let value = self.parse_expression()?;
220 Ok(Statement::Assignment { name, value })
221 } else {
222 self.current -= 1;
224 let expr = self.parse_expression()?;
225 Ok(Statement::Expression(expr))
226 }
227 }
228 _ => {
229 let expr = self.parse_expression()?;
230 Ok(Statement::Expression(expr))
231 }
232 }
233 }
234
235 fn parse_properties_block(&mut self) -> Result<Vec<Property>, String> {
237 let mut properties = Vec::new();
238
239 self.consume(&TokenType::Indent, "Expected indented block")?;
241
242 while !self.check(&TokenType::Dedent) && !self.is_at_end() {
243 if self.match_token(&[TokenType::Newline]) {
245 continue;
246 }
247
248 if self.check(&TokenType::Dedent) {
249 break;
250 }
251
252 let property = self.parse_property()?;
253 properties.push(property);
254 }
255
256 self.consume(&TokenType::Dedent, "Expected dedent after properties")?;
257
258 Ok(properties)
259 }
260
261 fn parse_property(&mut self) -> Result<Property, String> {
263 let name = self.consume_identifier("Expected property name")?;
264
265 self.consume(&TokenType::Colon, "Expected ':' after property name")?;
266
267 let value = self.parse_expression()?;
268
269 Ok(Property::new(name, value))
270 }
271
272 fn parse_expression(&mut self) -> Result<Expr, String> {
274 self.parse_binary_expression(0)
275 }
276
277 fn parse_binary_expression(&mut self, min_precedence: u8) -> Result<Expr, String> {
279 let mut left = self.parse_primary()?;
280
281 loop {
282 let op = match &self.peek().token_type {
283 TokenType::Plus => BinaryOp::Add,
284 TokenType::Minus => BinaryOp::Subtract,
285 TokenType::Star => BinaryOp::Multiply,
286 TokenType::Slash => BinaryOp::Divide,
287 TokenType::Percent => BinaryOp::Modulo,
288 TokenType::Equal => BinaryOp::Equal,
289 TokenType::NotEqual => BinaryOp::NotEqual,
290 TokenType::Less => BinaryOp::Less,
291 TokenType::Greater => BinaryOp::Greater,
292 TokenType::LessEqual => BinaryOp::LessEqual,
293 TokenType::GreaterEqual => BinaryOp::GreaterEqual,
294 _ => break,
295 };
296
297 let precedence = op.precedence();
298 if precedence < min_precedence {
299 break;
300 }
301
302 self.advance(); let right = self.parse_binary_expression(precedence + 1)?;
305
306 left = Expr::Binary {
307 op,
308 left: Box::new(left),
309 right: Box::new(right),
310 };
311 }
312
313 Ok(left)
314 }
315
316 fn parse_primary(&mut self) -> Result<Expr, String> {
318 match &self.peek().token_type.clone() {
319 TokenType::Number(n) => {
320 let num = *n;
321 self.advance();
322 Ok(Expr::Number(num))
323 }
324 TokenType::Unit(unit) => {
325 let lexeme = self.peek().lexeme.clone();
326 let unit_str = unit.clone();
327 self.advance();
328
329 let num_str = lexeme.trim_end_matches(&unit_str);
331 let value = num_str.parse::<f64>()
332 .map_err(|_| format!("Invalid number in unit: {}", num_str))?;
333
334 Ok(Expr::Unit { value, unit: unit_str })
335 }
336 TokenType::String(s) => {
337 let string = s.clone();
338 self.advance();
339 Ok(Expr::Literal(string))
340 }
341 TokenType::Color(c) => {
342 let color = c.clone();
343 self.advance();
344 Ok(Expr::Color(color))
345 }
346 TokenType::Identifier(id) => {
347 let name = id.clone();
348 self.advance();
349
350 if self.check(&TokenType::LeftParen) {
352 self.advance(); let mut args = Vec::new();
355 if !self.check(&TokenType::RightParen) {
356 loop {
357 let arg = self.parse_expression()?;
358 args.push(arg);
359
360 if !self.match_token(&[TokenType::Comma]) {
361 break;
362 }
363 }
364 }
365
366 self.consume(&TokenType::RightParen, "Expected ')' after arguments")?;
367
368 Ok(Expr::FunctionCall { name, args })
369 } else {
370 Ok(Expr::Variable(name))
371 }
372 }
373 TokenType::LeftParen => {
374 self.advance(); let expr = self.parse_expression()?;
376 self.consume(&TokenType::RightParen, "Expected ')' after expression")?;
377 Ok(expr)
378 }
379 TokenType::LeftBracket => {
380 self.advance(); let mut elements = Vec::new();
382
383 if !self.check(&TokenType::RightBracket) {
384 loop {
385 let elem = self.parse_expression()?;
386 elements.push(elem);
387
388 if !self.match_token(&[TokenType::Comma]) {
389 break;
390 }
391 }
392 }
393
394 self.consume(&TokenType::RightBracket, "Expected ']' after array elements")?;
395 Ok(Expr::Array(elements))
396 }
397 TokenType::LeftBrace => {
398 self.advance(); let mut pairs = Vec::new();
400
401 if !self.check(&TokenType::RightBrace) {
402 loop {
403 let key = self.consume_identifier("Expected object key")?;
404 self.consume(&TokenType::Colon, "Expected ':' after object key")?;
405 let value = self.parse_expression()?;
406 pairs.push((key, value));
407
408 if !self.match_token(&[TokenType::Comma]) {
409 break;
410 }
411 }
412 }
413
414 self.consume(&TokenType::RightBrace, "Expected '}' after object")?;
415 Ok(Expr::Object(pairs))
416 }
417 _ => Err(format!(
418 "Unexpected token in expression at {}:{}: {:?}",
419 self.peek().line,
420 self.peek().column,
421 self.peek().token_type
422 )),
423 }
424 }
425
426 fn is_at_end(&self) -> bool {
429 matches!(self.peek().token_type, TokenType::Eof)
430 }
431
432 fn peek(&self) -> &Token {
433 &self.tokens[self.current]
434 }
435
436 fn advance(&mut self) -> &Token {
437 if !self.is_at_end() {
438 self.current += 1;
439 }
440 &self.tokens[self.current - 1]
441 }
442
443 fn check(&self, token_type: &TokenType) -> bool {
444 if self.is_at_end() {
445 return false;
446 }
447 std::mem::discriminant(&self.peek().token_type) == std::mem::discriminant(token_type)
448 }
449
450 fn match_token(&mut self, types: &[TokenType]) -> bool {
451 for token_type in types {
452 if self.check(token_type) {
453 self.advance();
454 return true;
455 }
456 }
457 false
458 }
459
460 fn consume(&mut self, token_type: &TokenType, message: &str) -> Result<&Token, String> {
461 if self.check(token_type) {
462 Ok(self.advance())
463 } else {
464 Err(format!(
465 "{} at {}:{}, found {:?}",
466 message,
467 self.peek().line,
468 self.peek().column,
469 self.peek().token_type
470 ))
471 }
472 }
473
474 fn consume_identifier(&mut self, message: &str) -> Result<String, String> {
475 match &self.peek().token_type {
476 TokenType::Identifier(id) => {
477 let name = id.clone();
478 self.advance();
479 Ok(name)
480 }
481 _ => Err(format!(
482 "{} at {}:{}, found {:?}",
483 message,
484 self.peek().line,
485 self.peek().column,
486 self.peek().token_type
487 )),
488 }
489 }
490}
491
492#[cfg(test)]
493mod tests {
494 use super::*;
495 use crate::lexer::Lexer;
496
497 #[test]
498 fn test_parse_variable() {
499 let source = "@var primary-color: #3498db";
500 let mut lexer = Lexer::new(source);
501 let tokens = lexer.tokenize().unwrap();
502 let mut parser = Parser::new(tokens);
503 let program = parser.parse().unwrap();
504
505 assert_eq!(program.nodes.len(), 1);
506 match &program.nodes[0] {
507 ASTNode::Variable { name, value } => {
508 assert_eq!(name, "primary-color");
509 assert!(matches!(value, Expr::Color(_)));
510 }
511 _ => panic!("Expected variable node"),
512 }
513 }
514
515 #[test]
516 fn test_parse_function() {
517 let source = "@fn spacing(x):\n return x * 16px";
518 let mut lexer = Lexer::new(source);
519 let tokens = lexer.tokenize().unwrap();
520 let mut parser = Parser::new(tokens);
521 let program = parser.parse().unwrap();
522
523 assert_eq!(program.nodes.len(), 1);
524 match &program.nodes[0] {
525 ASTNode::Function { name, params, body } => {
526 assert_eq!(name, "spacing");
527 assert_eq!(params.len(), 1);
528 assert_eq!(params[0], "x");
529 assert_eq!(body.len(), 1);
530 }
531 _ => panic!("Expected function node"),
532 }
533 }
534
535 #[test]
536 fn test_parse_expression() {
537 let source = "@var result: 2 * 16px + 8px";
538 let mut lexer = Lexer::new(source);
539 let tokens = lexer.tokenize().unwrap();
540 let mut parser = Parser::new(tokens);
541 let program = parser.parse().unwrap();
542
543 assert_eq!(program.nodes.len(), 1);
544 match &program.nodes[0] {
545 ASTNode::Variable { value, .. } => {
546 assert!(matches!(value, Expr::Binary { .. }));
547 }
548 _ => panic!("Expected variable node"),
549 }
550 }
551
552 #[test]
553 fn test_parse_css_rule() {
554 let source = ".button:\n padding: 16px\n color: #fff";
555 let mut lexer = Lexer::new(source);
556 let tokens = lexer.tokenize().unwrap();
557 let mut parser = Parser::new(tokens);
558 let program = parser.parse().unwrap();
559
560 assert_eq!(program.nodes.len(), 1);
561 match &program.nodes[0] {
562 ASTNode::CSSRule { selector, properties } => {
563 assert_eq!(selector, ".button");
564 assert_eq!(properties.len(), 2);
565 }
566 _ => panic!("Expected CSS rule node"),
567 }
568 }
569}
570
571
572
573