netidx_bscript/expr/parser/
mod.rs

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