graphix_compiler/expr/parser/
mod.rs

1use crate::{
2    expr::{
3        get_origin, set_origin, Arg, Bind, Expr, ExprId, ExprKind, Lambda, ModPath,
4        ModuleKind, Origin, Pattern, Sandbox, Sig, SigItem, StructurePattern, TryCatch,
5        TypeDef,
6    },
7    typ::{FnArgType, FnType, TVar, Type},
8};
9use anyhow::{bail, Result};
10use arcstr::{literal, ArcStr};
11use combine::{
12    attempt, between, chainl1, choice, eof, look_ahead, many, many1, none_of,
13    not_followed_by, optional,
14    parser::{
15        char::{alpha_num, digit, space, string},
16        combinator::recognize,
17        range::{take_while, take_while1},
18    },
19    position, sep_by, sep_by1, skip_many,
20    stream::{
21        position::{self, SourcePosition},
22        Range,
23    },
24    token, unexpected_any, value, EasyParser, ParseError, Parser, RangeStream,
25};
26use compact_str::CompactString;
27use escaping::Escape;
28use fxhash::FxHashSet;
29use netidx::{
30    path::Path,
31    publisher::{Typ, Value},
32    utils::Either,
33};
34use netidx_value::parser::{
35    escaped_string, int, value as parse_value, VAL_ESC, VAL_MUST_ESC,
36};
37use parking_lot::RwLock;
38use poolshark::local::LPooled;
39use std::sync::LazyLock;
40use triomphe::Arc;
41
42#[cfg(test)]
43mod test;
44
45fn escape_generic(c: char) -> bool {
46    c.is_control()
47}
48
49pub const GRAPHIX_MUST_ESC: [char; 4] = ['"', '\\', '[', ']'];
50pub static GRAPHIX_ESC: LazyLock<Escape> = LazyLock::new(|| {
51    Escape::new(
52        '\\',
53        &['"', '\\', '[', ']', '\n', '\r', '\t', '\0'],
54        &[('\n', "n"), ('\r', "r"), ('\t', "t"), ('\0', "0")],
55        Some(escape_generic),
56    )
57    .unwrap()
58});
59pub const RESERVED: LazyLock<FxHashSet<&str>> = LazyLock::new(|| {
60    FxHashSet::from_iter([
61        "true", "false", "ok", "null", "mod", "let", "select", "pub", "type", "fn",
62        "cast", "if", "u32", "v32", "i32", "z32", "u64", "v64", "i64", "z64", "f32",
63        "f64", "decimal", "datetime", "duration", "bool", "string", "bytes", "result",
64        "null", "_", "?", "fn", "Array", "Map", "any", "Any", "use", "rec", "catch",
65        "try",
66    ])
67});
68
69fn spaces<I>() -> impl Parser<I, Output = ()>
70where
71    I: RangeStream<Token = char>,
72    I::Error: ParseError<I::Token, I::Range, I::Position>,
73    I::Range: Range,
74{
75    combine::parser::char::spaces().with(skip_many(attempt(
76        string("//")
77            .with(not_followed_by(token('/')))
78            .with(skip_many(none_of(['\n'])))
79            .with(combine::parser::char::spaces()),
80    )))
81}
82
83fn doc_comment<I>() -> impl Parser<I, Output = Option<ArcStr>>
84where
85    I: RangeStream<Token = char>,
86    I::Error: ParseError<I::Token, I::Range, I::Position>,
87    I::Range: Range,
88{
89    combine::parser::char::spaces()
90        .with(many(
91            string("///")
92                .with(many(none_of(['\n'])))
93                .skip(combine::parser::char::spaces()),
94        ))
95        .map(
96            |lines: LPooled<Vec<String>>| {
97                if lines.len() == 0 {
98                    None
99                } else {
100                    Some(ArcStr::from(lines.join("\n")))
101                }
102            },
103        )
104}
105
106fn spstring<'a, I>(s: &'static str) -> impl Parser<I, Output = &'a str>
107where
108    I: RangeStream<Token = char>,
109    I::Error: ParseError<I::Token, I::Range, I::Position>,
110    I::Range: Range,
111{
112    spaces().with(string(s))
113}
114
115fn ident<I>(cap: bool) -> impl Parser<I, Output = ArcStr>
116where
117    I: RangeStream<Token = char>,
118    I::Error: ParseError<I::Token, I::Range, I::Position>,
119    I::Range: Range,
120{
121    recognize((
122        take_while1(move |c: char| c.is_alphabetic() && cap == c.is_uppercase()),
123        take_while(|c: char| c.is_alphanumeric() || c == '_'),
124    ))
125    .map(|s: CompactString| ArcStr::from(s.as_str()))
126}
127
128fn fname<I>() -> impl Parser<I, Output = ArcStr>
129where
130    I: RangeStream<Token = char>,
131    I::Error: ParseError<I::Token, I::Range, I::Position>,
132    I::Range: Range,
133{
134    ident(false).then(|s| {
135        if RESERVED.contains(&s.as_str()) {
136            unexpected_any("can't use keyword as a function or variable name").left()
137        } else {
138            value(s).right()
139        }
140    })
141}
142
143fn spfname<I>() -> impl Parser<I, Output = ArcStr>
144where
145    I: RangeStream<Token = char>,
146    I::Error: ParseError<I::Token, I::Range, I::Position>,
147    I::Range: Range,
148{
149    spaces().with(fname())
150}
151
152fn typname<I>() -> impl Parser<I, Output = ArcStr>
153where
154    I: RangeStream<Token = char>,
155    I::Error: ParseError<I::Token, I::Range, I::Position>,
156    I::Range: Range,
157{
158    ident(true).then(|s| {
159        if RESERVED.contains(&s.as_str()) {
160            unexpected_any("can't use keyword as a type name").left()
161        } else {
162            value(s).right()
163        }
164    })
165}
166
167fn sptypname<I>() -> impl Parser<I, Output = ArcStr>
168where
169    I: RangeStream<Token = char>,
170    I::Error: ParseError<I::Token, I::Range, I::Position>,
171    I::Range: Range,
172{
173    spaces().with(typname())
174}
175
176pub(crate) fn modpath<I>() -> impl Parser<I, Output = ModPath>
177where
178    I: RangeStream<Token = char>,
179    I::Error: ParseError<I::Token, I::Range, I::Position>,
180    I::Range: Range,
181{
182    sep_by1(fname(), string("::"))
183        .map(|mut v: LPooled<Vec<ArcStr>>| ModPath(Path::from_iter(v.drain(..))))
184}
185
186fn spmodpath<I>() -> impl Parser<I, Output = ModPath>
187where
188    I: RangeStream<Token = char>,
189    I::Error: ParseError<I::Token, I::Range, I::Position>,
190    I::Range: Range,
191{
192    spaces().with(modpath())
193}
194
195fn typath<I>() -> impl Parser<I, Output = ModPath>
196where
197    I: RangeStream<Token = char>,
198    I::Error: ParseError<I::Token, I::Range, I::Position>,
199    I::Range: Range,
200{
201    sep_by1(choice((attempt(spfname()), sptypname())), string("::")).then(
202        |mut parts: LPooled<Vec<ArcStr>>| {
203            if parts.len() == 0 {
204                unexpected_any("empty type path").left()
205            } else {
206                match parts.last().unwrap().chars().next() {
207                    None => unexpected_any("empty name").left(),
208                    Some(c) if c.is_lowercase() => {
209                        unexpected_any("type names must be capitalized").left()
210                    }
211                    Some(_) => value(ModPath::from(parts.drain(..))).right(),
212                }
213            }
214        },
215    )
216}
217
218fn sptypath<I>() -> impl Parser<I, Output = ModPath>
219where
220    I: RangeStream<Token = char>,
221    I::Error: ParseError<I::Token, I::Range, I::Position>,
222    I::Range: Range,
223{
224    spaces().with(typath())
225}
226
227fn csep<I>() -> impl Parser<I, Output = char>
228where
229    I: RangeStream<Token = char>,
230    I::Error: ParseError<I::Token, I::Range, I::Position>,
231    I::Range: Range,
232{
233    attempt(spaces().with(token(',')))
234}
235
236fn sptoken<I>(t: char) -> impl Parser<I, Output = char>
237where
238    I: RangeStream<Token = char>,
239    I::Error: ParseError<I::Token, I::Range, I::Position>,
240    I::Range: Range,
241{
242    spaces().with(token(t))
243}
244
245parser! {
246    fn interpolated[I]()(I) -> Expr
247    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
248    {
249        #[derive(Debug, Clone)]
250        enum Intp {
251            Lit(SourcePosition, String),
252            Expr(Expr),
253        }
254        impl Intp {
255            fn to_expr(self) -> Expr {
256                match self {
257                    Intp::Lit(pos, s) => Expr {
258                        id: ExprId::new(),
259                        ori: get_origin(),
260                        pos,
261                        kind: ExprKind::Constant(Value::from(s)),
262                    },
263                    Intp::Expr(s) => s,
264                }
265            }
266        }
267        (
268            position(),
269            between(
270                token('"'),
271                token('"'),
272                many(choice((
273                    attempt(between(token('['), sptoken(']'), expr()).map(Intp::Expr)),
274                    (position(), escaped_string(&GRAPHIX_MUST_ESC, &GRAPHIX_ESC))
275                    .then(|(pos, s)| {
276                        if s.is_empty() {
277                            unexpected_any("empty string").right()
278                        } else {
279                            value(Intp::Lit(pos, s)).left()
280                        }
281                    }),
282                ))),
283            ),
284        )
285            .map(|(pos, mut toks): (_, LPooled<Vec<Intp>>)| {
286                let mut argvec = vec![];
287                toks.drain(..)
288                    .fold(None, |src, tok| -> Option<Expr> {
289                        match (src, tok) {
290                            (None, t @ Intp::Lit(_, _)) => Some(t.to_expr()),
291                            (None, Intp::Expr(s)) => {
292                                argvec.push(s);
293                                Some(
294                                    ExprKind::StringInterpolate {
295                                        args: Arc::from_iter(argvec.clone().into_iter()),
296                                    }
297                                    .to_expr(pos),
298                                )
299                            }
300                            (Some(src @ Expr { kind: ExprKind::Constant(_), .. }), s) => {
301                                argvec.extend([src, s.to_expr()]);
302                                Some(
303                                    ExprKind::StringInterpolate {
304                                        args: Arc::from_iter(argvec.clone().into_iter()),
305                                    }
306                                    .to_expr(pos),
307                                )
308                            }
309                            (
310                                Some(Expr {
311                                    kind: ExprKind::StringInterpolate { args: _ },
312                                    ..
313                                }),
314                                s,
315                            ) => {
316                                argvec.push(s.to_expr());
317                                Some(
318                                    ExprKind::StringInterpolate {
319                                        args: Arc::from_iter(argvec.clone().into_iter()),
320                                    }
321                                    .to_expr(pos),
322                                )
323                            }
324                            (Some(Expr { kind: ExprKind::Bind { .. }, .. }), _)
325                                | (Some(Expr { kind: ExprKind::StructWith { .. }, .. }), _)
326                                | (Some(Expr { kind: ExprKind::Array { .. }, .. }), _)
327                                | (Some(Expr { kind: ExprKind::Map { .. }, .. }), _)
328                                | (Some(Expr { kind: ExprKind::MapRef { .. }, .. }), _)
329                                | (Some(Expr { kind: ExprKind::Any { .. }, .. }), _)
330                                | (Some(Expr { kind: ExprKind::StructRef { .. }, .. }), _)
331                                | (Some(Expr { kind: ExprKind::TupleRef { .. }, .. }), _)
332                                | (Some(Expr { kind: ExprKind::Tuple { .. }, .. }), _)
333                                | (Some(Expr { kind: ExprKind::Variant { .. }, .. }), _)
334                                | (Some(Expr { kind: ExprKind::Struct { .. }, .. }), _)
335                                | (Some(Expr { kind: ExprKind::Qop(_), .. }), _)
336                                | (Some(Expr { kind: ExprKind::OrNever(_), .. }), _)
337                                | (Some(Expr { kind: ExprKind::TryCatch(_), .. }), _)
338                                | (Some(Expr { kind: ExprKind::Do { .. }, .. }), _)
339                                | (Some(Expr { kind: ExprKind::Module { .. }, .. }), _)
340                                | (Some(Expr { kind: ExprKind::Use { .. }, .. }), _)
341                                | (Some(Expr { kind: ExprKind::Connect { .. }, .. }), _)
342                                | (Some(Expr { kind: ExprKind::Ref { .. }, .. }), _)
343                                | (Some(Expr { kind: ExprKind::Eq { .. }, .. }), _)
344                                | (Some(Expr { kind: ExprKind::Ne { .. }, .. }), _)
345                                | (Some(Expr { kind: ExprKind::Lt { .. }, .. }), _)
346                                | (Some(Expr { kind: ExprKind::Gt { .. }, .. }), _)
347                                | (Some(Expr { kind: ExprKind::Gte { .. }, .. }), _)
348                                | (Some(Expr { kind: ExprKind::Lte { .. }, .. }), _)
349                                | (Some(Expr { kind: ExprKind::And { .. }, .. }), _)
350                                | (Some(Expr { kind: ExprKind::Or { .. }, .. }), _)
351                                | (Some(Expr { kind: ExprKind::Not { .. }, .. }), _)
352                                | (Some(Expr { kind: ExprKind::Add { .. }, .. }), _)
353                                | (Some(Expr { kind: ExprKind::Sub { .. }, .. }), _)
354                                | (Some(Expr { kind: ExprKind::Mul { .. }, .. }), _)
355                                | (Some(Expr { kind: ExprKind::Div { .. }, .. }), _)
356                                | (Some(Expr { kind: ExprKind::Mod { .. }, .. }), _)
357                                | (Some(Expr { kind: ExprKind::Select { .. }, .. }), _)
358                                | (Some(Expr { kind: ExprKind::TypeCast { .. }, .. }), _)
359                                | (Some(Expr { kind: ExprKind::TypeDef { .. }, .. }), _)
360                                | (Some(Expr { kind: ExprKind::ArrayRef { .. }, .. }), _)
361                                | (Some(Expr { kind: ExprKind::ArraySlice { .. }, .. }), _)
362                                | (Some(Expr { kind: ExprKind::Apply { .. }, .. }), _)
363                                | (Some(Expr { kind: ExprKind::ByRef(_), .. }), _)
364                                | (Some(Expr { kind: ExprKind::Deref(_), .. }), _)
365                                | (Some(Expr { kind: ExprKind::Sample { .. }, .. }), _)
366                                | (Some(Expr { kind: ExprKind::Lambda { .. }, .. }), _) => {
367                                    unreachable!()
368                                }
369                        }
370                    })
371                    .unwrap_or_else(|| ExprKind::Constant(Value::from("")).to_expr(pos))
372            })
373    }
374}
375
376parser! {
377    fn sig_item[I]()(I) -> SigItem
378    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
379    {
380        choice((
381            attempt(spaces().with(typedef())).map(|e| match e.kind {
382                ExprKind::TypeDef(td) => SigItem::TypeDef(td),
383                _ => unreachable!()
384            }),
385            attempt(spstring("val").with(space()).with((spfname(), sptoken(':').with(typexp()))))
386                .map(|(name, typ)| {
387                    SigItem::Bind(name, typ)
388                }),
389            attempt(spstring("mod").with(space()).with((
390                spfname().skip(sptoken(':')).skip(spstring("sig")),
391                between(sptoken('{'), sptoken('}'),
392                    sep_by1(sig_item(), attempt(sptoken(';'))))
393            ))).map(|(name, mut items): (ArcStr, LPooled<Vec<SigItem>>)| {
394                SigItem::Module(name, Sig(Arc::from_iter(items.drain(..))))
395            })
396        ))
397    }
398}
399
400parser! {
401    fn sandbox[I]()(I) -> Sandbox
402    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
403    {
404        choice((
405            spstring("unrestricted").map(|_| Sandbox::Unrestricted),
406            spstring("blacklist").with(between(
407                sptoken('['), sptoken(']'),
408                sep_by1(spaces().with(modpath()), csep())
409            )).map(|l: Vec<ModPath>| Sandbox::Blacklist(Arc::from(l))),
410            spstring("whitelist").with(between(
411                sptoken('['), sptoken(']'),
412                sep_by1(spaces().with(modpath()), csep())
413            )).map(|l: Vec<ModPath>| Sandbox::Whitelist(Arc::from(l)))
414        ))
415        .skip(sptoken(';'))
416    }
417}
418
419parser! {
420    fn dynamic_module[I]()(I) -> ModuleKind
421    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
422    {
423        space().with(spstring("dynamic")).with(between(
424            sptoken('{'), sptoken('}'),
425            (
426                spstring("sandbox").with(space()).with(sandbox()),
427                spstring("sig").with(between(
428                    sptoken('{'), sptoken('}'),
429                    sep_by1(sig_item(), attempt(sptoken(';')))
430                        .map(|i: Vec<SigItem>| Sig(Arc::from(i)))
431                ))
432                .skip(sptoken(';')),
433                spstring("source").with(space()).with(expr())
434            )
435        )).map(|(sandbox, sig, source)| {
436            ModuleKind::Dynamic { sandbox, sig, source: Arc::new(source) }
437        })
438    }
439}
440
441parser! {
442    fn inline_module[I]()(I) -> ModuleKind
443    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
444    {
445        between(
446            sptoken('{'), sptoken('}'),
447            sep_by(expr(), attempt(sptoken(';')))
448        )
449        .map(|m: Vec<Expr>| ModuleKind::Inline(Arc::from(m)))
450    }
451}
452
453parser! {
454    fn module[I]()(I) -> Expr
455    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
456    {
457        (
458            position(),
459            optional(string("pub").skip(space())).map(|o| o.is_some()),
460            spstring("mod").with(space()).with(spfname()),
461            optional(choice((
462                attempt(inline_module()),
463                attempt(dynamic_module())
464            ))).map(|m| m.unwrap_or(ModuleKind::Unresolved))
465        )
466            .map(|(pos, export, name, value)| {
467                ExprKind::Module { name, export, value }.to_expr(pos)
468            })
469    }
470}
471
472fn use_module<I>() -> impl Parser<I, Output = Expr>
473where
474    I: RangeStream<Token = char, Position = SourcePosition>,
475    I::Error: ParseError<I::Token, I::Range, I::Position>,
476    I::Range: Range,
477{
478    (position(), string("use").with(space()).with(spmodpath()))
479        .map(|(pos, name)| ExprKind::Use { name }.to_expr(pos))
480}
481
482parser! {
483    fn do_block[I]()(I) -> Expr
484    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
485    {
486        (
487            position(),
488            between(token('{'), sptoken('}'), sep_by1(expr(), attempt(sptoken(';')))),
489        )
490            .then(|(pos, args): (_, Vec<Expr>)| {
491                if args.len() < 2 {
492                    unexpected_any("do must contain at least 2 expressions").left()
493                } else {
494                    value(ExprKind::Do { exprs: Arc::from(args) }.to_expr(pos)).right()
495                }
496            })
497    }
498}
499
500parser! {
501    fn array[I]()(I) -> Expr
502    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
503    {
504        (position(), between(token('['), sptoken(']'), sep_by(expr(), csep()))).map(
505            |(pos, mut args): (_, LPooled<Vec<Expr>>)| {
506                ExprKind::Array { args: Arc::from_iter(args.drain(..)) }.to_expr(pos)
507            },
508        )
509    }
510}
511
512parser! {
513    fn apply_pexp[I]()(I) -> Expr
514    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
515    {
516        choice((
517            attempt(spaces().with(qop(reference()))),
518            between(sptoken('('), sptoken(')'), expr()),
519        ))
520    }
521}
522
523parser! {
524    fn ref_pexp[I]()(I) -> Expr
525    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
526    {
527        choice((
528            attempt(spaces().with(qop(reference()))),
529            between(sptoken('('), sptoken(')'), expr()),
530        ))
531    }
532}
533
534parser! {
535    fn structref[I]()(I) -> Expr
536    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
537    {
538        (position(), ref_pexp().skip(sptoken('.')), spfname()).map(|(pos, source, field)| {
539            ExprKind::StructRef { source: Arc::new(source), field }.to_expr(pos)
540        })
541    }
542}
543
544parser! {
545    fn tupleref[I]()(I) -> Expr
546    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
547    {
548        (position(), ref_pexp().skip(sptoken('.')), int::<_, usize>()).map(
549            |(pos, source, field)| {
550                ExprKind::TupleRef { source: Arc::new(source), field }.to_expr(pos)
551            },
552        )
553    }
554}
555
556parser! {
557    fn arrayref[I]()(I) -> Expr
558    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
559    {
560        (
561            position(),
562            ref_pexp(),
563            between(
564                token('['),
565                sptoken(']'),
566                choice((
567                    attempt(
568                        (
569                            position(),
570                            spaces().with(optional(many1(digit()))).skip(spstring("..")),
571                            spaces().with(optional(many1(digit()))),
572                        )
573                            .skip(look_ahead(sptoken(']'))),
574                    )
575                        .map(
576                            |(pos, start, end): (
577                                _,
578                                Option<CompactString>,
579                                Option<CompactString>,
580                            )| {
581                                let start = start.map(|i| Value::U64(i.parse().unwrap()));
582                                let start = start.map(|e| ExprKind::Constant(e).to_expr(pos));
583                                let end = end.map(|i| Value::U64(i.parse().unwrap()));
584                                let end = end.map(|e| ExprKind::Constant(e).to_expr(pos));
585                                Either::Left((start, end))
586                            },
587                        ),
588                    attempt((
589                        optional(attempt(expr())).skip(spstring("..")),
590                        optional(attempt(expr())),
591                    ))
592                        .map(|(start, end)| Either::Left((start, end))),
593                    attempt(expr()).map(|e| Either::Right(e)),
594                )),
595            ),
596        )
597            .map(|(pos, a, args)| match args {
598                Either::Left((start, end)) => ExprKind::ArraySlice {
599                    source: Arc::new(a),
600                    start: start.map(Arc::new),
601                    end: end.map(Arc::new),
602                }
603                .to_expr(pos),
604                Either::Right(i) => {
605                    ExprKind::ArrayRef { source: Arc::new(a), i: Arc::new(i) }.to_expr(pos)
606                }
607            })
608    }
609}
610
611parser! {
612    fn mapref[I]()(I) -> Expr
613    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
614    {
615        (position(), ref_pexp(), between(sptoken('{'), sptoken('}'), expr())).map(|(pos, source, key)| {
616            ExprKind::MapRef { source: Arc::new(source), key: Arc::new(key) }.to_expr(pos)
617        })
618    }
619}
620
621parser! {
622    fn apply[I]()(I) -> Expr
623    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
624    {
625        (
626            position(),
627            apply_pexp(),
628            between(
629                sptoken('('),
630                sptoken(')'),
631                sep_by(
632                    choice((
633                        attempt((sptoken('#').with(fname()).skip(token(':')), expr()))
634                            .map(|(n, e)| (Some(n), e)),
635                        attempt((
636                            position(),
637                            sptoken('#').with(fname()),
638                        ))
639                            .map(|(pos, n)| {
640                                let e = ExprKind::Ref { name: [n.clone()].into() }.to_expr(pos);
641                                (Some(n), e)
642                            }),
643                        expr().map(|e| (None, e)),
644                    )),
645                    csep(),
646                ),
647            ),
648        )
649            .then(|(pos, function, args): (_, Expr, Vec<(Option<ArcStr>, Expr)>)| {
650                let mut anon = false;
651                for (a, _) in &args {
652                    if a.is_some() && anon {
653                        return unexpected_any(
654                            "labeled arguments must come before anonymous arguments",
655                        )
656                            .right();
657                    }
658                    anon |= a.is_none();
659                }
660                value((pos, function, args)).left()
661            })
662            .map(|(pos, function, args): (_, Expr, Vec<(Option<ArcStr>, Expr)>)| {
663                ExprKind::Apply { function: Arc::new(function), args: Arc::from(args) }
664                .to_expr(pos)
665            })
666    }
667}
668
669parser! {
670    fn any[I]()(I) -> Expr
671    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
672    {
673        (
674            position(),
675            string("any").with(between(sptoken('('), sptoken(')'), sep_by(expr(), csep()))),
676        )
677            .map(|(pos, args): (_, Vec<Expr>)| {
678                ExprKind::Any { args: Arc::from(args) }.to_expr(pos)
679            })
680    }
681}
682
683fn typeprim<I>() -> impl Parser<I, Output = Typ>
684where
685    I: RangeStream<Token = char>,
686    I::Error: ParseError<I::Token, I::Range, I::Position>,
687    I::Range: Range,
688{
689    choice((
690        attempt(spstring("u32").map(|_| Typ::U32)),
691        attempt(spstring("v32").map(|_| Typ::V32)),
692        attempt(spstring("i32").map(|_| Typ::I32)),
693        attempt(spstring("z32").map(|_| Typ::Z32)),
694        attempt(spstring("u64").map(|_| Typ::U64)),
695        attempt(spstring("v64").map(|_| Typ::V64)),
696        attempt(spstring("i64").map(|_| Typ::I64)),
697        attempt(spstring("z64").map(|_| Typ::Z64)),
698        attempt(spstring("f32").map(|_| Typ::F32)),
699        attempt(spstring("f64").map(|_| Typ::F64)),
700        attempt(spstring("decimal").map(|_| Typ::Decimal)),
701        attempt(spstring("datetime").map(|_| Typ::DateTime)),
702        attempt(spstring("duration").map(|_| Typ::Duration)),
703        attempt(spstring("bool").map(|_| Typ::Bool)),
704        attempt(spstring("string").map(|_| Typ::String)),
705        attempt(spstring("bytes").map(|_| Typ::Bytes)),
706        attempt(spstring("error").map(|_| Typ::Error)),
707        attempt(spstring("array").map(|_| Typ::Array)),
708        attempt(spstring("null").map(|_| Typ::Null)),
709    ))
710    .skip(not_followed_by(choice((alpha_num(), token('_')))))
711}
712
713parser! {
714    fn fntype[I]()(I) -> FnType
715    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
716    {
717        spstring("fn")
718            .with((
719                optional(attempt(between(
720                    token('<'),
721                    sptoken('>'),
722                    sep_by1((tvar().skip(sptoken(':')), typexp()), csep()),
723                )))
724                    .map(|cs: Option<LPooled<Vec<(TVar, Type)>>>| match cs {
725                        Some(cs) => Arc::new(RwLock::new(cs)),
726                        None => Arc::new(RwLock::new(LPooled::take())),
727                    }),
728                between(
729                    token('('),
730                    sptoken(')'),
731                    sep_by(
732                        choice((
733                            attempt(
734                                (
735                                    spaces()
736                                        .with(optional(token('?')).map(|o| o.is_some()))
737                                        .skip(token('#')),
738                                    fname().skip(token(':')),
739                                    typexp(),
740                                )
741                                    .map(
742                                        |(optional, name, typ)| {
743                                            Either::Left(FnArgType {
744                                                label: Some((name.into(), optional)),
745                                                typ,
746                                            })
747                                        },
748                                    ),
749                            ),
750                            attempt(
751                                typexp()
752                                    .map(|typ| Either::Left(FnArgType { label: None, typ })),
753                            ),
754                            attempt(
755                                spstring("@args:").with(typexp()).map(|e| Either::Right(e)),
756                            ),
757                        )),
758                        csep(),
759                    ),
760                ),
761                spstring("->").with(typexp()),
762                optional(attempt(space().with(spstring("throws")).with(space()).with(typexp())))
763            ))
764            .then(
765                |(constraints, mut args, rtype, throws): (
766                    Arc<RwLock<LPooled<Vec<(TVar, Type)>>>>,
767                    Vec<Either<FnArgType, Type>>,
768                    Type,
769                    Option<Type>
770                )| {
771                    let vargs = match args.pop() {
772                        None => None,
773                        Some(Either::Right(t)) => Some(t),
774                        Some(Either::Left(t)) => {
775                            args.push(Either::Left(t));
776                            None
777                        }
778                    };
779                    if !args.iter().all(|a| a.is_left()) {
780                        return unexpected_any(
781                            "vargs must appear once at the end of the args",
782                        )
783                            .left();
784                    }
785                    let args = Arc::from_iter(args.into_iter().map(|t| match t {
786                        Either::Left(t) => t,
787                        Either::Right(_) => unreachable!(),
788                    }));
789                    let mut anon = false;
790                    for a in args.iter() {
791                        if anon && a.label.is_some() {
792                            return unexpected_any(
793                                "anonymous args must appear after labeled args",
794                            )
795                                .left();
796                        }
797                        anon |= a.label.is_none();
798                    }
799                    let throws = throws.unwrap_or(Type::Bottom);
800                    value(FnType { args, vargs, rtype, constraints, throws }).right()
801                },
802            )
803    }
804}
805
806fn tvar<I>() -> impl Parser<I, Output = TVar>
807where
808    I: RangeStream<Token = char>,
809    I::Error: ParseError<I::Token, I::Range, I::Position>,
810    I::Range: Range,
811{
812    sptoken('\'').with(fname()).map(TVar::empty_named)
813}
814
815parser! {
816    fn typexp[I]()(I) -> Type
817    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
818    {
819        choice((
820            attempt(sptoken('&').with(typexp()).map(|t| Type::ByRef(Arc::new(t)))),
821            attempt(sptoken('_').map(|_| Type::Bottom)),
822            attempt(
823                between(sptoken('['), sptoken(']'), sep_by(typexp(), csep()))
824                    .map(|mut ts: LPooled<Vec<Type>>| Type::flatten_set(ts.drain(..))),
825            ),
826            attempt(between(sptoken('('), sptoken(')'), sep_by1(typexp(), csep())).map(
827                |mut exps: LPooled<Vec<Type>>| {
828                    if exps.len() == 1 {
829                        exps.pop().unwrap()
830                    } else {
831                        Type::Tuple(Arc::from_iter(exps.drain(..)))
832                    }
833                },
834            )),
835            attempt(
836                between(
837                    sptoken('{'),
838                    sptoken('}'),
839                    sep_by1((spfname().skip(sptoken(':')), typexp()), csep()),
840                )
841                    .then(|mut exps: LPooled<Vec<(ArcStr, Type)>>| {
842                        let s = exps.iter().map(|(n, _)| n).collect::<LPooled<FxHashSet<_>>>();
843                        if s.len() < exps.len() {
844                            return unexpected_any("struct field names must be unique").left();
845                        }
846                        drop(s);
847                        exps.sort_by_key(|(n, _)| n.clone());
848                        value(Type::Struct(Arc::from_iter(exps.drain(..)))).right()
849                    }),
850            ),
851            attempt(
852                (
853                    sptoken('`').with(typname()),
854                    optional(attempt(between(
855                        token('('),
856                        sptoken(')'),
857                        sep_by1(typexp(), csep()),
858                    ))),
859                )
860                    .map(|(tag, typs): (ArcStr, Option<LPooled<Vec<Type>>>)| {
861                        let mut t = match typs {
862                            None => LPooled::take(),
863                            Some(v) => v,
864                        };
865                        Type::Variant(tag.clone(), Arc::from_iter(t.drain(..)))
866                    }),
867            ),
868            attempt(fntype().map(|f| Type::Fn(Arc::new(f)))),
869            attempt(spstring("Array").with(between(sptoken('<'), sptoken('>'), typexp())))
870                .map(|t| Type::Array(Arc::new(t))),
871            attempt(spstring("Map").with(
872                between(sptoken('<'), sptoken('>'),
873                    (typexp().skip(sptoken(',')), typexp())
874                )))
875                .map(|(k, v)| Type::Map { key: Arc::new(k), value: Arc::new(v) }),
876            attempt(spstring("Error").with(between(sptoken('<'), sptoken('>'), typexp())))
877                .map(|t| Type::Error(Arc::new(t))),
878            attempt((
879                sptypath(),
880                optional(attempt(between(
881                    sptoken('<'),
882                    sptoken('>'),
883                    sep_by1(typexp(), csep()),
884                ))),
885            ))
886                .map(|(n, params): (ModPath, Option<LPooled<Vec<Type>>>)| {
887                    let params = params
888                        .map(|mut a| Arc::from_iter(a.drain(..)))
889                        .unwrap_or_else(|| Arc::from_iter([]));
890                    Type::Ref { scope: ModPath::root(), name: n, params }
891                }),
892            attempt(spstring("Any")).map(|_| Type::Any),
893            attempt(typeprim()).map(|typ| Type::Primitive(typ.into())),
894            attempt(tvar()).map(|tv| Type::TVar(tv)),
895        ))
896    }
897}
898
899parser! {
900    fn lambda_args[I]()(I) -> (LPooled<Vec<Arg>>, Option<Option<Type>>)
901    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
902    {
903        sep_by(
904            (
905                choice((
906                    attempt(spaces().with(structure_pattern())).map(|p| (false, p)),
907                    attempt(spaces().with(token('#').with(fname())))
908                        .map(|b| (true, StructurePattern::Bind(b))),
909                    attempt(spstring("@args"))
910                        .map(|s| (false, StructurePattern::Bind(ArcStr::from(s)))),
911                )),
912                optional(attempt(sptoken(':').with(typexp()))),
913                optional(attempt(sptoken('=').with(expr()))),
914            ),
915            csep(),
916        )
917            .then(|v: Vec<((bool, StructurePattern), Option<Type>, Option<Expr>)>| {
918                let args = v
919                    .into_iter()
920                    .map(|((labeled, pattern), constraint, default)| {
921                        if !labeled && default.is_some() {
922                            bail!("labeled")
923                        } else {
924                            Ok(Arg { labeled: labeled.then_some(default), pattern, constraint })
925                        }
926                    })
927                    .collect::<Result<LPooled<Vec<_>>>>();
928                match args {
929                    Ok(a) => value(a).right(),
930                    Err(_) => {
931                        unexpected_any("only labeled arguments may have a default value").left()
932                    }
933                }
934            })
935        // @args must be last
936            .then(|mut v: LPooled<Vec<Arg>>| {
937                match v.iter().enumerate().find(|(_, a)| match &a.pattern {
938                    StructurePattern::Bind(n) if n == "@args" => true,
939                    _ => false,
940                }) {
941                    None => value((v, None)).left(),
942                    Some((i, _)) => {
943                        if i == v.len() - 1 {
944                            let a = v.pop().unwrap();
945                            value((v, Some(a.constraint))).left()
946                        } else {
947                            unexpected_any("@args must be the last argument").right()
948                        }
949                    }
950                }
951            })
952        // labeled before anonymous args
953            .then(|(v, vargs): (LPooled<Vec<Arg>>, Option<Option<Type>>)| {
954                let mut anon = false;
955                for a in v.iter() {
956                    if a.labeled.is_some() && anon {
957                        return unexpected_any("labeled args must come before anon args").right();
958                    }
959                    anon |= a.labeled.is_none();
960                }
961                value((v, vargs)).left()
962            })
963    }
964}
965
966parser! {
967    fn lambda[I]()(I) -> Expr
968    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
969    {
970        (
971            position(),
972            attempt(sep_by((tvar().skip(sptoken(':')), typexp()), csep()))
973                .map(|mut tvs: LPooled<Vec<(TVar, Type)>>| Arc::from_iter(tvs.drain(..))),
974            between(sptoken('|'), sptoken('|'), lambda_args()),
975            optional(attempt(spstring("->").with(typexp()))),
976            optional(attempt(space().with(spstring("throws").with(space()).with(typexp())))),
977            space().with(choice((
978                attempt(sptoken('\'').with(fname()).skip(not_followed_by(sptoken(':'))))
979                    .map(Either::Right),
980                expr().map(|e| Either::Left(e)),
981            ))),
982        )
983            .map(|(pos, constraints, (mut args, vargs), rtype, throws, body)| {
984                let args = Arc::from_iter(args.drain(..));
985                ExprKind::Lambda(Arc::new(Lambda { args, vargs, rtype, throws, constraints, body }))
986                    .to_expr(pos)
987            })
988    }
989}
990
991parser! {
992    fn letbind[I]()(I) -> Expr
993    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
994    {
995        (
996            position(),
997            doc_comment(),
998            optional(string("pub").skip(space())).map(|o| o.is_some()),
999            spstring("let")
1000                .with(space())
1001                .with((
1002                    optional(attempt(spstring("rec").with(space()))),
1003                    structure_pattern(),
1004                    optional(attempt(sptoken(':').with(typexp())))
1005                ))
1006                .skip(spstring("=")),
1007            expr(),
1008        )
1009            .map(|(pos, doc, export, (rec, pattern, typ), value)| {
1010                let rec = rec.is_some();
1011                ExprKind::Bind(Arc::new(Bind { rec, doc, export, pattern, typ, value }))
1012                    .to_expr(pos)
1013            })
1014    }
1015}
1016
1017parser! {
1018    fn connect[I]()(I) -> Expr
1019    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1020    {
1021        (position(), optional(token('*')), spmodpath().skip(spstring("<-")), expr()).map(
1022            |(pos, deref, name, e)| {
1023                ExprKind::Connect { name, value: Arc::new(e), deref: deref.is_some() }
1024                .to_expr(pos)
1025            },
1026        )
1027    }
1028}
1029
1030fn literal<I>() -> impl Parser<I, Output = Expr>
1031where
1032    I: RangeStream<Token = char, Position = SourcePosition>,
1033    I::Error: ParseError<I::Token, I::Range, I::Position>,
1034    I::Range: Range,
1035{
1036    (position(), parse_value(&VAL_MUST_ESC, &VAL_ESC).skip(not_followed_by(token('_'))))
1037        .then(|(pos, v)| match v {
1038            Value::String(_) => {
1039                unexpected_any("parse error in string interpolation").left()
1040            }
1041            v => value(ExprKind::Constant(v).to_expr(pos)).right(),
1042        })
1043}
1044
1045fn reference<I>() -> impl Parser<I, Output = Expr>
1046where
1047    I: RangeStream<Token = char, Position = SourcePosition>,
1048    I::Error: ParseError<I::Token, I::Range, I::Position>,
1049    I::Range: Range,
1050{
1051    (position(), modpath()).map(|(pos, name)| ExprKind::Ref { name }.to_expr(pos))
1052}
1053
1054parser! {
1055    fn deref_arith[I]()(I) -> Expr
1056    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1057    {
1058        (position(), token('*').with(arith_term()))
1059            .map(|(pos, expr)| ExprKind::Deref(Arc::new(expr)).to_expr(pos))
1060    }
1061}
1062
1063parser! {
1064    fn qop[I, P](p: P)(I) -> Expr
1065    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range, P: Parser<I, Output = Expr>]
1066    {
1067        enum Op {
1068            Qop,
1069            OrNever,
1070        }
1071        (
1072            position(),
1073            p,
1074            optional(choice((
1075                attempt(sptoken('?')).map(|_| Op::Qop),
1076                attempt(sptoken('$')).map(|_| Op::OrNever)
1077            )))
1078        ).map(|(pos, e, qop)| match qop {
1079            None => e,
1080            Some(Op::Qop) => ExprKind::Qop(Arc::new(e)).to_expr(pos),
1081            Some(Op::OrNever) => ExprKind::OrNever(Arc::new(e)).to_expr(pos)
1082        })
1083    }
1084}
1085
1086parser! {
1087    fn arith_term[I]()(I) -> Expr
1088    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1089    {
1090        choice((
1091            attempt(spaces().with(qop(deref_arith()))),
1092            attempt(spaces().with(raw_string())),
1093            attempt(spaces().with(array())),
1094            attempt(spaces().with(byref_arith())),
1095            attempt(spaces().with(tuple())),
1096            attempt(spaces().with(structure())),
1097            attempt(spaces().with(map())),
1098            attempt(spaces().with(variant())),
1099            attempt(spaces().with(structwith())),
1100            attempt(spaces().with(qop(arrayref()))),
1101            attempt(spaces().with(qop(tupleref()))),
1102            attempt(spaces().with(qop(structref()))),
1103            attempt(spaces().with(qop(mapref()))),
1104            attempt(spaces().with(qop(apply()))),
1105            attempt(spaces().with(qop(do_block()))),
1106            attempt(spaces().with(qop(select()))),
1107            attempt(spaces().with(qop(cast()))),
1108            attempt(spaces().with(qop(any()))),
1109            attempt(spaces().with(interpolated())),
1110            attempt(spaces().with(literal())),
1111            attempt(spaces().with(qop(reference()))),
1112            attempt(
1113                (position(), sptoken('!').with(arith()))
1114                    .map(|(pos, expr)| ExprKind::Not { expr: Arc::new(expr) }.to_expr(pos)),
1115            ),
1116            attempt(between(sptoken('('), sptoken(')'), arith())),
1117        ))
1118            .skip(spaces())
1119    }
1120}
1121
1122parser! {
1123    fn arith[I]()(I) -> Expr
1124    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1125    {
1126        choice((
1127            attempt(chainl1(
1128                arith_term(),
1129                choice((
1130                    attempt(spstring("+")),
1131                    attempt(spstring("-")),
1132                    attempt(spstring("*")),
1133                    attempt(spstring("/")),
1134                    attempt(spstring("%")),
1135                    attempt(spstring("==")),
1136                    attempt(spstring("!=")),
1137                    attempt(spstring(">=")),
1138                    attempt(spstring("<=")),
1139                    attempt(spstring(">")),
1140                    attempt(spstring("<")),
1141                    attempt(spstring("&&")),
1142                    attempt(spstring("||")),
1143                    attempt(spstring("~")),
1144                ))
1145                    .map(|op: &str| match op {
1146                        "+" => |lhs: Expr, rhs: Expr| {
1147                            let pos = lhs.pos;
1148                            ExprKind::Add { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1149                        },
1150                        "-" => |lhs: Expr, rhs: Expr| {
1151                            let pos = lhs.pos;
1152                            ExprKind::Sub { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1153                        },
1154                        "*" => |lhs: Expr, rhs: Expr| {
1155                            let pos = lhs.pos;
1156                            ExprKind::Mul { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1157                        },
1158                        "/" => |lhs: Expr, rhs: Expr| {
1159                            let pos = lhs.pos;
1160                            ExprKind::Div { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1161                        },
1162                        "%" => |lhs: Expr, rhs: Expr| {
1163                            let pos = lhs.pos;
1164                            ExprKind::Mod { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1165                        },
1166                        "==" => |lhs: Expr, rhs: Expr| {
1167                            let pos = lhs.pos;
1168                            ExprKind::Eq { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1169                        },
1170                        "!=" => |lhs: Expr, rhs: Expr| {
1171                            let pos = lhs.pos;
1172                            ExprKind::Ne { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1173                        },
1174                        ">" => |lhs: Expr, rhs: Expr| {
1175                            let pos = lhs.pos;
1176                            ExprKind::Gt { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1177                        },
1178                        "<" => |lhs: Expr, rhs: Expr| {
1179                            let pos = lhs.pos;
1180                            ExprKind::Lt { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1181                        },
1182                        ">=" => |lhs: Expr, rhs: Expr| {
1183                            let pos = lhs.pos;
1184                            ExprKind::Gte { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1185                        },
1186                        "<=" => |lhs: Expr, rhs: Expr| {
1187                            let pos = lhs.pos;
1188                            ExprKind::Lte { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1189                        },
1190                        "&&" => |lhs: Expr, rhs: Expr| {
1191                            let pos = lhs.pos;
1192                            ExprKind::And { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1193                        },
1194                        "||" => |lhs: Expr, rhs: Expr| {
1195                            let pos = lhs.pos;
1196                            ExprKind::Or { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1197                        },
1198                        "~" => |lhs: Expr, rhs: Expr| {
1199                            let pos = lhs.pos;
1200                            ExprKind::Sample { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }
1201                            .to_expr(pos)
1202                        },
1203                        _ => unreachable!(),
1204                    }),
1205            )),
1206            attempt((position(), sptoken('!').with(arith_term())))
1207                .map(|(pos, expr)| ExprKind::Not { expr: Arc::new(expr) }.to_expr(pos)),
1208            attempt(between(sptoken('('), sptoken(')'), arith())),
1209        ))
1210    }
1211}
1212
1213parser! {
1214    fn slice_pattern[I]()(I) -> StructurePattern
1215    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1216    {
1217        macro_rules! all_left {
1218            ($pats:expr) => {{
1219                let mut err = false;
1220                let pats: Arc<[StructurePattern]> =
1221                    Arc::from_iter($pats.drain(..).map(|s| match s {
1222                        Either::Left(s) => s,
1223                        Either::Right(_) => {
1224                            err = true;
1225                            StructurePattern::Ignore
1226                        }
1227                    }));
1228                if err {
1229                    return unexpected_any("invalid pattern").left();
1230                }
1231                pats
1232            }};
1233        }
1234        (
1235            optional(attempt(spfname().skip(sptoken('@')))),
1236            between(
1237                sptoken('['),
1238                sptoken(']'),
1239                sep_by(
1240                    choice((
1241                        attempt(spstring("..")).map(|_| Either::Right(None)),
1242                        attempt(spfname().skip(spstring("..")))
1243                            .map(|n| Either::Right(Some(n))),
1244                        structure_pattern().map(|p| Either::Left(p)),
1245                    )),
1246                    csep(),
1247                ),
1248            ),
1249        )
1250            .then(
1251                |(all, mut pats): (
1252                    Option<ArcStr>,
1253                    LPooled<Vec<Either<StructurePattern, Option<ArcStr>>>>,
1254                )| {
1255                    if pats.len() == 0 {
1256                        value(StructurePattern::Slice { all, binds: Arc::from_iter([]) })
1257                            .right()
1258                    } else if pats.len() == 1 {
1259                        match pats.pop().unwrap() {
1260                            Either::Left(s) => value(StructurePattern::Slice {
1261                                all,
1262                                binds: Arc::from_iter([s]),
1263                            })
1264                                .right(),
1265                            Either::Right(_) => {
1266                                unexpected_any("invalid singular range match").left()
1267                            }
1268                        }
1269                    } else {
1270                        match (&pats[0], &pats[pats.len() - 1]) {
1271                            (Either::Right(_), Either::Right(_)) => {
1272                                unexpected_any("invalid pattern").left()
1273                            }
1274                            (Either::Right(_), Either::Left(_)) => {
1275                                let head = pats.remove(0).right().unwrap();
1276                                let suffix = all_left!(pats);
1277                                value(StructurePattern::SliceSuffix { all, head, suffix })
1278                                    .right()
1279                            }
1280                            (Either::Left(_), Either::Right(_)) => {
1281                                let tail = pats.pop().unwrap().right().unwrap();
1282                                let prefix = all_left!(pats);
1283                                value(StructurePattern::SlicePrefix { all, tail, prefix })
1284                                    .right()
1285                            }
1286                            (Either::Left(_), Either::Left(_)) => {
1287                                value(StructurePattern::Slice { all, binds: all_left!(pats) })
1288                                    .right()
1289                            }
1290                        }
1291                    }
1292                },
1293            )
1294    }
1295}
1296
1297fn raw_string<I>() -> impl Parser<I, Output = Expr>
1298where
1299    I: RangeStream<Token = char, Position = SourcePosition>,
1300    I::Error: ParseError<I::Token, I::Range, I::Position>,
1301    I::Range: Range,
1302{
1303    static MUST_ESC: [char; 2] = ['\\', '\''];
1304    static ESC: LazyLock<Escape> =
1305        LazyLock::new(|| Escape::new('\\', &MUST_ESC, &[], None).unwrap());
1306    (position(), between(string("r\'"), token('\''), escaped_string(&MUST_ESC, &ESC)))
1307        .map(|(pos, s): (_, String)| {
1308            ExprKind::Constant(Value::String(s.into())).to_expr(pos)
1309        })
1310}
1311
1312parser! {
1313    fn tuple_pattern[I]()(I) -> StructurePattern
1314    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1315    {
1316        (
1317            optional(attempt(spfname().skip(sptoken('@')))),
1318            between(sptoken('('), sptoken(')'), sep_by1(structure_pattern(), csep())),
1319        )
1320            .then(|(all, mut binds): (Option<ArcStr>, LPooled<Vec<StructurePattern>>)| {
1321                if binds.len() < 2 {
1322                    unexpected_any("tuples must have at least 2 elements").left()
1323                } else {
1324                    value(StructurePattern::Tuple { all, binds: Arc::from_iter(binds.drain(..)) })
1325                        .right()
1326                }
1327            })
1328    }
1329}
1330
1331parser! {
1332    fn variant_pattern[I]()(I) -> StructurePattern
1333    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1334    {
1335        (
1336            optional(attempt(spfname().skip(sptoken('@')))),
1337            sptoken('`').with(typname()),
1338            optional(attempt(between(
1339                sptoken('('),
1340                sptoken(')'),
1341                sep_by1(structure_pattern(), csep()),
1342            ))),
1343        )
1344            .map(
1345                |(all, tag, binds): (
1346                    Option<ArcStr>,
1347                    ArcStr,
1348                    Option<LPooled<Vec<StructurePattern>>>,
1349                )| {
1350                    let mut binds = match binds {
1351                        None => LPooled::take(),
1352                        Some(a) => a,
1353                    };
1354                    StructurePattern::Variant { all, tag, binds: Arc::from_iter(binds.drain(..)) }
1355                },
1356            )
1357    }
1358}
1359
1360parser! {
1361    fn struct_pattern[I]()(I) -> StructurePattern
1362    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1363    {
1364        (
1365            optional(attempt(spfname().skip(sptoken('@')))),
1366            between(
1367                sptoken('{'),
1368                sptoken('}'),
1369                sep_by1(
1370                    choice((
1371                        attempt((spfname().skip(sptoken(':')), structure_pattern()))
1372                            .map(|(s, p)| (s, p, true)),
1373                        attempt(spfname()).map(|s| {
1374                            let p = StructurePattern::Bind(s.clone());
1375                            (s, p, true)
1376                        }),
1377                        spstring("..")
1378                            .map(|_| (literal!(""), StructurePattern::Ignore, false)),
1379                    )),
1380                    csep(),
1381                ),
1382            ),
1383        )
1384            .then(
1385                |(all, mut binds): (
1386                    Option<ArcStr>,
1387                    LPooled<Vec<(ArcStr, StructurePattern, bool)>>,
1388                )| {
1389                    let mut exhaustive = true;
1390                    binds.retain(|(_, _, ex)| {
1391                        exhaustive &= *ex;
1392                        *ex
1393                    });
1394                    binds.sort_by_key(|(s, _, _)| s.clone());
1395                    let s = binds.iter().map(|(s, _, _)| s).collect::<LPooled<FxHashSet<_>>>();
1396                    if s.len() < binds.len() {
1397                        unexpected_any("struct fields must be unique").left()
1398                    } else {
1399                        drop(s);
1400                        let binds = Arc::from_iter(binds.drain(..).map(|(s, p, _)| (s, p)));
1401                        value(StructurePattern::Struct { all, exhaustive, binds }).right()
1402                    }
1403                },
1404            )
1405    }
1406}
1407
1408parser! {
1409    fn structure_pattern[I]()(I) -> StructurePattern
1410    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1411    {
1412        choice((
1413            attempt(slice_pattern()),
1414            attempt(tuple_pattern()),
1415            attempt(struct_pattern()),
1416            attempt(variant_pattern()),
1417            attempt(parse_value(&VAL_MUST_ESC, &VAL_ESC).skip(not_followed_by(token('_'))))
1418                .map(|v| StructurePattern::Literal(v)),
1419            attempt(sptoken('_')).map(|_| StructurePattern::Ignore),
1420            spfname().map(|name| StructurePattern::Bind(name)),
1421        ))
1422    }
1423}
1424
1425parser! {
1426    fn pattern[I]()(I) -> Pattern
1427    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1428    {
1429        (
1430            optional(attempt(typexp().skip(space().with(spstring("as "))))),
1431            structure_pattern(),
1432            optional(attempt(space().with(spstring("if").with(space()).with(expr())))),
1433        )
1434            .map(
1435                |(type_predicate, structure_predicate, guard): (
1436                    Option<Type>,
1437                    StructurePattern,
1438                    Option<Expr>,
1439                )| { Pattern { type_predicate, structure_predicate, guard } },
1440            )
1441    }
1442}
1443
1444parser! {
1445    fn select[I]()(I) -> Expr
1446    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1447    {
1448        (
1449            position(),
1450            string("select").with(space()).with((
1451                expr(),
1452                between(
1453                    sptoken('{'),
1454                    sptoken('}'),
1455                    sep_by1((pattern(), spstring("=>").with(expr())), csep()),
1456                ),
1457            )),
1458        )
1459            .map(|(pos, (arg, arms)): (_, (Expr, Vec<(Pattern, Expr)>))| {
1460                ExprKind::Select { arg: Arc::new(arg), arms: Arc::from(arms) }.to_expr(pos)
1461            })
1462    }
1463}
1464
1465parser! {
1466    fn cast[I]()(I) -> Expr
1467    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1468    {
1469        (
1470            position(),
1471            string("cast").with(between(token('<'), sptoken('>'), typexp())),
1472            between(sptoken('('), sptoken(')'), expr()),
1473        )
1474            .map(|(pos, typ, e)| ExprKind::TypeCast { expr: Arc::new(e), typ }.to_expr(pos))
1475    }
1476}
1477
1478parser! {
1479    fn typedef[I]()(I) -> Expr
1480    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1481    {
1482        (
1483            position(),
1484            string("type").with(sptypname()),
1485            optional(attempt(between(
1486                sptoken('<'),
1487                sptoken('>'),
1488                sep_by1((tvar(), optional(attempt(sptoken(':').with(typexp())))), csep()),
1489            ))),
1490            sptoken('=').with(typexp()),
1491        )
1492            .map(|(pos, name, params, typ)| {
1493                let params = params
1494                    .map(|mut ps: LPooled<Vec<(TVar, Option<Type>)>>| {
1495                        Arc::from_iter(ps.drain(..))
1496                    })
1497                    .unwrap_or_else(|| Arc::<[(TVar, Option<Type>)]>::from(Vec::new()));
1498                ExprKind::TypeDef(TypeDef { name, params, typ }).to_expr(pos)
1499            })
1500    }
1501}
1502
1503parser! {
1504    fn tuple[I]()(I) -> Expr
1505    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1506    {
1507        (position(), between(token('('), sptoken(')'), sep_by1(expr(), csep()))).then(
1508            |(pos, mut exprs): (_, LPooled<Vec<Expr>>)| {
1509                if exprs.len() < 2 {
1510                    unexpected_any("tuples must have at least 2 elements").left()
1511                } else {
1512                    value(ExprKind::Tuple { args: Arc::from_iter(exprs.drain(..)) }.to_expr(pos))
1513                        .right()
1514                }
1515            },
1516        )
1517    }
1518}
1519
1520parser! {
1521    fn structure[I]()(I) -> Expr
1522    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1523    {
1524        (
1525            position(),
1526            between(
1527                token('{'),
1528                sptoken('}'),
1529                sep_by1((spfname(), optional(attempt(sptoken(':')).with(expr()))), csep()),
1530            ),
1531        )
1532            .then(|(pos, mut exprs): (_, LPooled<Vec<(ArcStr, Option<Expr>)>>)| {
1533                let s = exprs.iter().map(|(n, _)| n).collect::<LPooled<FxHashSet<_>>>();
1534                if s.len() < exprs.len() {
1535                    return unexpected_any("struct fields must be unique").left();
1536                }
1537                drop(s);
1538                exprs.sort_by_key(|(n, _)| n.clone());
1539                let args = exprs.drain(..).map(|(n, e)| match e {
1540                    Some(e) => (n, e),
1541                    None => {
1542                        let e = ExprKind::Ref { name: [n.clone()].into() }.to_expr(pos);
1543                        (n, e)
1544                    }
1545                });
1546                value(ExprKind::Struct { args: Arc::from_iter(args) }.to_expr(pos)).right()
1547            })
1548    }
1549}
1550
1551parser! {
1552    fn map[I]()(I) -> Expr
1553    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1554    {
1555        (
1556            position(),
1557            between(
1558                token('{'),
1559                sptoken('}'),
1560                sep_by((expr(), spstring("=>").with(expr())), csep()),
1561            ),
1562        )
1563            .map(|(pos, mut args): (_, LPooled<Vec<(Expr, Expr)>>)| {
1564                ExprKind::Map { args: Arc::from_iter(args.drain(..)) }.to_expr(pos)
1565            })
1566    }
1567}
1568
1569parser! {
1570    fn variant[I]()(I) -> Expr
1571    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1572    {
1573        (
1574            position(),
1575            token('`').with(typname()),
1576            optional(attempt(between(token('('), sptoken(')'), sep_by1(expr(), csep())))),
1577        )
1578            .map(|(pos, tag, args): (_, ArcStr, Option<LPooled<Vec<Expr>>>)| {
1579                let mut args = match args {
1580                    None => LPooled::take(),
1581                    Some(a) => a,
1582                };
1583                ExprKind::Variant { tag, args: Arc::from_iter(args.drain(..)) }.to_expr(pos)
1584            })
1585    }
1586}
1587
1588parser! {
1589    fn structwith[I]()(I) -> Expr
1590    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1591    {
1592        (
1593            position(),
1594            between(
1595                token('{'),
1596                sptoken('}'),
1597                (
1598                    ref_pexp().skip(space()).skip(spstring("with")).skip(space()),
1599                    sep_by1((spfname(), optional(attempt(sptoken(':').with(expr())))), csep()),
1600                ),
1601            ),
1602        )
1603            .then(
1604                |(pos, (source, mut exprs)): (_, (Expr, LPooled<Vec<(ArcStr, Option<Expr>)>>))| {
1605                    let s = exprs.iter().map(|(n, _)| n).collect::<LPooled<FxHashSet<_>>>();
1606                    if s.len() < exprs.len() {
1607                        return unexpected_any("struct fields must be unique").left();
1608                    }
1609                    drop(s);
1610                    exprs.sort_by_key(|(n, _)| n.clone());
1611                    let exprs = exprs.drain(..).map(|(name, e)| match e {
1612                        Some(e) => (name, e),
1613                        None => {
1614                            let e = ExprKind::Ref { name: ModPath::from([name.clone()]) }.to_expr(pos);
1615                            (name, e)
1616                        }
1617                    });
1618                    let e = ExprKind::StructWith {
1619                        source: Arc::new(source),
1620                        replace: Arc::from_iter(exprs),
1621                    }
1622                    .to_expr(pos);
1623                    value(e).right()
1624                },
1625            )
1626    }
1627}
1628
1629parser! {
1630    fn try_catch[I]()(I) -> Expr
1631    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1632    {
1633        (
1634            position().skip(string("try")).skip(space()),
1635            sep_by1(expr(), attempt(sptoken(';'))),
1636            spstring("catch").with(
1637                between(
1638                    sptoken('('),
1639                    sptoken(')'),
1640                    (spfname(), optional(attempt(sptoken(':').with(typexp()))))
1641                )
1642            ),
1643            spstring("=>").with(expr())
1644        )
1645            .map(|(pos, mut exprs, (bind, constraint), handler):
1646                  (_, LPooled<Vec<Expr>>, _, _)|
1647            {
1648                ExprKind::TryCatch(Arc::new(TryCatch {
1649                    bind,
1650                    constraint,
1651                    exprs: Arc::from_iter(exprs.drain(..)),
1652                    handler: Arc::new(handler)
1653                })).to_expr(pos)
1654            })
1655    }
1656}
1657
1658parser! {
1659    fn byref[I]()(I) -> Expr
1660    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1661    {
1662        (position(), token('&').with(expr()))
1663            .map(|(pos, expr)| ExprKind::ByRef(Arc::new(expr)).to_expr(pos))
1664    }
1665}
1666
1667parser! {
1668    fn byref_arith[I]()(I) -> Expr
1669    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1670    {
1671        (position(), token('&').with(arith_term()))
1672            .map(|(pos, expr)| ExprKind::ByRef(Arc::new(expr)).to_expr(pos))
1673    }
1674}
1675
1676parser! {
1677    fn deref[I]()(I) -> Expr
1678    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1679    {
1680        (position(), token('*').with(expr()))
1681            .map(|(pos, expr)| ExprKind::Deref(Arc::new(expr)).to_expr(pos))
1682    }
1683}
1684
1685parser! {
1686    fn expr[I]()(I) -> Expr
1687    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1688    {
1689        choice((
1690            attempt(choice((
1691                attempt(spaces().with(try_catch())),
1692                attempt(spaces().with(module())),
1693                attempt(spaces().with(use_module())),
1694                attempt(spaces().with(typedef())),
1695                attempt(spaces().with(raw_string())),
1696                attempt(spaces().with(array())),
1697                attempt(spaces().with(byref())),
1698                attempt(spaces().with(connect())),
1699                attempt(spaces().with(arith())),
1700                attempt(spaces().with(qop(mapref()))),
1701                attempt(spaces().with(qop(arrayref()))),
1702                attempt(spaces().with(qop(tupleref()))),
1703                attempt(spaces().with(qop(structref()))),
1704                attempt(spaces().with(qop(deref()))),
1705                attempt(spaces().with(qop(apply()))),
1706                attempt(spaces().with(tuple())),
1707                attempt(spaces().with(between(token('('), sptoken(')'), expr()))),
1708            ))),
1709            attempt(spaces().with(structure())),
1710            attempt(spaces().with(map())),
1711            attempt(spaces().with(variant())),
1712            attempt(spaces().with(structwith())),
1713            attempt(spaces().with(qop(do_block()))),
1714            attempt(spaces().with(lambda())),
1715            attempt(spaces().with(letbind())),
1716            attempt(spaces().with(qop(select()))),
1717            attempt(spaces().with(qop(cast()))),
1718            attempt(spaces().with(qop(any()))),
1719            attempt(spaces().with(interpolated())),
1720            attempt(spaces().with(literal())),
1721            attempt(spaces().with(qop(reference())))
1722        ))
1723    }
1724}
1725
1726/// Parse one or more expressions
1727///
1728/// followed by (optional) whitespace and then eof. At least one
1729/// expression is required otherwise this function will fail.
1730pub fn parse(ori: Origin) -> anyhow::Result<Arc<[Expr]>> {
1731    let ori = Arc::new(ori);
1732    set_origin(ori.clone());
1733    let r: Vec<Expr> = sep_by1(expr(), attempt(sptoken(';')))
1734        .skip(spaces())
1735        .skip(eof())
1736        .easy_parse(position::Stream::new(&*ori.text))
1737        .map(|(r, _)| r)
1738        .map_err(|e| anyhow::anyhow!(format!("{}", e)))?;
1739    Ok(Arc::from(r))
1740}
1741
1742/// Parse one and only one expression.
1743pub fn parse_one(s: &str) -> anyhow::Result<Expr> {
1744    expr()
1745        .skip(spaces())
1746        .skip(eof())
1747        .easy_parse(position::Stream::new(&*s))
1748        .map(|(r, _)| r)
1749        .map_err(|e| anyhow::anyhow!(format!("{e}")))
1750}
1751
1752pub fn test_parse_mapref(s: &str) -> anyhow::Result<Expr> {
1753    mapref()
1754        .skip(spaces())
1755        .skip(eof())
1756        .easy_parse(position::Stream::new(&*s))
1757        .map(|(r, _)| r)
1758        .map_err(|e| anyhow::anyhow!(format!("{e}")))
1759}
1760
1761/// Parse one fntype expression
1762pub fn parse_fn_type(s: &str) -> anyhow::Result<FnType> {
1763    fntype()
1764        .skip(spaces())
1765        .skip(eof())
1766        .easy_parse(position::Stream::new(s))
1767        .map(|(r, _)| r)
1768        .map_err(|e| anyhow::anyhow!(format!("{e}")))
1769}
1770
1771/// Parse one type expression
1772pub fn parse_type(s: &str) -> anyhow::Result<Type> {
1773    typexp()
1774        .skip(spaces())
1775        .skip(eof())
1776        .easy_parse(position::Stream::new(s))
1777        .map(|(r, _)| r)
1778        .map_err(|e| anyhow::anyhow!(format!("{e}")))
1779}
1780
1781pub(super) fn parse_modpath(s: &str) -> anyhow::Result<ModPath> {
1782    modpath()
1783        .skip(spaces())
1784        .skip(eof())
1785        .easy_parse(position::Stream::new(s))
1786        .map(|(r, _)| r)
1787        .map_err(|e| anyhow::anyhow!(format!("{e}")))
1788}