1use crate::ast::*;
4use crate::error::{NewtError, Span};
5use crate::lexer::{Lexer, Token, TokenKind};
6
7pub struct Parser<'a> {
8 tokens: Vec<Token>,
9 index: usize,
10 errors: Vec<NewtError>,
11 _marker: std::marker::PhantomData<&'a str>,
12}
13
14impl<'a> Parser<'a> {
15 pub fn new(source: &'a str, path: Option<&'a str>) -> Result<Self, NewtError> {
16 let mut lexer = Lexer::new(source, path);
17 let mut tokens = Vec::new();
18 loop {
19 let t = lexer.next_token()?;
20 let is_eof = matches!(t.kind, TokenKind::Eof);
21 tokens.push(t);
22 if is_eof {
23 break;
24 }
25 }
26 Ok(Self {
27 tokens,
28 index: 0,
29 errors: Vec::new(),
30 _marker: std::marker::PhantomData,
31 })
32 }
33
34 fn current(&self) -> &Token {
35 self.tokens.get(self.index).unwrap_or_else(|| self.tokens.last().unwrap())
36 }
37
38 fn advance(&mut self) -> Token {
39 let t = self.current().clone();
40 if self.index < self.tokens.len() {
41 self.index += 1;
42 }
43 t
44 }
45
46 fn expect(&mut self, kind: TokenKind) -> Result<Token, NewtError> {
47 let cur = self.current();
48 if std::mem::discriminant(&cur.kind) == std::mem::discriminant(&kind) {
49 return Ok(self.advance());
50 }
51 Err(NewtError::parse(
52 cur.span,
53 format!("expected {}, got {}", kind, cur.kind),
54 ))
55 }
56
57 fn expect_ident(&mut self) -> Result<String, NewtError> {
58 let cur = self.current();
59 match &cur.kind {
60 TokenKind::Ident(s) => {
61 let name = s.clone();
62 self.advance();
63 Ok(name)
64 }
65 _ => Err(NewtError::parse(
66 cur.span,
67 format!("expected identifier, got {}", cur.kind),
68 )),
69 }
70 }
71
72 fn at(&self, kind: TokenKind) -> bool {
73 std::mem::discriminant(&self.current().kind) == std::mem::discriminant(&kind)
74 }
75
76 fn at_ident(&self) -> bool {
77 matches!(self.current().kind, TokenKind::Ident(_))
78 }
79
80 fn peek_next(&self) -> Option<&Token> {
81 self.tokens.get(self.index + 1)
82 }
83
84 fn at_ident_then_colon(&self) -> bool {
85 if !self.at_ident() {
86 return false;
87 }
88 self.peek_next()
89 .map(|t| std::mem::discriminant(&t.kind) == std::mem::discriminant(&TokenKind::Colon))
90 .unwrap_or(false)
91 }
92
93 pub fn parse(&mut self) -> Result<Program, Vec<NewtError>> {
94 let mut items = Vec::new();
95 while !self.at(TokenKind::Eof) {
96 match self.parse_top_level_item() {
97 Ok(item) => items.push(item),
98 Err(e) => {
99 self.errors.push(e);
100 self.synchronize();
101 }
102 }
103 }
104 if self.errors.is_empty() {
105 Ok(Program { items })
106 } else {
107 Err(std::mem::take(&mut self.errors))
108 }
109 }
110
111 fn parse_top_level_item(&mut self) -> Result<ProgramItem, NewtError> {
112 if self.at(TokenKind::Import) {
113 Ok(ProgramItem::Import(self.parse_import()?))
114 } else if self.at(TokenKind::Theme) {
115 Ok(ProgramItem::Theme(self.parse_theme()?))
116 } else if self.at(TokenKind::Use) {
117 Ok(ProgramItem::UseTheme(self.parse_use_theme()?))
118 } else if self.at(TokenKind::Let) {
119 Ok(ProgramItem::Variable(self.parse_variable()?))
120 } else if self.at(TokenKind::Component) {
121 Ok(ProgramItem::Component(self.parse_component()?))
122 } else if self.at(TokenKind::Screen) {
123 Ok(ProgramItem::Screen(self.parse_screen()?))
124 } else if self.at(TokenKind::State) {
125 Ok(ProgramItem::StateDecl(self.parse_state_decl()?))
126 } else {
127 let cur = self.current();
128 let msg = format!(
129 "expected import, theme, use theme, let, state, component, or screen at top level, got {}",
130 cur.kind
131 );
132 let err = if let TokenKind::Ident(ref s) = cur.kind {
133 if let Some(suggestion) = closest_top_level_keyword(s) {
134 NewtError::parse_with_suggestion(cur.span, msg, format!("did you mean `{}`?", suggestion))
135 } else {
136 NewtError::parse(cur.span, msg)
137 }
138 } else {
139 NewtError::parse(cur.span, msg)
140 };
141 Err(err)
142 }
143 }
144
145 fn synchronize(&mut self) {
148 let mut depth = 0i32;
149 loop {
150 match self.current().kind {
151 TokenKind::Eof => break,
152 TokenKind::LeftBrace => { depth += 1; self.advance(); }
153 TokenKind::RightBrace => {
154 if depth > 0 {
155 depth -= 1;
156 self.advance();
157 if depth == 0 {
158 break;
160 }
161 } else {
162 self.advance();
163 }
164 }
165 TokenKind::Semicolon if depth == 0 => { self.advance(); break; }
166 TokenKind::Let | TokenKind::Component | TokenKind::Screen
167 | TokenKind::Theme | TokenKind::Import | TokenKind::Use
168 | TokenKind::State if depth == 0 => break,
169 _ => { self.advance(); }
170 }
171 }
172 }
173
174 fn parse_import(&mut self) -> Result<ImportDecl, NewtError> {
175 let span = self.current().span;
176 self.expect(TokenKind::Import)?;
177 let path = match &self.current().kind {
178 TokenKind::String(s) => s.clone(),
179 _ => return Err(NewtError::parse(self.current().span, "import expects a string path")),
180 };
181 self.advance();
182 self.expect(TokenKind::Semicolon)?;
183 Ok(ImportDecl { path, span })
184 }
185
186 fn parse_theme(&mut self) -> Result<ThemeDecl, NewtError> {
187 let span = self.current().span;
188 self.expect(TokenKind::Theme)?;
189 let name = self.expect_ident()?;
190 self.expect(TokenKind::LeftBrace)?;
191 let mut vars = Vec::new();
192 while !self.at(TokenKind::RightBrace) && !self.at(TokenKind::Eof) {
193 if self.at(TokenKind::Let) {
194 vars.push(self.parse_variable()?);
195 } else {
196 return Err(NewtError::parse(
197 self.current().span,
198 "theme body may only contain let declarations",
199 ));
200 }
201 }
202 self.expect(TokenKind::RightBrace)?;
203 Ok(ThemeDecl { name, vars, span })
204 }
205
206 fn parse_use_theme(&mut self) -> Result<String, NewtError> {
207 self.expect(TokenKind::Use)?;
208 self.expect(TokenKind::Theme)?;
209 let name = self.expect_ident()?;
210 self.expect(TokenKind::Semicolon)?;
211 Ok(name)
212 }
213
214 fn parse_variable(&mut self) -> Result<VariableDecl, NewtError> {
215 let span = self.current().span;
216 self.expect(TokenKind::Let)?;
217 let name = self.expect_ident()?;
218 self.expect(TokenKind::Eq)?;
219 let value = self.parse_expr()?;
220 self.expect(TokenKind::Semicolon)?;
221 Ok(VariableDecl { name, value, span })
222 }
223
224 fn parse_state_decl(&mut self) -> Result<StateVarDecl, NewtError> {
225 let span = self.current().span;
226 self.expect(TokenKind::State)?;
227 let name = self.expect_ident()?;
228 self.expect(TokenKind::Eq)?;
229 let initial_value = self.parse_expr()?;
230 self.expect(TokenKind::Semicolon)?;
231 Ok(StateVarDecl { name, initial_value, span })
232 }
233
234 fn parse_component(&mut self) -> Result<ComponentDecl, NewtError> {
235 let span = self.current().span;
236 self.expect(TokenKind::Component)?;
237 let name = self.expect_ident()?;
238 let params = if self.at(TokenKind::LeftParen) {
239 self.advance();
240 let mut p = Vec::new();
241 if !self.at(TokenKind::RightParen) {
242 p.push(self.expect_ident()?);
243 while self.at(TokenKind::Comma) {
244 self.advance();
245 p.push(self.expect_ident()?);
246 }
247 }
248 self.expect(TokenKind::RightParen)?;
249 p
250 } else {
251 Vec::new()
252 };
253 self.expect(TokenKind::LeftBrace)?;
254 let body = self.parse_expr()?;
255 self.expect(TokenKind::RightBrace)?;
256 Ok(ComponentDecl { name, params, body, span })
257 }
258
259 fn parse_block_body(&mut self, span: Span) -> Result<Expr, NewtError> {
261 let mut stmts = Vec::new();
262 while !self.at(TokenKind::RightBrace) && !self.at(TokenKind::Eof) {
263 if self.at(TokenKind::Let) {
264 self.advance();
265 let name = self.expect_ident()?;
266 self.expect(TokenKind::Eq)?;
267 let value = self.parse_expr()?;
268 self.expect(TokenKind::Semicolon)?;
269 stmts.push(Stmt::Let {
270 name,
271 value,
272 span: self.current().span,
273 });
274 } else if self.at(TokenKind::State) {
275 let sd = self.parse_state_decl()?;
276 stmts.push(Stmt::StateDecl(sd));
277 } else {
278 stmts.push(Stmt::Expr(self.parse_expr()?));
279 if self.at(TokenKind::Semicolon) {
280 self.advance();
281 }
282 }
283 }
284 Ok(Expr::Block { stmts, span })
285 }
286
287 fn parse_screen(&mut self) -> Result<ScreenDecl, NewtError> {
288 let span = self.current().span;
289 self.expect(TokenKind::Screen)?;
290 let name = if self.at(TokenKind::LeftParen) {
291 self.advance();
292 let n = self.expect_ident()?;
293 self.expect(TokenKind::RightParen)?;
294 n
295 } else if self.at_ident() {
296 self.expect_ident()?
297 } else {
298 "Main".to_string()
299 };
300 self.expect(TokenKind::LeftBrace)?;
301 let body = self.parse_block_body(span)?;
302 self.expect(TokenKind::RightBrace)?;
303 Ok(ScreenDecl { name, body, span })
304 }
305
306 fn parse_expr(&mut self) -> Result<Expr, NewtError> {
307 self.parse_or()
308 }
309
310 fn parse_or(&mut self) -> Result<Expr, NewtError> {
311 let mut left = self.parse_and()?;
312 while self.at(TokenKind::Or) {
313 let span = self.current().span;
314 self.advance();
315 let right = self.parse_and()?;
316 left = Expr::Binary {
317 left: Box::new(left),
318 op: BinaryOp::Or,
319 right: Box::new(right),
320 span,
321 };
322 }
323 Ok(left)
324 }
325
326 fn parse_and(&mut self) -> Result<Expr, NewtError> {
327 let mut left = self.parse_equality()?;
328 while self.at(TokenKind::And) {
329 let span = self.current().span;
330 self.advance();
331 let right = self.parse_equality()?;
332 left = Expr::Binary {
333 left: Box::new(left),
334 op: BinaryOp::And,
335 right: Box::new(right),
336 span,
337 };
338 }
339 Ok(left)
340 }
341
342 fn parse_equality(&mut self) -> Result<Expr, NewtError> {
343 let mut left = self.parse_comparison()?;
344 loop {
345 let span = self.current().span;
346 if self.at(TokenKind::EqEq) {
347 self.advance();
348 left = Expr::Binary {
349 left: Box::new(left),
350 op: BinaryOp::Eq,
351 right: Box::new(self.parse_comparison()?),
352 span,
353 };
354 } else if self.at(TokenKind::NotEq) {
355 self.advance();
356 left = Expr::Binary {
357 left: Box::new(left),
358 op: BinaryOp::Ne,
359 right: Box::new(self.parse_comparison()?),
360 span,
361 };
362 } else {
363 break;
364 }
365 }
366 Ok(left)
367 }
368
369 fn parse_comparison(&mut self) -> Result<Expr, NewtError> {
370 let mut left = self.parse_term()?;
371 loop {
372 let span = self.current().span;
373 let op = if self.at(TokenKind::Lt) {
374 self.advance();
375 BinaryOp::Lt
376 } else if self.at(TokenKind::Le) {
377 self.advance();
378 BinaryOp::Le
379 } else if self.at(TokenKind::Gt) {
380 self.advance();
381 BinaryOp::Gt
382 } else if self.at(TokenKind::Ge) {
383 self.advance();
384 BinaryOp::Ge
385 } else {
386 break;
387 };
388 left = Expr::Binary {
389 left: Box::new(left),
390 op,
391 right: Box::new(self.parse_term()?),
392 span,
393 };
394 }
395 Ok(left)
396 }
397
398 fn parse_term(&mut self) -> Result<Expr, NewtError> {
399 let mut left = self.parse_factor()?;
400 loop {
401 let span = self.current().span;
402 let op = if self.at(TokenKind::Plus) {
403 self.advance();
404 BinaryOp::Add
405 } else if self.at(TokenKind::Minus) {
406 self.advance();
407 BinaryOp::Sub
408 } else {
409 break;
410 };
411 left = Expr::Binary {
412 left: Box::new(left),
413 op,
414 right: Box::new(self.parse_factor()?),
415 span,
416 };
417 }
418 Ok(left)
419 }
420
421 fn parse_factor(&mut self) -> Result<Expr, NewtError> {
422 let mut left = self.parse_unary()?;
423 loop {
424 let span = self.current().span;
425 let op = if self.at(TokenKind::Star) {
426 self.advance();
427 BinaryOp::Mul
428 } else if self.at(TokenKind::Slash) {
429 self.advance();
430 BinaryOp::Div
431 } else if self.at(TokenKind::Percent) {
432 self.advance();
433 BinaryOp::Mod
434 } else {
435 break;
436 };
437 left = Expr::Binary {
438 left: Box::new(left),
439 op,
440 right: Box::new(self.parse_unary()?),
441 span,
442 };
443 }
444 Ok(left)
445 }
446
447 fn parse_unary(&mut self) -> Result<Expr, NewtError> {
448 let span = self.current().span;
449 if self.at(TokenKind::Not) {
450 self.advance();
451 let inner = self.parse_unary()?;
452 return Ok(Expr::Unary {
453 op: UnaryOp::Not,
454 inner: Box::new(inner),
455 span,
456 });
457 }
458 if self.at(TokenKind::Minus) {
459 self.advance();
460 let inner = self.parse_unary()?;
461 return Ok(Expr::Unary {
462 op: UnaryOp::Neg,
463 inner: Box::new(inner),
464 span,
465 });
466 }
467 self.parse_primary()
468 }
469
470 fn parse_primary(&mut self) -> Result<Expr, NewtError> {
471 let span = self.current().span;
472 match &self.current().kind {
473 TokenKind::Number(n) => {
474 let v = *n;
475 self.advance();
476 return Ok(Expr::Literal(Literal::Number(v)));
477 }
478 TokenKind::String(s) => {
479 let v = s.clone();
480 self.advance();
481 return Ok(Expr::Literal(Literal::String(v)));
482 }
483 TokenKind::InterpolatedString(parts) => {
484 let parts = parts.clone();
485 self.advance();
486 return self.build_interp_expr(parts, span);
487 }
488 TokenKind::True => {
489 self.advance();
490 return Ok(Expr::Literal(Literal::Bool(true)));
491 }
492 TokenKind::False => {
493 self.advance();
494 return Ok(Expr::Literal(Literal::Bool(false)));
495 }
496 TokenKind::HexColor(r, g, b, a) => {
497 let (r, g, b, a) = (*r, *g, *b, *a);
498 self.advance();
499 return Ok(Expr::Literal(Literal::Color { r, g, b, a }));
500 }
501 TokenKind::LeftBracket => {
502 self.advance();
503 let mut elems = Vec::new();
504 while !self.at(TokenKind::RightBracket) && !self.at(TokenKind::Eof) {
505 elems.push(self.parse_expr()?);
506 if self.at(TokenKind::Comma) {
507 self.advance();
508 }
509 }
510 self.expect(TokenKind::RightBracket)?;
511 return Ok(Expr::Literal(Literal::Array(elems)));
512 }
513 TokenKind::LeftBrace => {
514 self.advance();
515 let mut stmts = Vec::new();
516 while !self.at(TokenKind::RightBrace) && !self.at(TokenKind::Eof) {
517 if self.at(TokenKind::Let) {
518 self.advance();
519 let name = self.expect_ident()?;
520 self.expect(TokenKind::Eq)?;
521 let value = self.parse_expr()?;
522 self.expect(TokenKind::Semicolon)?;
523 stmts.push(Stmt::Let {
524 name,
525 value,
526 span: self.current().span,
527 });
528 } else if self.at(TokenKind::State) {
529 let sd = self.parse_state_decl()?;
530 stmts.push(Stmt::StateDecl(sd));
531 } else {
532 stmts.push(Stmt::Expr(self.parse_expr()?));
533 if self.at(TokenKind::Semicolon) {
534 self.advance();
535 }
536 }
537 }
538 self.expect(TokenKind::RightBrace)?;
539 return Ok(Expr::Block { stmts, span });
540 }
541 TokenKind::If => {
542 self.advance();
543 let cond = Box::new(self.parse_expr()?);
544 self.expect(TokenKind::LeftBrace)?;
545 let then_branch = Box::new(self.parse_expr()?);
546 self.expect(TokenKind::RightBrace)?;
547 let else_branch = if self.at(TokenKind::Else) {
548 self.advance();
549 self.expect(TokenKind::LeftBrace)?;
550 let e = self.parse_expr()?;
551 self.expect(TokenKind::RightBrace)?;
552 Some(Box::new(e))
553 } else {
554 None
555 };
556 return Ok(Expr::If {
557 cond,
558 then_branch,
559 else_branch,
560 span,
561 });
562 }
563 TokenKind::For => {
564 self.advance();
565 let var = self.expect_ident()?;
566 self.expect(TokenKind::In)?;
567 let iter = Box::new(self.parse_expr()?);
568 self.expect(TokenKind::LeftBrace)?;
569 let body = Box::new(self.parse_expr()?);
570 self.expect(TokenKind::RightBrace)?;
571 return Ok(Expr::For { var, iter, body, span });
572 }
573 TokenKind::Ident(_) => {
574 let name = self.expect_ident()?;
575 if self.at(TokenKind::LeftParen) {
576 self.advance();
577 let (args, slot_args) = if !self.at(TokenKind::RightParen) && self.at_ident_then_colon() {
578 let mut slot_args = Vec::new();
579 while !self.at(TokenKind::RightParen) && !self.at(TokenKind::Eof) {
580 let slot_name = self.expect_ident()?;
581 self.expect(TokenKind::Colon)?;
582 let e = self.parse_expr()?;
583 slot_args.push((slot_name, e));
584 if self.at(TokenKind::Comma) {
585 self.advance();
586 }
587 }
588 (Vec::new(), Some(slot_args))
589 } else {
590 let mut args = Vec::new();
591 if !self.at(TokenKind::RightParen) {
592 args.push(self.parse_expr()?);
593 while self.at(TokenKind::Comma) {
594 self.advance();
595 args.push(self.parse_expr()?);
596 }
597 }
598 (args, None)
599 };
600 self.expect(TokenKind::RightParen)?;
601 return Ok(Expr::Call {
602 callee: name,
603 args,
604 slot_args,
605 span,
606 });
607 }
608 if let Some(kind) = ElementKind::from_token_kind(&TokenKind::Ident(name.clone())) {
609 return self.parse_element_props_and_children(kind, span);
611 }
612 if self.at(TokenKind::Eq) {
613 self.advance();
614 let value = self.parse_expr()?;
615 return Ok(Expr::Assignment { name, value: Box::new(value), span });
616 }
617 return Ok(Expr::Ident(name, span));
618 }
619 _ => {}
620 }
621
622 if let Some(kind) = ElementKind::from_token_kind(&self.current().kind) {
624 let span = self.current().span;
625 self.advance();
626 return self.parse_element_props_and_children(kind, span);
627 }
628
629 Err(NewtError::parse(
630 self.current().span,
631 format!("expected expression, got {}", self.current().kind),
632 ))
633 }
634
635 fn parse_element_props_and_children(&mut self, kind: ElementKind, span: Span) -> Result<Expr, NewtError> {
636 let mut props = Vec::new();
637 let mut children = Vec::new();
638
639 if self.at(TokenKind::LeftParen) {
641 self.advance();
642 if matches!(self.current().kind, TokenKind::String(_))
643 && (kind == ElementKind::Text || kind == ElementKind::Button)
644 {
645 let s = match &self.current().kind {
646 TokenKind::String(x) => x.clone(),
647 _ => unreachable!(),
648 };
649 self.advance();
650 props.push(Prop {
651 name: PropName::Content,
652 value: PropValue::String(s),
653 span: self.current().span,
654 });
655 while self.at(TokenKind::Comma) {
656 self.advance();
657 self.parse_prop_or_semantic_tokens(&mut props)?;
658 }
659 self.expect(TokenKind::RightParen)?;
660 } else if matches!(self.current().kind, TokenKind::InterpolatedString(_))
661 && (kind == ElementKind::Text || kind == ElementKind::Button)
662 {
663 let (parts, ispan) = match &self.current().kind {
664 TokenKind::InterpolatedString(p) => (p.clone(), self.current().span),
665 _ => unreachable!(),
666 };
667 self.advance();
668 let expr = self.build_interp_expr(parts, ispan)?;
669 props.push(Prop {
670 name: PropName::Content,
671 value: PropValue::Expr(expr),
672 span: ispan,
673 });
674 while self.at(TokenKind::Comma) {
675 self.advance();
676 self.parse_prop_or_semantic_tokens(&mut props)?;
677 }
678 self.expect(TokenKind::RightParen)?;
679 } else if self.at_ident_then_colon() || self.is_prop_keyword() || self.at_semantic_token() {
680 while !self.at(TokenKind::RightParen) && !self.at(TokenKind::Eof) {
681 self.parse_prop_or_semantic_tokens(&mut props)?;
682 if self.at(TokenKind::Comma) {
683 self.advance();
684 }
685 }
686 self.expect(TokenKind::RightParen)?;
687 } else {
688 while !self.at(TokenKind::RightParen) && !self.at(TokenKind::Eof) {
689 children.push(self.parse_expr()?);
690 if self.at(TokenKind::Comma) {
691 self.advance();
692 }
693 }
694 self.expect(TokenKind::RightParen)?;
695 }
696 }
697
698 if self.at(TokenKind::LeftParen) {
700 self.advance();
701 while !self.at(TokenKind::RightParen) && !self.at(TokenKind::Eof) {
702 children.push(self.parse_expr()?);
703 if self.at(TokenKind::Comma) {
704 self.advance();
705 }
706 }
707 self.expect(TokenKind::RightParen)?;
708 }
709
710 if self.at(TokenKind::LeftBrace) {
712 self.advance();
713 let mut in_first_brace = true;
714 while !self.at(TokenKind::RightBrace) && !self.at(TokenKind::Eof) {
715 if in_first_brace && (self.at_semantic_token() || self.at_ident_then_colon() || self.is_prop_keyword()) {
716 self.parse_prop_or_semantic_tokens(&mut props)?;
717 if self.at(TokenKind::Comma) {
718 self.advance();
719 }
720 } else if in_first_brace && self.at_ident() && !self.at_ident_then_colon() {
721 in_first_brace = false;
723 children.push(self.parse_expr()?);
724 if self.at(TokenKind::Comma) {
725 self.advance();
726 }
727 } else {
728 in_first_brace = false;
729 children.push(self.parse_expr()?);
730 if self.at(TokenKind::Comma) {
731 self.advance();
732 }
733 }
734 }
735 self.expect(TokenKind::RightBrace)?;
736 if self.at(TokenKind::LeftBrace) {
738 self.advance();
739 while !self.at(TokenKind::RightBrace) && !self.at(TokenKind::Eof) {
740 children.push(self.parse_expr()?);
741 if self.at(TokenKind::Comma) {
742 self.advance();
743 }
744 }
745 self.expect(TokenKind::RightBrace)?;
746 }
747 }
748
749 Ok(Expr::Element {
750 kind,
751 props,
752 children,
753 span,
754 })
755 }
756
757 fn build_interp_expr(
759 &self,
760 parts: Vec<crate::lexer::InterpPart>,
761 span: Span,
762 ) -> Result<Expr, NewtError> {
763 use crate::lexer::InterpPart;
764 let mut segments = Vec::with_capacity(parts.len());
765 for part in parts {
766 match part {
767 InterpPart::Literal(s) => {
768 segments.push(InterpSegment::Literal(s));
769 }
770 InterpPart::ExprSource(src) => {
771 let mut sub_parser = Parser::new(&src, None)?;
772 let expr = sub_parser.parse_expr()?;
773 segments.push(InterpSegment::Expr(Box::new(expr)));
774 }
775 }
776 }
777 Ok(Expr::InterpolatedString { parts: segments, span })
778 }
779
780 fn is_prop_keyword(&self) -> bool {
781 matches!(
782 self.current().kind,
783 TokenKind::Width
784 | TokenKind::Height
785 | TokenKind::Fill
786 | TokenKind::Stroke
787 | TokenKind::Radius
788 | TokenKind::Padding
789 | TokenKind::Gap
790 | TokenKind::Grow
791 | TokenKind::Shrink
792 | TokenKind::Align
793 | TokenKind::Justify
794 | TokenKind::Direction
795 | TokenKind::FontSize
796 | TokenKind::FontWeight
797 | TokenKind::Shadow
798 )
799 }
800
801 fn at_semantic_token(&self) -> bool {
803 if let TokenKind::Ident(ref s) = self.current().kind {
804 semantic_token_props(s).is_some()
805 } else {
806 false
807 }
808 }
809
810 fn parse_prop_or_semantic_tokens(&mut self, out: &mut Vec<Prop>) -> Result<(), NewtError> {
813 if let TokenKind::Ident(ref s) = self.current().kind {
815 if !self.at_ident_then_colon() {
816 if let Some(expanded) = semantic_token_props(s) {
817 let span = self.current().span;
818 self.advance();
819 for (name, value) in expanded {
820 out.push(Prop { name, value, span });
821 }
822 return Ok(());
823 }
824 }
825 }
826 out.push(self.parse_prop()?);
827 Ok(())
828 }
829
830 fn parse_prop(&mut self) -> Result<Prop, NewtError> {
831 let span = self.current().span;
832 let name = match &self.current().kind {
833 TokenKind::Ident(s) => {
834 let n = s.clone();
835 self.advance();
836 PropName::Ident(n)
837 }
838 TokenKind::Width => {
839 self.advance();
840 PropName::Width
841 }
842 TokenKind::Height => {
843 self.advance();
844 PropName::Height
845 }
846 TokenKind::Fill => {
847 self.advance();
848 PropName::Fill
849 }
850 TokenKind::Stroke => {
851 self.advance();
852 PropName::Stroke
853 }
854 TokenKind::Radius => {
855 self.advance();
856 PropName::Radius
857 }
858 TokenKind::Padding => {
859 self.advance();
860 PropName::Padding
861 }
862 TokenKind::Gap => {
863 self.advance();
864 PropName::Gap
865 }
866 TokenKind::Grow => {
867 self.advance();
868 PropName::Grow
869 }
870 TokenKind::Shrink => {
871 self.advance();
872 PropName::Shrink
873 }
874 TokenKind::Align => {
875 self.advance();
876 PropName::Align
877 }
878 TokenKind::Justify => {
879 self.advance();
880 PropName::Justify
881 }
882 TokenKind::Direction => {
883 self.advance();
884 PropName::Direction
885 }
886 TokenKind::FontSize => {
887 self.advance();
888 PropName::FontSize
889 }
890 TokenKind::FontWeight => {
891 self.advance();
892 PropName::FontWeight
893 }
894 TokenKind::Shadow => {
895 self.advance();
896 PropName::Shadow
897 }
898 _ => {
899 return Err(NewtError::parse(
900 span,
901 "expected property name",
902 ));
903 }
904 };
905 self.expect(TokenKind::Colon)?;
906 let value = self.parse_prop_value()?;
907 Ok(Prop { name, value, span })
908 }
909
910 fn parse_prop_value(&mut self) -> Result<PropValue, NewtError> {
911 match &self.current().kind {
912 TokenKind::Number(n) => {
913 let v = *n;
914 self.advance();
915 Ok(PropValue::Number(v))
916 }
917 TokenKind::String(s) => {
918 let v = s.clone();
919 self.advance();
920 Ok(PropValue::String(v))
921 }
922 TokenKind::InterpolatedString(parts) => {
923 let parts = parts.clone();
924 let span = self.current().span;
925 self.advance();
926 let expr = self.build_interp_expr(parts, span)?;
927 Ok(PropValue::Expr(expr))
928 }
929 TokenKind::HexColor(r, g, b, a) => {
930 let (r, g, b, a) = (*r, *g, *b, *a);
931 self.advance();
932 Ok(PropValue::Color { r, g, b, a })
933 }
934 _ => {
935 let e = self.parse_expr()?;
936 Ok(PropValue::Expr(e))
937 }
938 }
939 }
940}
941
942const TOP_LEVEL_KEYWORDS: &[&str] = &["import", "theme", "use", "let", "state", "component", "screen"];
944
945fn levenshtein(a: &str, b: &str) -> usize {
946 let a: Vec<char> = a.chars().collect();
947 let b: Vec<char> = b.chars().collect();
948 let mut prev = (0..=b.len()).collect::<Vec<_>>();
949 for (i, ca) in a.iter().enumerate() {
950 let mut curr = vec![i + 1];
951 for (j, cb) in b.iter().enumerate() {
952 let cost = if ca == cb { 0 } else { 1 };
953 curr.push((prev[j] + cost).min(prev[j + 1] + 1).min(curr[j] + 1));
954 }
955 prev = curr;
956 }
957 prev[b.len()]
958}
959
960fn closest_top_level_keyword(ident: &str) -> Option<String> {
961 let ident_lower = ident.to_lowercase();
962 TOP_LEVEL_KEYWORDS
963 .iter()
964 .min_by_key(|kw| levenshtein(&ident_lower, kw))
965 .filter(|kw| levenshtein(&ident_lower, kw) <= 2)
966 .map(|s| (*s).to_string())
967}
968
969fn semantic_token_props(name: &str) -> Option<Vec<(PropName, PropValue)>> {
972 match name {
973 "primary" => Some(vec![
975 (PropName::Fill, PropValue::Color { r: 124, g: 58, b: 237, a: 255 }),
976 (PropName::Ident("textColor".into()), PropValue::Color { r: 255, g: 255, b: 255, a: 255 }),
977 ]),
978 "secondary" => Some(vec![
979 (PropName::Fill, PropValue::Color { r: 107, g: 114, b: 128, a: 255 }),
980 (PropName::Ident("textColor".into()), PropValue::Color { r: 255, g: 255, b: 255, a: 255 }),
981 ]),
982 "danger" => Some(vec![
983 (PropName::Fill, PropValue::Color { r: 239, g: 68, b: 68, a: 255 }),
984 (PropName::Ident("textColor".into()), PropValue::Color { r: 255, g: 255, b: 255, a: 255 }),
985 ]),
986 "success" => Some(vec![
987 (PropName::Fill, PropValue::Color { r: 16, g: 185, b: 129, a: 255 }),
988 (PropName::Ident("textColor".into()), PropValue::Color { r: 255, g: 255, b: 255, a: 255 }),
989 ]),
990 "warning" => Some(vec![
991 (PropName::Fill, PropValue::Color { r: 245, g: 158, b: 11, a: 255 }),
992 (PropName::Ident("textColor".into()), PropValue::Color { r: 255, g: 255, b: 255, a: 255 }),
993 ]),
994 "muted" => Some(vec![
995 (PropName::Fill, PropValue::Color { r: 243, g: 244, b: 246, a: 255 }),
996 (PropName::Ident("textColor".into()), PropValue::Color { r: 107, g: 114, b: 128, a: 255 }),
997 ]),
998 "ghost" => Some(vec![
999 (PropName::Fill, PropValue::Color { r: 0, g: 0, b: 0, a: 0 }),
1000 (PropName::Stroke, PropValue::Color { r: 229, g: 231, b: 235, a: 255 }),
1001 ]),
1002
1003 "bold" => Some(vec![
1005 (PropName::FontWeight, PropValue::String("700".into())),
1006 ]),
1007 "semibold" => Some(vec![
1008 (PropName::FontWeight, PropValue::String("600".into())),
1009 ]),
1010 "heading" => Some(vec![
1011 (PropName::FontSize, PropValue::Number(24.0)),
1012 (PropName::FontWeight, PropValue::String("700".into())),
1013 ]),
1014 "subheading" => Some(vec![
1015 (PropName::FontSize, PropValue::Number(18.0)),
1016 (PropName::FontWeight, PropValue::String("600".into())),
1017 ]),
1018 "caption" => Some(vec![
1019 (PropName::FontSize, PropValue::Number(12.0)),
1020 ]),
1021 "small" => Some(vec![
1022 (PropName::FontSize, PropValue::Number(14.0)),
1023 ]),
1024
1025 "compact" => Some(vec![
1027 (PropName::Padding, PropValue::Number(8.0)),
1028 (PropName::Radius, PropValue::Number(4.0)),
1029 ]),
1030 "comfortable" => Some(vec![
1031 (PropName::Padding, PropValue::Number(16.0)),
1032 (PropName::Radius, PropValue::Number(8.0)),
1033 ]),
1034 "spacious" => Some(vec![
1035 (PropName::Padding, PropValue::Number(24.0)),
1036 (PropName::Radius, PropValue::Number(12.0)),
1037 ]),
1038 "rounded" => Some(vec![
1039 (PropName::Radius, PropValue::Number(999.0)),
1040 ]),
1041 "pill" => Some(vec![
1042 (PropName::Radius, PropValue::Number(999.0)),
1043 (PropName::Padding, PropValue::Number(8.0)),
1044 ]),
1045
1046 "elevated" => Some(vec![
1048 (PropName::Shadow, PropValue::Number(8.0)),
1049 ]),
1050 "floating" => Some(vec![
1051 (PropName::Shadow, PropValue::Number(16.0)),
1052 ]),
1053
1054 _ => None,
1055 }
1056}