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