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::{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        // Parse array type [T]
143        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        //Currently Integer literals are treated as float until the integer type is introduced in type system.
202        // Token::Int(x) => Literal::Int(x),
203        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
267// Parameter parser with support for default values
268fn 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            // Parse optional default value: = expr
278            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        // Note: _ represents an unused variable, but it is treated as
297        // an ordinary symbol here.
298        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 // this boxing is necessary for windows CI environment
384        .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    // allow pipe opertor to absorb linebreaks so that it can be also used at
425    // the head of the line.
426    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    //defining binary operators in order of precedence.
433    // The order of precedence is from the lowest to the highest.
434    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            // Create a nested expression that constructs an array with the given items
556            // For now, we create a special AST node type for array literals
557            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    // Combined parser for record literals and record updates
567    let record_parser = choice((
568        // Record update syntax: { expr <- field1 = value1, field2 = value2 }
569        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        // Regular record literal: { field1 = value1, field2 = value2 } or { field1 = value1, .. }
590        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    //tuple must  lower precedence than parenexpr, not to parse single element tuple without trailing comma
625    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        //todo: should be recursive(to paranthes be not needed)
825        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_statement_parser(expr_group.clone(), expr_group))
850            .or(expr.clone())
851            // we have to recover from nested delimiters at exactly here, not each of record literal parser and block parser,
852            // because we have to try parsing to distinguish them.
853            .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
1012// fn preprocess_parser(
1013//     ctx: ParseContext,
1014// ) -> impl Parser<Token, ExprNodeId, Error = ParseError> + Clone {
1015//     just(Token::Include)
1016//         .ignore_then(
1017//             select! {Token::Str(s) => s}
1018//                 .delimited_by(just(Token::ParenBegin), just(Token::ParenEnd)),
1019//         )
1020//         .try_map(move |filename, span: Span| {
1021//             let cfile = ctx.file_path.as_str();
1022//             let (c, errs) = resolve_include(cfile, &filename, span.clone());
1023//             if errs.is_empty() {
1024//                 Ok(c)
1025//             } else {
1026//                 let e = errs.into_iter().fold(
1027//                     Simple::<Token>::custom(
1028//                         span.clone(),
1029//                         format!("failed to resolve include for {filename}"),
1030//                     ),
1031//                     |simple_e, reportable_e| {
1032//                         let wrapped =
1033//                             Simple::<Token>::custom(span.clone(), reportable_e.to_string());
1034//                         wrapped.merge(simple_e)
1035//                     },
1036//                 );
1037//                 Err(e)
1038//             }
1039//         })
1040// }
1041fn 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}