mimium_lang/compiler/
parser.rs

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