1use crate::ast::operators::Op;
2use crate::ast::*;
3use crate::interner::{ExprNodeId, Symbol, ToSymbol, TypeNodeId};
4use crate::pattern::{Pattern, TypedId, TypedPattern};
5use crate::types::{PType, RecordTypeField, Type};
6use crate::utils::error::ReportableError;
7use crate::utils::metadata::*;
8use std::path::PathBuf;
9
10use chumsky::input::{Stream, ValueInput};
11use chumsky::{Parser, prelude::*};
12mod token;
13pub use token::Token;
14mod error;
15mod lexer;
16use crate::ast::program::{Program, ProgramStatement, expr_from_program};
17use crate::ast::statement;
18use statement::{Statement, into_then_expr};
19
20use super::intrinsics;
21
22#[cfg(test)]
23mod test;
24
25#[derive(Clone)]
26pub(super) struct ParseContext {
27 file_path: PathBuf,
28}
29impl ParseContext {
30 pub fn gen_loc(&self, span: SimpleSpan) -> Location {
31 Location {
32 span: span.start()..span.end(),
33 path: self.file_path.clone(),
34 }
35 }
36}
37pub(crate) type ParseError<'src> = chumsky::extra::Err<Rich<'src, Token, SimpleSpan>>;
38fn merge_span(a: Span, b: Span) -> Span {
39 a.start..b.end
40}
41fn get_span<T: chumsky::span::Span<Offset = usize>>(e: T) -> Span {
42 e.start()..e.end()
43}
44
45fn breakable_comma<'src, I>() -> impl Parser<'src, I, (), ParseError<'src>> + Clone
46where
47 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
48{
49 just(Token::Comma)
50 .ignore_then(just(Token::LineBreak).or_not())
51 .ignored()
52}
53fn breakable_blockbegin<'src, I>() -> impl Parser<'src, I, (), ParseError<'src>> + Clone
54where
55 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
56{
57 just(Token::BlockBegin)
58 .then(just(Token::LineBreak).or(just(Token::SemiColon)).repeated())
59 .ignored()
60}
61fn breakable_blockend<'src, I>() -> impl Parser<'src, I, (), ParseError<'src>> + Clone
62where
63 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
64{
65 just(Token::LineBreak)
66 .or(just(Token::SemiColon))
67 .repeated()
68 .then(just(Token::BlockEnd))
69 .ignored()
70}
71
72fn type_primitive<'src, I>(
73 ctx: ParseContext,
74) -> impl Parser<'src, I, TypeNodeId, ParseError<'src>> + Clone
75where
76 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
77{
78 select! {
79 Token::FloatType => PType::Numeric,
80 Token::StringType => PType::String,
81 Token::IntegerType => PType::Int,
82 }
83 .map_with(move |t, e| {
84 Type::Primitive(t)
85 .into_id_with_location(Location::new(get_span(e.span()), ctx.file_path.clone()))
86 })
87 .labelled("primitive type")
88}
89
90fn type_parser<'src, I>(
91 ctx: ParseContext,
92) -> impl Parser<'src, I, TypeNodeId, ParseError<'src>> + Clone
93where
94 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
95{
96 let path = ctx.file_path.clone();
97 recursive(move |ty| {
98 let path2 = path.clone();
99 let tuple = ty
100 .clone()
101 .separated_by(just(Token::Comma))
102 .at_least(1)
103 .allow_trailing()
104 .collect::<Vec<_>>()
105 .delimited_by(just(Token::ParenBegin), just(Token::ParenEnd))
106 .map_with(move |item: Vec<TypeNodeId>, e| {
107 Type::Tuple(item).into_id_with_location(Location {
108 span: get_span(e.span()),
109 path: path.clone(),
110 })
111 })
112 .recover_with(via_parser(nested_delimiters(
113 Token::ParenBegin,
114 Token::ParenEnd,
115 [],
116 move |_span| Type::Failure.into_id(),
117 )))
118 .labelled("Tuple Type");
119 let path = path2.clone();
120
121 let record = ident_parser()
122 .then_ignore(just(Token::Colon))
123 .then(ty.clone())
124 .map(|(key, ty)| RecordTypeField::new(key, ty, false))
125 .separated_by(breakable_comma())
126 .allow_trailing()
127 .collect::<Vec<_>>()
128 .delimited_by(just(Token::BlockBegin), just(Token::BlockEnd))
129 .map_with(move |fields, e| {
130 Type::Record(fields).into_id_with_location(Location {
131 span: get_span(e.span()),
132 path: path.clone(),
133 })
134 })
135 .recover_with(via_parser(nested_delimiters(
136 Token::BlockBegin,
137 Token::BlockEnd,
138 [],
139 move |_span| Type::Failure.into_id(),
140 )))
141 .labelled("Record Type");
142 let path = path2.clone();
144
145 let array = ty
146 .clone()
147 .delimited_by(just(Token::ArrayBegin), just(Token::ArrayEnd))
148 .map_with(move |element_type, e| {
149 Type::Array(element_type).into_id_with_location(Location {
150 span: get_span(e.span()),
151 path: path.clone(),
152 })
153 })
154 .boxed()
155 .labelled("Array");
156 let path = path2.clone();
157
158 let code = just(Token::BackQuote)
159 .ignore_then(ty.clone())
160 .map_with(move |inner_type, e| {
161 Type::Code(inner_type).into_id_with_location(Location {
162 span: get_span(e.span()),
163 path: path.clone(),
164 })
165 })
166 .labelled("Code");
167 let atom = choice((type_primitive(ctx.clone()), record, tuple, array, code));
168 let func = atom
169 .clone()
170 .separated_by(just(Token::Comma))
171 .collect::<Vec<_>>()
172 .map_with(move |arg, e| (arg, e.span()))
173 .delimited_by(just(Token::ParenBegin), just(Token::ParenEnd))
174 .then(just(Token::Arrow).ignore_then(ty.clone()))
175 .map_with(move |((body, bspan), ret), e| {
176 Type::Function {
177 arg: Type::Tuple(body).into_id_with_location(ctx.gen_loc(bspan)),
178 ret,
179 }
180 .into_id_with_location(ctx.gen_loc(e.span()))
181 })
182 .boxed()
183 .labelled("function");
184
185 func.or(atom).labelled("Type")
186 })
187}
188pub(super) fn ident_parser<'src, I>() -> impl Parser<'src, I, Symbol, ParseError<'src>> + Clone
189where
190 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
191{
192 select! { Token::Ident(s) => s }.labelled("ident")
193}
194fn literals_parser<'src, I>(
195 ctx: ParseContext,
196) -> impl Parser<'src, I, ExprNodeId, ParseError<'src>> + Clone
197where
198 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
199{
200 select! {
201 Token::Int(x)=>Literal::Float(x.to_string().to_symbol()),
204 Token::Float(x) =>Literal::Float(x.to_symbol()),
205 Token::Str(s) => Literal::String(s.to_symbol()),
206 Token::SelfLit => Literal::SelfLit,
207 Token::Now => Literal::Now,
208 Token::SampleRate => Literal::SampleRate,
209 Token::PlaceHolder => Literal::PlaceHolder,
210 }
211 .map_with(move |lit, e| {
212 Expr::Literal(lit).into_id(Location {
213 span: get_span(e.span()),
214 path: ctx.file_path.clone(),
215 })
216 })
217 .labelled("literal")
218}
219fn var_parser<'src, I>(
220 ctx: ParseContext,
221) -> impl Parser<'src, I, ExprNodeId, ParseError<'src>> + Clone
222where
223 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
224{
225 ident_parser().map_with(move |s, e| {
226 Expr::Var(s).into_id(Location {
227 span: get_span(e.span()),
228 path: ctx.file_path.clone(),
229 })
230 })
231}
232fn with_type_annotation<'src, I, T>(
233 parser: impl Parser<'src, I, T, ParseError<'src>> + Clone,
234 ctx: ParseContext,
235) -> impl Parser<'src, I, (T, Option<TypeNodeId>), ParseError<'src>> + Clone
236where
237 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
238{
239 parser.then(just(Token::Colon).ignore_then(type_parser(ctx)).or_not())
240}
241
242fn lvar_parser_typed<'src, I>(
243 ctx: ParseContext,
244) -> impl Parser<'src, I, TypedId, ParseError<'src>> + Clone
245where
246 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
247{
248 with_type_annotation(ident_parser(), ctx.clone())
249 .map_with(move |(sym, t), e| match t {
250 Some(ty) => TypedId {
251 id: sym,
252 ty,
253 default_value: None,
254 },
255 None => TypedId {
256 id: sym,
257 ty: Type::Unknown.into_id_with_location(Location {
258 span: get_span(e.span()),
259 path: ctx.file_path.clone(),
260 }),
261 default_value: None,
262 },
263 })
264 .labelled("lvar_typed")
265}
266
267fn lvar_parser_typed_with_default<'src, I>(
269 ctx: ParseContext,
270 expr: impl Parser<'src, I, ExprNodeId, ParseError<'src>> + Clone,
271) -> impl Parser<'src, I, TypedPattern, ParseError<'src>> + Clone
272where
273 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
274{
275 lvar_parser_typed(ctx.clone())
276 .then(
277 just(Token::Assign).ignore_then(expr).or_not(),
279 )
280 .map(|(param, default_value)| TypedId {
281 id: param.id,
282 ty: param.ty,
283 default_value,
284 })
285 .map(TypedPattern::from)
286 .labelled("lvar_typed_with_default")
287}
288fn pattern_parser<'src, I>(
289 ctx: ParseContext,
290) -> impl Parser<'src, I, TypedPattern, ParseError<'src>> + Clone
291where
292 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
293{
294 let single_pat = select! {
295 Token::Ident(s) => Pattern::Single(s),
296 Token::PlaceHolder => Pattern::Single("_".to_symbol())
299
300 }
301 .labelled("single pattern");
302 let pat = recursive(|pat| {
303 let tup = pat
304 .clone()
305 .separated_by(just(Token::Comma))
306 .at_least(1)
307 .allow_trailing()
308 .collect::<Vec<_>>()
309 .delimited_by(just(Token::ParenBegin), just(Token::ParenEnd))
310 .map(Pattern::Tuple)
311 .labelled("tuple pattern");
312 let record = (ident_parser()
313 .then_ignore(just(Token::Assign))
314 .then(pat.clone()))
315 .separated_by(breakable_comma())
316 .at_least(1)
317 .allow_trailing()
318 .collect::<Vec<_>>()
319 .delimited_by(breakable_blockbegin(), breakable_blockend())
320 .map(Pattern::Record)
321 .recover_with(via_parser(nested_delimiters(
322 Token::BlockBegin,
323 Token::BlockEnd,
324 [],
325 |_| Pattern::Error,
326 )))
327 .labelled("record pattern");
328 choice((single_pat, tup, record)).labelled("pattern")
329 });
330 with_type_annotation(pat, ctx.clone())
331 .map_with(move |(pat, ty), e| match ty {
332 Some(ty) => TypedPattern::new(pat, ty),
333 None => TypedPattern::new(
334 pat,
335 Type::Unknown.into_id_with_location(Location {
336 span: get_span(e.span()),
337 path: ctx.file_path.clone(),
338 }),
339 ),
340 })
341 .boxed()
342}
343
344fn items_parser<'src, I, E>(
345 expr: E,
346 allow_empty: bool,
347) -> impl Parser<'src, I, Vec<ExprNodeId>, ParseError<'src>> + Clone
348where
349 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
350 E: Parser<'src, I, ExprNodeId, ParseError<'src>> + Clone,
351{
352 let least_repeat = if allow_empty { 0 } else { 1 };
353 expr.separated_by(breakable_comma())
354 .allow_trailing()
355 .at_least(least_repeat)
356 .collect::<Vec<_>>()
357}
358enum DotField {
359 Index(i64),
360 Ident(Symbol),
361}
362fn dot_field<'src, I>() -> impl Parser<'src, I, (DotField, Span), ParseError<'src>> + Clone
363where
364 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
365{
366 select! {
367 Token::Int(i) => DotField::Index(i),
368 Token::Ident(s) => DotField::Ident(s),
369 }
370 .map_with(|field, e| (field, get_span(e.span())))
371 .labelled("dot_field")
372}
373fn op_parser<'src, I, P>(
374 apply: P,
375 ctx: ParseContext,
376) -> impl Parser<'src, I, ExprNodeId, ParseError<'src>> + Clone
377where
378 P: Parser<'src, I, ExprNodeId, ParseError<'src>> + Clone + 'src,
379 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
380{
381 let ctx = ctx.clone();
382 let path = ctx.file_path.clone();
383 let dot = apply .foldl(
385 just(Token::Dot).ignore_then(dot_field()).repeated(),
386 move |lhs, (rhs, rspan)| {
387 let span = lhs.to_span().start..rspan.end;
388
389 let loc = Location {
390 span,
391 path: path.clone(),
392 };
393 match rhs {
394 DotField::Ident(name) => Expr::FieldAccess(lhs, name).into_id(loc),
395 DotField::Index(idx) => Expr::Proj(lhs, idx).into_id(loc),
396 }
397 },
398 )
399 .labelled("dot");
400 let path = ctx.file_path.clone();
401 let unary = one_of([Token::Op(Op::Minus), Token::BackQuote, Token::Dollar])
402 .map_with(|token, e| (token, get_span(e.span())))
403 .repeated()
404 .foldr(dot, move |(op, op_span), rhs| {
405 let rhs_span = rhs.to_span();
406 let loc = Location {
407 span: op_span.start..rhs_span.end,
408 path: path.clone(),
409 };
410 match op {
411 Token::BackQuote => Expr::Bracket(rhs).into_id(loc.clone()),
412 Token::Dollar => Expr::Escape(rhs).into_id(loc.clone()),
413 Token::Op(Op::Minus) => Expr::UniOp((Op::Minus, op_span), rhs).into_id(loc),
414 _ => unreachable!("Unexpected unary operator: {:?}", op),
415 }
416 })
417 .labelled("unary");
418 let optoken = move |target: Op| {
419 select! {
420 Token::Op(o) if o == target => o,
421 }
422 .boxed()
423 };
424 let pipe = just(Token::LineBreak)
427 .repeated()
428 .collect::<Vec<_>>()
429 .ignore_then(just(Token::Op(Op::Pipe)))
430 .to(Op::Pipe)
431 .boxed();
432 let ops = [
435 optoken(Op::Exponent),
436 choice((
437 optoken(Op::Product),
438 optoken(Op::Divide),
439 optoken(Op::Modulo),
440 ))
441 .boxed(),
442 optoken(Op::Sum).or(optoken(Op::Minus)).boxed(),
443 optoken(Op::Equal).or(optoken(Op::NotEqual)).boxed(),
444 optoken(Op::And),
445 optoken(Op::Or),
446 choice((
447 optoken(Op::LessThan),
448 optoken(Op::LessEqual),
449 optoken(Op::GreaterThan),
450 optoken(Op::GreaterEqual),
451 ))
452 .boxed(),
453 pipe,
454 optoken(Op::At),
455 ];
456 ops.into_iter().fold(unary.boxed(), move |prec, op| {
457 let path = ctx.file_path.clone();
458 prec.clone()
459 .foldl(
460 op.then_ignore(just(Token::LineBreak).repeated())
461 .map_with(move |op, e| (op, get_span(e.span())))
462 .then(prec)
463 .repeated(),
464 move |x, ((op, opspan), y)| {
465 let span = x.to_span().start..y.to_span().end;
466 let loc = Location {
467 span,
468 path: path.clone(),
469 };
470 Expr::BinOp(x, (op, opspan), y).into_id(loc)
471 },
472 )
473 .boxed()
474 })
475}
476fn record_fields<'src, I, P>(expr: P) -> impl Parser<'src, I, RecordField, ParseError<'src>> + Clone
477where
478 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
479 P: Parser<'src, I, ExprNodeId, ParseError<'src>> + Clone,
480{
481 ident_parser()
482 .then_ignore(just(Token::Assign))
483 .then(expr.clone())
484 .map(move |(name, expr)| RecordField { name, expr })
485}
486
487pub(super) fn atom_parser<'src, I>(
488 expr: impl Parser<'src, I, ExprNodeId, ParseError<'src>> + Clone + 'src,
489 expr_group: impl Parser<'src, I, ExprNodeId, ParseError<'src>> + Clone + 'src,
490 ctx: ParseContext,
491) -> impl Parser<'src, I, ExprNodeId, ParseError<'src>> + Clone
492where
493 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
494{
495 let path = ctx.file_path.clone();
496 let lambda = lvar_parser_typed(ctx.clone())
497 .separated_by(just(Token::Comma))
498 .collect::<Vec<_>>()
499 .delimited_by(
500 just(Token::LambdaArgBeginEnd),
501 just(Token::LambdaArgBeginEnd),
502 )
503 .then(
504 just(Token::Arrow)
505 .ignore_then(type_parser(ctx.clone()))
506 .or_not(),
507 )
508 .then(expr_group.clone())
509 .map_with(move |((ids, r_type), body), e| {
510 Expr::Lambda(ids, r_type, body).into_id(Location {
511 span: get_span(e.span()),
512 path: path.clone(),
513 })
514 })
515 .labelled("lambda");
516 let path = ctx.file_path.clone();
517 let path2 = ctx.file_path.clone();
518 let macro_expand = select! { Token::MacroExpand(s) => Expr::Var(s) }
519 .map_with(move |v, e| {
520 v.into_id(Location {
521 span: get_span(e.span()),
522 path: path.clone(),
523 })
524 })
525 .then_ignore(just(Token::ParenBegin))
526 .then(
527 expr_group
528 .clone()
529 .separated_by(breakable_comma())
530 .collect::<Vec<_>>(),
531 )
532 .then_ignore(just(Token::ParenEnd))
533 .map_with(move |(id, then), e| {
534 let loc = Location {
535 span: get_span(e.span()),
536 path: path2.clone(),
537 };
538 Expr::MacroExpand(id, then).into_id(loc.clone())
539 })
540 .labelled("macroexpand");
541 let path = ctx.file_path.clone();
542 let tuple = items_parser(expr.clone(), false)
543 .delimited_by(just(Token::ParenBegin), just(Token::ParenEnd))
544 .map_with(move |items, e| {
545 Expr::Tuple(items).into_id(Location {
546 span: get_span(e.span()),
547 path: path.clone(),
548 })
549 })
550 .labelled("tuple");
551 let path = ctx.file_path.clone();
552 let array_literal = items_parser(expr.clone(), true)
553 .delimited_by(just(Token::ArrayBegin), just(Token::ArrayEnd))
554 .map_with(move |items, e| {
555 let loc = Location {
558 span: get_span(e.span()),
559 path: path.clone(),
560 };
561 Expr::ArrayLiteral(items).into_id(loc)
562 })
563 .labelled("array_literal");
564 let path = ctx.file_path.clone();
565 let path2 = ctx.file_path.clone();
566 let record_parser = choice((
568 expr_group
570 .clone()
571 .then_ignore(just(Token::LeftArrow))
572 .then(
573 record_fields(expr.clone())
574 .separated_by(breakable_comma())
575 .allow_trailing()
576 .collect::<Vec<_>>(),
577 )
578 .delimited_by(breakable_blockbegin(), breakable_blockend())
579 .map_with(move |(record, fields), e| {
580 let mut fields = fields;
581 fields.sort_by(|a, b| a.name.cmp(&b.name));
582 let loc = Location {
583 span: get_span(e.span()),
584 path: path.clone(),
585 };
586 Expr::RecordUpdate(record, fields).into_id(loc)
587 })
588 .labelled("record_update"),
589 record_fields(expr.clone())
591 .separated_by(breakable_comma())
592 .allow_trailing()
593 .collect::<Vec<_>>()
594 .then(just(Token::DoubleDot).or_not())
595 .delimited_by(breakable_blockbegin(), breakable_blockend())
596 .map_with(move |(fields, is_imcomplete), e| {
597 let mut fields = fields;
598 fields.sort_by(|a, b| a.name.cmp(&b.name));
599 let loc = Location {
600 span: get_span(e.span()),
601 path: path2.clone(),
602 };
603 if is_imcomplete.is_some() {
604 log::trace!("is imcomplete record literal");
605 Expr::ImcompleteRecord(fields).into_id(loc)
606 } else {
607 Expr::RecordLiteral(fields).into_id(loc)
608 }
609 })
610 .labelled("record_literal"),
611 ))
612 .labelled("record_parser");
613 let path = ctx.file_path.clone();
614 let parenexpr = expr
615 .clone()
616 .delimited_by(just(Token::ParenBegin), just(Token::ParenEnd))
617 .map_with(move |e, e_s| {
618 Expr::Paren(e).into_id(Location {
619 span: get_span(e_s.span()),
620 path: path.clone(),
621 })
622 })
623 .labelled("paren_expr");
624 choice((
626 literals_parser(ctx.clone()),
627 var_parser(ctx.clone()),
628 lambda,
629 macro_expand,
630 parenexpr,
631 record_parser,
632 array_literal,
633 tuple,
634 ))
635 .boxed()
636 .labelled("atom")
637}
638fn expr_parser<'src, I>(
639 expr_group: impl Parser<'src, I, ExprNodeId, ParseError<'src>> + Clone + 'src,
640 ctx: ParseContext,
641) -> impl Parser<'src, I, ExprNodeId, ParseError<'src>> + Clone
642where
643 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
644{
645 let path = ctx.file_path.clone();
646 recursive(|expr| {
647 enum FoldItem {
648 Args(Vec<ExprNodeId>),
649 ArrayIndex(ExprNodeId),
650 }
651 let parenitems = items_parser(expr.clone(), true)
652 .delimited_by(just(Token::ParenBegin), just(Token::ParenEnd))
653 .map_with(|args, e| (FoldItem::Args(args), get_span(e.span())));
654 let angle_paren_expr = expr
655 .clone()
656 .delimited_by(just(Token::ArrayBegin), just(Token::ArrayEnd))
657 .map_with(|v, e| (FoldItem::ArrayIndex(v), get_span(e.span())));
658
659 let folder = move |f: ExprNodeId, (item, args_span): (FoldItem, Span)| {
660 let f_span = f.to_span();
661 let span = f_span.start..args_span.end;
662 let loc = Location {
663 span,
664 path: path.clone(),
665 };
666 match item {
667 FoldItem::Args(args) => Expr::Apply(f, args).into_id(loc),
668 FoldItem::ArrayIndex(index) => Expr::ArrayAccess(f, index).into_id(loc),
669 }
670 };
671
672 let apply = atom_parser(expr.clone(), expr_group, ctx.clone())
673 .foldl(angle_paren_expr.or(parenitems).repeated(), folder)
674 .labelled("apply");
675
676 op_parser(apply, ctx).boxed()
677 })
678}
679fn validate_reserved_pat<'src>(
680 id: &TypedPattern,
681 span: SimpleSpan,
682) -> Result<(), Rich<'src, Token>> {
683 match &id.pat {
684 Pattern::Single(symbol) => validate_reserved_ident(*symbol, span),
685 _ => Ok(()),
686 }
687}
688
689fn validate_reserved_ident<'src>(id: Symbol, span: SimpleSpan) -> Result<(), Rich<'src, Token>> {
690 if intrinsics::BUILTIN_SYMS.with(|syms| syms.binary_search(&id).is_ok()) {
691 Err(Rich::custom(
692 span,
693 "Builtin functions cannot be re-defined.",
694 ))
695 } else {
696 Ok(())
697 }
698}
699
700fn statement_parser<'src, I>(
701 expr: impl Parser<'src, I, ExprNodeId, ParseError<'src>> + Clone + 'src,
702 ctx: ParseContext,
703) -> impl Parser<'src, I, (Statement, Location), ParseError<'src>> + Clone
704where
705 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
706{
707 let let_ = just(Token::Let)
708 .ignore_then(pattern_parser(ctx.clone()).validate(|pat, e, emitter| {
709 if let Err(e) = validate_reserved_pat(&pat, e.span()) {
710 emitter.emit(e);
711 }
712 pat
713 }))
714 .then_ignore(just(Token::Assign).then(just(Token::LineBreak).repeated()))
715 .then(expr.clone())
716 .map_with(|(ident, body), e| (Statement::Let(ident, body), get_span(e.span())))
717 .labelled("let");
718 let letrec = just(Token::LetRec)
719 .ignore_then(
720 lvar_parser_typed(ctx.clone()).validate(|ident, e, emitter| {
721 if let Err(e) = validate_reserved_ident(ident.id, e.span()) {
722 emitter.emit(e);
723 }
724 ident
725 }),
726 )
727 .then_ignore(just(Token::Assign).then(just(Token::LineBreak).repeated()))
728 .then(expr.clone())
729 .map_with(|(ident, body), e| (Statement::LetRec(ident, body), get_span(e.span())))
730 .labelled("letrec");
731 let assign = expr
732 .clone()
733 .validate(|v, _e, emitter| match v.to_expr() {
734 Expr::Var(_) | Expr::FieldAccess(_, _) | Expr::ArrayAccess(_, _) => v,
735 _ => {
736 emitter.emit(Rich::custom(
737 v.to_span().into(),
738 "Left hand side of assignment must denotes specific memory address.",
739 ));
740 v
741 }
742 })
743 .then_ignore(just(Token::Assign))
744 .then(expr.clone())
745 .map_with(|(lvar, body), e| (Statement::Assign(lvar, body), get_span(e.span())))
746 .labelled("assign");
747 let single = expr
748 .map_with(|s, e| (Statement::Single(s), get_span(e.span())))
749 .labelled("single");
750 choice((let_, letrec, assign, single))
751 .boxed()
752 .map(move |(t, span)| {
753 (
754 t,
755 Location {
756 span: span.start()..span.end(),
757 path: ctx.file_path.clone(),
758 },
759 )
760 })
761}
762fn statements_parser<'src, I>(
763 expr: impl Parser<'src, I, ExprNodeId, ParseError<'src>> + Clone + 'src,
764 ctx: ParseContext,
765) -> impl Parser<'src, I, Option<ExprNodeId>, ParseError<'src>> + Clone
766where
767 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
768{
769 statement_parser(expr, ctx.clone())
770 .separated_by(just(Token::LineBreak).or(just(Token::SemiColon)).repeated())
771 .allow_leading()
772 .allow_trailing()
773 .collect::<Vec<_>>()
774 .recover_with(skip_then_retry_until(
775 any().ignored(),
776 one_of([Token::LineBreak, Token::SemiColon])
777 .ignored()
778 .or(end()),
779 ))
780 .map(|stmts| into_then_expr(&stmts))
781 .boxed()
782}
783
784fn block_parser<'src, I>(
785 expr: impl Parser<'src, I, ExprNodeId, ParseError<'src>> + Clone + 'src,
786 ctx: ParseContext,
787) -> impl Parser<'src, I, ExprNodeId, ParseError<'src>> + Clone
788where
789 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
790{
791 let stmts = statements_parser(expr, ctx.clone());
792 let ctx3 = ctx.clone();
793 let block = stmts
794 .delimited_by(breakable_blockbegin(), breakable_blockend())
795 .map_with(move |stmts, e| Expr::Block(stmts).into_id(ctx.clone().gen_loc(e.span())));
796 one_of([Token::BackQuote, Token::Dollar])
797 .map_with(move |op, e| (op, get_span(e.span())))
798 .repeated()
799 .foldr(block, move |(op, op_span), rhs| {
800 let rhs_span = rhs.to_span();
801 let loc = Location {
802 span: merge_span(op_span, rhs_span),
803 path: ctx3.file_path.clone(),
804 };
805 match op {
806 Token::BackQuote => Expr::Bracket(rhs).into_id(loc.clone()),
807 Token::Dollar => Expr::Escape(rhs).into_id(loc.clone()),
808 _ => unreachable!("Unexpected block operator: {:?}", op),
809 }
810 })
811}
812
813fn exprgroup_parser<'src, I>(
814 ctx: ParseContext,
815) -> impl Parser<'src, I, ExprNodeId, ParseError<'src>> + Clone + 'src
816where
817 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
818{
819 recursive(move |expr_group: Recursive<_>| {
820 let expr = expr_parser(expr_group.clone(), ctx.clone());
821
822 let block = block_parser(expr_group.clone(), ctx.clone());
823 let path = ctx.file_path.clone();
824 let if_ = just(Token::If)
826 .ignore_then(
827 expr_group
828 .clone()
829 .delimited_by(just(Token::ParenBegin), just(Token::ParenEnd)),
830 )
831 .padded_by(just(Token::LineBreak).repeated())
832 .then(expr_group.clone())
833 .then(
834 just(Token::Else)
835 .padded_by(just(Token::LineBreak).repeated())
836 .ignore_then(expr_group.clone())
837 .or_not(),
838 )
839 .map_with(move |((cond, then), opt_else), e| {
840 Expr::If(cond, then, opt_else).into_id(Location {
841 span: get_span(e.span()),
842 path: path.clone(),
843 })
844 })
845 .labelled("if");
846 let ctx = ctx.clone();
847 block
848 .or(if_)
849 .or(expr.clone())
851 .recover_with(via_parser(nested_delimiters(
854 Token::BlockBegin,
855 Token::BlockEnd,
856 [(Token::ParenBegin, Token::ParenEnd)],
857 move |span| Expr::Error.into_id(ctx.clone().gen_loc(span)),
858 )))
859 })
860 .boxed()
861}
862
863fn top_stage_parser<'src, I>(
864 ctx: ParseContext,
865) -> impl Parser<'src, I, (ProgramStatement, Location), ParseError<'src>> + Clone
866where
867 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
868{
869 let stages = one_of([Token::Macro, Token::Main]).map(move |token| match token {
870 Token::Macro => StageKind::Macro,
871 Token::Main => StageKind::Main,
872 _ => unreachable!(),
873 });
874 just(Token::Sharp)
875 .ignore_then(
876 just(Token::StageKwd)
877 .ignore_then(stages.delimited_by(just(Token::ParenBegin), just(Token::ParenEnd))),
878 )
879 .map_with(move |stage: StageKind, e| {
880 (
881 ProgramStatement::StageDeclaration { stage },
882 Location {
883 span: get_span(e.span()),
884 path: ctx.file_path.clone(),
885 },
886 )
887 })
888 .labelled("Stage Declaration")
889}
890
891fn toplevel_parser<'src, I>(
892 ctx: ParseContext,
893) -> impl Parser<'src, I, Program, ParseError<'src>> + Clone
894where
895 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
896{
897 let exprgroup = exprgroup_parser(ctx.clone());
898 let lvar =
899 lvar_parser_typed_with_default(ctx.clone(), exprgroup.clone()).try_map(|ty, span| {
900 TypedId::try_from(ty).map_err(|err| Rich::custom(span, err.to_string()))
901 });
902 let path = ctx.file_path.clone();
903
904 let fnparams = lvar
905 .clone()
906 .separated_by(breakable_comma())
907 .collect()
908 .delimited_by(just(Token::ParenBegin), just(Token::ParenEnd))
909 .map_with(move |params, e| {
910 (
911 params,
912 Location {
913 span: get_span(e.span()),
914 path: path.clone(),
915 },
916 )
917 })
918 .labelled("fnparams");
919 let path = ctx.file_path.clone();
920 let path2 = ctx.file_path.clone();
921 let function_s = just(Token::Function)
922 .ignore_then(ident_parser().clone().validate(|ident, e, emitter| {
923 if let Err(e) = validate_reserved_ident(ident, e.span()) {
924 emitter.emit(e);
925 }
926 ident
927 }))
928 .then(fnparams.clone())
929 .then(
930 just(Token::Arrow)
931 .ignore_then(type_parser(ctx.clone()))
932 .or_not(),
933 )
934 .then(
935 block_parser(exprgroup.clone(), ctx.clone())
936 .map(|e| match e.to_expr() {
937 Expr::Block(e) => e.unwrap(),
938 _ => e,
939 })
940 .recover_with(via_parser(nested_delimiters(
941 Token::BlockBegin,
942 Token::BlockEnd,
943 [(Token::ParenBegin, Token::ParenEnd)],
944 move |span| {
945 Expr::Error.into_id(Location {
946 span: get_span(span),
947 path: path.clone(),
948 })
949 },
950 ))),
951 )
952 .map_with(move |(((name, args), return_type), body), e| {
953 (
954 ProgramStatement::FnDefinition {
955 name,
956 args,
957 return_type,
958 body,
959 },
960 Location {
961 span: get_span(e.span()),
962 path: path2.clone(),
963 },
964 )
965 })
966 .labelled("function decl");
967 let path = ctx.file_path.clone();
968
969 let global_stmt = statement_parser(exprgroup.clone(), ctx.clone())
970 .map(|(s, span)| (ProgramStatement::GlobalStatement(s), span));
971 let import = just(Token::Include)
972 .ignore_then(
973 select! {Token::Str(s) => s.to_symbol()}
974 .delimited_by(just(Token::ParenBegin), just(Token::ParenEnd)),
975 )
976 .map_with(move |path_sym, e| {
977 (
978 ProgramStatement::Import(path_sym),
979 Location::new(get_span(e.span()), path.clone()),
980 )
981 });
982 let stage = top_stage_parser(ctx.clone());
983 let stmt = choice((function_s, global_stmt, import, stage))
984 .recover_with(skip_then_retry_until(
985 any().ignored(),
986 one_of([Token::LineBreak, Token::SemiColon])
987 .ignored()
988 .or(end()),
989 ))
990 .labelled("toplevel statement");
991 let separator = just(Token::LineBreak).or(just(Token::SemiColon)).repeated();
992
993 stmt.separated_by(separator.clone())
994 .collect()
995 .padded_by(separator)
996 .then_ignore(end())
997 .recover_with(skip_then_retry_until(
998 any().ignored(),
999 one_of([Token::LineBreak, Token::SemiColon])
1000 .ignored()
1001 .or(end()),
1002 ))
1003 .map(|stmts: Vec<(ProgramStatement, Location)>| Program {
1004 statements: stmts
1005 .into_iter()
1006 .map(|(s, loc)| (s, loc.span))
1007 .collect::<Vec<_>>(),
1008 })
1009 .boxed()
1010}
1011
1012fn parser<'src, I>(
1042 current_file: Option<PathBuf>,
1043) -> impl Parser<'src, I, Program, ParseError<'src>> + Clone
1044where
1045 I: ValueInput<'src, Token = Token, Span = SimpleSpan>,
1046{
1047 let ctx = ParseContext {
1048 file_path: current_file.unwrap_or_default(),
1049 };
1050 toplevel_parser(ctx)
1051}
1052
1053pub(crate) fn add_global_context(ast: ExprNodeId, file_path: PathBuf) -> ExprNodeId {
1054 let span = ast.to_span();
1055 let loc = Location {
1056 span: span.clone(),
1057 path: file_path,
1058 };
1059 let res = Expr::Let(
1060 TypedPattern::new(
1061 Pattern::Single(GLOBAL_LABEL.to_symbol()),
1062 Type::Unknown.into_id_with_location(loc.clone()),
1063 ),
1064 Expr::Lambda(vec![], None, ast).into_id(loc.clone()),
1065 None,
1066 );
1067 res.into_id(loc)
1068}
1069pub fn lex(
1070 src: &str,
1071 current_file: Option<PathBuf>,
1072) -> (
1073 Option<Vec<(Token, SimpleSpan)>>,
1074 Vec<Box<dyn ReportableError>>,
1075) {
1076 let (tokens, lex_errs) = lexer::lexer().parse(src).into_output_errors();
1077 let lex_errs = lex_errs.into_iter().map(|e| -> Box<dyn ReportableError> {
1078 Box::new(error::ParseError::<char>::new(
1079 e,
1080 current_file.clone().unwrap_or_default(),
1081 ))
1082 });
1083 (tokens, lex_errs.collect())
1084}
1085pub(super) fn convert_parse_errors<'src>(
1086 errs: &[Rich<'src, Token>],
1087) -> impl Iterator<Item = Box<dyn ReportableError>> {
1088 errs.iter().map(move |e| -> Box<dyn ReportableError> {
1089 Box::new(error::ParseError::new(e.clone(), Default::default()))
1090 })
1091}
1092
1093pub fn parse(
1094 src: &'_ str,
1095 current_file: Option<PathBuf>,
1096) -> (Program, Vec<Box<dyn ReportableError>>) {
1097 let (tokens, lex_errs) = lex(src, current_file.clone());
1098 if let Some(t) = tokens {
1099 let tokens_comment_filtered = t
1100 .into_iter()
1101 .filter_map(move |(tkn, span)| match tkn {
1102 Token::Comment(token::Comment::SingleLine(_)) => Some((Token::LineBreak, span)),
1103 Token::Comment(token::Comment::MultiLine(_)) => None,
1104 _ => Some((tkn.clone(), span)),
1105 })
1106 .collect::<Vec<_>>();
1107
1108 let (ast, errs) = parser(current_file.clone())
1109 .parse(
1110 Stream::from_iter(tokens_comment_filtered)
1111 .map((src.len()..src.len()).into(), |(t, s)| (t, s)),
1112 )
1113 .into_output_errors();
1114 let errs = convert_parse_errors(&errs)
1115 .chain(lex_errs)
1116 .collect::<Vec<_>>();
1117 (ast.unwrap_or_default(), errs)
1118 } else {
1119 (Program::default(), lex_errs)
1120 }
1121}
1122pub fn parse_to_expr(
1123 src: &str,
1124 current_file: Option<PathBuf>,
1125) -> (ExprNodeId, Vec<Box<dyn ReportableError>>) {
1126 let (prog, mut errs) = parse(src, current_file.clone());
1127 if prog.statements.is_empty() {
1128 return (Expr::Error.into_id_without_span(), errs);
1129 }
1130 let (expr, mut new_errs) = expr_from_program(prog, current_file.unwrap_or_default());
1131 errs.append(&mut new_errs);
1132 (expr, errs)
1133}