1mod error;
5mod helpers;
6mod parse_context;
7pub mod parsers;
8
9pub use error::{ParseError, ParseErrorKind, ParseErrors, RichError};
10pub use parse_context::ParseContext;
11
12use crate::ast;
13use crate::parser::{error::Rich, helpers::*};
14use crate::tokens::*;
15
16use chumsky::{
17 Parser, extra,
18 input::{Input, MappedInput},
19 prelude::*,
20 select_ref,
21};
22
23use std::str::FromStr;
24
25use microcad_lang_base::Span;
26
27pub type Extra<'tokens> = extra::Err<RichError<'tokens>>;
29
30pub type InputMap<'input, 'token> =
31 fn(&'input SpannedToken<Token<'token>>) -> (&'input Token<'token>, &'input Span);
32
33pub type ParserInput<'input, 'token> = MappedInput<
34 'input,
35 Token<'token>,
36 Span,
37 &'input [SpannedToken<Token<'token>>],
38 InputMap<'input, 'token>,
39>;
40
41pub fn input<'input, 'tokens>(
43 input: &'input [SpannedToken<Token<'tokens>>],
44) -> ParserInput<'input, 'tokens> {
45 fn map_token_input<'a, 'token>(
46 spanned: &'a SpannedToken<Token<'token>>,
47 ) -> (&'a Token<'token>, &'a Span) {
48 (&spanned.token, &spanned.span)
49 }
50
51 let end = input.last().map(|t| t.span.end).unwrap_or_default();
52 Input::map(input, end..end, map_token_input)
53}
54
55pub fn parse<'tokens>(
57 tokens: &'tokens [SpannedToken<Token<'tokens>>],
58) -> Result<ast::Program, ParseErrors> {
59 parser()
60 .parse(input(tokens))
61 .into_result()
62 .map_err(|errors| errors.into())
63}
64
65const STRUCTURAL_TOKENS: &[Token] = &[
66 Token::SigilOpenCurlyBracket,
67 Token::SigilCloseCurlyBracket,
68 Token::SigilOpenBracket,
69 Token::SigilCloseBracket,
70 Token::SigilOpenSquareBracket,
71 Token::SigilCloseSquareBracket,
72 Token::SigilSemiColon,
73];
74
75fn parser<'tokens>()
76-> impl Parser<'tokens, ParserInput<'tokens, 'tokens>, ast::Program, Extra<'tokens>> {
77 use crate::ast::Dummy;
78
79 let mut statement_list_parser = Recursive::declare();
80 let mut statement_parser = Recursive::declare();
81 let mut expression_parser = Recursive::declare();
82 let mut type_parser = Recursive::declare();
83 let mut outer_attribute_parser = Recursive::declare();
84 let mut if_inner = Recursive::declare();
85
86 let semi_recovery = none_of(Token::SigilSemiColon).repeated().ignored();
87
88 let reserved_keyword = select_ref! {
89 token @ (
90 Token::KeywordPlugin |
91 Token::KeywordAssembly |
92 Token::KeywordMaterial |
93 Token::KeywordUnit |
94 Token::KeywordEnum |
95 Token::KeywordStruct |
96 Token::KeywordMatch |
97 Token::KeywordType |
98 Token::KeywordExtern
99 ) => token.kind(),
100 }
101 .boxed();
102 let keyword = select_ref! {
103 token @ (
104 Token::KeywordMod |
105 Token::KeywordPart |
106 Token::KeywordSketch |
107 Token::KeywordOp |
108 Token::KeywordFn |
109 Token::KeywordIf |
110 Token::KeywordElse |
111 Token::KeywordUse |
112 Token::KeywordAs |
113 Token::KeywordReturn |
114 Token::KeywordPub |
115 Token::KeywordConst |
116 Token::KeywordProp |
117 Token::KeywordInit
118 ) => token.kind(),
119 }
120 .boxed();
121
122 statement_list_parser.define({
123 let trailing_expr = outer_attribute_parser
124 .clone()
125 .then(expression_parser.clone())
126 .with_extras()
127 .map_with(
128 |((attributes, expression), extras), e| ast::ExpressionStatement {
129 span: e.span(),
130 extras,
131 attributes,
132 expression,
133 },
134 )
135 .map(Box::new)
136 .or_not()
137 .boxed();
138
139 parsers::whitespace()
140 .or_not()
141 .ignore_then(statement_parser.clone())
142 .then(parsers::trailing_extras())
143 .repeated()
144 .collect::<Vec<(ast::Statement, ast::TrailingExtras)>>()
145 .then(trailing_expr)
146 .with_extras()
147 .map_with(|((statements, tail), extras), e| ast::StatementList {
148 span: e.span(),
149 extras,
150 statements,
151 tail,
152 })
153 .boxed()
154 });
155
156 let block_recovery =
157 ignore_till_matched_curly().map_with(|_, e| ast::StatementList::dummy(e.span()));
158
159 let body = parsers::whitespace()
160 .or_not()
161 .ignore_then(statement_list_parser.clone().delimited_with_spanned_error(
162 just(Token::SigilOpenCurlyBracket),
163 just(Token::SigilCloseCurlyBracket),
164 |err: RichError, open, end| {
165 Rich::custom(
166 err.span().clone(),
167 ParseErrorKind::UnclosedBracket {
168 open,
169 end,
170 kind: "code block",
171 close_token: Token::SigilCloseCurlyBracket,
172 },
173 )
174 },
175 ))
176 .recover_with(via_parser(block_recovery))
177 .map_with(|statements, e| ast::Body {
178 span: e.span(),
179 statements,
180 })
181 .boxed();
182
183 let identifier_parser = select_ref! { Token::Identifier(ident) = e => ast::Identifier {
184 span: e.span(),
185 name: ident.as_ref().into(),
186 } }
187 .or(reserved_keyword
188 .clone()
189 .validate(|kind, e, emitter| {
190 emitter.emit(Rich::custom(
191 e.span(),
192 ParseErrorKind::ReservedKeywordAsIdentifier(kind),
193 ));
194 kind
195 })
196 .map_with(|kind, e| ast::Identifier {
197 span: e.span(),
198 name: kind.into(),
199 }))
200 .or(keyword
201 .validate(|kind, e, emitter| {
202 emitter.emit(Rich::custom(
203 e.span(),
204 ParseErrorKind::KeywordAsIdentifier(kind),
205 ));
206 kind
207 })
208 .map_with(|kind, e| ast::Identifier {
209 span: e.span(),
210 name: kind.into(),
211 }))
212 .labelled("identifier")
213 .boxed();
214
215 let qualified_name = identifier_parser
216 .clone()
217 .separated_by(just(Token::SigilDoubleColon))
218 .at_least(1)
219 .collect::<Vec<_>>()
220 .with_extras()
221 .map_with(|(parts, extras), e| ast::QualifiedName {
222 span: e.span(),
223 parts,
224 extras,
225 })
226 .labelled("qualified name")
227 .boxed();
228
229 let unit = parsers::unit().boxed();
230
231 type_parser.define({
232 let single = select_ref! {
233 Token::Identifier(ident) = e => ast::SingleType {
234 span: e.span(),
235 name: ident.as_ref().into()
236 },
237 }
238 .map(ast::Type::Single)
239 .labelled("single type")
240 .boxed();
241
242 let array = parsers::whitespace()
243 .or_not()
244 .ignore_then(type_parser.clone())
245 .then_maybe_whitespace()
246 .delimited_by(
247 just(Token::SigilOpenSquareBracket),
248 just(Token::SigilCloseSquareBracket),
249 )
250 .map_with(|inner, e| {
251 ast::Type::Array(ast::ArrayType {
252 span: e.span(),
253 inner: Box::new(inner),
254 })
255 })
256 .labelled("array type")
257 .boxed();
258
259 let tuple = parsers::whitespace()
260 .or_not()
261 .ignore_then(identifier_parser.clone())
262 .then_ignore(just(Token::SigilColon))
263 .or_not()
264 .then_maybe_whitespace()
265 .then(type_parser.clone())
266 .then_maybe_whitespace()
267 .separated_by(just(Token::SigilComma))
268 .allow_trailing()
269 .collect::<Vec<_>>()
270 .then_maybe_whitespace()
271 .delimited_with_spanned_error(
272 just(Token::SigilOpenBracket),
273 just(Token::SigilCloseBracket),
274 |err: RichError, open, end| {
275 Rich::custom(
276 err.span().clone(),
277 ParseErrorKind::UnclosedBracket {
278 open,
279 end,
280 kind: "tuple type",
281 close_token: Token::SigilCloseBracket,
282 },
283 )
284 },
285 )
286 .map_with(|inner, e| {
287 ast::Type::Tuple(ast::TupleType {
288 span: e.span(),
289 inner,
290 })
291 })
292 .labelled("tuple type")
293 .boxed();
294
295 single.or(array).or(tuple).labelled("type").boxed()
296 });
297
298 let unary_operator_parser = select_ref! {
299 Token::OperatorSubtract = e => ast::UnaryOperator { span: e.span(), operation: ast::UnaryOperatorType::Minus },
300 Token::OperatorAdd = e => ast::UnaryOperator { span: e.span(), operation: ast::UnaryOperatorType::Plus },
301 Token::OperatorNot = e => ast::UnaryOperator { span: e.span(), operation: ast::UnaryOperatorType::Not },
302 }
303 .labelled("unary operator")
304 .boxed();
305
306 let doc_block = select_ref! {
308 Token::DocComment(comment) => comment.to_string(),
309 }
310 .then_whitespace()
311 .repeated()
312 .collect::<Vec<_>>()
313 .map_with(|lines, e| ast::DocBlock {
314 span: e.span(),
315 lines,
316 })
317 .labelled("doc block")
318 .boxed();
319
320 let tuple_recovery = nested_delimiters(
321 Token::SigilOpenBracket,
322 Token::SigilCloseBracket,
323 [
324 (
325 Token::SigilOpenSquareBracket,
326 Token::SigilCloseSquareBracket,
327 ),
328 (Token::SigilOpenCurlyBracket, Token::SigilCloseCurlyBracket),
329 ],
330 |_| (),
331 )
332 .map_with(|_, e| {
333 (
334 vec![ast::TupleItem::dummy(e.span())],
335 ast::ItemExtras::default(),
336 )
337 });
338
339 let tuple_body = identifier_parser
340 .clone()
341 .then_maybe_whitespace()
342 .then_ignore(just(Token::OperatorAssignment).then_maybe_whitespace())
343 .or_not()
344 .then(expression_parser.clone())
345 .with_extras()
346 .map_with(|((name, value), extras), e| ast::TupleItem {
347 span: e.span(),
348 extras,
349 name,
350 value,
351 })
352 .then_maybe_whitespace()
353 .separated_by(just(Token::SigilComma).then_maybe_whitespace())
354 .allow_trailing()
355 .collect::<Vec<_>>()
356 .boxed();
357
358 let call_inner = qualified_name
359 .clone()
360 .then(
361 tuple_body
362 .clone()
363 .with_extras()
364 .map_with(|(arguments, extras), e| ast::ArgumentList {
365 span: e.span(),
366 extras,
367 arguments: arguments
368 .into_iter()
369 .map(|item| match item.name {
370 Some(name) => ast::Argument::Named(ast::NamedArgument {
371 span: item.span,
372 extras: item.extras,
373 name,
374 value: item.value,
375 }),
376 None => ast::Argument::Unnamed(ast::UnnamedArgument {
377 span: item.span,
378 extras: item.extras,
379 value: item.value,
380 }),
381 })
382 .collect::<Vec<_>>(),
383 })
384 .labelled("function arguments")
385 .delimited_with_spanned_error(
386 just(Token::SigilOpenBracket),
387 just(Token::SigilCloseBracket),
388 |err: RichError, open, end| {
389 Rich::custom(
390 err.span().clone(),
391 ParseErrorKind::UnclosedBracket {
392 open,
393 end,
394 kind: "function arguments",
395 close_token: Token::SigilCloseBracket,
396 },
397 )
398 },
399 )
400 .recover_with(via_parser(
401 tuple_recovery
402 .clone()
403 .map_with(|_, e| ast::ArgumentList::dummy(e.span())),
404 )),
405 )
406 .with_extras()
407 .map_with(|((name, arguments), extras), e| ast::Call {
408 span: e.span(),
409 extras,
410 name,
411 arguments,
412 })
413 .boxed();
414
415 statement_parser.define({
416 let visibility = select_ref! {
417 Token::KeywordPub => ast::Visibility::Public,
418 }
419 .labelled("visibility");
420
421 let expression = outer_attribute_parser
422 .clone()
423 .then(expression_parser.clone())
424 .with_extras()
425 .map_with(
426 |((attributes, expression), extras), e| ast::ExpressionStatement {
427 span: e.span(), extras,
429 attributes,
430 expression,
431 },
432 )
433 .map(ast::Statement::Expression)
434 .boxed();
435
436 let expression_without_semi = outer_attribute_parser
437 .clone()
438 .then(expression_parser.clone().try_map(|expr, span| {
439 if expr.is_also_statement() {
440 Ok(expr)
441 } else {
442 Err(Rich::custom(
443 span.clone(),
444 ParseErrorKind::ExpressionMissingSemicolon { span },
445 ))
446 }
447 }))
448 .with_extras()
449 .map_with(
450 |((attributes, expression), extras), e| ast::ExpressionStatement {
451 span: e.span(), extras,
453 attributes,
454 expression,
455 },
456 )
457 .map(ast::Statement::Expression)
458 .boxed();
459
460 let local_assignment_inner = outer_attribute_parser
461 .clone()
462 .then(identifier_parser.clone())
463 .then_maybe_whitespace()
464 .then(
465 just(Token::SigilColon)
466 .then_maybe_whitespace()
467 .ignore_then(type_parser.clone())
468 .then_maybe_whitespace()
469 .or_not(),
470 )
471 .then_ignore(just(Token::OperatorAssignment))
472 .then_maybe_whitespace()
473 .then(
474 expression_parser.clone().recover_with(via_parser(
475 semi_recovery
476 .clone()
477 .map_with(|_, e| ast::Expression::Error(e.span())),
478 )),
479 )
480 .with_extras()
481 .map_with(
482 |((((attributes, name), ty), value), extras), e| ast::LocalAssignment {
483 span: e.span(),
484 extras,
485 attributes,
486 name,
487 value: Box::new(value),
488 ty,
489 },
490 )
491 .boxed();
492
493 let local_assignment = local_assignment_inner
494 .clone()
495 .map(ast::Statement::LocalAssignment)
496 .labelled("local assignment");
497
498 let const_assignment_inner = doc_block
499 .clone()
500 .then(outer_attribute_parser.clone())
501 .then(visibility.then_whitespace().or_not())
502 .then(just(Token::KeywordConst).map_with(|_, e| e.span()))
503 .then_maybe_whitespace()
504 .then(identifier_parser.clone())
505 .then_maybe_whitespace()
506 .then(
507 just(Token::SigilColon)
508 .then_maybe_whitespace()
509 .ignore_then(type_parser.clone())
510 .then_maybe_whitespace()
511 .or_not(),
512 )
513 .then_ignore(just(Token::OperatorAssignment))
514 .then_maybe_whitespace()
515 .then(
516 expression_parser.clone().recover_with(via_parser(
517 semi_recovery
518 .clone()
519 .map_with(|_, e| ast::Expression::Error(e.span())),
520 )),
521 )
522 .with_extras()
523 .map_with(
524 |(
525 ((((((doc, attributes), visibility), keyword_span), name), ty), value),
526 extras,
527 ),
528 e| {
529 ast::ConstAssignment {
530 span: e.span(),
531 keyword_span,
532 extras,
533 doc,
534 attributes,
535 visibility,
536 name,
537 value: Box::new(value),
538 ty,
539 }
540 },
541 )
542 .boxed();
543
544 let const_assignment = const_assignment_inner
545 .clone()
546 .map(ast::Statement::Const)
547 .labelled("const assignment");
548
549 let pub_assignment_inner = doc_block
551 .clone()
552 .then(outer_attribute_parser.clone())
553 .then(just(Token::KeywordPub).map_with(|_, e| e.span()))
554 .then_maybe_whitespace()
555 .then(identifier_parser.clone())
556 .then_maybe_whitespace()
557 .then(
558 just(Token::SigilColon)
559 .then_maybe_whitespace()
560 .ignore_then(type_parser.clone())
561 .then_maybe_whitespace()
562 .or_not(),
563 )
564 .then_ignore(just(Token::OperatorAssignment))
565 .then_maybe_whitespace()
566 .then(
567 expression_parser.clone().recover_with(via_parser(
568 semi_recovery
569 .clone()
570 .map_with(|_, e| ast::Expression::Error(e.span())),
571 )),
572 )
573 .with_extras()
574 .map_with(
575 |((((((doc, attributes), keyword_span), name), ty), value), extras), e| {
576 ast::ConstAssignment {
577 span: e.span(),
578 keyword_span,
579 extras,
580 doc,
581 attributes,
582 visibility: Some(ast::Visibility::Public),
583 name,
584 value: Box::new(value),
585 ty,
586 }
587 },
588 )
589 .boxed();
590
591 let pub_assignment = pub_assignment_inner
592 .clone()
593 .map(ast::Statement::Const)
594 .labelled("pub const assignment");
595
596 let property_assignment_inner = doc_block
597 .clone()
598 .then(outer_attribute_parser.clone())
599 .then(just(Token::KeywordProp).map_with(|_, e| e.span()))
600 .then_maybe_whitespace()
601 .then(identifier_parser.clone())
602 .then_maybe_whitespace()
603 .then(
604 just(Token::SigilColon)
605 .then_maybe_whitespace()
606 .ignore_then(type_parser.clone())
607 .then_maybe_whitespace()
608 .or_not(),
609 )
610 .then_ignore(just(Token::OperatorAssignment))
611 .then_maybe_whitespace()
612 .then(
613 expression_parser.clone().recover_with(via_parser(
614 semi_recovery
615 .clone()
616 .map_with(|_, e| ast::Expression::Error(e.span())),
617 )),
618 )
619 .with_extras()
620 .map_with(
621 |((((((doc, attributes), keyword_span), name), ty), value), extras), e| {
622 ast::PropertyAssignment {
623 span: e.span(),
624 keyword_span,
625 extras,
626 doc,
627 attributes,
628 name,
629 value: Box::new(value),
630 ty,
631 }
632 },
633 )
634 .boxed();
635
636 let property_assignment = property_assignment_inner
637 .clone()
638 .map(ast::Statement::Property)
639 .labelled("property assignment");
640
641 let attribute_command = local_assignment_inner
642 .clone()
643 .map(ast::AttributeCommand::Assignment)
644 .or(call_inner.clone().map(ast::AttributeCommand::Call))
645 .or(identifier_parser.clone().map(ast::AttributeCommand::Ident));
646
647 let attribute_inner = attribute_command
648 .separated_by(just(Token::SigilComma).then_maybe_whitespace())
649 .at_least(1)
650 .collect::<Vec<_>>()
651 .then_maybe_whitespace()
652 .delimited_by(
653 just(Token::SigilOpenSquareBracket),
654 just(Token::SigilCloseSquareBracket),
655 )
656 .boxed();
657
658 outer_attribute_parser.define({
659 just(Token::SigilHash)
660 .ignore_then(attribute_inner.clone())
661 .then_whitespace()
662 .with_extras()
663 .map_with(|(commands, extras), e| ast::Attribute {
664 span: e.span(),
665 is_inner: false,
666 extras,
667 commands,
668 })
669 .labelled("attribute")
670 .repeated()
671 .collect::<Vec<ast::Attribute>>()
672 .boxed()
673 });
674
675 let parameter_list_inner = parsers::whitespace()
676 .or_not()
677 .ignore_then(identifier_parser.clone())
678 .then_maybe_whitespace()
679 .then(
680 just(Token::SigilColon)
681 .then_maybe_whitespace()
682 .ignore_then(
683 type_parser.clone().recover_with(via_parser(
684 recovery_expect_any_except(&[
685 Token::SigilComma,
686 Token::OperatorAssignment,
687 Token::SigilCloseBracket,
688 ])
689 .map_with(|_, e| ast::Type::dummy(e.span())),
690 )),
691 )
692 .then_maybe_whitespace()
693 .or_not(),
694 )
695 .then(
696 just(Token::OperatorAssignment)
697 .then_maybe_whitespace()
698 .ignore_then(
699 expression_parser.clone().recover_with(via_parser(
700 recovery_expect_any_except(&[
701 Token::SigilComma,
702 Token::SigilCloseBracket,
703 ])
704 .map_with(|_, e| ast::Expression::Error(e.span())),
705 )),
706 )
707 .then_maybe_whitespace()
708 .or_not(),
709 )
710 .with_extras()
711 .map_with(|(((name, ty), default), extras), e| ast::Parameter {
712 span: e.span(),
713 extras,
714 name,
715 ty,
716 default,
717 })
718 .separated_by(just(Token::SigilComma))
719 .allow_trailing()
720 .collect::<Vec<_>>()
721 .boxed();
722
723 let parameter_list = parameter_list_inner
724 .then_maybe_whitespace()
725 .with_extras()
726 .map_with(|(parameters, extras), e| ast::ParameterList {
727 span: e.span(),
728 extras,
729 parameters,
730 })
731 .delimited_with_spanned_error(
732 just(Token::SigilOpenBracket),
733 just(Token::SigilCloseBracket),
734 |err: RichError, open, end| {
735 Rich::custom(
736 err.span().clone(),
737 ParseErrorKind::UnclosedBracket {
738 open,
739 end,
740 kind: "function parameters",
741 close_token: Token::SigilCloseBracket,
742 },
743 )
744 },
745 )
746 .recover_with(via_parser(
747 ignore_till_matched_brackets()
748 .or(none_of(STRUCTURAL_TOKENS).repeated())
749 .map_with(|_, e| ast::ParameterList::dummy(e.span())),
750 ))
751 .boxed();
752
753 let inline_module = doc_block
754 .clone()
755 .then(outer_attribute_parser.clone())
756 .then(visibility.then_whitespace().or_not())
757 .then(just(Token::KeywordMod).map_with(|_, e| e.span()))
758 .then_whitespace()
759 .then(
760 identifier_parser.clone().recover_with(via_parser(
761 recovery_expect_any_except(&[Token::SigilOpenCurlyBracket])
762 .map_with(|_, e| ast::Identifier::dummy(e.span())),
763 )),
764 )
765 .then_maybe_whitespace()
766 .then(body.clone())
767 .with_extras()
768 .map_with(
769 |((((((doc, attributes), visibility), keyword_span), name), body), extras), e| {
770 ast::Statement::InlineModule(ast::InlineModule {
771 span: e.span(),
772 keyword_span,
773 extras,
774 doc,
775 attributes,
776 visibility,
777 name,
778 body,
779 })
780 },
781 )
782 .boxed();
783
784 let file_module = doc_block
785 .clone()
786 .then(outer_attribute_parser.clone())
787 .then(visibility.then_whitespace().or_not())
788 .then(just(Token::KeywordMod).map_with(|_, e| e.span()))
789 .then_whitespace()
790 .then(
791 identifier_parser.clone().recover_with(via_parser(
792 recovery_expect_any_except(&[Token::SigilOpenCurlyBracket])
793 .map_with(|_, e| ast::Identifier::dummy(e.span())),
794 )),
795 )
796 .with_extras()
797 .map_with(
798 |(((((doc, attributes), visibility), keyword_span), name), extras), e| {
799 ast::Statement::FileModule(ast::FileModule {
800 span: e.span(),
801 keyword_span,
802 extras,
803 doc,
804 attributes,
805 visibility,
806 name,
807 })
808 },
809 )
810 .boxed();
811
812 let use_part = identifier_parser
813 .clone()
814 .map(ast::UseStatementPart::Identifier)
815 .or(just(Token::OperatorMultiply)
816 .map_with(|_, e| ast::UseStatementPart::Glob(e.span())))
817 .recover_with(via_parser(
818 recovery_expect_any_except(&[Token::SigilDoubleColon])
819 .map_with(|_, e| ast::UseStatementPart::Error(e.span())),
820 ))
821 .boxed();
822
823 let use_parts = use_part
824 .separated_by(just(Token::SigilDoubleColon))
825 .at_least(1)
826 .collect::<Vec<_>>()
827 .with_extras()
828 .map_with(|(parts, extras), e| ast::UseName {
829 span: e.span(),
830 extras,
831 parts,
832 })
833 .boxed();
834
835 let use_statement = outer_attribute_parser
836 .clone()
837 .then(visibility.then_whitespace().or_not())
838 .then(just(Token::KeywordUse).map_with(|_, e| e.span()))
839 .then_whitespace()
840 .then(use_parts)
841 .then(
842 select_ref! {
843 Token::KeywordAs => (),
844 }
845 .then_whitespace()
846 .ignore_then(identifier_parser.clone().recover_with(via_parser(
847 recovery_expect_any().map_with(|_, e| ast::Identifier::dummy(e.span())),
848 )))
849 .or_not(),
850 )
851 .with_extras()
852 .map_with(
853 |(((((attributes, visibility), keyword_span), name), use_as), extras), e| {
854 ast::Statement::Use(ast::UseStatement {
855 span: e.span(),
856 attributes,
857 visibility,
858 keyword_span,
859 extras,
860 name,
861 use_as,
862 })
863 },
864 )
865 .boxed();
866
867 let workbench_kind = select_ref! {
868 Token::KeywordSketch => ast::WorkbenchKind::Sketch,
869 Token::KeywordPart => ast::WorkbenchKind::Part,
870 Token::KeywordOp => ast::WorkbenchKind::Op,
871 }
872 .boxed();
873
874 let init = doc_block
875 .clone()
876 .then(outer_attribute_parser.clone())
877 .then(just(Token::KeywordInit).map_with(|_, e| e.span()))
878 .then_maybe_whitespace()
879 .then(parameter_list.clone())
880 .then(body.clone())
881 .with_extras()
882 .map_with(
883 |(((((doc, attributes), keyword_span), arguments), body), extras), e| {
884 ast::Statement::Init(ast::InitDefinition {
885 span: e.span(),
886 keyword_span,
887 extras,
888 doc,
889 attributes,
890 parameters: arguments,
891 body,
892 })
893 },
894 )
895 .boxed();
896 let workbench = doc_block
897 .clone()
898 .then(outer_attribute_parser.clone())
899 .then(visibility.then_whitespace().or_not())
900 .then(workbench_kind.map_with(|kind, e| (kind, e.span())))
901 .then_whitespace()
902 .then(
903 identifier_parser.clone().recover_with(via_parser(
904 recovery_expect_any_except(&[
905 Token::SigilOpenCurlyBracket,
906 Token::SigilOpenBracket,
907 ])
908 .map_with(|_, e| ast::Identifier::dummy(e.span())),
909 )),
910 )
911 .then_maybe_whitespace()
912 .then(parameter_list.clone())
913 .then_maybe_whitespace()
914 .then(body.clone())
915 .with_extras()
916 .map_with(
917 |(
918 (
919 (
920 ((((doc, attributes), visibility), (kind, keyword_span)), name),
921 arguments,
922 ),
923 body,
924 ),
925 extras,
926 ),
927 e| {
928 ast::Statement::Workbench(ast::WorkbenchDefinition {
929 span: e.span(),
930 keyword_span,
931 extras,
932 kind,
933 doc,
934 attributes,
935 visibility,
936 name,
937 plan: arguments,
938 body,
939 })
940 },
941 )
942 .boxed();
943
944 let return_statement = just(Token::KeywordReturn)
945 .map_with(|_, e| e.span())
946 .then_maybe_whitespace()
947 .then(expression_parser.clone().or_not())
948 .with_extras()
949 .map_with(|((keyword_span, value), extras), e| {
950 ast::Statement::Return(ast::Return {
951 span: e.span(),
952 keyword_span,
953 extras,
954 value,
955 })
956 })
957 .boxed();
958
959 let function = doc_block
960 .clone()
961 .then(outer_attribute_parser.clone())
962 .then(visibility.then_whitespace().or_not())
963 .then(just(Token::KeywordFn).map_with(|_, e| e.span()))
964 .then_whitespace()
965 .then(
966 identifier_parser.clone().recover_with(via_parser(
967 recovery_expect_any_except(&[
968 Token::SigilOpenCurlyBracket,
969 Token::SigilOpenBracket,
970 ])
971 .map_with(|_, e| ast::Identifier::dummy(e.span())),
972 )),
973 )
974 .then_maybe_whitespace()
975 .then(parameter_list.clone())
976 .then_maybe_whitespace()
977 .then(
978 just(Token::SigilSingleArrow)
979 .then_maybe_whitespace()
980 .ignore_then(type_parser.clone())
981 .then_maybe_whitespace()
982 .or_not(),
983 )
984 .then(body.clone())
985 .with_extras()
986 .map_with(
987 |(
988 (
989 (
990 (((((doc, attributes), visibility), keyword_span), name), arguments),
991 return_type,
992 ),
993 body,
994 ),
995 extras,
996 ),
997 e| {
998 ast::Statement::Function(ast::FunctionDefinition {
999 span: e.span(),
1000 keyword_span,
1001 extras,
1002 doc,
1003 attributes,
1004 visibility,
1005 name,
1006 parameters: arguments,
1007 return_type,
1008 body,
1009 })
1010 },
1011 )
1012 .boxed();
1013
1014 let inner_doc_comment = select_ref! {
1015 Token::InnerDocComment(comment) => comment.to_string(),
1016 }
1017 .labelled("inner doc-block")
1018 .map_with(|line, e| {
1019 ast::Statement::InnerDocComment(ast::InnerDocComment {
1020 span: e.span(),
1021 line,
1022 })
1023 })
1024 .boxed();
1025
1026 let inner_attribute = just(Token::SigilHash)
1027 .ignore_then(just(Token::OperatorNot))
1028 .ignore_then(attribute_inner)
1029 .with_extras()
1030 .map_with(|(commands, extras), e| ast::Attribute {
1031 span: e.span(),
1032 is_inner: true,
1033 extras,
1034 commands,
1035 })
1036 .labelled("inner attribute")
1037 .map(ast::Statement::InnerAttribute)
1038 .boxed();
1039
1040 let not_assignment = parsers::whitespace()
1041 .or_not()
1042 .then(none_of([
1043 Token::OperatorAssignment,
1044 Token::SigilDoubleColon,
1045 ]))
1046 .ignored()
1047 .or(just(Token::SigilSemiColon).ignored())
1048 .rewind()
1049 .boxed();
1050
1051 let reserved_keyword_statement = reserved_keyword
1052 .clone()
1053 .then_ignore(not_assignment.clone())
1054 .try_map_with(|kind, e| {
1055 Err::<(), _>(Rich::custom(
1056 e.span(),
1057 ParseErrorKind::ReservedKeyword(kind),
1058 ))
1059 })
1060 .ignored()
1061 .recover_with(via_parser(
1062 reserved_keyword
1063 .then_ignore(not_assignment)
1064 .clone()
1065 .ignore_then(
1066 none_of(STRUCTURAL_TOKENS)
1067 .repeated()
1068 .then_ignore(ignore_till_matched_curly())
1069 .or(ignore_till_semi().then_ignore(just(Token::SigilSemiColon))),
1070 ),
1071 ))
1072 .map_with(|_, e| ast::Statement::Error(e.span()))
1073 .boxed();
1074
1075 let with_semi = return_statement
1076 .or(use_statement)
1077 .or(const_assignment)
1078 .or(pub_assignment)
1079 .or(file_module)
1080 .or(property_assignment)
1081 .or(local_assignment)
1082 .or(expression)
1083 .then_ignore(
1084 just(Token::SigilSemiColon)
1085 .labelled("semicolon")
1086 .ignored()
1087 .recover_with(via_parser(
1088 none_of(STRUCTURAL_TOKENS)
1089 .repeated()
1090 .then_ignore(just(Token::SigilSemiColon)),
1091 )),
1092 )
1093 .boxed();
1094
1095 let without_semi = function
1096 .or(inner_doc_comment)
1097 .or(inner_attribute)
1098 .or(init)
1099 .or(workbench)
1100 .or(inline_module)
1101 .or(expression_without_semi)
1102 .boxed();
1103
1104 with_semi
1105 .or(reserved_keyword_statement)
1106 .or(without_semi)
1107 .boxed()
1108 .labelled("statement")
1109 });
1110
1111 expression_parser.define({
1112 let unclosed_string = select_ref! {
1113 Token::Error(LexerError::UnclosedString(_)) => (),
1114 }
1115 .ignore_then(
1116 semi_recovery
1117 .clone()
1118 .try_map_with(|_, e| {
1119 let span: Span = e.span();
1120 Err::<ast::Expression, _>(Rich::custom(
1121 (span.start - 1)..span.end,
1122 ParseErrorKind::UnterminatedString,
1123 ))
1124 })
1125 .recover_with(via_parser(
1126 semi_recovery
1127 .clone()
1128 .map_with(|_, e| ast::Expression::Error(e.span())),
1129 )),
1130 )
1131 .labelled("unclosed string")
1132 .boxed();
1133
1134 let literal = parsers::literal()
1135 .map(ast::Expression::Literal)
1136 .labelled("literal")
1137 .boxed()
1138 .or(unclosed_string);
1139
1140 let marker = just(Token::SigilAt)
1141 .ignore_then(identifier_parser.clone())
1142 .map(ast::Expression::Marker)
1143 .labelled("marker")
1144 .boxed();
1145
1146 let string_content_part = select_ref! {
1147 Token::StringContent(content) = e => ast::StringPart::Content(ast::StringLiteral {
1148 span: e.span(),
1149 content: content.as_ref().into(),
1150 }),
1151 Token::Character(char) = e => ast::StringPart::Char(ast::StringCharacter {
1152 span: e.span(),
1153 character: *char,
1154 }),
1155 }
1156 .labelled("string content")
1157 .boxed();
1158
1159 let format_precision = select_ref!(
1160 Token::StringFormatPrecision(precision) = e => {
1161 u32::from_str(&precision[1..]).map_err(|err| (err, e.span()))
1162 }
1163 );
1164 let format_width = select_ref!(
1165 Token::StringFormatWidth(width) = e => {
1166 u32::from_str(&width[1..]).map_err(|err| (err, e.span()))
1167 }
1168 );
1169 let format_spec = format_width
1170 .or_not()
1171 .then(format_precision.or_not())
1172 .map_with(|(width, precision), e| ast::StringFormatSpecification {
1173 span: e.span(),
1174 width,
1175 precision,
1176 })
1177 .labelled("string format specification")
1178 .boxed();
1179
1180 let string_format_part = expression_parser
1181 .clone()
1182 .then(format_spec)
1183 .with_extras()
1184 .delimited_by(
1185 just(Token::StringFormatOpen),
1186 just(Token::StringFormatClose),
1187 )
1188 .map_with(
1189 |((expression, specification), extras), e| ast::StringExpression {
1190 span: e.span(),
1191 extras,
1192 expression: Box::new(expression),
1193 specification: Box::new(specification),
1194 },
1195 )
1196 .map(ast::StringPart::Expression)
1197 .labelled("string format expression")
1198 .boxed();
1199 let string_part = string_content_part
1200 .or(string_format_part)
1201 .labelled("format string content");
1202
1203 let string_format = string_part
1204 .repeated()
1205 .collect::<Vec<_>>()
1206 .delimited_by(just(Token::FormatStringStart), just(Token::FormatStringEnd))
1207 .with_extras()
1208 .map_with(|(parts, extras), e| ast::FormatString {
1209 span: e.span(),
1210 extras,
1211 parts,
1212 })
1213 .map(ast::Expression::String)
1214 .boxed();
1215
1216 let tuple = parsers::whitespace()
1217 .or_not()
1218 .ignore_then(tuple_body.clone())
1219 .with_extras()
1220 .delimited_with_spanned_error(
1221 just(Token::SigilOpenBracket),
1222 just(Token::SigilCloseBracket),
1223 |err: RichError, open, end| {
1224 Rich::custom(
1225 err.span().clone(),
1226 ParseErrorKind::UnclosedBracket {
1227 open,
1228 end,
1229 kind: "tuple",
1230 close_token: Token::SigilCloseBracket,
1231 },
1232 )
1233 },
1234 )
1235 .map_with(|(values, extras), e| {
1236 ast::Expression::Tuple(ast::TupleExpression {
1237 span: e.span(),
1238 extras,
1239 values,
1240 })
1241 })
1242 .labelled("tuple");
1243
1244 let bracketed = expression_parser
1245 .clone()
1246 .then_maybe_whitespace()
1247 .delimited_with_spanned_error(
1248 just(Token::SigilOpenBracket).then_maybe_whitespace(),
1249 just(Token::SigilCloseBracket),
1250 |err: RichError, open, end| {
1251 Rich::custom(
1252 err.span().clone(),
1253 ParseErrorKind::UnclosedBracket {
1254 open,
1255 end,
1256 kind: "bracketed expression",
1257 close_token: Token::SigilCloseBracket,
1258 },
1259 )
1260 },
1261 )
1262 .map_with(|expression, e| ast::Expression::Bracketed(Box::new(expression), e.span()))
1263 .boxed();
1264
1265 let array_item = expression_parser
1266 .clone()
1267 .with_extras()
1268 .map_with(|(expression, extras), e| ast::ArrayItem {
1269 span: e.span(),
1270 extras,
1271 expression,
1272 })
1273 .boxed();
1274
1275 let array_range = array_item
1276 .clone()
1277 .then_ignore(just(Token::SigilDoubleDot))
1278 .then(array_item.clone())
1279 .with_extras()
1280 .delimited_by(
1281 just(Token::SigilOpenSquareBracket).then_maybe_whitespace(),
1282 just(Token::SigilCloseSquareBracket),
1283 )
1284 .then(unit.clone().or_not())
1285 .map_with(|(((start, end), extras), unit), e| {
1286 ast::Expression::ArrayRange(ast::ArrayRangeExpression {
1287 span: e.span(),
1288 extras,
1289 start: Box::new(start),
1290 end: Box::new(end),
1291 unit,
1292 })
1293 })
1294 .labelled("array range")
1295 .boxed();
1296
1297 let array_list = array_item
1298 .clone()
1299 .separated_by(just(Token::SigilComma).then_maybe_whitespace())
1300 .allow_trailing()
1301 .collect::<Vec<_>>()
1302 .with_extras()
1303 .delimited_by(
1304 just(Token::SigilOpenSquareBracket).then_maybe_whitespace(),
1305 just(Token::SigilCloseSquareBracket),
1306 )
1307 .then(unit.clone().or_not())
1308 .map_with(|((items, extras), unit), e| {
1309 ast::Expression::ArrayList(ast::ArrayListExpression {
1310 span: e.span(),
1311 extras,
1312 items,
1313 unit,
1314 })
1315 })
1316 .labelled("array")
1317 .boxed();
1318
1319 let body_expression = body
1320 .clone()
1321 .map(ast::Expression::Body)
1322 .labelled("body expression")
1323 .boxed();
1324
1325 if_inner.define(
1326 just(Token::KeywordIf)
1327 .map_with(|_, e| e.span())
1328 .then_whitespace()
1329 .then(expression_parser.clone())
1330 .then_maybe_whitespace()
1331 .then(body.clone())
1332 .then_maybe_whitespace()
1333 .then(
1334 just(Token::KeywordElse)
1335 .map_with(|_, e| e.span())
1336 .then_maybe_whitespace()
1337 .then(if_inner.clone())
1338 .map(|(span, inner)| (span, Box::new(inner)))
1339 .or_not(),
1340 )
1341 .then(
1342 just(Token::KeywordElse)
1343 .map_with(|_, e| e.span())
1344 .then_maybe_whitespace()
1345 .then(body.clone())
1346 .or_not(),
1347 )
1348 .with_extras()
1349 .map_with(
1350 |(((((if_span, condition), body), next_if), else_body), extras), e| {
1351 let (next_if_span, next_if) = next_if
1352 .map(|(span, if_expr)| (Some(span), Some(if_expr)))
1353 .unwrap_or((None, None));
1354 let (else_span, else_body) = else_body
1355 .map(|(span, body)| (Some(span), Some(body)))
1356 .unwrap_or((None, None));
1357 ast::If {
1358 span: e.span(),
1359 if_span,
1360 extras,
1361 condition: Box::new(condition),
1362 body,
1363 next_if_span,
1364 next_if,
1365 else_span,
1366 else_body,
1367 }
1368 },
1369 )
1370 .boxed(),
1371 );
1372 let if_expression = if_inner
1373 .map(ast::Expression::If)
1374 .labelled("if expression")
1375 .boxed();
1376
1377 let qualified_name_expr = identifier_parser
1378 .clone()
1379 .map_with(|ident, e| ast::QualifiedName {
1380 span: e.span(),
1381 parts: vec![ident],
1382 extras: ast::ItemExtras::default(),
1383 })
1384 .foldl_with(
1385 just(Token::SigilDoubleColon)
1386 .ignore_then(identifier_parser.clone())
1387 .repeated(),
1388 |mut acc, part, _| {
1389 acc.span.end = part.span.end;
1390 acc.parts.push(part);
1391 acc
1392 },
1393 )
1394 .with_extras()
1395 .map(|(mut name, extras)| {
1396 name.extras = extras;
1397 name
1398 })
1399 .map(ast::Expression::QualifiedName)
1400 .boxed();
1401
1402 let call = call_inner
1403 .clone()
1404 .map(ast::Expression::Call)
1405 .labelled("method call");
1406
1407 let bracket_based = bracketed.or(tuple).recover_with(via_parser(
1408 tuple_recovery
1409 .clone()
1410 .map_with(|_, e| ast::Expression::Error(e.span())),
1411 ));
1412
1413 let base = literal
1414 .or(string_format)
1415 .or(call)
1416 .or(marker)
1417 .or(bracket_based)
1418 .or(array_range)
1419 .or(array_list)
1420 .or(body_expression)
1421 .or(if_expression)
1422 .or(qualified_name_expr)
1423 .boxed();
1424
1425 let access_attribute = just(Token::SigilHash)
1426 .ignore_then(identifier_parser.clone())
1427 .map(ast::ElementInner::Attribute)
1428 .labelled("attribute access")
1429 .boxed();
1430
1431 let access_tuple = just(Token::SigilDot)
1432 .ignore_then(identifier_parser.clone())
1433 .map(ast::ElementInner::Tuple)
1434 .labelled("tuple access")
1435 .boxed();
1436
1437 let access_method = just(Token::SigilDot)
1438 .ignore_then(call_inner)
1439 .map(ast::ElementInner::Method)
1440 .labelled("method call")
1441 .boxed();
1442
1443 let access_array = expression_parser
1444 .clone()
1445 .delimited_by(
1446 just(Token::SigilOpenSquareBracket),
1447 just(Token::SigilCloseSquareBracket),
1448 )
1449 .map(Box::new)
1450 .map(ast::ElementInner::ArrayElement)
1451 .labelled("array access")
1452 .boxed();
1453
1454 let access_item = access_attribute
1455 .or(access_method)
1456 .or(access_tuple)
1457 .or(access_array)
1458 .with_extras()
1459 .map_with(|(inner, extras), e| ast::Element {
1460 span: e.span(),
1461 inner,
1462 extras,
1463 })
1464 .repeated()
1465 .at_least(1)
1466 .collect::<Vec<ast::Element>>();
1467
1468 let element_access = base
1469 .clone()
1470 .foldl_with(access_item.repeated(), |value, element_chain, e| {
1471 ast::Expression::ElementAccess(ast::ElementAccess {
1472 span: e.span(),
1473 value: value.into(),
1474 element_chain,
1475 })
1476 })
1477 .labelled("element access")
1478 .boxed();
1479
1480 let unary_expression = unary_operator_parser
1481 .then_maybe_whitespace()
1482 .then(element_access.clone())
1483 .with_extras()
1484 .map_with(|((op, rhs), extras), e| {
1485 ast::Expression::UnaryOperation(ast::UnaryOperation {
1486 span: e.span(),
1487 extras,
1488 operation: op,
1489 rhs: rhs.into(),
1490 })
1491 })
1492 .boxed();
1493
1494 let binary_param = element_access.or(unary_expression.clone());
1495
1496 let near = binop(binary_param, &[Token::OperatorNear]);
1497 let xor = binop(near, &[Token::OperatorPowerXor, Token::OperatorXor]);
1498 let union_intersect = binop(xor, &[Token::OperatorUnion, Token::OperatorIntersect]);
1499 let mul_div = binop(
1500 union_intersect,
1501 &[Token::OperatorMultiply, Token::OperatorDivide],
1502 );
1503 let add_sub = binop(mul_div, &[Token::OperatorAdd, Token::OperatorSubtract]);
1504 let less_greater_eq = binop(
1505 add_sub,
1506 &[Token::OperatorLessEqual, Token::OperatorGreaterEqual],
1507 );
1508 let less_greater = binop(
1509 less_greater_eq,
1510 &[Token::OperatorLessThan, Token::OperatorGreaterThan],
1511 );
1512 let eq_neq = binop(
1513 less_greater,
1514 &[Token::OperatorEqual, Token::OperatorNotEqual],
1515 );
1516 let or_and = binop(eq_neq, &[Token::OperatorOr, Token::OperatorAnd]);
1517
1518 or_and.labelled("expression").boxed()
1519 });
1520
1521 statement_list_parser
1522 .then_ignore(end())
1523 .map_with(move |statements, ex| ast::Program {
1524 span: ex.span(),
1525 statements,
1526 })
1527}
1528
1529impl crate::Parse for ast::Literal {
1530 fn parse(context: &ParseContext) -> Result<Self, ParseErrors> {
1531 fn literal<'tokens>()
1532 -> impl Parser<'tokens, ParserInput<'tokens, 'tokens>, ast::Literal, Extra<'tokens>>
1533 {
1534 crate::parsers::literal()
1535 }
1536
1537 match context {
1538 ParseContext::Element(source) => {
1539 use chumsky::Parser;
1540 let tokens = crate::tokens::lex(source.value()).collect::<Vec<_>>();
1541 literal()
1542 .parse(crate::parser::input(&tokens))
1543 .into_result()
1544 .map_err(|errors| errors.into())
1545 }
1546 _ => panic!("Not possible"),
1547 }
1548 }
1549}