1#![doc = include_str!("../README.md")]
2
3use dst_factory::make_dst_factory;
4use espy_eyes::{Lexer, Lexigram, Token};
5use std::iter::Peekable;
6
7#[cfg(test)]
8mod tests;
9
10#[derive(Debug, Eq, PartialEq)]
11pub enum Error<'source> {
12 Lexer(espy_eyes::Error<'source>),
19 MissingToken {
20 expected: &'static [Lexigram],
22 actual: Option<Token<'source>>,
24 },
25 ExpectedExpression(Option<Token<'source>>),
28 ExpectedStatementOrExpression(Token<'source>),
30 UnexpectedCloseParen(Token<'source>),
34 IncompleteExpression,
37}
38
39#[derive(Debug, Default, Eq, PartialEq)]
41pub struct Diagnostics<'source> {
42 pub errors: Vec<Error<'source>>,
43}
44
45impl<'source> Diagnostics<'source> {
46 fn expect(
47 &mut self,
48 t: Option<espy_eyes::Result<'source>>,
49 expected: &'static [Lexigram],
50 ) -> Option<Token<'source>> {
51 let actual = self.wrap(t);
52 if actual.is_some_and(|actual| expected.contains(&actual.lexigram)) {
53 actual
54 } else {
55 self.errors.push(Error::MissingToken { expected, actual });
56 None
57 }
58 }
59
60 fn expect_expression(
61 &mut self,
62 lexer: &mut Peekable<Lexer<'source>>,
63 ) -> Option<Box<Expression<'source>>> {
64 let expression = Expression::new(lexer);
65 if expression.is_none() {
66 self.errors.push(Error::ExpectedExpression(
67 lexer.peek().copied().transpose().ok().flatten(),
68 ));
69 }
70 expression
71 }
72
73 fn next_if(
74 &mut self,
75 lexer: &mut Peekable<Lexer<'source>>,
76 expected: &'static [Lexigram],
77 ) -> Option<Token<'source>> {
78 self.expect(lexer.peek().copied(), expected).inspect(|_| {
79 lexer.next();
80 })
81 }
82
83 fn wrap(&mut self, t: Option<espy_eyes::Result<'source>>) -> Option<Token<'source>> {
84 match t? {
85 Ok(t) => Some(t),
86 Err(e) => {
87 let t = if let espy_eyes::Error {
88 origin,
89 kind: espy_eyes::ErrorKind::ReservedSymbol,
90 } = e
91 {
92 Some(Token {
93 origin,
94 lexigram: Lexigram::Ident,
95 })
96 } else {
97 None
98 };
99 self.errors.push(Error::Lexer(e));
100 t
101 }
102 }
103 }
104}
105
106#[derive(Debug, Eq, PartialEq)]
110pub enum Node<'source> {
111 Unit(Token<'source>, Token<'source>),
112 Bool(bool, Token<'source>),
113 Number(Token<'source>),
114 String(Token<'source>),
115 Variable(Token<'source>),
116 PointFreeParameter(Token<'source>),
117 Block(Box<Block<'source>>),
118 PointFreeFunction {
119 brace_pipe: Token<'source>,
120 body: Box<Block<'source>>,
121 },
122 If(Box<If<'source>>),
123 Match(Box<Match<'source>>),
124 Enum(Box<Enum<'source>>),
125
126 Pipe(Token<'source>),
127 Call(Token<'source>),
128 Bind(Token<'source>),
129 Positive(Token<'source>),
130 Negative(Token<'source>),
131 Annotation(Box<Annotation<'source>>),
132 Not(Token<'source>),
133 Deref(Token<'source>),
134 Mul(Token<'source>),
135 Div(Token<'source>),
136 Add(Token<'source>),
137 Sub(Token<'source>),
138 EqualTo(Token<'source>),
139 NotEqualTo(Token<'source>),
140 Greater(Token<'source>),
141 GreaterEqual(Token<'source>),
142 Lesser(Token<'source>),
143 LesserEqual(Token<'source>),
144 LogicalAnd(Token<'source>),
145 LogicalOr(Token<'source>),
146 Name {
147 name: Token<'source>,
148 colon_token: Token<'source>,
149 },
150 Field {
151 dot_token: Token<'source>,
152 index: Token<'source>,
153 },
154 OptionalField {
155 dot_question_token: Token<'source>,
156 index: Token<'source>,
157 },
158 Join(Token<'source>),
159 List {
160 length: u32,
161 },
162}
163
164#[derive(Debug, Eq, PartialEq)]
165enum Operation<'source> {
166 Call(Token<'source>),
167 Pipe(Token<'source>),
168 Bind(Token<'source>),
169 Positive(Token<'source>),
170 Negative(Token<'source>),
171 Annotation(Box<Annotation<'source>>),
172 Not(Token<'source>),
173 Deref(Token<'source>),
174 Mul(Token<'source>),
175 Div(Token<'source>),
176 Add(Token<'source>),
177 Sub(Token<'source>),
178 EqualTo(Token<'source>),
179 NotEqualTo(Token<'source>),
180 Greater(Token<'source>),
181 GreaterEqual(Token<'source>),
182 Lesser(Token<'source>),
183 LesserEqual(Token<'source>),
184 LogicalAnd(Token<'source>),
185 LogicalOr(Token<'source>),
186 Name {
187 name: Token<'source>,
188 colon_token: Token<'source>,
189 },
190 Field {
191 dot_token: Token<'source>,
192 index: Token<'source>,
193 },
194 OptionalField {
195 dot_question_token: Token<'source>,
196 index: Token<'source>,
197 },
198 Join(Token<'source>),
199}
200
201impl Operation<'_> {
202 fn precedence(&self) -> usize {
204 match self {
205 Operation::Field { .. } | Operation::OptionalField { .. } | Operation::Deref(_) => 10,
206 Operation::Positive(_)
207 | Operation::Negative(_)
208 | Operation::Annotation(_)
209 | Operation::Not(_) => 9,
210 Operation::Mul(_) | Operation::Div(_) => 8,
211 Operation::Add(_) | Operation::Sub(_) => 7,
212 Operation::EqualTo(_)
213 | Operation::NotEqualTo(_)
214 | Operation::Greater(_)
215 | Operation::GreaterEqual(_)
216 | Operation::Lesser(_)
217 | Operation::LesserEqual(_) => 6,
218 Operation::LogicalAnd(_) => 5,
219 Operation::LogicalOr(_) => 4,
220 Operation::Name { .. } => 3,
221 Operation::Join(_) => 2,
222 Operation::Pipe(_) | Operation::Call(_) | Operation::Bind(_) => 1,
223 }
224 }
225
226 fn left_associative(&self) -> bool {
228 match self {
229 Operation::Field { .. }
230 | Operation::OptionalField { .. }
231 | Operation::Deref(_)
232 | Operation::Mul(_)
233 | Operation::Div(_)
234 | Operation::Add(_)
235 | Operation::Sub(_)
236 | Operation::EqualTo(_)
237 | Operation::NotEqualTo(_)
238 | Operation::Greater(_)
239 | Operation::GreaterEqual(_)
240 | Operation::Lesser(_)
241 | Operation::LesserEqual(_)
242 | Operation::LogicalAnd(_)
243 | Operation::LogicalOr(_)
244 | Operation::Join(_)
245 | Operation::Call(_)
246 | Operation::Bind(_)
247 | Operation::Pipe(_) => true,
248 Operation::Positive(_)
250 | Operation::Negative(_)
251 | Operation::Annotation(_)
252 | Operation::Not(_)
253 | Operation::Name { .. } => false,
254 }
255 }
256}
257
258impl<'source> From<Operation<'source>> for Node<'source> {
259 fn from(op: Operation<'source>) -> Self {
260 match op {
261 Operation::Field { dot_token, index } => Node::Field { dot_token, index },
262 Operation::OptionalField {
263 dot_question_token,
264 index,
265 } => Node::OptionalField {
266 dot_question_token,
267 index,
268 },
269 Operation::Pipe(t) => Node::Pipe(t),
270 Operation::Bind(t) => Node::Bind(t),
271 Operation::Call(t) => Node::Call(t),
272 Operation::Positive(t) => Node::Positive(t),
273 Operation::Negative(t) => Node::Negative(t),
274 Operation::Annotation(t) => Node::Annotation(t),
275 Operation::Not(t) => Node::Not(t),
276 Operation::Deref(t) => Node::Deref(t),
277 Operation::Mul(t) => Node::Mul(t),
278 Operation::Div(t) => Node::Div(t),
279 Operation::Add(t) => Node::Add(t),
280 Operation::Sub(t) => Node::Sub(t),
281 Operation::EqualTo(t) => Node::EqualTo(t),
282 Operation::NotEqualTo(t) => Node::NotEqualTo(t),
283 Operation::Greater(t) => Node::Greater(t),
284 Operation::GreaterEqual(t) => Node::GreaterEqual(t),
285 Operation::Lesser(t) => Node::Lesser(t),
286 Operation::LesserEqual(t) => Node::LesserEqual(t),
287 Operation::LogicalAnd(t) => Node::LogicalAnd(t),
288 Operation::LogicalOr(t) => Node::LogicalOr(t),
289 Operation::Name { name, colon_token } => Node::Name { name, colon_token },
290 Operation::Join(t) => Node::Join(t),
291 }
292 }
293}
294
295#[derive(Debug, Eq, PartialEq)]
297#[make_dst_factory(pub)]
298pub struct Expression<'source> {
299 pub first_token: Option<Token<'source>>,
300 pub last_token: Option<Token<'source>>,
301 pub diagnostics: Diagnostics<'source>,
302 pub contents: [Node<'source>],
303}
304
305impl<'source> Expression<'source> {
306 pub fn new(lexer: &mut Peekable<Lexer<'source>>) -> Option<Box<Self>> {
308 Self::new_internal(lexer, None, None, false)
309 }
310
311 pub fn list(lexer: &mut Peekable<Lexer<'source>>) -> Option<Box<Self>> {
313 Self::new_internal(lexer, None, None, true)
314 }
315
316 pub fn new_point_free(
317 brace_pipe: Token<'source>,
318 lexer: &mut Peekable<Lexer<'source>>,
319 ) -> Option<Box<Self>> {
320 Self::new_internal(
321 lexer,
322 Some(Node::PointFreeParameter(brace_pipe)),
323 Some(brace_pipe),
324 false,
325 )
326 }
327
328 fn new_internal(
330 lexer: &mut Peekable<Lexer<'source>>,
331 first_node: Option<Node<'source>>,
332 mut last_token: Option<Token<'source>>,
333 list_mode: bool,
334 ) -> Option<Box<Self>> {
335 fn flush_by_precedence<'source>(
336 output: &mut Vec<Node<'source>>,
337 stack: &mut Vec<Operation<'source>>,
338 operator: &Operation<'source>,
339 ) {
340 while let Some(op) = stack.pop_if(|x| {
341 if operator.left_associative() {
342 x.precedence() >= operator.precedence()
343 } else {
344 x.precedence() > operator.precedence()
345 }
346 }) {
347 output.push(op.into());
348 }
349 }
350 fn push_with_precedence<'source>(
351 output: &mut Vec<Node<'source>>,
352 stack: &mut Vec<Operation<'source>>,
353 operator: Operation<'source>,
354 ) {
355 flush_by_precedence(output, stack, &operator);
356 stack.push(operator);
357 }
358 const UNARY_POSITION: &[Lexigram] = &[
361 Lexigram::Plus,
362 Lexigram::Minus,
363 Lexigram::Star,
364 Lexigram::Slash,
365 Lexigram::Not,
366 Lexigram::Caret,
367 Lexigram::Pipe,
368 Lexigram::DoubleEqual,
369 Lexigram::BangEqual,
370 Lexigram::Greater,
371 Lexigram::GreaterEqual,
372 Lexigram::Lesser,
373 Lexigram::LesserEqual,
374 Lexigram::And,
375 Lexigram::Or,
376 Lexigram::Comma,
377 Lexigram::Colon,
378 Lexigram::At,
382 ];
383 const EXPRESSION_TERMINATORS: &[Lexigram] = &[
389 Lexigram::CloseParen,
390 Lexigram::CloseSquare,
391 Lexigram::CloseBrace,
392 Lexigram::Then,
393 Lexigram::End,
394 Lexigram::SingleEqual,
395 Lexigram::Semicolon,
396 ];
397 let first_token = last_token.or_else(|| lexer.peek().copied().transpose().ok().flatten());
398 let mut diagnostics = Diagnostics::default();
399 let mut contents = Vec::from_iter(first_node);
400 let mut stack = Vec::new();
401 let mut list_length = list_mode.then_some(1);
403 loop {
404 let unary_position = last_token.is_none_or(|t| UNARY_POSITION.contains(&t.lexigram));
405 let t = diagnostics.wrap(lexer.peek().copied());
406 macro_rules! lexi {
407 ($($name:ident)? @ $lexi:ident) => {
408 Some($($name @)? Token {
409 lexigram: Lexigram::$lexi,
410 ..
411 })
412 };
413 }
414 macro_rules! op {
415 ($op:ident($inner:expr)) => {
416 push_with_precedence(&mut contents, &mut stack, Operation::$op($inner))
417 };
418 }
419 macro_rules! imp_op {
420 ($inner:expr) => {
421 if let Some(list_length) = &mut list_length {
422 flush_by_precedence(&mut contents, &mut stack, &Operation::Call($inner));
425 *list_length += 1;
426 } else {
427 push_with_precedence(&mut contents, &mut stack, Operation::Call($inner))
428 }
429 };
430 }
431 match t {
432 lexi!(number @ Number) => {
437 if !unary_position {
438 imp_op!(number);
439 }
440 contents.push(Node::Number(number));
441 }
442 lexi!(string @ String) => {
443 if !unary_position {
444 imp_op!(string);
445 }
446 contents.push(Node::String(string));
447 }
448 lexi!(ident @ Ident) => {
449 if !unary_position {
450 imp_op!(ident);
451 }
452 last_token = lexer.next().transpose().ok().flatten();
453 if let Some(Ok(
454 colon_token @ Token {
455 lexigram: Lexigram::Colon,
456 ..
457 },
458 )) = lexer.peek().copied()
459 {
460 last_token = lexer.next().transpose().ok().flatten();
461 push_with_precedence(
462 &mut contents,
463 &mut stack,
464 Operation::Name {
465 name: ident,
466 colon_token,
467 },
468 );
469 } else {
470 contents.push(Node::Variable(ident));
471 }
472 continue;
473 }
474 lexi!(t @ True) => {
475 if !unary_position {
476 imp_op!(t);
477 }
478 contents.push(Node::Bool(true, t));
479 }
480 lexi!(t @ False) => {
481 if !unary_position {
482 imp_op!(t);
483 }
484 contents.push(Node::Bool(false, t));
485 }
486 lexi!(t @ OpenParen) => {
487 if !unary_position {
488 imp_op!(t);
489 }
490 lexer.next();
491 if let Some(close) = lexer.peek().copied().transpose().ok().flatten()
492 && close.lexigram == Lexigram::CloseParen
493 {
494 contents.push(Node::Unit(t, close));
495 } else {
496 contents.push(Node::Block(Block::build(
497 BlockResult::Expression(Expression::new(lexer)),
498 Diagnostics::default(),
499 [],
500 )));
501 diagnostics.expect(lexer.peek().copied(), &[Lexigram::CloseParen]);
502 }
503 }
504 lexi!(t @ OpenSquare) => {
505 if !unary_position {
506 imp_op!(t);
507 }
508 lexer.next();
509 contents.push(Node::Block(Block::build(
510 BlockResult::Expression(Expression::list(lexer)),
511 Diagnostics::default(),
512 [],
513 )));
514 diagnostics.expect(lexer.peek().copied(), &[Lexigram::CloseSquare]);
515 }
516 lexi!(t @ OpenBrace) => {
517 if !unary_position {
518 imp_op!(t);
519 }
520 lexer.next();
521 contents.push(Node::Block(Block::child(&mut *lexer)));
522 diagnostics.expect(lexer.peek().copied(), &[Lexigram::CloseBrace]);
523 }
524 lexi!(t @ OpenBracePipe) => {
525 if !unary_position {
526 imp_op!(t);
527 }
528 lexer.next();
529 let expression = Expression::new_point_free(t, lexer);
530 if expression.is_none() {
531 diagnostics.errors.push(Error::ExpectedExpression(
532 lexer.peek().copied().transpose().ok().flatten(),
533 ));
534 }
535 let body = if expression.is_some()
537 && let Some(Ok(semicolon_token)) = lexer.next_if(|x| {
538 matches!(
539 x,
540 Ok(Token {
541 lexigram: Lexigram::Semicolon,
542 ..
543 })
544 )
545 }) {
546 Block::parse_after(
547 Vec::from_iter([Statement::Sequence(Sequence {
548 expression,
549 semicolon_token,
550 })]),
551 &mut *lexer,
552 false,
553 )
554 } else {
555 Block::build(
556 BlockResult::Expression(expression),
557 Diagnostics::default(),
558 [],
559 )
560 };
561 contents.push(Node::PointFreeFunction {
562 brace_pipe: t,
563 body,
564 });
565 diagnostics.expect(lexer.peek().copied(), &[Lexigram::CloseBrace]);
566 }
567
568 lexi!(t @ Plus) if unary_position => op!(Positive(t)),
570 lexi!(t @ Minus) if unary_position => op!(Negative(t)),
571 lexi!(t @ Not) if unary_position => op!(Not(t)),
572 lexi!(t @ At) if unary_position => {
573 lexer.next();
574 let annotation = Annotation::new(t, lexer);
575 last_token = Some(t);
576 op!(Annotation(Box::new(annotation)));
577 continue;
578 }
579 lexi!(dot_token @ Dot) if !unary_position => {
581 last_token = lexer.next().transpose().ok().flatten();
582 if let Some(index) =
583 diagnostics.next_if(lexer, &[Lexigram::Ident, Lexigram::Number])
584 {
585 last_token = Some(index);
586 push_with_precedence(
587 &mut contents,
588 &mut stack,
589 Operation::Field { dot_token, index },
590 );
591 }
592 continue;
593 }
594 lexi!(dot_question_token @ DotQuestion) if !unary_position => {
595 last_token = lexer.next().transpose().ok().flatten();
596 if let Some(index) =
597 diagnostics.next_if(lexer, &[Lexigram::Ident, Lexigram::Number])
598 {
599 last_token = Some(index);
600 push_with_precedence(
601 &mut contents,
602 &mut stack,
603 Operation::OptionalField {
604 dot_question_token,
605 index,
606 },
607 );
608 }
609 continue;
610 }
611 lexi!(t @ DotStar) if !unary_position => op!(Deref(t)),
612 lexi!(t @ Bang) if !unary_position => op!(Bind(t)),
613 lexi!(t @ Plus) if !unary_position => op!(Add(t)),
615 lexi!(t @ Minus) if !unary_position => op!(Sub(t)),
616 lexi!(t @ Star) if !unary_position => op!(Mul(t)),
617 lexi!(t @ Slash) if !unary_position => op!(Div(t)),
618 lexi!(t @ Pipe) if !unary_position => op!(Pipe(t)),
619 lexi!(t @ DoubleEqual) if !unary_position => op!(EqualTo(t)),
620 lexi!(t @ BangEqual) if !unary_position => op!(NotEqualTo(t)),
621 lexi!(t @ Greater) if !unary_position => op!(Greater(t)),
622 lexi!(t @ GreaterEqual) if !unary_position => op!(GreaterEqual(t)),
623 lexi!(t @ Lesser) if !unary_position => op!(Lesser(t)),
624 lexi!(t @ LesserEqual) if !unary_position => op!(LesserEqual(t)),
625 lexi!(t @ And) if !unary_position => op!(LogicalAnd(t)),
626 lexi!(t @ Or) if !unary_position => op!(LogicalOr(t)),
627 lexi!(t @ Comma) if !unary_position => {
628 let potential_last_token = lexer.next().transpose().ok().flatten();
630 if !lexer
631 .peek()
632 .copied()
633 .transpose()
634 .ok()
635 .flatten()
636 .is_none_or(|t| EXPRESSION_TERMINATORS.contains(&t.lexigram))
637 {
638 op!(Join(t));
639 last_token = potential_last_token;
640 }
641 continue;
642 }
643 lexi!( @ If) => contents.push(If::from(&mut *lexer).into()),
644 lexi!( @ Match) => contents.push(Match::new(&mut *lexer).into()),
645 lexi!( @ Enum) => contents.push(Enum::from(&mut *lexer).into()),
646 _ => {
647 if unary_position {
648 if !contents.is_empty() || !stack.is_empty() {
649 diagnostics.errors.push(Error::IncompleteExpression);
650 }
651 } else {
652 while let Some(op) = stack.pop() {
653 contents.push(op.into());
654 }
655 }
656 if contents.is_empty() && diagnostics.errors.is_empty() {
657 return None;
658 }
659 if let Some(length) = list_length {
660 contents.push(Node::List { length });
661 }
662 return Some(Expression::build(
663 first_token,
664 last_token,
665 diagnostics,
666 contents,
667 ));
668 }
669 }
670 last_token = lexer.next().transpose().unwrap_or(None);
672 }
673 }
674}
675
676#[derive(Debug, Eq, PartialEq)]
677pub struct Annotation<'source> {
678 pub at_sign: Token<'source>,
679 pub name: Option<Token<'source>>,
680 pub open_square: Option<Token<'source>>,
681 pub tokens: Box<[Token<'source>]>,
682 pub close_square: Option<Token<'source>>,
683 pub diagnostics: Diagnostics<'source>,
684}
685
686impl<'source> Annotation<'source> {
687 fn new(at_sign: Token<'source>, lexer: &mut Peekable<Lexer<'source>>) -> Self {
688 let mut diagnostics = Diagnostics::default();
689 let name = diagnostics.next_if(lexer, &[Lexigram::Ident]);
690 let open_square = diagnostics.next_if(lexer, &[Lexigram::OpenSquare]);
691 let mut tokens = Vec::new();
692 let mut square_level = 0;
693 loop {
694 let token = match diagnostics.wrap(lexer.peek().copied()) {
695 Some(
696 token @ Token {
697 lexigram: Lexigram::OpenSquare,
698 ..
699 },
700 ) => {
701 square_level += 1;
702 token
703 }
704 Some(
705 token @ Token {
706 lexigram: Lexigram::CloseSquare,
707 ..
708 },
709 ) => {
710 if square_level > 0 {
711 square_level -= 1;
712 token
713 } else {
714 break;
715 }
716 }
717 Some(token) => token,
718 None => break,
719 };
720 lexer.next();
721 tokens.push(token);
722 }
723 let close_square = diagnostics.next_if(lexer, &[Lexigram::CloseSquare]);
724 Self {
725 at_sign,
726 name,
727 open_square,
728 tokens: tokens.into_boxed_slice(),
729 close_square,
730 diagnostics,
731 }
732 }
733}
734
735#[derive(Debug, Eq, PartialEq)]
736pub struct If<'source> {
737 pub if_token: Token<'source>,
738 pub condition: Option<Box<Expression<'source>>>,
739 pub then_token: Option<Token<'source>>,
740 pub first: Box<Block<'source>>,
741 pub else_token: Option<Token<'source>>,
742 pub else_kind: Option<Token<'source>>,
743 pub second: Box<Block<'source>>,
744 pub end_token: Option<Token<'source>>,
745 pub diagnostics: Diagnostics<'source>,
746}
747
748impl<'source> From<If<'source>> for Node<'source> {
749 fn from(if_block: If<'source>) -> Self {
750 Self::If(Box::new(if_block))
751 }
752}
753
754impl<'source> From<&mut Peekable<Lexer<'source>>> for If<'source> {
755 fn from(lexer: &mut Peekable<Lexer<'source>>) -> Self {
756 let if_token = lexer
757 .next()
758 .transpose()
759 .ok()
760 .flatten()
761 .expect("caller must have peeked a token");
762 let mut diagnostics = Diagnostics::default();
763 let condition = diagnostics.expect_expression(lexer);
764 let then_token = diagnostics.next_if(lexer, &[Lexigram::Then]);
765 let first = Block::child(&mut *lexer);
766 let (second, else_token, else_kind) = if let else_token @ Some(Token {
767 lexigram: Lexigram::Else,
768 ..
769 }) = diagnostics.wrap(lexer.peek().copied())
770 {
771 lexer.next();
772 let (second, else_kind) = match diagnostics.wrap(lexer.peek().copied()) {
773 else_kind @ Some(Token {
774 lexigram: Lexigram::Then,
775 ..
776 }) => {
777 lexer.next();
778 (Block::child(&mut *lexer), else_kind)
779 }
780 else_kind @ Some(Token {
781 lexigram: Lexigram::If,
782 ..
783 }) => (
784 Block::build(
785 Expression::build(
786 None,
787 None,
788 Diagnostics::default(),
789 [Self::from(&mut *lexer).into()],
790 )
791 .into(),
792 Diagnostics::default(),
793 [],
794 ),
795 else_kind,
796 ),
797 _ => {
798 diagnostics.expect(lexer.peek().copied(), &[Lexigram::Then, Lexigram::If]);
799 (Box::default(), None)
800 }
801 };
802 (second, else_token, else_kind)
803 } else {
804 (Box::default(), None, None)
805 };
806 let end_token = diagnostics.expect(lexer.peek().copied(), &[Lexigram::End]);
807 Self {
808 if_token,
809 condition,
810 then_token,
811 first,
812 else_token,
813 else_kind,
814 second,
815 end_token,
816 diagnostics,
817 }
818 }
819}
820
821#[derive(Debug, Eq, PartialEq)]
822pub struct MatchCase<'source> {
823 pub let_token: Option<Token<'source>>,
824 pub binding: Option<Binding<'source>>,
825 pub equals_token: Option<Token<'source>>,
826 pub case: Option<Box<Expression<'source>>>,
827 pub arrow_token: Option<Token<'source>>,
828 pub expression: Option<Box<Expression<'source>>>,
829 pub semicolon_token: Option<Token<'source>>,
830}
831
832#[derive(Debug, Eq, PartialEq)]
833#[make_dst_factory(pub)]
834pub struct Match<'source> {
835 pub match_token: Token<'source>,
836 pub expression: Option<Box<Expression<'source>>>,
837 pub then_token: Option<Token<'source>>,
838 pub end_token: Option<Token<'source>>,
839 pub diagnostics: Diagnostics<'source>,
840 pub cases: [MatchCase<'source>],
841}
842
843impl<'source> From<Box<Match<'source>>> for Node<'source> {
844 fn from(struct_block: Box<Match<'source>>) -> Self {
845 Self::Match(struct_block)
846 }
847}
848
849impl<'source> Match<'source> {
850 pub fn new(lexer: &mut Peekable<Lexer<'source>>) -> Box<Self> {
856 let match_token = lexer
857 .next()
858 .transpose()
859 .ok()
860 .flatten()
861 .expect("caller must have peeked a token");
862 let mut diagnostics = Diagnostics::default();
863
864 let expression = diagnostics.expect_expression(lexer);
865 let then_token = diagnostics.next_if(lexer, &[Lexigram::Then]);
866 let mut cases = Vec::new();
867
868 loop {
870 let (let_token, binding, equals_token, case) = if let let_token @ Some(Token {
871 lexigram: Lexigram::Let,
872 ..
873 }) =
874 diagnostics.wrap(lexer.peek().copied())
875 {
876 lexer.next();
877 let binding = Binding::new(lexer)
878 .map_err(|e| diagnostics.errors.push(e))
879 .ok();
880 let (equal_token, case) = if let equal_token @ Some(Token {
881 lexigram: Lexigram::SingleEqual,
882 ..
883 }) = diagnostics.wrap(lexer.peek().copied())
884 {
885 lexer.next();
886 let case = diagnostics.expect_expression(lexer);
887 (equal_token, case)
888 } else {
889 (None, None)
890 };
891 (let_token, binding, equal_token, case)
892 } else {
893 let case = diagnostics.expect_expression(lexer);
894 (None, None, None, case)
895 };
896 let arrow_token = diagnostics.next_if(lexer, &[Lexigram::DoubleArrow]);
897 let expression = diagnostics.expect_expression(lexer);
898 let semicolon_token = diagnostics.next_if(lexer, &[Lexigram::Semicolon]);
899 cases.push(MatchCase {
900 let_token,
901 binding,
902 equals_token,
903 case,
904 arrow_token,
905 expression,
906 semicolon_token,
907 });
908 if semicolon_token.is_none()
909 || diagnostics
910 .wrap(lexer.peek().copied())
911 .is_some_and(|t| t.lexigram == Lexigram::End)
912 {
913 break;
914 }
915 }
916 let end_token = diagnostics.expect(lexer.peek().copied(), &[Lexigram::End]);
917 Match::build(
918 match_token,
919 expression,
920 then_token,
921 end_token,
922 diagnostics,
923 cases,
924 )
925 }
926}
927
928#[derive(Debug, Eq, PartialEq)]
929pub struct Enum<'source> {
930 pub enum_token: Token<'source>,
931 pub variants: Option<Box<Expression<'source>>>,
932 pub end_token: Option<Token<'source>>,
933 pub diagnostics: Diagnostics<'source>,
934}
935
936impl<'source> From<Enum<'source>> for Node<'source> {
937 fn from(struct_block: Enum<'source>) -> Self {
938 Self::Enum(Box::new(struct_block))
939 }
940}
941
942impl<'source> From<&mut Peekable<Lexer<'source>>> for Enum<'source> {
943 fn from(lexer: &mut Peekable<Lexer<'source>>) -> Self {
944 let enum_token = lexer
945 .next()
946 .transpose()
947 .ok()
948 .flatten()
949 .expect("caller must have peeked a token");
950 let mut diagnostics = Diagnostics::default();
951 let variants = diagnostics.expect_expression(lexer);
952 let end_token = diagnostics.expect(lexer.peek().copied(), &[Lexigram::End]);
953 Self {
954 enum_token,
955 variants,
956 end_token,
957 diagnostics,
958 }
959 }
960}
961
962#[derive(Debug, Eq, PartialEq)]
963pub enum Statement<'source> {
964 Sequence(Sequence<'source>),
965 Let(Let<'source>),
966 WhereIs(WhereIs<'source>),
967 Set(Set<'source>),
968}
969
970#[derive(Debug, Eq, PartialEq)]
971pub struct Let<'source> {
972 pub let_token: Token<'source>,
973 pub binding: Option<Binding<'source>>,
974 pub equals_token: Option<Token<'source>>,
975 pub expression: Option<Box<Expression<'source>>>,
976 pub semicolon_token: Option<Token<'source>>,
977 pub diagnostics: Diagnostics<'source>,
978}
979
980impl<'source> Let<'source> {
981 pub fn new(let_token: Token<'source>, lexer: &mut Peekable<Lexer<'source>>) -> Self {
982 let mut diagnostics = Diagnostics::default();
983 let binding = Binding::new(lexer)
984 .map_err(|e| diagnostics.errors.push(e))
985 .ok();
986 let equals_token = diagnostics.next_if(lexer, &[Lexigram::SingleEqual]);
987 let expression = diagnostics.expect_expression(lexer);
988 let semicolon_token = diagnostics.next_if(lexer, &[Lexigram::Semicolon]);
989
990 Let {
991 let_token,
992 binding,
993 equals_token,
994 expression,
995 semicolon_token,
996 diagnostics,
997 }
998 }
999}
1000
1001#[derive(Debug, Eq, PartialEq)]
1002pub struct WhereIs<'source> {
1003 pub where_token: Token<'source>,
1004 pub expression: Option<Box<Expression<'source>>>,
1005 pub is_token: Option<Token<'source>>,
1006 pub binding: Option<Binding<'source>>,
1007 pub semicolon_token: Option<Token<'source>>,
1008 pub diagnostics: Diagnostics<'source>,
1009}
1010
1011impl<'source> WhereIs<'source> {
1012 pub fn new(where_token: Token<'source>, lexer: &mut Peekable<Lexer<'source>>) -> Self {
1013 let mut diagnostics = Diagnostics::default();
1014 let expression = diagnostics.expect_expression(lexer);
1015 let is_token = diagnostics.next_if(lexer, &[Lexigram::Is]);
1016 let binding = Binding::new(lexer)
1017 .map_err(|e| diagnostics.errors.push(e))
1018 .ok();
1019 let semicolon_token = diagnostics.next_if(lexer, &[Lexigram::Semicolon]);
1020
1021 WhereIs {
1022 where_token,
1023 expression,
1024 is_token,
1025 binding,
1026 semicolon_token,
1027 diagnostics,
1028 }
1029 }
1030}
1031
1032#[derive(Debug, Eq, PartialEq)]
1033pub struct Sequence<'source> {
1034 pub expression: Option<Box<Expression<'source>>>,
1035 pub semicolon_token: Token<'source>,
1036}
1037
1038impl<'source> Sequence<'source> {
1039 pub fn try_sequence(
1043 lexer: &mut Peekable<Lexer<'source>>,
1044 ) -> Result<Self, Option<Box<Expression<'source>>>> {
1045 let expression = Expression::new(&mut *lexer);
1046 if let Some(Ok(
1047 semicolon_token @ Token {
1048 lexigram: Lexigram::Semicolon,
1049 ..
1050 },
1051 )) = lexer.peek().copied()
1052 {
1053 lexer.next();
1054 Ok(Sequence {
1055 expression,
1056 semicolon_token,
1057 })
1058 } else {
1059 Err(expression)
1060 }
1061 }
1062}
1063
1064#[derive(Debug, Eq, PartialEq)]
1065pub struct Set<'source> {
1066 pub set_token: Token<'source>,
1067 pub target: Option<Box<Expression<'source>>>,
1068 pub equals_token: Option<Token<'source>>,
1069 pub expression: Option<Box<Expression<'source>>>,
1070 pub semicolon_token: Option<Token<'source>>,
1071 pub diagnostics: Diagnostics<'source>,
1072}
1073
1074impl<'source> Set<'source> {
1075 pub fn new(lexer: &mut Peekable<Lexer<'source>>) -> Self {
1081 let mut diagnostics = Diagnostics::default();
1082 let set_token = lexer
1083 .next()
1084 .transpose()
1085 .ok()
1086 .flatten()
1087 .expect("caller must have peeked a token");
1088 let target = diagnostics.expect_expression(lexer);
1089 let equals_token = diagnostics.next_if(lexer, &[Lexigram::SingleEqual]);
1090 let expression = diagnostics.expect_expression(lexer);
1091 let semicolon_token = diagnostics.next_if(lexer, &[Lexigram::Semicolon]);
1092
1093 Set {
1094 set_token,
1095 target,
1096 equals_token,
1097 expression,
1098 semicolon_token,
1099 diagnostics,
1100 }
1101 }
1102}
1103
1104#[derive(Debug, Eq, PartialEq)]
1105pub struct Use<'source> {
1106 pub use_token: Token<'source>,
1107 pub expression: Option<Box<Expression<'source>>>,
1108 pub semicolon_token: Option<Token<'source>>,
1109 pub body: Box<Block<'source>>,
1110 pub diagnostics: Diagnostics<'source>,
1111}
1112
1113impl<'source> Use<'source> {
1114 pub fn new(lexer: &mut Peekable<Lexer<'source>>) -> Self {
1120 let mut diagnostics = Diagnostics::default();
1121 let use_token = lexer
1122 .next()
1123 .transpose()
1124 .ok()
1125 .flatten()
1126 .expect("caller must have peeked a token");
1127 let expression = diagnostics.expect_expression(lexer);
1128 let semicolon_token = diagnostics.next_if(lexer, &[Lexigram::Semicolon]);
1129 let body = Block::child(lexer);
1130
1131 Self {
1132 use_token,
1133 expression,
1134 semicolon_token,
1135 body,
1136 diagnostics,
1137 }
1138 }
1139}
1140
1141#[derive(Debug, Eq, PartialEq)]
1142pub struct NumericBinding<'source> {
1143 pub binding: Binding<'source>,
1144 pub comma_token: Option<Token<'source>>,
1145}
1146
1147#[derive(Debug, Eq, PartialEq)]
1148pub struct NamedBinding<'source> {
1149 pub field: Token<'source>,
1150 pub action: Option<NamedBindingAction<'source>>,
1151 pub comma_token: Option<Token<'source>>,
1152}
1153
1154#[derive(Debug, Eq, PartialEq)]
1155pub enum NamedBindingAction<'source> {
1156 Optional(Token<'source>),
1157 Binding(NamedSubBinding<'source>),
1158}
1159
1160#[derive(Debug, Eq, PartialEq)]
1161pub struct NamedSubBinding<'source> {
1162 pub colon_token: Token<'source>,
1163 pub binding: Binding<'source>,
1164}
1165
1166#[derive(Debug, Eq, PartialEq)]
1167pub enum BindingMethod<'source> {
1168 Single(Token<'source>),
1169 Numeric {
1170 open_paren: Token<'source>,
1171 bindings: Box<[NumericBinding<'source>]>,
1172 close_paren: Option<Token<'source>>,
1173 },
1174 Named {
1175 open_brace: Token<'source>,
1176 bindings: Box<[NamedBinding<'source>]>,
1177 close_brace: Option<Token<'source>>,
1178 },
1179}
1180
1181#[derive(Debug, Eq, PartialEq)]
1182pub struct Binding<'source> {
1183 pub method: BindingMethod<'source>,
1184 pub diagnostics: Diagnostics<'source>,
1185}
1186
1187impl<'source> Binding<'source> {
1188 pub fn new(lexer: &mut Peekable<Lexer<'source>>) -> Result<Self, Error<'source>> {
1192 match lexer.peek().copied().transpose().map_err(Error::Lexer)? {
1193 Some(
1194 t @ Token {
1195 lexigram: Lexigram::Ident | Lexigram::Discard,
1196 ..
1197 },
1198 ) => {
1199 lexer.next();
1200 Ok(Binding {
1201 method: BindingMethod::Single(t),
1202 diagnostics: Diagnostics::default(),
1203 })
1204 }
1205 Some(
1206 open_paren @ Token {
1207 lexigram: Lexigram::OpenParen,
1208 ..
1209 },
1210 ) => {
1211 let mut diagnostics = Diagnostics::default();
1212 let mut bindings = Vec::new();
1213 lexer.next();
1214 loop {
1215 let t = diagnostics.wrap(lexer.peek().copied());
1216 if let Some(Token {
1217 lexigram: Lexigram::CloseParen,
1218 ..
1219 }) = t
1220 {
1221 break;
1222 }
1223 if let Ok(binding) = Binding::new(lexer) {
1224 let comma_token = diagnostics
1225 .wrap(lexer.peek().copied())
1226 .filter(|t| t.lexigram == Lexigram::Comma);
1227 bindings.push(NumericBinding {
1228 binding,
1229 comma_token,
1230 });
1231 if comma_token.is_some() {
1232 lexer.next();
1233 } else {
1234 break;
1235 }
1236 } else {
1237 diagnostics.errors.push(Error::MissingToken {
1238 expected: &[
1239 Lexigram::Ident,
1240 Lexigram::Discard,
1241 Lexigram::OpenParen,
1242 Lexigram::OpenBrace,
1243 Lexigram::CloseParen,
1244 ],
1245 actual: t,
1246 });
1247 break;
1248 }
1249 }
1250 let close_paren = diagnostics.next_if(lexer, &[Lexigram::CloseParen]);
1251 Ok(Binding {
1252 method: BindingMethod::Numeric {
1253 open_paren,
1254 bindings: bindings.into_boxed_slice(),
1255 close_paren,
1256 },
1257 diagnostics,
1258 })
1259 }
1260 Some(
1261 open_brace @ Token {
1262 lexigram: Lexigram::OpenBrace,
1263 ..
1264 },
1265 ) => {
1266 let mut diagnostics = Diagnostics::default();
1267 let mut bindings = Vec::new();
1268 lexer.next();
1269 loop {
1270 match diagnostics.wrap(lexer.peek().copied()) {
1271 Some(Token {
1272 lexigram: Lexigram::CloseBrace,
1273 ..
1274 }) => break,
1275 Some(
1276 field @ Token {
1277 lexigram: Lexigram::Ident,
1278 ..
1279 },
1280 ) => {
1281 lexer.next();
1282 match diagnostics.wrap(lexer.peek().copied()) {
1283 Some(
1284 question_token @ Token {
1285 lexigram: Lexigram::Question,
1286 ..
1287 },
1288 ) => {
1289 lexer.next();
1290 let comma_token = diagnostics
1291 .wrap(lexer.peek().copied())
1292 .filter(|t| t.lexigram == Lexigram::Comma);
1293 bindings.push(NamedBinding {
1294 field,
1295 action: Some(NamedBindingAction::Optional(question_token)),
1296 comma_token,
1297 });
1298 if comma_token.is_some() {
1299 lexer.next();
1300 } else {
1301 break;
1302 }
1303 }
1304 Some(
1305 colon_token @ Token {
1306 lexigram: Lexigram::Colon,
1307 ..
1308 },
1309 ) => {
1310 lexer.next();
1311 match Binding::new(lexer) {
1312 Ok(binding) => {
1313 let comma_token = diagnostics
1314 .wrap(lexer.peek().copied())
1315 .filter(|t| t.lexigram == Lexigram::Comma);
1316 bindings.push(NamedBinding {
1317 field,
1318 action: Some(NamedBindingAction::Binding(
1319 NamedSubBinding {
1320 colon_token,
1321 binding,
1322 },
1323 )),
1324 comma_token,
1325 });
1326 if comma_token.is_some() {
1327 lexer.next();
1328 } else {
1329 break;
1330 }
1331 }
1332 Err(e) => {
1333 diagnostics.errors.push(e);
1334 break;
1335 }
1336 }
1337 }
1338 comma_token @ Some(Token {
1339 lexigram: Lexigram::Comma,
1340 ..
1341 }) => {
1342 lexer.next();
1343 bindings.push(NamedBinding {
1344 field,
1345 action: None,
1346 comma_token,
1347 });
1348 }
1349 _ => {
1350 bindings.push(NamedBinding {
1351 field,
1352 action: None,
1353 comma_token: None,
1354 });
1355 break;
1356 }
1357 }
1358 }
1359 actual => {
1360 diagnostics.errors.push(Error::MissingToken {
1361 expected: &[Lexigram::Ident, Lexigram::CloseBrace],
1362 actual,
1363 });
1364 break;
1365 }
1366 }
1367 }
1368 let close_brace = diagnostics.next_if(lexer, &[Lexigram::CloseBrace]);
1369 Ok(Binding {
1370 method: BindingMethod::Named {
1371 open_brace,
1372 bindings: bindings.into_boxed_slice(),
1373 close_brace,
1374 },
1375 diagnostics,
1376 })
1377 }
1378 actual => Err(Error::MissingToken {
1379 expected: &[
1380 Lexigram::Ident,
1381 Lexigram::Discard,
1382 Lexigram::OpenParen,
1383 Lexigram::OpenBrace,
1384 ],
1385 actual,
1386 }),
1387 }
1388 }
1389}
1390
1391#[derive(Debug, Eq, PartialEq)]
1392pub struct Function<'source> {
1393 pub with_token: Token<'source>,
1394 pub argument: Option<Binding<'source>>,
1395 pub semicolon_token: Option<Token<'source>>,
1396 pub body: Box<Block<'source>>,
1397 pub diagnostics: Diagnostics<'source>,
1398}
1399
1400#[derive(Debug, Eq, PartialEq)]
1401#[allow(
1402 clippy::large_enum_variant,
1403 reason = "this is already inside of a (very large) boxed block"
1404)]
1405pub enum BlockResult<'source> {
1406 Expression(Option<Box<Expression<'source>>>),
1407 Function(Function<'source>),
1408 Use(Use<'source>),
1409}
1410
1411impl BlockResult<'_> {
1412 #[must_use]
1413 pub fn is_empty(&self) -> bool {
1414 match self {
1415 BlockResult::Expression(expression) => expression.is_none(),
1416 _ => false,
1417 }
1418 }
1419}
1420
1421impl Default for BlockResult<'_> {
1422 fn default() -> Self {
1423 Self::Expression(None)
1424 }
1425}
1426
1427impl<'source> From<Box<Expression<'source>>> for BlockResult<'source> {
1428 fn from(expression: Box<Expression<'source>>) -> Self {
1429 Self::Expression(Some(expression))
1430 }
1431}
1432
1433impl<'source> From<Function<'source>> for BlockResult<'source> {
1434 fn from(function: Function<'source>) -> Self {
1435 Self::Function(function)
1436 }
1437}
1438
1439#[derive(Debug, Eq, PartialEq)]
1440#[make_dst_factory(pub)]
1441pub struct Block<'source> {
1442 pub result: BlockResult<'source>,
1443 pub diagnostics: Diagnostics<'source>,
1444 pub statements: [Statement<'source>],
1445}
1446
1447impl Default for Box<Block<'_>> {
1448 fn default() -> Self {
1449 Block::build(BlockResult::Expression(None), Diagnostics::default(), [])
1450 }
1451}
1452
1453impl<'source> Block<'source> {
1454 pub fn new(lexer: &mut Peekable<Lexer<'source>>) -> Box<Self> {
1455 Self::parse(lexer, true)
1456 }
1457
1458 fn child(lexer: &mut Peekable<Lexer<'source>>) -> Box<Self> {
1459 Self::parse(lexer, false)
1460 }
1461
1462 fn parse(lexer: &mut Peekable<Lexer<'source>>, root: bool) -> Box<Self> {
1463 Self::parse_after(Vec::new(), lexer, root)
1464 }
1465
1466 fn parse_after(
1467 mut statements: Vec<Statement<'source>>,
1468 lexer: &mut Peekable<Lexer<'source>>,
1469 root: bool,
1470 ) -> Box<Self> {
1471 let mut diagnostics = Diagnostics::default();
1472 let result = loop {
1473 let statement = match diagnostics.wrap(lexer.peek().copied()) {
1474 Some(
1475 let_token @ Token {
1476 lexigram: Lexigram::Let,
1477 ..
1478 },
1479 ) => {
1480 lexer.next();
1481 Statement::Let(Let::new(let_token, lexer))
1482 }
1483 Some(
1484 where_token @ Token {
1485 lexigram: Lexigram::Where,
1486 ..
1487 },
1488 ) => {
1489 lexer.next();
1490 Statement::WhereIs(WhereIs::new(where_token, lexer))
1491 }
1492 Some(Token {
1493 lexigram: Lexigram::Set,
1494 ..
1495 }) => Statement::Set(Set::new(lexer)),
1496 Some(Token {
1497 lexigram: Lexigram::Use,
1498 ..
1499 }) => break BlockResult::Use(Use::new(lexer)),
1500 Some(
1501 with_token @ Token {
1502 lexigram: Lexigram::With,
1503 ..
1504 },
1505 ) => {
1506 lexer.next();
1507 let mut st_diagnostics = Diagnostics::default();
1508 let argument = Binding::new(lexer)
1509 .map_err(|e| st_diagnostics.errors.push(e))
1510 .ok();
1511 let semicolon_token = diagnostics.next_if(lexer, &[Lexigram::Semicolon]);
1512 let body = Block::parse(&mut *lexer, root);
1513
1514 break Function {
1515 with_token,
1516 argument,
1517 semicolon_token,
1518 body,
1519 diagnostics: st_diagnostics,
1520 }
1521 .into();
1522 }
1523 _ => match Sequence::try_sequence(&mut *lexer) {
1524 Ok(sequence) => Statement::Sequence(sequence),
1525 Err(expression) => {
1526 break BlockResult::Expression(expression);
1527 }
1528 },
1529 };
1530 statements.push(statement);
1531 };
1532 if root && let Some(t) = lexer.peek().copied().transpose().ok().flatten() {
1533 diagnostics
1534 .errors
1535 .push(Error::ExpectedStatementOrExpression(t));
1536 }
1537 Self::build(result, diagnostics, statements)
1538 }
1539}