1use crate::ast::*;
6use std::collections::BTreeMap;
7
8const MAX_SOURCE_BYTES: usize = 1 << 20;
9const MAX_TOKENS: usize = 100_000;
10const MAX_NESTING: usize = 64;
11
12#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
14pub struct Token {
15 pub kind: String,
17 pub text: String,
19 pub span: Span,
21}
22
23#[derive(Clone, Debug)]
24struct LexToken {
25 token: Token,
26 value: Option<String>,
27}
28
29pub fn tokenize(source: &str, module: &str) -> Result<Vec<Token>, Vec<Diagnostic>> {
31 lex(source, module).map(|tokens| tokens.into_iter().map(|token| token.token).collect())
32}
33
34pub fn parse(source: &str, module: &str) -> Result<Vec<Item>, Vec<Diagnostic>> {
36 if source.len() > MAX_SOURCE_BYTES {
37 return Err(vec![Diagnostic::new(
38 "E_LIMIT",
39 "source exceeds the 1 MiB limit",
40 Span::new(module, 0, source.len()),
41 )]);
42 }
43 let tokens = lex(source, module)?
44 .into_iter()
45 .filter(|token| token.token.kind != "comment")
46 .collect();
47 let mut parser = Parser {
48 tokens,
49 at: 0,
50 module: module.into(),
51 source_len: source.len(),
52 nesting: 0,
53 };
54 parser.module_items()
55}
56
57fn lex(source: &str, module: &str) -> Result<Vec<LexToken>, Vec<Diagnostic>> {
58 if source.len() > MAX_SOURCE_BYTES {
59 return Err(vec![Diagnostic::new(
60 "E_LIMIT",
61 "source exceeds the 1 MiB limit",
62 Span::new(module, 0, source.len()),
63 )]);
64 }
65 let mut tokens = Vec::new();
66 let mut at = 0;
67 while at < source.len() {
68 let start = at;
69 let ch = source[at..].chars().next().expect("valid UTF-8 boundary");
70 if ch.is_whitespace() {
71 at += ch.len_utf8();
72 continue;
73 }
74 let (kind, text_end, value) = if source[at..].starts_with("//") {
75 let end = source[at..]
76 .find('\n')
77 .map_or(source.len(), |offset| at + offset);
78 ("comment", end, None)
79 } else if ch == '"' {
80 at += 1;
81 let mut value = String::new();
82 let mut closed = false;
83 while at < source.len() {
84 let current = source[at..].chars().next().expect("valid UTF-8 boundary");
85 if current == '"' {
86 at += 1;
87 closed = true;
88 break;
89 }
90 if current == '\\' {
91 let escape_at = at;
92 at += 1;
93 let Some(escaped) = source[at..].chars().next() else {
94 return Err(vec![diagnostic(
95 module,
96 "E_LEX",
97 "unterminated string",
98 start,
99 source.len(),
100 )]);
101 };
102 match escaped {
103 'n' => value.push('\n'),
104 'r' => value.push('\r'),
105 't' => value.push('\t'),
106 '"' => value.push('"'),
107 '\\' => value.push('\\'),
108 _ => {
109 return Err(vec![diagnostic(
110 module,
111 "E_LEX",
112 "unsupported string escape",
113 escape_at,
114 at + escaped.len_utf8(),
115 )]);
116 }
117 };
118 at += escaped.len_utf8();
119 } else {
120 value.push(current);
121 at += current.len_utf8();
122 }
123 }
124 if !closed {
125 return Err(vec![diagnostic(
126 module,
127 "E_LEX",
128 "unterminated string",
129 start,
130 source.len(),
131 )]);
132 }
133 ("string", at, Some(value))
134 } else if ch.is_ascii_digit() {
135 at += 1;
136 while source.as_bytes().get(at).is_some_and(u8::is_ascii_digit) {
137 at += 1;
138 }
139 if source.as_bytes().get(at) == Some(&b'.')
140 && source
141 .as_bytes()
142 .get(at + 1)
143 .is_some_and(u8::is_ascii_digit)
144 {
145 at += 1;
146 while source.as_bytes().get(at).is_some_and(u8::is_ascii_digit) {
147 at += 1;
148 }
149 }
150 ("number", at, None)
151 } else if ch.is_ascii_alphabetic() || ch == '_' {
152 at += ch.len_utf8();
153 while let Some(next) = source[at..].chars().next() {
154 if next.is_ascii_alphanumeric() || next == '_' {
155 at += next.len_utf8();
156 } else {
157 break;
158 }
159 }
160 let word = &source[start..at];
161 (
162 if is_keyword(word) {
163 "keyword"
164 } else {
165 "identifier"
166 },
167 at,
168 None,
169 )
170 } else if source[at..].starts_with("&&") || source[at..].starts_with("||") {
171 let legacy = &source[at..at + 2];
172 let replacement = if legacy == "&&" { "and" } else { "or" };
173 return Err(vec![diagnostic(
174 module,
175 "E_PARSE",
176 &format!("`{legacy}` is no longer supported; use `{replacement}`"),
177 start,
178 start + legacy.len(),
179 )]);
180 } else if let Some(punctuation) = punctuation_at(source, at) {
181 at += punctuation.len();
182 ("punctuation", at, None)
183 } else {
184 return Err(vec![diagnostic(
185 module,
186 "E_LEX",
187 "unexpected character",
188 start,
189 start + ch.len_utf8(),
190 )]);
191 };
192 let text = source[start..text_end].to_owned();
193 tokens.push(LexToken {
194 token: Token {
195 kind: kind.into(),
196 text,
197 span: Span::new(module, start, text_end),
198 },
199 value,
200 });
201 if tokens.len() > MAX_TOKENS {
202 return Err(vec![diagnostic(
203 module,
204 "E_LIMIT",
205 "token count exceeds the 100000 limit",
206 start,
207 text_end,
208 )]);
209 }
210 at = text_end;
211 }
212 Ok(tokens)
213}
214
215fn punctuation_at(source: &str, at: usize) -> Option<&'static str> {
216 for punctuation in [
217 "...", "->", "=>", "==", "!=", "<=", ">=", "{", "}", "(", ")", "[", "]", ",", ";", ":",
218 ".", "=", "+", "-", "*", "/", "%", "@", "<", ">", "!", "?",
219 ] {
220 if source[at..].starts_with(punctuation) {
221 return Some(punctuation);
222 }
223 }
224 None
225}
226
227fn is_keyword(word: &str) -> bool {
228 matches!(
229 word,
230 "class"
231 | "type"
232 | "enum"
233 | "match"
234 | "func"
235 | "trait"
236 | "impl"
237 | "for"
238 | "system"
239 | "of"
240 | "import"
241 | "export"
242 | "let"
243 | "mut"
244 | "if"
245 | "else"
246 | "while"
247 | "in"
248 | "ret"
249 | "return"
250 | "break"
251 | "continue"
252 | "true"
253 | "false"
254 | "and"
255 | "or"
256 )
257}
258
259fn diagnostic(module: &str, code: &str, message: &str, start: usize, end: usize) -> Diagnostic {
260 Diagnostic::new(code, message, Span::new(module, start, end))
261}
262
263struct Parser {
264 tokens: Vec<LexToken>,
265 at: usize,
266 module: String,
267 source_len: usize,
268 nesting: usize,
269}
270
271impl Parser {
272 fn module_items(&mut self) -> Result<Vec<Item>, Vec<Diagnostic>> {
273 let mut items = Vec::new();
274 while !self.eof() {
275 let item = match self.text() {
276 Some("type") => Item::Class(self.class()?),
277 Some("class") => {
278 return self
279 .error("`class` has been renamed to `type`; migrate this declaration");
280 }
281 Some("enum") => Item::Enum(self.enum_item()?),
282 Some("func") => Item::Function(self.function(false)?),
283 Some("trait") => Item::Trait(self.trait_item()?),
284 Some("impl") => Item::Implementation(self.implementation()?),
285 Some("system") => Item::System(self.system()?),
286 Some("import") => self.import()?,
287 Some("export") => self.export()?,
288 _ => Item::Statement(self.statement()?),
289 };
290 items.push(item);
291 self.optional(";");
292 }
293 Ok(items)
294 }
295
296 fn class(&mut self) -> Result<Class, Vec<Diagnostic>> {
297 let start = self.expect("type")?.span.start;
298 let (name, _) = self.identifier()?;
299 self.expect("{")?;
300 let mut fields = Vec::new();
301 let mut methods = Vec::new();
302 while !self.check("}") {
303 if self.eof() {
304 return self.error("expected `}` to close class");
305 }
306 if self.check("func") {
307 methods.push(self.function(false)?);
308 self.separator();
309 continue;
310 }
311 let (field_name, field_span) = self.identifier()?;
312 self.expect(":")?;
313 let ty = self.ty()?;
314 let default = if self.optional("=") {
315 Some(self.expression(0)?)
316 } else {
317 None
318 };
319 let end = default
320 .as_ref()
321 .map_or(field_span.end, |expr| expr.span.end);
322 fields.push(Field {
323 name: field_name,
324 ty,
325 default,
326 span: Span::new(&self.module, field_span.start, end),
327 });
328 self.separator();
329 }
330 let end = self.expect("}")?.span.end;
331 Ok(Class {
332 name,
333 fields,
334 methods,
335 span: Span::new(&self.module, start, end),
336 })
337 }
338
339 fn enum_item(&mut self) -> Result<Enum, Vec<Diagnostic>> {
340 let start = self.expect("enum")?.span.start;
341 let (name, _) = self.identifier()?;
342 self.expect("{")?;
343 let mut cases = Vec::new();
344 while !self.check("}") {
345 if self.eof() {
346 return self.error("expected `}` to close enum");
347 }
348 let (case_name, case_span) = self.identifier()?;
349 let mut payload = Vec::new();
350 let end = if self.optional("(") {
351 while !self.check(")") {
352 payload.push(self.ty()?);
353 if !self.optional(",") {
354 break;
355 }
356 }
357 self.expect(")")?.span.end
358 } else {
359 case_span.end
360 };
361 cases.push(EnumCase {
362 name: case_name,
363 payload,
364 span: Span::new(&self.module, case_span.start, end),
365 });
366 self.separator();
367 }
368 let end = self.expect("}")?.span.end;
369 Ok(Enum {
370 name,
371 cases,
372 span: Span::new(&self.module, start, end),
373 })
374 }
375
376 fn function(&mut self, signature_only: bool) -> Result<Function, Vec<Diagnostic>> {
377 let start = self.expect("func")?.span.start;
378 let (name, _) = self.identifier()?;
379 self.expect("(")?;
380 let mut parameters = Vec::new();
381 while !self.check(")") {
382 let (parameter_name, parameter_span) = self.identifier()?;
383 self.expect(":")?;
384 let ty = self.ty()?;
385 parameters.push(Parameter {
386 name: parameter_name,
387 ty,
388 span: parameter_span,
389 });
390 if !self.optional(",") {
391 break;
392 }
393 }
394 self.expect(")")?;
395 self.expect("->")?;
396 let returns = self.ty()?;
397 let body = if signature_only {
398 if !self.optional(";") {
399 return self.error("trait methods require a signature ending in `;`; default method bodies are not supported");
400 }
401 Vec::new()
402 } else {
403 if self.check(";") {
404 return self
405 .error("functions require a body; only trait method signatures end in `;`");
406 }
407 self.block()?
408 };
409 let end = body
410 .last()
411 .map_or_else(|| self.previous_end(), |statement| statement.span.end);
412 Ok(Function {
413 name,
414 parameters,
415 returns,
416 body,
417 span: Span::new(&self.module, start, end),
418 })
419 }
420
421 fn trait_item(&mut self) -> Result<Trait, Vec<Diagnostic>> {
422 let start = self.expect("trait")?.span.start;
423 let (name, _) = self.identifier()?;
424 self.expect("{")?;
425 let mut methods = Vec::new();
426 while !self.check("}") {
427 if self.eof() {
428 return self.error("expected `}` to close trait");
429 }
430 if !self.check("func") {
431 return self.error("expected trait method signature");
432 }
433 methods.push(self.function(true)?);
434 self.separator();
435 }
436 let end = self.expect("}")?.span.end;
437 Ok(Trait {
438 name,
439 methods,
440 span: Span::new(&self.module, start, end),
441 })
442 }
443
444 fn implementation(&mut self) -> Result<Implementation, Vec<Diagnostic>> {
445 let start = self.expect("impl")?.span.start;
446 let (first, _) = self.qualified_identifier()?;
447 let (trait_name, class) = if self.optional("for") {
448 let (class, _) = self.qualified_identifier()?;
449 (Some(first), class)
450 } else {
451 (None, first)
452 };
453 self.expect("{")?;
454 let mut methods = Vec::new();
455 while !self.check("}") {
456 if self.eof() {
457 return self.error("expected `}` to close impl");
458 }
459 if !self.check("func") {
460 return self.error("expected implementation method");
461 }
462 methods.push(self.function(false)?);
463 self.separator();
464 }
465 let end = self.expect("}")?.span.end;
466 Ok(Implementation {
467 trait_name,
468 class,
469 methods,
470 span: Span::new(&self.module, start, end),
471 })
472 }
473
474 fn system(&mut self) -> Result<System, Vec<Diagnostic>> {
475 let start = self.expect("system")?.span.start;
476 let (name, _) = self.identifier()?;
477 self.expect("of")?;
478 let mut bindings = Vec::new();
479 if self.optional("(") {
480 while !self.check(")") {
481 let (binding_name, span) = self.identifier()?;
482 self.expect(":")?;
483 let ty = self.ty()?;
484 bindings.push(Parameter {
485 name: binding_name,
486 ty,
487 span,
488 });
489 if !self.optional(",") {
490 break;
491 }
492 }
493 self.expect(")")?;
494 } else {
495 let (component, span) = self.qualified_identifier()?;
496 bindings.push(Parameter {
497 name: "self".into(),
498 ty: Type::named(component),
499 span,
500 });
501 }
502 self.expect("{")?;
503 let mut callbacks = Vec::new();
504 while !self.check("}") {
505 if !self.check("func") {
506 return self.error(
507 "systems declare lifecycle functions: func frame(dt: Number) -> Unit { ... }",
508 );
509 }
510 callbacks.push(self.function(false)?);
511 self.separator();
512 }
513 let end = self.expect("}")?.span.end;
514 Ok(System {
515 name,
516 bindings,
517 callbacks,
518 span: Span::new(&self.module, start, end),
519 })
520 }
521
522 fn import(&mut self) -> Result<Item, Vec<Diagnostic>> {
523 let start = self.expect("import")?.span.start;
524 let (mut module, _) = self.identifier()?;
525 while self.optional(".") {
526 let (part, _) = self.identifier()?;
527 module.push('.');
528 module.push_str(&part);
529 }
530 let end = self.previous_end();
531 Ok(Item::Import {
532 module,
533 span: Span::new(&self.module, start, end),
534 })
535 }
536 fn export(&mut self) -> Result<Item, Vec<Diagnostic>> {
537 let start = self.expect("export")?.span.start;
538 let (name, span) = self.identifier()?;
539 Ok(Item::Export {
540 name,
541 span: Span::new(&self.module, start, span.end),
542 })
543 }
544
545 fn block(&mut self) -> Result<Vec<Stmt>, Vec<Diagnostic>> {
546 self.enter()?;
547 self.expect("{")?;
548 let mut body = Vec::new();
549 while !self.check("}") {
550 if self.eof() {
551 self.leave();
552 return self.error("expected `}` to close block");
553 }
554 body.push(self.statement()?);
555 self.optional(";");
556 }
557 self.expect("}")?;
558 self.leave();
559 Ok(body)
560 }
561
562 fn statement(&mut self) -> Result<Stmt, Vec<Diagnostic>> {
563 self.enter()?;
564 let result = self.statement_inner();
565 self.leave();
566 result
567 }
568 fn statement_inner(&mut self) -> Result<Stmt, Vec<Diagnostic>> {
569 let start = self.current_start();
570 match self.text() {
571 Some("let") => {
572 self.advance();
573 let mutable = self.optional("mut");
574 let (name, _) = self.identifier()?;
575 let ty = if self.optional(":") {
576 Some(self.ty()?)
577 } else {
578 None
579 };
580 self.expect("=")?;
581 let value = self.expression(0)?;
582 let end = value.span.end;
583 Ok(Stmt {
584 kind: StmtKind::Let {
585 name,
586 ty,
587 mutable,
588 value,
589 },
590 span: Span::new(&self.module, start, end),
591 })
592 }
593 Some("ret") | Some("return") => {
594 self.advance();
595 let value = if self.check(";") || self.check("}") || self.eof() {
596 None
597 } else {
598 Some(self.expression(0)?)
599 };
600 let end = value
601 .as_ref()
602 .map_or_else(|| self.previous_end(), |expr| expr.span.end);
603 Ok(Stmt {
604 kind: StmtKind::Return(value),
605 span: Span::new(&self.module, start, end),
606 })
607 }
608 Some("if") => {
609 self.advance();
610 let condition = self.expression(0)?;
611 let then_body = self.block()?;
612 let else_body = if self.optional("else") {
613 if self.check("if") {
614 vec![self.statement()?]
615 } else {
616 self.block()?
617 }
618 } else {
619 Vec::new()
620 };
621 Ok(Stmt {
622 kind: StmtKind::If {
623 condition,
624 then_body,
625 else_body,
626 },
627 span: Span::new(&self.module, start, self.previous_end()),
628 })
629 }
630 Some("while") => {
631 self.advance();
632 let condition = self.expression(0)?;
633 let body = self.block()?;
634 Ok(Stmt {
635 kind: StmtKind::While { condition, body },
636 span: Span::new(&self.module, start, self.previous_end()),
637 })
638 }
639 Some("for") => {
640 self.advance();
641 let (name, _) = self.identifier()?;
642 self.expect("in")?;
643 let collection = self.expression(0)?;
644 let body = self.block()?;
645 Ok(Stmt {
646 kind: StmtKind::For {
647 name,
648 collection,
649 body,
650 },
651 span: Span::new(&self.module, start, self.previous_end()),
652 })
653 }
654 Some("break") => {
655 let end = self.advance().token.span.end;
656 Ok(Stmt {
657 kind: StmtKind::Break,
658 span: Span::new(&self.module, start, end),
659 })
660 }
661 Some("continue") => {
662 let end = self.advance().token.span.end;
663 Ok(Stmt {
664 kind: StmtKind::Continue,
665 span: Span::new(&self.module, start, end),
666 })
667 }
668 _ => {
669 let target = self.expression(0)?;
670 if self.optional("=") {
671 let value = self.expression(0)?;
672 let end = value.span.end;
673 Ok(Stmt {
674 kind: StmtKind::Assign { target, value },
675 span: Span::new(&self.module, start, end),
676 })
677 } else {
678 let end = target.span.end;
679 Ok(Stmt {
680 kind: StmtKind::Expr(target),
681 span: Span::new(&self.module, start, end),
682 })
683 }
684 }
685 }
686 }
687
688 fn ty(&mut self) -> Result<Type, Vec<Diagnostic>> {
689 self.enter()?;
690 if self.optional("func") {
691 self.expect("(")?;
692 let mut parameters = Vec::new();
693 while !self.check(")") {
694 parameters.push(self.ty()?);
695 if !self.optional(",") {
696 break;
697 }
698 }
699 self.expect(")")?;
700 self.expect("->")?;
701 let returns = self.ty()?;
702 self.leave();
703 return Ok(Type::function(parameters, returns));
704 }
705 let (name, _) = self.qualified_identifier()?;
706 if self.optional("[") {
707 let mut arguments = Vec::new();
708 while !self.check("]") {
709 arguments.push(self.ty()?);
710 if !self.optional(",") {
711 break;
712 }
713 }
714 self.expect("]")?;
715 self.leave();
716 Ok(match name.as_str() {
717 "List" if arguments.len() == 1 => Type::List(Box::new(arguments.remove(0))),
718 "ComponentReference" if arguments.len() == 1 => {
719 Type::ComponentReference(Box::new(arguments.remove(0)))
720 }
721 "Tensor" if arguments.len() == 1 => Type::Tensor(Box::new(arguments.remove(0))),
722 _ => Type::Applied { name, arguments },
723 })
724 } else {
725 self.leave();
726 Ok(Type::named(name))
727 }
728 }
729
730 fn expression(&mut self, min_binding_power: u8) -> Result<Expr, Vec<Diagnostic>> {
731 self.enter()?;
732 let mut left = self.prefix()?;
733 let mut chain_length = 0;
734 loop {
735 chain_length += 1;
736 if chain_length > MAX_NESTING {
737 return self.error("expression operator chain exceeds nesting limit");
738 }
739 if let Some((left_power, right_power)) = self.infix_binding_power() {
740 if left_power < min_binding_power {
741 break;
742 }
743 let op = self.advance().token.text;
744 let right = self.expression(right_power)?;
745 let span = Span::new(&self.module, left.span.start, right.span.end);
746 left = Expr {
747 kind: ExprKind::Binary {
748 op,
749 left: Box::new(left),
750 right: Box::new(right),
751 },
752 span,
753 };
754 } else {
755 break;
756 }
757 }
758 self.leave();
759 Ok(left)
760 }
761
762 fn prefix(&mut self) -> Result<Expr, Vec<Diagnostic>> {
763 let token = self.current().cloned().ok_or_else(|| {
764 vec![diagnostic(
765 &self.module,
766 "E_PARSE",
767 "expected expression",
768 self.source_len,
769 self.source_len,
770 )]
771 })?;
772 match token.token.kind.as_str() {
773 "number" => {
774 self.advance();
775 self.postfix(Expr {
776 kind: ExprKind::Number(token.token.text),
777 span: token.token.span,
778 })
779 }
780 "string" => {
781 self.advance();
782 self.postfix(Expr {
783 kind: ExprKind::Text(token.value.unwrap_or_default()),
784 span: token.token.span,
785 })
786 }
787 "identifier" | "keyword"
788 if token.token.text == "true" || token.token.text == "false" =>
789 {
790 self.advance();
791 self.postfix(Expr {
792 kind: ExprKind::Bool(token.token.text == "true"),
793 span: token.token.span,
794 })
795 }
796 "identifier" => {
797 self.advance();
798 let mut expr = Expr {
799 kind: ExprKind::Name(token.token.text.clone()),
800 span: token.token.span.clone(),
801 };
802 if is_uppercase_name(&token.token.text) && self.check("{") {
803 expr = self.record(token.token.text, expr.span.start)?;
804 }
805 self.postfix(expr)
806 }
807 "keyword" if token.token.text == "match" => self.match_expression(),
808 "punctuation" if token.token.text == "-" || token.token.text == "!" => {
809 self.advance();
810 let value = if token.token.text == "-"
811 && self
812 .current()
813 .is_some_and(|next| next.token.kind == "number")
814 {
815 let number = self.advance().token;
816 Expr {
817 kind: ExprKind::Number(number.text),
818 span: number.span,
819 }
820 } else {
821 self.expression(13)?
822 };
823 let span = Span::new(&self.module, token.token.span.start, value.span.end);
824 self.postfix(Expr {
825 kind: ExprKind::Unary {
826 op: token.token.text,
827 value: Box::new(value),
828 },
829 span,
830 })
831 }
832 "punctuation" if token.token.text == "(" => {
833 self.advance();
834 if self.optional(")") {
835 self.postfix(Expr {
836 kind: ExprKind::Unit,
837 span: Span::new(&self.module, token.token.span.start, self.previous_end()),
838 })
839 } else {
840 let target = self.expression(0)?;
841 let expr = if self.optional("=") {
842 let value = self.expression(0)?;
843 Expr {
844 span: Span::new(&self.module, target.span.start, value.span.end),
845 kind: ExprKind::Assign {
846 target: Box::new(target),
847 value: Box::new(value),
848 },
849 }
850 } else {
851 target
852 };
853 self.expect(")")?;
854 self.postfix(expr)
855 }
856 }
857 "punctuation" if token.token.text == "[" => self.list(),
858 _ => self.error("expected expression"),
859 }
860 }
861
862 fn match_expression(&mut self) -> Result<Expr, Vec<Diagnostic>> {
863 let start = self.expect("match")?.span.start;
864 let value = self.expression(0)?;
865 self.expect("{")?;
866 let mut arms = Vec::new();
867 while !self.check("}") {
868 if self.eof() {
869 return self.error("expected `}` to close match");
870 }
871 let pattern_start = self.current_start();
872 let pattern = self.pattern()?;
873 self.expect("=>")?;
874 let arm_value = self.expression(0)?;
875 let arm_span = Span::new(&self.module, pattern_start, arm_value.span.end);
876 arms.push(MatchArm {
877 pattern,
878 value: arm_value,
879 span: arm_span,
880 });
881 if !self.optional(",") {
882 break;
883 }
884 }
885 let end = self.expect("}")?.span.end;
886 self.postfix(Expr {
887 kind: ExprKind::Match {
888 value: Box::new(value),
889 arms,
890 },
891 span: Span::new(&self.module, start, end),
892 })
893 }
894
895 fn pattern(&mut self) -> Result<Pattern, Vec<Diagnostic>> {
896 let token = self.current().cloned().ok_or_else(|| {
897 vec![diagnostic(
898 &self.module,
899 "E_PARSE",
900 "expected pattern",
901 self.source_len,
902 self.source_len,
903 )]
904 })?;
905 match token.token.kind.as_str() {
906 "number" => {
907 self.advance();
908 Ok(Pattern::Literal(Box::new(Expr {
909 kind: ExprKind::Number(token.token.text),
910 span: token.token.span,
911 })))
912 }
913 "string" => {
914 self.advance();
915 Ok(Pattern::Literal(Box::new(Expr {
916 kind: ExprKind::Text(token.value.unwrap_or_default()),
917 span: token.token.span,
918 })))
919 }
920 "keyword" if token.token.text == "true" || token.token.text == "false" => {
921 self.advance();
922 Ok(Pattern::Literal(Box::new(Expr {
923 kind: ExprKind::Bool(token.token.text == "true"),
924 span: token.token.span,
925 })))
926 }
927 "punctuation" if token.token.text == "(" => {
928 let start = self.advance().token.span.start;
929 self.expect(")")?;
930 Ok(Pattern::Literal(Box::new(Expr {
931 kind: ExprKind::Unit,
932 span: Span::new(&self.module, start, self.previous_end()),
933 })))
934 }
935 "identifier" => {
936 let (name, _) = self.qualified_identifier()?;
937 if name == "_" {
938 return Ok(Pattern::Wildcard);
939 }
940 if self.check("{") {
941 return self.record_pattern(name);
942 }
943 if self.optional("(") {
944 let mut payload = Vec::new();
945 while !self.check(")") {
946 payload.push(self.pattern()?);
947 if !self.optional(",") {
948 break;
949 }
950 }
951 self.expect(")")?;
952 return Ok(Pattern::Case { name, payload });
953 }
954 if name.contains('.') || matches!(name.as_str(), "None" | "Some" | "Ok" | "Err") {
955 Ok(Pattern::Case {
956 name,
957 payload: Vec::new(),
958 })
959 } else {
960 Ok(Pattern::Binding(name))
961 }
962 }
963 _ => self.error("expected pattern"),
964 }
965 }
966
967 fn record_pattern(&mut self, class: String) -> Result<Pattern, Vec<Diagnostic>> {
968 self.expect("{")?;
969 let mut fields = BTreeMap::new();
970 while !self.check("}") {
971 if self.eof() {
972 return self.error("expected `}` to close record pattern");
973 }
974 let (name, _) = self.identifier()?;
975 let pattern = if self.optional(":") {
976 self.pattern()?
977 } else {
978 Pattern::Binding(name.clone())
979 };
980 if fields.insert(name.clone(), pattern).is_some() {
981 return self.error(&format!("duplicate record pattern field `{name}`"));
982 }
983 if !self.optional(",") {
984 break;
985 }
986 }
987 self.expect("}")?;
988 Ok(Pattern::Record { class, fields })
989 }
990
991 fn typed_intrinsic_ahead(&self, expr: &Expr) -> bool {
992 let Some(name) = expression_path(expr) else {
993 return false;
994 };
995 if !matches!(
996 name.strip_prefix("builtin.").unwrap_or(&name),
997 "get" | "has" | "query" | "bind" | "tensor"
998 ) || !self.check("[")
999 {
1000 return false;
1001 }
1002 let mut depth = 1usize;
1003 for (offset, token) in self.tokens.iter().skip(self.at + 1).enumerate() {
1006 if offset > MAX_NESTING * 4 {
1007 return false;
1008 }
1009 match token.token.text.as_str() {
1010 "[" => {
1011 depth += 1;
1012 if depth > MAX_NESTING {
1013 return false;
1014 }
1015 }
1016 "]" => {
1017 depth -= 1;
1018 if depth == 0 {
1019 return self.tokens.get(self.at + offset + 2).is_none_or(|token| {
1020 matches!(
1021 token.token.text.as_str(),
1022 "(" | ";"
1023 | ")"
1024 | ","
1025 | "]"
1026 | "}"
1027 | "."
1028 | "=="
1029 | "!="
1030 | "["
1031 | "<="
1032 | ">"
1033 | ">="
1034 | "+"
1035 | "-"
1036 | "*"
1037 | "/"
1038 | "%"
1039 | "@"
1040 | "and"
1041 | "or"
1042 )
1043 });
1044 }
1045 }
1046 "." => (),
1047 _ if token.token.kind == "identifier" => (),
1048 _ => return false,
1049 }
1050 }
1051 false
1052 }
1053
1054 fn typed_literal_ahead(&self, expr: &Expr) -> bool {
1055 let numeric = matches!(&expr.kind, ExprKind::Number(_))
1056 || matches!(&expr.kind, ExprKind::Unary { op, value }
1057 if op == "-" && matches!(value.kind, ExprKind::Number(_)));
1058 numeric
1059 && self.check(":")
1060 && self.tokens.get(self.at + 1).is_some_and(|token| {
1061 token.token.kind == "identifier"
1062 && crate::data::named_dtype(&token.token.text).is_some()
1063 })
1064 }
1065
1066 fn postfix(&mut self, mut expr: Expr) -> Result<Expr, Vec<Diagnostic>> {
1067 let mut chain_length = 0;
1068 loop {
1069 chain_length += 1;
1070 if chain_length > MAX_NESTING {
1071 return self.error("expression access chain exceeds nesting limit");
1072 }
1073 if self.typed_intrinsic_ahead(&expr) {
1074 self.expect("[")?;
1075 let ty = self.ty()?;
1076 self.expect("]")?;
1077 let name = expression_path(&expr).expect("typed intrinsic name checked above");
1078 if self.optional("(") {
1079 let mut arguments = Vec::new();
1080 while !self.check(")") {
1081 arguments.push(self.expression(0)?);
1082 if !self.optional(",") {
1083 break;
1084 }
1085 }
1086 let end = self.expect(")")?.span.end;
1087 expr = Expr {
1088 span: Span::new(&self.module, expr.span.start, end),
1089 kind: ExprKind::TypedCall {
1090 name,
1091 ty,
1092 arguments,
1093 },
1094 };
1095 } else {
1096 expr = Expr {
1097 span: Span::new(&self.module, expr.span.start, self.previous_end()),
1098 kind: ExprKind::TypedFunction { name, ty },
1099 };
1100 }
1101 } else if self.typed_literal_ahead(&expr) {
1102 let start = expr.span.start;
1103 self.expect(":")?;
1104 let ty = self.ty()?;
1105 let end = self.previous_end();
1106 expr = Expr {
1107 kind: ExprKind::TypedLiteral {
1108 value: Box::new(expr),
1109 ty,
1110 },
1111 span: Span::new(&self.module, start, end),
1112 };
1113 } else if self.optional("(") {
1114 let mut arguments = Vec::new();
1115 while !self.check(")") {
1116 arguments.push(self.expression(0)?);
1117 if !self.optional(",") {
1118 break;
1119 }
1120 }
1121 let end = self.expect(")")?.span.end;
1122 let start = expr.span.start;
1123 expr = Expr {
1124 kind: ExprKind::Call {
1125 callee: Box::new(expr),
1126 arguments,
1127 },
1128 span: Span::new(&self.module, start, end),
1129 };
1130 } else if self.optional(".") {
1131 let (field, field_span) = self.identifier()?;
1132 let start = expr.span.start;
1133 if field == "convert" && self.optional("[") {
1134 let ty = self.ty()?;
1135 let end = self.expect("]")?.span.end;
1136 expr = Expr {
1137 kind: ExprKind::TypedMethod {
1138 object: Box::new(expr),
1139 method: field,
1140 ty,
1141 },
1142 span: Span::new(&self.module, start, end),
1143 };
1144 continue;
1145 }
1146 if is_uppercase_name(&field) && self.check("{") {
1150 if let Some(prefix) = expression_path(&expr) {
1151 expr = self.record(format!("{prefix}.{field}"), start)?;
1152 } else {
1153 expr = Expr {
1154 kind: ExprKind::Field {
1155 object: Box::new(expr),
1156 field,
1157 },
1158 span: Span::new(&self.module, start, field_span.end),
1159 };
1160 }
1161 } else {
1162 expr = Expr {
1163 kind: ExprKind::Field {
1164 object: Box::new(expr),
1165 field,
1166 },
1167 span: Span::new(&self.module, start, field_span.end),
1168 };
1169 }
1170 } else if self.optional("[") {
1171 let indices = self.indices()?;
1172 let end = self.expect("]")?.span.end;
1173 let start = expr.span.start;
1174 expr = Expr {
1175 kind: ExprKind::Index {
1176 object: Box::new(expr),
1177 indices,
1178 },
1179 span: Span::new(&self.module, start, end),
1180 };
1181 } else if self.optional("?") {
1182 let start = expr.span.start;
1183 expr = Expr {
1184 kind: ExprKind::Propagate(Box::new(expr)),
1185 span: Span::new(&self.module, start, self.previous_end()),
1186 };
1187 } else {
1188 break;
1189 }
1190 }
1191 Ok(expr)
1192 }
1193
1194 fn indices(&mut self) -> Result<Vec<IndexExpr>, Vec<Diagnostic>> {
1195 let mut indices = Vec::new();
1196 while !self.check("]") {
1197 if self.eof() {
1198 return self.error("expected `]` to close index");
1199 }
1200 indices.push(self.index_expr()?);
1201 if !self.optional(",") {
1202 break;
1203 }
1204 }
1205 if indices.is_empty() {
1206 return self.error("index requires at least one selector");
1207 }
1208 Ok(indices)
1209 }
1210
1211 fn index_expr(&mut self) -> Result<IndexExpr, Vec<Diagnostic>> {
1212 if self.optional("...") {
1213 return Ok(IndexExpr::Ellipsis);
1214 }
1215 if matches!(self.text(), Some("None") | Some("newaxis")) {
1216 self.advance();
1217 return Ok(IndexExpr::NewAxis);
1218 }
1219 let start = if self.check(":") {
1220 None
1221 } else {
1222 Some(self.expression(0)?)
1223 };
1224 if !self.optional(":") {
1225 return Ok(IndexExpr::Index(
1226 start.expect("index expression is present"),
1227 ));
1228 }
1229 let stop = if self.check(":") || self.check(",") || self.check("]") {
1230 None
1231 } else {
1232 Some(self.expression(0)?)
1233 };
1234 let step = if self.optional(":") {
1235 if self.check(",") || self.check("]") {
1236 None
1237 } else {
1238 Some(self.expression(0)?)
1239 }
1240 } else {
1241 None
1242 };
1243 Ok(IndexExpr::Slice {
1244 start: start.map(Box::new),
1245 stop: stop.map(Box::new),
1246 step: step.map(Box::new),
1247 })
1248 }
1249
1250 fn list(&mut self) -> Result<Expr, Vec<Diagnostic>> {
1251 let start = self.expect("[")?.span.start;
1252 let mut items = Vec::new();
1253 while !self.check("]") {
1254 if self.eof() {
1255 return self.error("expected `]` to close list");
1256 }
1257 items.push(self.expression(0)?);
1258 if !self.optional(",") {
1259 break;
1260 }
1261 }
1262 let end = self.expect("]")?.span.end;
1263 let expr = if self.optional(":") {
1264 let dtype = self.ty()?;
1265 Expr {
1266 kind: ExprKind::TensorLiteral {
1267 values: items,
1268 dtype,
1269 },
1270 span: Span::new(&self.module, start, self.previous_end()),
1271 }
1272 } else {
1273 Expr {
1274 kind: ExprKind::List(items),
1275 span: Span::new(&self.module, start, end),
1276 }
1277 };
1278 self.postfix(expr)
1279 }
1280
1281 fn record(&mut self, class: String, start: usize) -> Result<Expr, Vec<Diagnostic>> {
1282 self.expect("{")?;
1283 let mut fields = BTreeMap::new();
1284 while !self.check("}") {
1285 if self.eof() {
1286 return self.error("expected `}` to close constructor");
1287 }
1288 let (name, _) = self.identifier()?;
1289 self.expect(":")?;
1290 let value = self.expression(0)?;
1291 if fields.insert(name.clone(), value).is_some() {
1292 return self.error(&format!("duplicate constructor field `{name}`"));
1293 }
1294 if !self.optional(",") {
1295 break;
1296 }
1297 }
1298 let end = self.expect("}")?.span.end;
1299 Ok(Expr {
1300 kind: ExprKind::Record { class, fields },
1301 span: Span::new(&self.module, start, end),
1302 })
1303 }
1304
1305 fn infix_binding_power(&self) -> Option<(u8, u8)> {
1306 Some(match self.text()? {
1307 "or" => (1, 2),
1308 "and" => (3, 4),
1309 "==" | "!=" => (5, 6),
1310 "<" | "<=" | ">" | ">=" => (7, 8),
1311 "+" | "-" => (9, 10),
1312 "*" | "/" | "%" | "@" => (11, 12),
1313 _ => return None,
1314 })
1315 }
1316 fn separator(&mut self) {
1317 if !self.optional(";") {
1318 self.optional(",");
1319 }
1320 }
1321 fn enter(&mut self) -> Result<(), Vec<Diagnostic>> {
1322 self.nesting += 1;
1323 if self.nesting > MAX_NESTING {
1324 self.nesting -= 1;
1325 self.error("nesting exceeds the 64 level limit")
1326 } else {
1327 Ok(())
1328 }
1329 }
1330 fn leave(&mut self) {
1331 self.nesting = self.nesting.saturating_sub(1);
1332 }
1333 fn qualified_identifier(&mut self) -> Result<(String, Span), Vec<Diagnostic>> {
1334 let (mut name, mut span) = self.identifier()?;
1335 while self.optional(".") {
1336 let (part, next) = self.identifier()?;
1337 name.push('.');
1338 name.push_str(&part);
1339 span.end = next.end;
1340 }
1341 Ok((name, span))
1342 }
1343 fn identifier(&mut self) -> Result<(String, Span), Vec<Diagnostic>> {
1344 let token = self.current().cloned().ok_or_else(|| {
1345 vec![diagnostic(
1346 &self.module,
1347 "E_PARSE",
1348 "expected identifier",
1349 self.source_len,
1350 self.source_len,
1351 )]
1352 })?;
1353 if token.token.kind == "identifier" {
1354 self.advance();
1355 Ok((token.token.text, token.token.span))
1356 } else {
1357 self.error("expected identifier")
1358 }
1359 }
1360 fn expect(&mut self, expected: &str) -> Result<Token, Vec<Diagnostic>> {
1361 if self.check(expected) {
1362 Ok(self.advance().token)
1363 } else {
1364 self.error(&format!("expected `{expected}`"))
1365 }
1366 }
1367 fn optional(&mut self, text: &str) -> bool {
1368 if self.check(text) {
1369 self.advance();
1370 true
1371 } else {
1372 false
1373 }
1374 }
1375 fn check(&self, text: &str) -> bool {
1376 self.text() == Some(text)
1377 }
1378 fn text(&self) -> Option<&str> {
1379 self.current().map(|token| token.token.text.as_str())
1380 }
1381 fn current(&self) -> Option<&LexToken> {
1382 self.tokens.get(self.at)
1383 }
1384 fn current_start(&self) -> usize {
1385 self.current()
1386 .map_or(self.source_len, |token| token.token.span.start)
1387 }
1388 fn previous_end(&self) -> usize {
1389 self.tokens
1390 .get(self.at.saturating_sub(1))
1391 .map_or(self.source_len, |token| token.token.span.end)
1392 }
1393 fn advance(&mut self) -> LexToken {
1394 let token = self.tokens[self.at].clone();
1395 self.at += 1;
1396 token
1397 }
1398 fn eof(&self) -> bool {
1399 self.at >= self.tokens.len()
1400 }
1401 fn error<T>(&self, message: &str) -> Result<T, Vec<Diagnostic>> {
1402 let span = self.current().map_or_else(
1403 || Span::new(&self.module, self.source_len, self.source_len),
1404 |token| token.token.span.clone(),
1405 );
1406 Err(vec![Diagnostic::new("E_PARSE", message, span)])
1407 }
1408}
1409
1410fn is_uppercase_name(name: &str) -> bool {
1411 name.as_bytes().first().is_some_and(u8::is_ascii_uppercase)
1412}
1413
1414fn expression_path(expr: &Expr) -> Option<String> {
1415 match &expr.kind {
1416 ExprKind::Name(n) => Some(n.clone()),
1417 ExprKind::Field { object, field } => {
1418 Some(format!("{}.{}", expression_path(object)?, field))
1419 }
1420 _ => None,
1421 }
1422}
1423
1424#[cfg(test)]
1425mod tests {
1426 use super::parse;
1427 use crate::ast::{ExprKind, IndexExpr, Item, StmtKind, Type};
1428
1429 fn let_value(source: &str) -> crate::ast::Expr {
1430 let items = parse(source, "parser-test").expect("source parses");
1431 let Item::Statement(statement) = items.into_iter().next().expect("one item") else {
1432 panic!("expected statement");
1433 };
1434 let StmtKind::Let { value, .. } = statement.kind else {
1435 panic!("expected let statement");
1436 };
1437 value
1438 }
1439
1440 #[test]
1441 fn parses_square_generics_and_typed_intrinsics_without_consuming_indexes() {
1442 let items = parse(
1443 "type Holder { values: List[Tensor[f64]]; ref: ComponentReference[Str]; } let getter = get[Holder]; let element = values[0];",
1444 "parser-test",
1445 )
1446 .expect("source parses");
1447 let Item::Class(class) = &items[0] else {
1448 panic!("expected class");
1449 };
1450 assert_eq!(
1451 class.fields[0].ty,
1452 Type::List(Box::new(Type::Tensor(Box::new(Type::named("f64")))))
1453 );
1454 assert_eq!(
1455 class.fields[1].ty,
1456 Type::ComponentReference(Box::new(Type::named("Str")))
1457 );
1458 let Item::Statement(statement) = &items[1] else {
1459 panic!("expected typed intrinsic binding");
1460 };
1461 assert!(matches!(
1462 statement.kind,
1463 StmtKind::Let {
1464 value: crate::ast::Expr {
1465 kind: ExprKind::TypedFunction { ref name, .. },
1466 ..
1467 },
1468 ..
1469 } if name == "get"
1470 ));
1471 let Item::Statement(statement) = &items[2] else {
1472 panic!("expected indexed binding");
1473 };
1474 assert!(matches!(
1475 statement.kind,
1476 StmtKind::Let {
1477 value: crate::ast::Expr { kind: ExprKind::Index { ref indices, .. }, .. },
1478 ..
1479 } if matches!(indices.as_slice(), [IndexExpr::Index(_)])
1480 ));
1481 }
1482
1483 #[test]
1484 fn preserves_raw_numbers_matrix_multiply_and_numpy_selectors() {
1485 let value = let_value(
1486 "let result = tensor[184467440737095516160000, :, -2::-1, None, ...] @ other;",
1487 );
1488 let ExprKind::Binary { op, left, .. } = value.kind else {
1489 panic!("expected binary expression");
1490 };
1491 assert_eq!(op, "@");
1492 let ExprKind::Index { indices, .. } = left.kind else {
1493 panic!("expected index expression");
1494 };
1495 assert!(matches!(
1496 &indices[0],
1497 IndexExpr::Index(crate::ast::Expr { kind: ExprKind::Number(raw), .. })
1498 if raw == "184467440737095516160000"
1499 ));
1500 assert!(matches!(
1501 &indices[1],
1502 IndexExpr::Slice {
1503 start: None,
1504 stop: None,
1505 step: None
1506 }
1507 ));
1508 assert!(matches!(
1509 &indices[2],
1510 IndexExpr::Slice {
1511 start: Some(_),
1512 stop: None,
1513 step: Some(_)
1514 }
1515 ));
1516 assert!(matches!(&indices[3], IndexExpr::NewAxis));
1517 assert!(matches!(&indices[4], IndexExpr::Ellipsis));
1518 }
1519
1520 #[test]
1521 fn rejects_angle_bracket_generics() {
1522 assert!(parse("let values: List<Number> = [];", "parser-test").is_err());
1523 }
1524
1525 #[test]
1526 fn parses_algebraic_types_matches_propagation_and_tensors() {
1527 let items = parse(
1528 "type Point { x: f32, y: f32 } enum State { Idle, Moving(f32) } let result: Res[f32, Str] = match state { State.Idle => 0, State.Moving(speed) => speed, }; let point = match value { Point { x, y: _ } => x, }; let matrix = [[1, 2], [3, 4]]:f32; let propagated = result?;",
1529 "parser-test",
1530 )
1531 .expect("source parses");
1532 assert!(matches!(items[0], Item::Class(_)));
1533 assert!(matches!(items[1], Item::Enum(_)));
1534 let Item::Statement(statement) = &items[2] else {
1535 panic!("expected match binding");
1536 };
1537 assert!(matches!(
1538 statement.kind,
1539 StmtKind::Let {
1540 ty: Some(Type::Applied { ref name, ref arguments }),
1541 value: crate::ast::Expr { kind: ExprKind::Match { ref arms, .. }, .. },
1542 ..
1543 } if name == "Res" && arguments.len() == 2 && arms.len() == 2
1544 ));
1545 let Item::Statement(statement) = &items[4] else {
1546 panic!("expected tensor binding");
1547 };
1548 assert!(matches!(
1549 statement.kind,
1550 StmtKind::Let {
1551 value: crate::ast::Expr { kind: ExprKind::TensorLiteral { ref values, ref dtype }, .. },
1552 ..
1553 } if values.len() == 2 && *dtype == Type::named("f32")
1554 ));
1555 let Item::Statement(statement) = &items[5] else {
1556 panic!("expected propagation binding");
1557 };
1558 assert!(matches!(
1559 statement.kind,
1560 StmtKind::Let {
1561 value: crate::ast::Expr {
1562 kind: ExprKind::Propagate(_),
1563 ..
1564 },
1565 ..
1566 }
1567 ));
1568
1569 let method = let_value("let converted = (a + b).convert[f32](matrix);");
1570 assert!(matches!(
1571 method.kind,
1572 ExprKind::Call { ref callee, .. }
1573 if matches!(callee.kind, ExprKind::TypedMethod { ref method, ref ty, .. }
1574 if method == "convert" && *ty == Type::named("f32"))
1575 ));
1576 }
1577
1578 #[test]
1579 fn rejects_legacy_class_declarations_with_migration_message() {
1580 let error = parse("class Point { x: f32 }", "parser-test").expect_err("class is retired");
1581 assert!(error[0].message.contains("renamed to `type`"));
1582 }
1583
1584 #[test]
1585 fn parses_parenthesized_assignment_as_a_result_expression() {
1586 let value = let_value("let outcome = (matrix[:, 1:] = values)?;");
1587 let ExprKind::Propagate(assign) = value.kind else {
1588 panic!("expected propagated assignment");
1589 };
1590 assert!(matches!(assign.kind, ExprKind::Assign { .. }));
1591 }
1592
1593 #[test]
1594 fn parses_typed_numeric_literals_without_consuming_slice_colons() {
1595 let positive = let_value("let value = 1:f32;");
1596 assert!(matches!(
1597 positive.kind,
1598 ExprKind::TypedLiteral { ref ty, .. } if *ty == Type::named("f32")
1599 ));
1600 let negative = let_value("let value = -128:i8;");
1601 assert!(matches!(
1602 negative.kind,
1603 ExprKind::TypedLiteral { ref value, ref ty }
1604 if *ty == Type::named("i8")
1605 && matches!(value.kind, ExprKind::Unary { ref op, .. } if op == "-")
1606 ));
1607 let indexed = let_value("let value = rows[0:2];");
1608 assert!(matches!(indexed.kind, ExprKind::Index { .. }));
1609 }
1610}