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, 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::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::ByRef(_), .. }), _)
345                        | (Some(Expr { kind: ExprKind::Deref(_), .. }), _)
346                        | (Some(Expr { kind: ExprKind::Lambda { .. }, .. }), _) => {
347                            unreachable!()
348                        }
349                    }
350                })
351                .unwrap_or_else(|| ExprKind::Constant(Value::from("")).to_expr(pos))
352        })
353}
354
355parser! {
356    fn interpolated[I]()(I) -> Expr
357    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
358    {
359        interpolated_()
360    }
361}
362
363fn module<I>() -> impl Parser<I, Output = Expr>
364where
365    I: RangeStream<Token = char, Position = SourcePosition>,
366    I::Error: ParseError<I::Token, I::Range, I::Position>,
367    I::Range: Range,
368{
369    (
370        position(),
371        optional(string("pub").skip(space())).map(|o| o.is_some()),
372        spstring("mod").with(space()).with(spfname()),
373        choice((
374            attempt(sptoken(';')).map(|_| ModuleKind::Unresolved),
375            between(sptoken('{'), sptoken('}'), sep_by(expr(), attempt(sptoken(';'))))
376                .map(|m: Vec<Expr>| ModuleKind::Inline(Arc::from(m))),
377        )),
378    )
379        .map(|(pos, export, name, value)| {
380            ExprKind::Module { name, export, value }.to_expr(pos)
381        })
382}
383
384fn use_module<I>() -> impl Parser<I, Output = Expr>
385where
386    I: RangeStream<Token = char, Position = SourcePosition>,
387    I::Error: ParseError<I::Token, I::Range, I::Position>,
388    I::Range: Range,
389{
390    (position(), string("use").with(space()).with(spmodpath()))
391        .map(|(pos, name)| ExprKind::Use { name }.to_expr(pos))
392}
393
394fn do_block<I>() -> impl Parser<I, Output = Expr>
395where
396    I: RangeStream<Token = char, Position = SourcePosition>,
397    I::Error: ParseError<I::Token, I::Range, I::Position>,
398    I::Range: Range,
399{
400    (position(), between(token('{'), sptoken('}'), sep_by(expr(), attempt(sptoken(';')))))
401        .map(|(pos, args): (_, Vec<Expr>)| {
402            ExprKind::Do { exprs: Arc::from(args) }.to_expr(pos)
403        })
404}
405
406fn array<I>() -> impl Parser<I, Output = Expr>
407where
408    I: RangeStream<Token = char, Position = SourcePosition>,
409    I::Error: ParseError<I::Token, I::Range, I::Position>,
410    I::Range: Range,
411{
412    (position(), between(token('['), sptoken(']'), sep_by(expr(), csep()))).map(
413        |(pos, args): (_, SmallVec<[Expr; 4]>)| {
414            ExprKind::Array { args: Arc::from_iter(args.into_iter()) }.to_expr(pos)
415        },
416    )
417}
418
419fn apply_pexp<I>() -> impl Parser<I, Output = Expr>
420where
421    I: RangeStream<Token = char, Position = SourcePosition>,
422    I::Error: ParseError<I::Token, I::Range, I::Position>,
423    I::Range: Range,
424{
425    choice((
426        attempt(spaces().with(qop(do_block()))),
427        attempt(spaces().with(qop(reference()))),
428        between(sptoken('('), sptoken(')'), expr()),
429    ))
430}
431
432fn ref_pexp<I>() -> impl Parser<I, Output = Expr>
433where
434    I: RangeStream<Token = char, Position = SourcePosition>,
435    I::Error: ParseError<I::Token, I::Range, I::Position>,
436    I::Range: Range,
437{
438    choice((
439        attempt(spaces().with(qop(apply()))),
440        attempt(spaces().with(qop(do_block()))),
441        attempt(spaces().with(qop(reference()))),
442        between(sptoken('('), sptoken(')'), expr()),
443    ))
444}
445
446fn structref<I>() -> impl Parser<I, Output = Expr>
447where
448    I: RangeStream<Token = char, Position = SourcePosition>,
449    I::Error: ParseError<I::Token, I::Range, I::Position>,
450    I::Range: Range,
451{
452    (position(), ref_pexp().skip(sptoken('.')), spfname()).map(|(pos, source, field)| {
453        ExprKind::StructRef { source: Arc::new(source), field }.to_expr(pos)
454    })
455}
456
457fn tupleref<I>() -> impl Parser<I, Output = Expr>
458where
459    I: RangeStream<Token = char, Position = SourcePosition>,
460    I::Error: ParseError<I::Token, I::Range, I::Position>,
461    I::Range: Range,
462{
463    (position(), ref_pexp().skip(sptoken('.')), int::<_, usize>()).map(
464        |(pos, source, field)| {
465            ExprKind::TupleRef { source: Arc::new(source), field }.to_expr(pos)
466        },
467    )
468}
469
470fn arrayref<I>() -> impl Parser<I, Output = Expr>
471where
472    I: RangeStream<Token = char, Position = SourcePosition>,
473    I::Error: ParseError<I::Token, I::Range, I::Position>,
474    I::Range: Range,
475{
476    (
477        position(),
478        ref_pexp(),
479        between(
480            token('['),
481            sptoken(']'),
482            choice((
483                attempt(
484                    (
485                        position(),
486                        spaces().with(optional(many1(digit()))).skip(spstring("..")),
487                        spaces().with(optional(many1(digit()))),
488                    )
489                        .skip(look_ahead(sptoken(']'))),
490                )
491                .map(
492                    |(pos, start, end): (
493                        _,
494                        Option<CompactString>,
495                        Option<CompactString>,
496                    )| {
497                        let start = start.map(|i| Value::U64(i.parse().unwrap()));
498                        let start = start.map(|e| ExprKind::Constant(e).to_expr(pos));
499                        let end = end.map(|i| Value::U64(i.parse().unwrap()));
500                        let end = end.map(|e| ExprKind::Constant(e).to_expr(pos));
501                        Either::Left((start, end))
502                    },
503                ),
504                attempt((
505                    optional(attempt(expr())).skip(spstring("..")),
506                    optional(attempt(expr())),
507                ))
508                .map(|(start, end)| Either::Left((start, end))),
509                attempt(expr()).map(|e| Either::Right(e)),
510            )),
511        ),
512    )
513        .map(|(pos, a, args)| match args {
514            Either::Left((start, end)) => ExprKind::ArraySlice {
515                source: Arc::new(a),
516                start: start.map(Arc::new),
517                end: end.map(Arc::new),
518            }
519            .to_expr(pos),
520            Either::Right(i) => {
521                ExprKind::ArrayRef { source: Arc::new(a), i: Arc::new(i) }.to_expr(pos)
522            }
523        })
524}
525
526fn apply<I>() -> impl Parser<I, Output = Expr>
527where
528    I: RangeStream<Token = char, Position = SourcePosition>,
529    I::Error: ParseError<I::Token, I::Range, I::Position>,
530    I::Range: Range,
531{
532    (
533        position(),
534        apply_pexp(),
535        between(
536            sptoken('('),
537            sptoken(')'),
538            sep_by(
539                choice((
540                    attempt((
541                        position(),
542                        sptoken('#').with(fname()).skip(not_followed_by(token(':'))),
543                    ))
544                    .map(|(pos, n)| {
545                        let e = ExprKind::Ref { name: [n.clone()].into() }.to_expr(pos);
546                        (Some(n), e)
547                    }),
548                    attempt((sptoken('#').with(fname()).skip(token(':')), expr()))
549                        .map(|(n, e)| (Some(n), e)),
550                    expr().map(|e| (None, e)),
551                )),
552                csep(),
553            ),
554        ),
555    )
556        .then(|(pos, function, args): (_, Expr, Vec<(Option<ArcStr>, Expr)>)| {
557            let mut anon = false;
558            for (a, _) in &args {
559                if a.is_some() && anon {
560                    return unexpected_any(
561                        "labeled arguments must come before anonymous arguments",
562                    )
563                    .right();
564                }
565                anon |= a.is_none();
566            }
567            value((pos, function, args)).left()
568        })
569        .map(|(pos, function, args): (_, Expr, Vec<(Option<ArcStr>, Expr)>)| {
570            ExprKind::Apply { function: Arc::new(function), args: Arc::from(args) }
571                .to_expr(pos)
572        })
573}
574
575fn any<I>() -> impl Parser<I, Output = Expr>
576where
577    I: RangeStream<Token = char, Position = SourcePosition>,
578    I::Error: ParseError<I::Token, I::Range, I::Position>,
579    I::Range: Range,
580{
581    (
582        position(),
583        string("any").with(between(sptoken('('), sptoken(')'), sep_by(expr(), csep()))),
584    )
585        .map(|(pos, args): (_, Vec<Expr>)| {
586            ExprKind::Any { args: Arc::from(args) }.to_expr(pos)
587        })
588}
589
590fn typeprim<I>() -> impl Parser<I, Output = Typ>
591where
592    I: RangeStream<Token = char>,
593    I::Error: ParseError<I::Token, I::Range, I::Position>,
594    I::Range: Range,
595{
596    choice((
597        attempt(spstring("u32").map(|_| Typ::U32)),
598        attempt(spstring("v32").map(|_| Typ::V32)),
599        attempt(spstring("i32").map(|_| Typ::I32)),
600        attempt(spstring("z32").map(|_| Typ::Z32)),
601        attempt(spstring("u64").map(|_| Typ::U64)),
602        attempt(spstring("v64").map(|_| Typ::V64)),
603        attempt(spstring("i64").map(|_| Typ::I64)),
604        attempt(spstring("z64").map(|_| Typ::Z64)),
605        attempt(spstring("f32").map(|_| Typ::F32)),
606        attempt(spstring("f64").map(|_| Typ::F64)),
607        attempt(spstring("decimal").map(|_| Typ::Decimal)),
608        attempt(spstring("datetime").map(|_| Typ::DateTime)),
609        attempt(spstring("duration").map(|_| Typ::Duration)),
610        attempt(spstring("bool").map(|_| Typ::Bool)),
611        attempt(spstring("string").map(|_| Typ::String)),
612        attempt(spstring("bytes").map(|_| Typ::Bytes)),
613        attempt(spstring("error").map(|_| Typ::Error)),
614        attempt(spstring("array").map(|_| Typ::Array)),
615        attempt(spstring("null").map(|_| Typ::Null)),
616    ))
617    .skip(not_followed_by(choice((alpha_num(), token('_')))))
618}
619
620fn fntype<I>() -> impl Parser<I, Output = FnType>
621where
622    I: RangeStream<Token = char>,
623    I::Error: ParseError<I::Token, I::Range, I::Position>,
624    I::Range: Range,
625{
626    spstring("fn")
627        .with((
628            optional(attempt(between(
629                token('<'),
630                sptoken('>'),
631                sep_by1((tvar().skip(sptoken(':')), typexp()), csep()),
632            )))
633            .map(|cs: Option<SmallVec<[(TVar, Type); 4]>>| match cs {
634                Some(cs) => Arc::new(RwLock::new(cs.into_iter().collect())),
635                None => Arc::new(RwLock::new(vec![])),
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, Type)>>>,
675                Vec<Either<FnArgType, Type>>,
676                Type,
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>
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>
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('&').with(typexp()).map(|t| Type::ByRef(Arc::new(t)))),
728        attempt(sptoken('_').map(|_| Type::Bottom)),
729        attempt(
730            between(sptoken('['), sptoken(']'), sep_by(typexp(), csep()))
731                .map(|ts: SmallVec<[Type; 16]>| Type::flatten_set(ts)),
732        ),
733        attempt(between(sptoken('('), sptoken(')'), sep_by1(typexp(), csep())).then(
734            |exps: SmallVec<[Type; 16]>| {
735                if exps.len() < 2 {
736                    unexpected_any("tuples must have at least 2 elements").left()
737                } else {
738                    value(Type::Tuple(Arc::from_iter(exps))).right()
739                }
740            },
741        )),
742        attempt(
743            between(
744                sptoken('{'),
745                sptoken('}'),
746                sep_by1((spfname().skip(sptoken(':')), typexp()), csep()),
747            )
748            .then(|mut exps: SmallVec<[(ArcStr, Type); 16]>| {
749                let s = exps.iter().map(|(n, _)| n).collect::<FxHashSet<_>>();
750                if s.len() < exps.len() {
751                    return unexpected_any("struct field names must be unique").left();
752                }
753                exps.sort_by_key(|(n, _)| n.clone());
754                value(Type::Struct(Arc::from_iter(exps))).right()
755            }),
756        ),
757        attempt(
758            (
759                sptoken('`').with(typname()),
760                optional(attempt(between(
761                    token('('),
762                    sptoken(')'),
763                    sep_by1(typexp(), csep()),
764                ))),
765            )
766                .map(|(tag, typs): (ArcStr, Option<SmallVec<[Type; 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        attempt(fntype().map(|f| Type::Fn(Arc::new(f)))),
775        attempt(spstring("Array").with(between(sptoken('<'), sptoken('>'), typexp())))
776            .map(|t| Type::Array(Arc::new(t))),
777        attempt((
778            sptypath(),
779            optional(attempt(between(
780                sptoken('<'),
781                sptoken('>'),
782                sep_by1(typexp(), csep()),
783            ))),
784        ))
785        .map(|(n, params): (ModPath, Option<SmallVec<[Type; 8]>>)| {
786            let params = params
787                .map(|a| Arc::from_iter(a.into_iter()))
788                .unwrap_or_else(|| Arc::from_iter([]));
789            Type::Ref { scope: ModPath::root(), name: n, params }
790        }),
791        attempt(typeprim()).map(|typ| Type::Primitive(typ.into())),
792        attempt(tvar()).map(|tv| Type::TVar(tv)),
793    ))
794}
795
796parser! {
797    fn typexp[I]()(I) -> Type
798    where [I: RangeStream<Token = char>, I::Range: Range]
799    {
800        typexp_()
801    }
802}
803
804fn lambda_args<I>() -> impl Parser<I, Output = (Vec<Arg>, Option<Option<Type>>)>
805where
806    I: RangeStream<Token = char, Position = SourcePosition>,
807    I::Error: ParseError<I::Token, I::Range, I::Position>,
808    I::Range: Range,
809{
810    sep_by(
811        (
812            choice((
813                attempt(spaces().with(structure_pattern())).map(|p| (false, p)),
814                attempt(spaces().with(token('#').with(fname())))
815                    .map(|b| (true, StructurePattern::Bind(b))),
816                attempt(spstring("@args"))
817                    .map(|s| (false, StructurePattern::Bind(ArcStr::from(s)))),
818            )),
819            optional(attempt(sptoken(':').with(typexp()))),
820            optional(attempt(sptoken('=').with(expr()))),
821        ),
822        csep(),
823    )
824    .then(|v: Vec<((bool, StructurePattern), Option<Type>, Option<Expr>)>| {
825        let args = v
826            .into_iter()
827            .map(|((labeled, pattern), constraint, default)| {
828                if !labeled && default.is_some() {
829                    bail!("labeled")
830                } else {
831                    Ok(Arg { labeled: labeled.then_some(default), pattern, constraint })
832                }
833            })
834            .collect::<Result<Vec<_>>>();
835        match args {
836            Ok(a) => value(a).right(),
837            Err(_) => {
838                unexpected_any("only labeled arguments may have a default value").left()
839            }
840        }
841    })
842    // @args must be last
843    .then(|mut v: Vec<Arg>| {
844        match v.iter().enumerate().find(|(_, a)| match &a.pattern {
845            StructurePattern::Bind(n) if n == "@args" => true,
846            _ => false,
847        }) {
848            None => value((v, None)).left(),
849            Some((i, _)) => {
850                if i == v.len() - 1 {
851                    let a = v.pop().unwrap();
852                    value((v, Some(a.constraint))).left()
853                } else {
854                    unexpected_any("@args must be the last argument").right()
855                }
856            }
857        }
858    })
859    // labeled before anonymous args
860    .then(|(v, vargs): (Vec<Arg>, Option<Option<Type>>)| {
861        let mut anon = false;
862        for a in &v {
863            if a.labeled.is_some() && anon {
864                return unexpected_any("labeled args must come before anon args").right();
865            }
866            anon |= a.labeled.is_none();
867        }
868        value((v, vargs)).left()
869    })
870}
871
872fn lambda<I>() -> impl Parser<I, Output = Expr>
873where
874    I: RangeStream<Token = char, Position = SourcePosition>,
875    I::Error: ParseError<I::Token, I::Range, I::Position>,
876    I::Range: Range,
877{
878    (
879        position(),
880        attempt(sep_by((tvar().skip(sptoken(':')), typexp()), csep()))
881            .map(|tvs: SmallVec<[(TVar, Type); 4]>| Arc::from_iter(tvs)),
882        between(sptoken('|'), sptoken('|'), lambda_args()),
883        optional(attempt(spstring("->").with(typexp()).skip(space()))),
884        choice((
885            attempt(sptoken('\'').with(fname()).skip(not_followed_by(sptoken(':'))))
886                .map(Either::Right),
887            expr().map(|e| Either::Left(e)),
888        )),
889    )
890        .map(|(pos, constraints, (args, vargs), rtype, body)| {
891            let args = Arc::from_iter(args);
892            ExprKind::Lambda(Arc::new(Lambda { args, vargs, rtype, constraints, body }))
893                .to_expr(pos)
894        })
895}
896
897fn letbind<I>() -> impl Parser<I, Output = Expr>
898where
899    I: RangeStream<Token = char, Position = SourcePosition>,
900    I::Error: ParseError<I::Token, I::Range, I::Position>,
901    I::Range: Range,
902{
903    (
904        position(),
905        doc_comment(),
906        optional(string("pub").skip(space())).map(|o| o.is_some()),
907        spstring("let")
908            .with(space())
909            .with((structure_pattern(), optional(attempt(sptoken(':').with(typexp())))))
910            .skip(spstring("=")),
911        expr(),
912    )
913        .map(|(pos, doc, export, (pattern, typ), value)| {
914            ExprKind::Bind(Arc::new(Bind { doc, export, pattern, typ, value }))
915                .to_expr(pos)
916        })
917}
918
919fn connect<I>() -> impl Parser<I, Output = Expr>
920where
921    I: RangeStream<Token = char, Position = SourcePosition>,
922    I::Error: ParseError<I::Token, I::Range, I::Position>,
923    I::Range: Range,
924{
925    (position(), modpath().skip(spstring("<-")), expr())
926        .map(|(pos, name, e)| ExprKind::Connect { name, value: Arc::new(e) }.to_expr(pos))
927}
928
929fn literal<I>() -> impl Parser<I, Output = Expr>
930where
931    I: RangeStream<Token = char, Position = SourcePosition>,
932    I::Error: ParseError<I::Token, I::Range, I::Position>,
933    I::Range: Range,
934{
935    (position(), netidx_value(&BSCRIPT_ESC).skip(not_followed_by(token('_'))))
936        .map(|(pos, v)| ExprKind::Constant(v).to_expr(pos))
937}
938
939fn reference<I>() -> impl Parser<I, Output = Expr>
940where
941    I: RangeStream<Token = char, Position = SourcePosition>,
942    I::Error: ParseError<I::Token, I::Range, I::Position>,
943    I::Range: Range,
944{
945    (position(), modpath()).map(|(pos, name)| ExprKind::Ref { name }.to_expr(pos))
946}
947
948fn qop<I, P: Parser<I, Output = Expr>>(p: P) -> impl Parser<I, Output = Expr>
949where
950    I: RangeStream<Token = char, Position = SourcePosition>,
951    I::Error: ParseError<I::Token, I::Range, I::Position>,
952    I::Range: Range,
953{
954    (position(), p, optional(attempt(sptoken('?')))).map(|(pos, e, qop)| match qop {
955        None => e,
956        Some(_) => ExprKind::Qop(Arc::new(e)).to_expr(pos),
957    })
958}
959
960fn arith_term<I>() -> impl Parser<I, Output = Expr>
961where
962    I: RangeStream<Token = char, Position = SourcePosition>,
963    I::Error: ParseError<I::Token, I::Range, I::Position>,
964    I::Range: Range,
965{
966    choice((
967        attempt(spaces().with(raw_string())),
968        attempt(spaces().with(array())),
969        attempt(spaces().with(qop(arrayref()))),
970        attempt(spaces().with(qop(tupleref()))),
971        attempt(spaces().with(qop(structref()))),
972        attempt(spaces().with(qop(apply()))),
973        attempt(spaces().with(qop(do_block()))),
974        attempt(spaces().with(qop(select()))),
975        attempt(spaces().with(qop(cast()))),
976        attempt(spaces().with(qop(any()))),
977        attempt(spaces().with(interpolated())),
978        attempt(spaces().with(literal())),
979        attempt(spaces().with(qop(reference()))),
980        attempt(
981            (position(), sptoken('!').with(arith()))
982                .map(|(pos, expr)| ExprKind::Not { expr: Arc::new(expr) }.to_expr(pos)),
983        ),
984        attempt(between(sptoken('('), sptoken(')'), arith())),
985    ))
986    .skip(spaces())
987}
988
989fn arith_<I>() -> impl Parser<I, Output = Expr>
990where
991    I: RangeStream<Token = char, Position = SourcePosition>,
992    I::Error: ParseError<I::Token, I::Range, I::Position>,
993    I::Range: Range,
994{
995    choice((
996        attempt(chainl1(
997            arith_term(),
998            choice((
999                attempt(spstring("+")),
1000                attempt(spstring("-")),
1001                attempt(spstring("*")),
1002                attempt(spstring("/")),
1003                attempt(spstring("==")),
1004                attempt(spstring("!=")),
1005                attempt(spstring(">=")),
1006                attempt(spstring("<=")),
1007                attempt(spstring(">")),
1008                attempt(spstring("<")),
1009                attempt(spstring("&&")),
1010                attempt(spstring("||")),
1011            ))
1012            .map(|op: &str| match op {
1013                "+" => |lhs: Expr, rhs: Expr| {
1014                    let pos = lhs.pos;
1015                    ExprKind::Add { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1016                },
1017                "-" => |lhs: Expr, rhs: Expr| {
1018                    let pos = lhs.pos;
1019                    ExprKind::Sub { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1020                },
1021                "*" => |lhs: Expr, rhs: Expr| {
1022                    let pos = lhs.pos;
1023                    ExprKind::Mul { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1024                },
1025                "/" => |lhs: Expr, rhs: Expr| {
1026                    let pos = lhs.pos;
1027                    ExprKind::Div { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1028                },
1029                "==" => |lhs: Expr, rhs: Expr| {
1030                    let pos = lhs.pos;
1031                    ExprKind::Eq { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1032                },
1033                "!=" => |lhs: Expr, rhs: Expr| {
1034                    let pos = lhs.pos;
1035                    ExprKind::Ne { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1036                },
1037                ">" => |lhs: Expr, rhs: Expr| {
1038                    let pos = lhs.pos;
1039                    ExprKind::Gt { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1040                },
1041                "<" => |lhs: Expr, rhs: Expr| {
1042                    let pos = lhs.pos;
1043                    ExprKind::Lt { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1044                },
1045                ">=" => |lhs: Expr, rhs: Expr| {
1046                    let pos = lhs.pos;
1047                    ExprKind::Gte { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1048                },
1049                "<=" => |lhs: Expr, rhs: Expr| {
1050                    let pos = lhs.pos;
1051                    ExprKind::Lte { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1052                },
1053                "&&" => |lhs: Expr, rhs: Expr| {
1054                    let pos = lhs.pos;
1055                    ExprKind::And { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1056                },
1057                "||" => |lhs: Expr, rhs: Expr| {
1058                    let pos = lhs.pos;
1059                    ExprKind::Or { lhs: Arc::new(lhs), rhs: Arc::new(rhs) }.to_expr(pos)
1060                },
1061                _ => unreachable!(),
1062            }),
1063        )),
1064        attempt((position(), sptoken('!').with(arith_term())))
1065            .map(|(pos, expr)| ExprKind::Not { expr: Arc::new(expr) }.to_expr(pos)),
1066        attempt(between(sptoken('('), sptoken(')'), arith())),
1067    ))
1068}
1069
1070parser! {
1071    fn arith[I]()(I) -> Expr
1072    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1073    {
1074        arith_()
1075    }
1076}
1077
1078fn slice_pattern<I>() -> impl Parser<I, Output = StructurePattern>
1079where
1080    I: RangeStream<Token = char>,
1081    I::Error: ParseError<I::Token, I::Range, I::Position>,
1082    I::Range: Range,
1083{
1084    macro_rules! all_left {
1085        ($pats:expr) => {{
1086            let mut err = false;
1087            let pats: Arc<[StructurePattern]> =
1088                Arc::from_iter($pats.into_iter().map(|s| match s {
1089                    Either::Left(s) => s,
1090                    Either::Right(_) => {
1091                        err = true;
1092                        StructurePattern::Ignore
1093                    }
1094                }));
1095            if err {
1096                return unexpected_any("invalid pattern").left();
1097            }
1098            pats
1099        }};
1100    }
1101    (
1102        optional(attempt(spfname().skip(sptoken('@')))),
1103        between(
1104            sptoken('['),
1105            sptoken(']'),
1106            sep_by(
1107                choice((
1108                    attempt(spstring("..")).map(|_| Either::Right(None)),
1109                    attempt(spfname().skip(spstring("..")))
1110                        .map(|n| Either::Right(Some(n))),
1111                    structure_pattern().map(|p| Either::Left(p)),
1112                )),
1113                csep(),
1114            ),
1115        ),
1116    )
1117        .then(
1118            |(all, mut pats): (
1119                Option<ArcStr>,
1120                SmallVec<[Either<StructurePattern, Option<ArcStr>>; 8]>,
1121            )| {
1122                if pats.len() == 0 {
1123                    value(StructurePattern::Slice { all, binds: Arc::from_iter([]) })
1124                        .right()
1125                } else if pats.len() == 1 {
1126                    match pats.pop().unwrap() {
1127                        Either::Left(s) => value(StructurePattern::Slice {
1128                            all,
1129                            binds: Arc::from_iter([s]),
1130                        })
1131                        .right(),
1132                        Either::Right(_) => {
1133                            unexpected_any("invalid singular range match").left()
1134                        }
1135                    }
1136                } else {
1137                    match (&pats[0], &pats[pats.len() - 1]) {
1138                        (Either::Right(_), Either::Right(_)) => {
1139                            unexpected_any("invalid pattern").left()
1140                        }
1141                        (Either::Right(_), Either::Left(_)) => {
1142                            let head = pats.remove(0).right().unwrap();
1143                            let suffix = all_left!(pats);
1144                            value(StructurePattern::SliceSuffix { all, head, suffix })
1145                                .right()
1146                        }
1147                        (Either::Left(_), Either::Right(_)) => {
1148                            let tail = pats.pop().unwrap().right().unwrap();
1149                            let prefix = all_left!(pats);
1150                            value(StructurePattern::SlicePrefix { all, tail, prefix })
1151                                .right()
1152                        }
1153                        (Either::Left(_), Either::Left(_)) => {
1154                            value(StructurePattern::Slice { all, binds: all_left!(pats) })
1155                                .right()
1156                        }
1157                    }
1158                }
1159            },
1160        )
1161}
1162
1163fn raw_string<I>() -> impl Parser<I, Output = Expr>
1164where
1165    I: RangeStream<Token = char, Position = SourcePosition>,
1166    I::Error: ParseError<I::Token, I::Range, I::Position>,
1167    I::Range: Range,
1168{
1169    const ESC: [char; 2] = ['\'', '\\'];
1170    (position(), between(string("r\'"), token('\''), escaped_string(&ESC))).map(
1171        |(pos, s): (_, String)| ExprKind::Constant(Value::String(s.into())).to_expr(pos),
1172    )
1173}
1174
1175fn tuple_pattern<I>() -> impl Parser<I, Output = StructurePattern>
1176where
1177    I: RangeStream<Token = char>,
1178    I::Error: ParseError<I::Token, I::Range, I::Position>,
1179    I::Range: Range,
1180{
1181    (
1182        optional(attempt(spfname().skip(sptoken('@')))),
1183        between(sptoken('('), sptoken(')'), sep_by1(structure_pattern(), csep())),
1184    )
1185        .then(|(all, binds): (Option<ArcStr>, SmallVec<[StructurePattern; 8]>)| {
1186            if binds.len() < 2 {
1187                unexpected_any("tuples must have at least 2 elements").left()
1188            } else {
1189                value(StructurePattern::Tuple { all, binds: Arc::from_iter(binds) })
1190                    .right()
1191            }
1192        })
1193}
1194
1195fn variant_pattern<I>() -> impl Parser<I, Output = StructurePattern>
1196where
1197    I: RangeStream<Token = char>,
1198    I::Error: ParseError<I::Token, I::Range, I::Position>,
1199    I::Range: Range,
1200{
1201    (
1202        optional(attempt(spfname().skip(sptoken('@')))),
1203        sptoken('`').with(typname()),
1204        optional(attempt(between(
1205            sptoken('('),
1206            sptoken(')'),
1207            sep_by1(structure_pattern(), csep()),
1208        ))),
1209    )
1210        .map(
1211            |(all, tag, binds): (
1212                Option<ArcStr>,
1213                ArcStr,
1214                Option<SmallVec<[StructurePattern; 8]>>,
1215            )| {
1216                let binds = match binds {
1217                    None => smallvec![],
1218                    Some(a) => a,
1219                };
1220                StructurePattern::Variant { all, tag, binds: Arc::from_iter(binds) }
1221            },
1222        )
1223}
1224
1225fn struct_pattern<I>() -> impl Parser<I, Output = StructurePattern>
1226where
1227    I: RangeStream<Token = char>,
1228    I::Error: ParseError<I::Token, I::Range, I::Position>,
1229    I::Range: Range,
1230{
1231    (
1232        optional(attempt(spfname().skip(sptoken('@')))),
1233        between(
1234            sptoken('{'),
1235            sptoken('}'),
1236            sep_by1(
1237                choice((
1238                    attempt((spfname().skip(sptoken(':')), structure_pattern()))
1239                        .map(|(s, p)| (s, p, true)),
1240                    attempt(spfname()).map(|s| {
1241                        let p = StructurePattern::Bind(s.clone());
1242                        (s, p, true)
1243                    }),
1244                    spstring("..")
1245                        .map(|_| (literal!(""), StructurePattern::Ignore, false)),
1246                )),
1247                csep(),
1248            ),
1249        ),
1250    )
1251        .then(
1252            |(all, mut binds): (
1253                Option<ArcStr>,
1254                SmallVec<[(ArcStr, StructurePattern, bool); 8]>,
1255            )| {
1256                let mut exhaustive = true;
1257                binds.retain(|(_, _, ex)| {
1258                    exhaustive &= *ex;
1259                    *ex
1260                });
1261                binds.sort_by_key(|(s, _, _)| s.clone());
1262                let s = binds.iter().map(|(s, _, _)| s).collect::<FxHashSet<_>>();
1263                if s.len() < binds.len() {
1264                    unexpected_any("struct fields must be unique").left()
1265                } else {
1266                    let binds = Arc::from_iter(binds.into_iter().map(|(s, p, _)| (s, p)));
1267                    value(StructurePattern::Struct { all, exhaustive, binds }).right()
1268                }
1269            },
1270        )
1271}
1272
1273fn structure_pattern_<I>() -> impl Parser<I, Output = StructurePattern>
1274where
1275    I: RangeStream<Token = char>,
1276    I::Error: ParseError<I::Token, I::Range, I::Position>,
1277    I::Range: Range,
1278{
1279    choice((
1280        attempt(slice_pattern()),
1281        attempt(tuple_pattern()),
1282        attempt(struct_pattern()),
1283        attempt(variant_pattern()),
1284        attempt(netidx_value(&VAL_ESC).skip(not_followed_by(token('_'))))
1285            .map(|v| StructurePattern::Literal(v)),
1286        attempt(sptoken('_')).map(|_| StructurePattern::Ignore),
1287        spfname().map(|name| StructurePattern::Bind(name)),
1288    ))
1289}
1290
1291parser! {
1292    fn structure_pattern[I]()(I) -> StructurePattern
1293    where [I: RangeStream<Token = char>, I::Range: Range]
1294    {
1295        structure_pattern_()
1296    }
1297}
1298
1299fn pattern<I>() -> impl Parser<I, Output = Pattern>
1300where
1301    I: RangeStream<Token = char, Position = SourcePosition>,
1302    I::Error: ParseError<I::Token, I::Range, I::Position>,
1303    I::Range: Range,
1304{
1305    (
1306        optional(attempt(typexp().skip(space().with(spstring("as "))))),
1307        structure_pattern(),
1308        optional(attempt(space().with(spstring("if").with(space()).with(expr())))),
1309    )
1310        .map(
1311            |(type_predicate, structure_predicate, guard): (
1312                Option<Type>,
1313                StructurePattern,
1314                Option<Expr>,
1315            )| { Pattern { type_predicate, structure_predicate, guard } },
1316        )
1317}
1318
1319fn select<I>() -> impl Parser<I, Output = Expr>
1320where
1321    I: RangeStream<Token = char, Position = SourcePosition>,
1322    I::Error: ParseError<I::Token, I::Range, I::Position>,
1323    I::Range: Range,
1324{
1325    (
1326        position(),
1327        string("select").with(space()).with((
1328            expr(),
1329            between(
1330                sptoken('{'),
1331                sptoken('}'),
1332                sep_by1((pattern(), spstring("=>").with(expr())), csep()),
1333            ),
1334        )),
1335    )
1336        .map(|(pos, (arg, arms)): (_, (Expr, Vec<(Pattern, Expr)>))| {
1337            ExprKind::Select { arg: Arc::new(arg), arms: Arc::from(arms) }.to_expr(pos)
1338        })
1339}
1340
1341fn cast<I>() -> impl Parser<I, Output = Expr>
1342where
1343    I: RangeStream<Token = char, Position = SourcePosition>,
1344    I::Error: ParseError<I::Token, I::Range, I::Position>,
1345    I::Range: Range,
1346{
1347    (
1348        position(),
1349        string("cast").with(between(token('<'), sptoken('>'), typexp())),
1350        between(sptoken('('), sptoken(')'), expr()),
1351    )
1352        .map(|(pos, typ, e)| ExprKind::TypeCast { expr: Arc::new(e), typ }.to_expr(pos))
1353}
1354
1355fn typedef<I>() -> impl Parser<I, Output = Expr>
1356where
1357    I: RangeStream<Token = char, Position = SourcePosition>,
1358    I::Error: ParseError<I::Token, I::Range, I::Position>,
1359    I::Range: Range,
1360{
1361    (
1362        position(),
1363        string("type").with(sptypname()),
1364        optional(attempt(between(
1365            sptoken('<'),
1366            sptoken('>'),
1367            sep_by1((tvar(), optional(attempt(sptoken(':').with(typexp())))), csep()),
1368        ))),
1369        sptoken('=').with(typexp()),
1370    )
1371        .map(|(pos, name, params, typ)| {
1372            let params = params
1373                .map(|ps: SmallVec<[(TVar, Option<Type>); 8]>| {
1374                    Arc::from_iter(ps.into_iter())
1375                })
1376                .unwrap_or_else(|| Arc::<[(TVar, Option<Type>)]>::from(Vec::new()));
1377            ExprKind::TypeDef { name, params, typ }.to_expr(pos)
1378        })
1379}
1380
1381fn tuple<I>() -> impl Parser<I, Output = Expr>
1382where
1383    I: RangeStream<Token = char, Position = SourcePosition>,
1384    I::Error: ParseError<I::Token, I::Range, I::Position>,
1385    I::Range: Range,
1386{
1387    (position(), between(token('('), sptoken(')'), sep_by1(expr(), csep()))).then(
1388        |(pos, exprs): (_, SmallVec<[Expr; 8]>)| {
1389            if exprs.len() < 2 {
1390                unexpected_any("tuples must have at least 2 elements").left()
1391            } else {
1392                value(ExprKind::Tuple { args: Arc::from_iter(exprs) }.to_expr(pos))
1393                    .right()
1394            }
1395        },
1396    )
1397}
1398
1399fn structure<I>() -> impl Parser<I, Output = Expr>
1400where
1401    I: RangeStream<Token = char, Position = SourcePosition>,
1402    I::Error: ParseError<I::Token, I::Range, I::Position>,
1403    I::Range: Range,
1404{
1405    (
1406        position(),
1407        between(
1408            token('{'),
1409            sptoken('}'),
1410            sep_by1((spfname().skip(sptoken(':')), expr()), csep()),
1411        ),
1412    )
1413        .then(|(pos, mut exprs): (_, SmallVec<[(ArcStr, Expr); 8]>)| {
1414            let s = exprs.iter().map(|(n, _)| n).collect::<FxHashSet<_>>();
1415            if s.len() < exprs.len() {
1416                return unexpected_any("struct fields must be unique").left();
1417            }
1418            exprs.sort_by_key(|(n, _)| n.clone());
1419            value(ExprKind::Struct { args: Arc::from_iter(exprs) }.to_expr(pos)).right()
1420        })
1421}
1422
1423fn variant<I>() -> impl Parser<I, Output = Expr>
1424where
1425    I: RangeStream<Token = char, Position = SourcePosition>,
1426    I::Error: ParseError<I::Token, I::Range, I::Position>,
1427    I::Range: Range,
1428{
1429    (
1430        position(),
1431        token('`').with(typname()),
1432        optional(attempt(between(token('('), sptoken(')'), sep_by1(expr(), csep())))),
1433    )
1434        .map(|(pos, tag, args): (_, ArcStr, Option<SmallVec<[Expr; 5]>>)| {
1435            let args = match args {
1436                None => smallvec![],
1437                Some(a) => a,
1438            };
1439            ExprKind::Variant { tag, args: Arc::from_iter(args.into_iter()) }.to_expr(pos)
1440        })
1441}
1442
1443fn structwith<I>() -> impl Parser<I, Output = Expr>
1444where
1445    I: RangeStream<Token = char, Position = SourcePosition>,
1446    I::Error: ParseError<I::Token, I::Range, I::Position>,
1447    I::Range: Range,
1448{
1449    (
1450        position(),
1451        between(
1452            token('{'),
1453            sptoken('}'),
1454            (
1455                ref_pexp().skip(space()).skip(spstring("with")).skip(space()),
1456                sep_by1((spfname().skip(sptoken(':')), expr()), csep()),
1457            ),
1458        ),
1459    )
1460        .then(
1461            |(pos, (source, mut exprs)): (_, (Expr, SmallVec<[(ArcStr, Expr); 8]>))| {
1462                let s = exprs.iter().map(|(n, _)| n).collect::<FxHashSet<_>>();
1463                if s.len() < exprs.len() {
1464                    return unexpected_any("struct fields must be unique").left();
1465                }
1466                exprs.sort_by_key(|(n, _)| n.clone());
1467                let e = ExprKind::StructWith {
1468                    source: Arc::new(source),
1469                    replace: Arc::from_iter(exprs),
1470                }
1471                .to_expr(pos);
1472                value(e).right()
1473            },
1474        )
1475}
1476
1477fn byref<I>() -> impl Parser<I, Output = Expr>
1478where
1479    I: RangeStream<Token = char, Position = SourcePosition>,
1480    I::Error: ParseError<I::Token, I::Range, I::Position>,
1481    I::Range: Range,
1482{
1483    (position(), token('&').with(expr()))
1484        .map(|(pos, expr)| ExprKind::ByRef(Arc::new(expr)).to_expr(pos))
1485}
1486
1487fn deref<I>() -> impl Parser<I, Output = Expr>
1488where
1489    I: RangeStream<Token = char, Position = SourcePosition>,
1490    I::Error: ParseError<I::Token, I::Range, I::Position>,
1491    I::Range: Range,
1492{
1493    (position(), token('*').with(expr()))
1494        .map(|(pos, expr)| ExprKind::Deref(Arc::new(expr)).to_expr(pos))
1495}
1496
1497fn expr_<I>() -> impl Parser<I, Output = Expr>
1498where
1499    I: RangeStream<Token = char, Position = SourcePosition>,
1500    I::Error: ParseError<I::Token, I::Range, I::Position>,
1501    I::Range: Range,
1502{
1503    choice((
1504        // nested due to limits on choice size
1505        attempt(choice((
1506            attempt(spaces().with(module())),
1507            attempt(spaces().with(use_module())),
1508            attempt(spaces().with(typedef())),
1509            attempt(spaces().with(raw_string())),
1510            attempt(spaces().with(array()))
1511        ))),
1512        attempt(spaces().with(byref())),
1513        attempt(spaces().with(deref())),
1514        attempt(spaces().with(arith())),
1515        attempt(spaces().with(tuple())),
1516        attempt(spaces().with(structure())),
1517        attempt(spaces().with(variant())),
1518        attempt(spaces().with(structwith())),
1519        attempt(spaces().with(qop(arrayref()))),
1520        attempt(spaces().with(qop(tupleref()))),
1521        attempt(spaces().with(qop(structref()))),
1522        attempt(spaces().with(qop(apply()))),
1523        attempt(spaces().with(qop(do_block()))),
1524        attempt(spaces().with(lambda())),
1525        attempt(spaces().with(letbind())),
1526        attempt(spaces().with(connect())),
1527        attempt(spaces().with(qop(select()))),
1528        attempt(spaces().with(qop(cast()))),
1529        attempt(spaces().with(qop(any()))),
1530        attempt(spaces().with(interpolated())),
1531        attempt(spaces().with(literal())),
1532        attempt(spaces().with(qop(reference())))
1533    ))
1534}
1535
1536parser! {
1537    fn expr[I]()(I) -> Expr
1538    where [I: RangeStream<Token = char, Position = SourcePosition>, I::Range: Range]
1539    {
1540        expr_()
1541    }
1542}
1543
1544/// Parse one or more toplevel module expressions
1545///
1546/// followed by (optional) whitespace and then eof. At least one
1547/// expression is required otherwise this function will fail.
1548pub fn parse(name: Option<ArcStr>, s: ArcStr) -> anyhow::Result<Origin> {
1549    let r: Vec<Expr> = sep_by1(expr(), attempt(sptoken(';')))
1550        .skip(spaces())
1551        .skip(eof())
1552        .easy_parse(position::Stream::new(&*s))
1553        .map(|(r, _)| r)
1554        .map_err(|e| anyhow::anyhow!(format!("{}", e)))?;
1555    Ok(Origin { name, source: s, exprs: Arc::from(r) })
1556}
1557
1558/// Parse one and only one expression. Do not wrap it in an origin.
1559pub fn parse_one(s: &str) -> anyhow::Result<Expr> {
1560    expr()
1561        .skip(spaces())
1562        .skip(eof())
1563        .easy_parse(position::Stream::new(&*s))
1564        .map(|(r, _)| r)
1565        .map_err(|e| anyhow::anyhow!(format!("{e}")))
1566}
1567
1568/// Parse a fntype
1569pub fn parse_fn_type(s: &str) -> anyhow::Result<FnType> {
1570    fntype()
1571        .skip(spaces())
1572        .skip(eof())
1573        .easy_parse(position::Stream::new(s))
1574        .map(|(r, _)| r)
1575        .map_err(|e| anyhow::anyhow!(format!("{e}")))
1576}
1577
1578pub(super) fn parse_modpath(s: &str) -> anyhow::Result<ModPath> {
1579    modpath()
1580        .skip(spaces())
1581        .skip(eof())
1582        .easy_parse(position::Stream::new(s))
1583        .map(|(r, _)| r)
1584        .map_err(|e| anyhow::anyhow!(format!("{e}")))
1585}