zngur_parser/
lib.rs

1use std::{fmt::Display, process::exit, sync::Mutex};
2
3use ariadne::{Color, Label, Report, ReportKind, sources};
4use chumsky::prelude::*;
5use itertools::{Either, Itertools};
6
7use zngur_def::{
8    LayoutPolicy, Mutability, PrimitiveRustType, RustPathAndGenerics, RustTrait, RustType,
9    ZngurConstructor, ZngurExternCppFn, ZngurExternCppImpl, ZngurFile, ZngurFn, ZngurMethod,
10    ZngurMethodDetails, ZngurMethodReceiver, ZngurTrait, ZngurType, ZngurWellknownTrait,
11};
12
13pub type Span = SimpleSpan<usize>;
14
15#[cfg(test)]
16mod tests;
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19struct Spanned<T> {
20    inner: T,
21    span: Span,
22}
23
24type ParserInput<'a> = chumsky::input::MappedInput<
25    Token<'a>,
26    Span,
27    &'a [(Token<'a>, Span)],
28    Box<
29        dyn for<'x> Fn(
30            &'x (Token<'_>, chumsky::span::SimpleSpan),
31        ) -> (&'x Token<'x>, &'x SimpleSpan),
32    >,
33>;
34
35#[derive(Debug)]
36pub struct ParsedZngFile<'a>(Vec<ParsedItem<'a>>);
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
39enum ParsedPathStart {
40    Absolute,
41    Relative,
42    Crate,
43}
44
45#[derive(Debug, Clone, PartialEq, Eq)]
46struct ParsedPath<'a> {
47    start: ParsedPathStart,
48    segments: Vec<&'a str>,
49    span: Span,
50}
51
52impl ParsedPath<'_> {
53    fn to_zngur(self, base: &[String]) -> Vec<String> {
54        match self.start {
55            ParsedPathStart::Absolute => self.segments.into_iter().map(|x| x.to_owned()).collect(),
56            ParsedPathStart::Relative => base
57                .iter()
58                .map(|x| x.as_str())
59                .chain(self.segments)
60                .map(|x| x.to_owned())
61                .collect(),
62            ParsedPathStart::Crate => ["crate"]
63                .into_iter()
64                .chain(self.segments)
65                .map(|x| x.to_owned())
66                .collect(),
67        }
68    }
69}
70
71#[derive(Debug, Clone, PartialEq, Eq)]
72enum ParsedItem<'a> {
73    ConvertPanicToException,
74    CppAdditionalInclude(&'a str),
75    Mod {
76        path: ParsedPath<'a>,
77        items: Vec<ParsedItem<'a>>,
78    },
79    Type {
80        ty: Spanned<ParsedRustType<'a>>,
81        items: Vec<Spanned<ParsedTypeItem<'a>>>,
82    },
83    Trait {
84        tr: ParsedRustTrait<'a>,
85        methods: Vec<ParsedMethod<'a>>,
86    },
87    Fn(ParsedMethod<'a>),
88    ExternCpp(Vec<ParsedExternCppItem<'a>>),
89}
90
91#[derive(Debug, Clone, PartialEq, Eq)]
92enum ParsedExternCppItem<'a> {
93    Function(ParsedMethod<'a>),
94    Impl {
95        tr: Option<ParsedRustTrait<'a>>,
96        ty: ParsedRustType<'a>,
97        methods: Vec<ParsedMethod<'a>>,
98    },
99}
100
101#[derive(Debug, Clone, PartialEq, Eq)]
102enum ParsedConstructorArgs<'a> {
103    Unit,
104    Tuple(Vec<ParsedRustType<'a>>),
105    Named(Vec<(&'a str, ParsedRustType<'a>)>),
106}
107
108#[derive(Debug, Clone, PartialEq, Eq)]
109enum ParsedLayoutPolicy<'a> {
110    StackAllocated(Vec<(Spanned<&'a str>, usize)>),
111    HeapAllocated,
112    OnlyByRef,
113}
114
115#[derive(Debug, Clone, PartialEq, Eq)]
116enum ParsedTypeItem<'a> {
117    Layout(Span, ParsedLayoutPolicy<'a>),
118    Traits(Vec<Spanned<ZngurWellknownTrait>>),
119    Constructor {
120        name: Option<&'a str>,
121        args: ParsedConstructorArgs<'a>,
122    },
123    Method {
124        data: ParsedMethod<'a>,
125        use_path: Option<ParsedPath<'a>>,
126        deref: Option<ParsedRustType<'a>>,
127    },
128    CppValue {
129        field: &'a str,
130        cpp_type: &'a str,
131    },
132    CppRef {
133        cpp_type: &'a str,
134    },
135}
136
137#[derive(Debug, Clone, PartialEq, Eq)]
138struct ParsedMethod<'a> {
139    name: &'a str,
140    receiver: ZngurMethodReceiver,
141    generics: Vec<ParsedRustType<'a>>,
142    inputs: Vec<ParsedRustType<'a>>,
143    output: ParsedRustType<'a>,
144}
145
146impl ParsedMethod<'_> {
147    fn to_zngur(self, base: &[String]) -> ZngurMethod {
148        ZngurMethod {
149            name: self.name.to_owned(),
150            generics: self
151                .generics
152                .into_iter()
153                .map(|x| x.to_zngur(base))
154                .collect(),
155            receiver: self.receiver,
156            inputs: self.inputs.into_iter().map(|x| x.to_zngur(base)).collect(),
157            output: self.output.to_zngur(base),
158        }
159    }
160}
161
162impl ParsedItem<'_> {
163    fn add_to_zngur_file(self, r: &mut ZngurFile, base: &[String]) {
164        match self {
165            ParsedItem::Mod { path, items } => {
166                let base = path.to_zngur(base);
167                for item in items {
168                    item.add_to_zngur_file(r, &base);
169                }
170            }
171            ParsedItem::Type { ty, items } => {
172                if ty.inner == ParsedRustType::Tuple(vec![]) {
173                    // We add unit type implicitly.
174                    create_and_emit_error(
175                        "Unit type is declared implicitly. Remove this entirely.",
176                        ty.span,
177                    );
178                }
179
180                let mut methods = vec![];
181                let mut constructors = vec![];
182                let mut wellknown_traits = vec![];
183                let mut layout = None;
184                let mut layout_span = None;
185                let mut cpp_value = None;
186                let mut cpp_ref = None;
187                for item in items {
188                    let item_span = item.span;
189                    let item = item.inner;
190                    match item {
191                        ParsedTypeItem::Layout(span, p) => {
192                            layout = Some(match p {
193                                ParsedLayoutPolicy::StackAllocated(p) => {
194                                    let mut size = None;
195                                    let mut align = None;
196                                    for (key, value) in p {
197                                        match key.inner {
198                                            "size" => size = Some(value),
199                                            "align" => align = Some(value),
200                                            _ => {
201                                                create_and_emit_error("Unknown property", key.span)
202                                            }
203                                        }
204                                    }
205                                    let Some(size) = size else {
206                                        create_and_emit_error(
207                                            "Size is not declared for this type",
208                                            ty.span,
209                                        );
210                                    };
211                                    let Some(align) = align else {
212                                        create_and_emit_error(
213                                            "Align is not declared for this type",
214                                            ty.span,
215                                        );
216                                    };
217                                    LayoutPolicy::StackAllocated { size, align }
218                                }
219                                ParsedLayoutPolicy::HeapAllocated => LayoutPolicy::HeapAllocated,
220                                ParsedLayoutPolicy::OnlyByRef => LayoutPolicy::OnlyByRef,
221                            });
222                            match layout_span {
223                                Some(_) => {
224                                    create_and_emit_error("Duplicate layout policy found", span);
225                                }
226                                None => layout_span = Some(span),
227                            }
228                        }
229                        ParsedTypeItem::Traits(tr) => {
230                            wellknown_traits.extend(tr);
231                        }
232                        ParsedTypeItem::Constructor { name, args } => {
233                            constructors.push(ZngurConstructor {
234                                name: name.map(|x| x.to_owned()),
235                                inputs: match args {
236                                    ParsedConstructorArgs::Unit => vec![],
237                                    ParsedConstructorArgs::Tuple(t) => t
238                                        .into_iter()
239                                        .enumerate()
240                                        .map(|(i, t)| (i.to_string(), t.to_zngur(base)))
241                                        .collect(),
242                                    ParsedConstructorArgs::Named(t) => t
243                                        .into_iter()
244                                        .map(|(i, t)| (i.to_owned(), t.to_zngur(base)))
245                                        .collect(),
246                                },
247                            })
248                        }
249                        ParsedTypeItem::Method {
250                            data,
251                            use_path,
252                            deref,
253                        } => {
254                            methods.push(ZngurMethodDetails {
255                                data: data.to_zngur(base),
256                                use_path: use_path.map(|x| x.to_zngur(base)),
257                                deref: deref.map(|x| x.to_zngur(base)),
258                            });
259                        }
260                        ParsedTypeItem::CppValue { field, cpp_type } => {
261                            cpp_value = Some((field.to_owned(), cpp_type.to_owned()));
262                        }
263                        ParsedTypeItem::CppRef { cpp_type } => {
264                            match layout_span {
265                                Some(span) => {
266                                    create_and_emit_error("Duplicate layout policy found", span);
267                                }
268                                None => {
269                                    layout =
270                                        Some(LayoutPolicy::StackAllocated { size: 0, align: 1 });
271                                    layout_span = Some(item_span);
272                                }
273                            }
274                            cpp_ref = Some(cpp_type.to_owned());
275                        }
276                    }
277                }
278                let is_unsized = wellknown_traits
279                    .iter()
280                    .find(|x| x.inner == ZngurWellknownTrait::Unsized)
281                    .cloned();
282                let is_copy = wellknown_traits
283                    .iter()
284                    .find(|x| x.inner == ZngurWellknownTrait::Copy)
285                    .cloned();
286                let mut wt = wellknown_traits
287                    .into_iter()
288                    .map(|x| x.inner)
289                    .collect::<Vec<_>>();
290                if is_copy.is_none() && is_unsized.is_none() {
291                    wt.push(ZngurWellknownTrait::Drop);
292                }
293                if let Some(is_unsized) = is_unsized {
294                    if let Some(span) = layout_span {
295                        let file_name = LATEST_FILENAME.lock().unwrap().to_owned();
296                        emit_ariadne_error(
297                            Report::build(
298                                ReportKind::Error,
299                                file_name.clone(),
300                                span.start,
301                            )
302                            .with_message("Duplicate layout policy found for unsized type.")
303                            .with_label(
304                                Label::new((file_name.clone(), span.start..span.end))
305                                    .with_message(
306                                        "Unsized types have implicit layout policy, remove this.",
307                                    )
308                                    .with_color(Color::Red),
309                            )
310                            .with_label(
311                                Label::new((file_name.clone(), is_unsized.span.start..is_unsized.span.end))
312                                    .with_message("Type declared as unsized here.")
313                                    .with_color(Color::Blue),
314                            )
315                            .finish(),
316                        )
317                    }
318                    layout = Some(LayoutPolicy::OnlyByRef);
319                }
320                let Some(layout) = layout else {
321                    create_and_emit_error(
322                        "No layout policy found for this type. \
323Use one of `#layout(size = X, align = Y)`, `#heap_allocated` or `#only_by_ref`.",
324                        ty.span,
325                    );
326                };
327                r.types.push(ZngurType {
328                    ty: ty.inner.to_zngur(base),
329                    layout,
330                    methods,
331                    wellknown_traits: wt,
332                    constructors,
333                    cpp_value,
334                    cpp_ref,
335                });
336            }
337            ParsedItem::Trait { tr, methods } => {
338                let tr = tr.to_zngur(base);
339                r.traits.insert(
340                    tr.clone(),
341                    ZngurTrait {
342                        tr,
343                        methods: methods.into_iter().map(|m| m.to_zngur(base)).collect(),
344                    },
345                );
346            }
347            ParsedItem::Fn(f) => {
348                let method = f.to_zngur(base);
349                r.funcs.push(ZngurFn {
350                    path: RustPathAndGenerics {
351                        path: base.iter().chain(Some(&method.name)).cloned().collect(),
352                        generics: method.generics,
353                        named_generics: vec![],
354                    },
355                    inputs: method.inputs,
356                    output: method.output,
357                })
358            }
359            ParsedItem::ExternCpp(items) => {
360                for item in items {
361                    match item {
362                        ParsedExternCppItem::Function(method) => {
363                            let method = method.to_zngur(base);
364                            r.extern_cpp_funcs.push(ZngurExternCppFn {
365                                name: method.name.to_string(),
366                                inputs: method.inputs,
367                                output: method.output,
368                            });
369                        }
370                        ParsedExternCppItem::Impl { tr, ty, methods } => {
371                            r.extern_cpp_impls.push(ZngurExternCppImpl {
372                                tr: tr.map(|x| x.to_zngur(base)),
373                                ty: ty.to_zngur(base),
374                                methods: methods.into_iter().map(|x| x.to_zngur(base)).collect(),
375                            });
376                        }
377                    }
378                }
379            }
380            ParsedItem::CppAdditionalInclude(s) => {
381                r.additional_includes += s;
382            }
383            ParsedItem::ConvertPanicToException => {
384                r.convert_panic_to_exception = true;
385            }
386        }
387    }
388}
389
390#[derive(Debug, Clone, PartialEq, Eq)]
391enum ParsedRustType<'a> {
392    Primitive(PrimitiveRustType),
393    Ref(Mutability, Box<ParsedRustType<'a>>),
394    Raw(Mutability, Box<ParsedRustType<'a>>),
395    Boxed(Box<ParsedRustType<'a>>),
396    Slice(Box<ParsedRustType<'a>>),
397    Dyn(ParsedRustTrait<'a>, Vec<&'a str>),
398    Tuple(Vec<ParsedRustType<'a>>),
399    Adt(ParsedRustPathAndGenerics<'a>),
400}
401
402impl ParsedRustType<'_> {
403    fn to_zngur(self, base: &[String]) -> RustType {
404        match self {
405            ParsedRustType::Primitive(s) => RustType::Primitive(s),
406            ParsedRustType::Ref(m, s) => RustType::Ref(m, Box::new(s.to_zngur(base))),
407            ParsedRustType::Raw(m, s) => RustType::Raw(m, Box::new(s.to_zngur(base))),
408            ParsedRustType::Boxed(s) => RustType::Boxed(Box::new(s.to_zngur(base))),
409            ParsedRustType::Slice(s) => RustType::Slice(Box::new(s.to_zngur(base))),
410            ParsedRustType::Dyn(tr, bounds) => RustType::Dyn(
411                tr.to_zngur(base),
412                bounds.into_iter().map(|x| x.to_owned()).collect(),
413            ),
414            ParsedRustType::Tuple(v) => {
415                RustType::Tuple(v.into_iter().map(|s| s.to_zngur(base)).collect())
416            }
417            ParsedRustType::Adt(s) => RustType::Adt(s.to_zngur(base)),
418        }
419    }
420}
421
422#[derive(Debug, Clone, PartialEq, Eq)]
423enum ParsedRustTrait<'a> {
424    Normal(ParsedRustPathAndGenerics<'a>),
425    Fn {
426        name: &'a str,
427        inputs: Vec<ParsedRustType<'a>>,
428        output: Box<ParsedRustType<'a>>,
429    },
430}
431
432impl ParsedRustTrait<'_> {
433    fn to_zngur(self, base: &[String]) -> RustTrait {
434        match self {
435            ParsedRustTrait::Normal(s) => RustTrait::Normal(s.to_zngur(base)),
436            ParsedRustTrait::Fn {
437                name,
438                inputs,
439                output,
440            } => RustTrait::Fn {
441                name: name.to_owned(),
442                inputs: inputs.into_iter().map(|s| s.to_zngur(base)).collect(),
443                output: Box::new(output.to_zngur(base)),
444            },
445        }
446    }
447}
448
449#[derive(Debug, Clone, PartialEq, Eq)]
450struct ParsedRustPathAndGenerics<'a> {
451    path: ParsedPath<'a>,
452    generics: Vec<ParsedRustType<'a>>,
453    named_generics: Vec<(&'a str, ParsedRustType<'a>)>,
454}
455
456impl ParsedRustPathAndGenerics<'_> {
457    fn to_zngur(self, base: &[String]) -> RustPathAndGenerics {
458        RustPathAndGenerics {
459            path: self.path.to_zngur(base),
460            generics: self
461                .generics
462                .into_iter()
463                .map(|x| x.to_zngur(base))
464                .collect(),
465            named_generics: self
466                .named_generics
467                .into_iter()
468                .map(|(name, x)| (name.to_owned(), x.to_zngur(base)))
469                .collect(),
470        }
471    }
472}
473
474static LATEST_FILENAME: Mutex<String> = Mutex::new(String::new());
475static LATEST_TEXT: Mutex<String> = Mutex::new(String::new());
476
477impl ParsedZngFile<'_> {
478    pub fn parse(filename: &str, text: &str) -> ZngurFile {
479        *LATEST_FILENAME.lock().unwrap() = filename.to_string();
480        *LATEST_TEXT.lock().unwrap() = text.to_string();
481        let (tokens, errs) = lexer().parse(text).into_output_errors();
482        let Some(tokens) = tokens else {
483            let errs = errs.into_iter().map(|e| e.map_token(|c| c.to_string()));
484            emit_error(errs);
485        };
486        let tokens: ParserInput<'_> = tokens
487            .as_slice()
488            .map((text.len()..text.len()).into(), Box::new(|(t, s)| (t, s)));
489        let (ast, errs) = file_parser()
490            .map_with(|ast, extra| (ast, extra.span()))
491            .parse(tokens)
492            .into_output_errors();
493        let Some(ast) = ast else {
494            let errs = errs.into_iter().map(|e| e.map_token(|c| c.to_string()));
495            emit_error(errs);
496        };
497        ast.0.into_zngur_file()
498    }
499
500    pub fn into_zngur_file(self) -> ZngurFile {
501        let mut r = ZngurFile::default();
502        for item in self.0 {
503            item.add_to_zngur_file(&mut r, &[]);
504        }
505        r
506    }
507}
508
509fn create_and_emit_error<'a>(error: &str, span: Span) -> ! {
510    emit_error([Rich::custom(span, error)].into_iter())
511}
512
513#[cfg(test)]
514fn emit_ariadne_error(err: Report<'_, (String, std::ops::Range<usize>)>) -> ! {
515    let mut r = Vec::<u8>::new();
516    // Block needed to drop lock guards before panic
517    {
518        let filename = &**LATEST_FILENAME.lock().unwrap();
519        let text = &**LATEST_TEXT.lock().unwrap();
520
521        err.write(sources([(filename.to_string(), text)]), &mut r)
522            .unwrap();
523    }
524    std::panic::resume_unwind(Box::new(tests::ErrorText(
525        String::from_utf8(strip_ansi_escapes::strip(r)).unwrap(),
526    )));
527}
528
529#[cfg(not(test))]
530fn emit_ariadne_error(err: Report<'_, (String, std::ops::Range<usize>)>) -> ! {
531    let filename = &**LATEST_FILENAME.lock().unwrap();
532    let text = &**LATEST_TEXT.lock().unwrap();
533
534    err.eprint(sources([(filename.to_string(), text)])).unwrap();
535    exit(101);
536}
537
538fn emit_error<'a>(errs: impl Iterator<Item = Rich<'a, String>>) -> ! {
539    let filename = LATEST_FILENAME.lock().unwrap().to_owned();
540    for e in errs {
541        emit_ariadne_error(
542            Report::build(ReportKind::Error, &filename, e.span().start)
543                .with_message(e.to_string())
544                .with_label(
545                    Label::new((filename.to_string(), e.span().into_range()))
546                        .with_message(e.reason().to_string())
547                        .with_color(Color::Red),
548                )
549                .with_labels(e.contexts().map(|(label, span)| {
550                    Label::new((filename.to_string(), span.into_range()))
551                        .with_message(format!("while parsing this {}", label))
552                        .with_color(Color::Yellow)
553                }))
554                .finish(),
555        )
556    }
557    exit(101);
558}
559
560#[derive(Debug, Clone, PartialEq, Eq, Hash)]
561enum Token<'a> {
562    Arrow,
563    AngleOpen,
564    AngleClose,
565    BracketOpen,
566    BracketClose,
567    Colon,
568    ColonColon,
569    ParenOpen,
570    ParenClose,
571    BraceOpen,
572    BraceClose,
573    And,
574    Star,
575    Sharp,
576    Plus,
577    Eq,
578    Question,
579    Comma,
580    Semicolon,
581    KwDyn,
582    KwUse,
583    KwFor,
584    KwMod,
585    KwCrate,
586    KwType,
587    KwTrait,
588    KwFn,
589    KwMut,
590    KwConst,
591    KwExtern,
592    KwImpl,
593    Ident(&'a str),
594    Str(&'a str),
595    Number(usize),
596}
597
598impl<'a> Token<'a> {
599    fn ident_or_kw(ident: &'a str) -> Self {
600        match ident {
601            "dyn" => Token::KwDyn,
602            "mod" => Token::KwMod,
603            "type" => Token::KwType,
604            "trait" => Token::KwTrait,
605            "crate" => Token::KwCrate,
606            "fn" => Token::KwFn,
607            "mut" => Token::KwMut,
608            "const" => Token::KwConst,
609            "use" => Token::KwUse,
610            "for" => Token::KwFor,
611            "extern" => Token::KwExtern,
612            "impl" => Token::KwImpl,
613            x => Token::Ident(x),
614        }
615    }
616}
617
618impl Display for Token<'_> {
619    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
620        match self {
621            Token::Arrow => write!(f, "->"),
622            Token::AngleOpen => write!(f, "<"),
623            Token::AngleClose => write!(f, ">"),
624            Token::BracketOpen => write!(f, "["),
625            Token::BracketClose => write!(f, "]"),
626            Token::ParenOpen => write!(f, "("),
627            Token::ParenClose => write!(f, ")"),
628            Token::BraceOpen => write!(f, "{{"),
629            Token::BraceClose => write!(f, "}}"),
630            Token::Colon => write!(f, ":"),
631            Token::ColonColon => write!(f, "::"),
632            Token::And => write!(f, "&"),
633            Token::Star => write!(f, "*"),
634            Token::Sharp => write!(f, "#"),
635            Token::Plus => write!(f, "+"),
636            Token::Eq => write!(f, "="),
637            Token::Question => write!(f, "?"),
638            Token::Comma => write!(f, ","),
639            Token::Semicolon => write!(f, ";"),
640            Token::KwDyn => write!(f, "dyn"),
641            Token::KwUse => write!(f, "use"),
642            Token::KwFor => write!(f, "for"),
643            Token::KwMod => write!(f, "mod"),
644            Token::KwCrate => write!(f, "crate"),
645            Token::KwType => write!(f, "type"),
646            Token::KwTrait => write!(f, "trait"),
647            Token::KwFn => write!(f, "fn"),
648            Token::KwMut => write!(f, "mut"),
649            Token::KwConst => write!(f, "const"),
650            Token::KwExtern => write!(f, "extern"),
651            Token::KwImpl => write!(f, "impl"),
652            Token::Ident(i) => write!(f, "{i}"),
653            Token::Number(n) => write!(f, "{n}"),
654            Token::Str(s) => write!(f, r#""{s}""#),
655        }
656    }
657}
658
659fn lexer<'src>()
660-> impl Parser<'src, &'src str, Vec<(Token<'src>, Span)>, extra::Err<Rich<'src, char, Span>>> {
661    let token = choice((
662        choice([
663            just("->").to(Token::Arrow),
664            just("<").to(Token::AngleOpen),
665            just(">").to(Token::AngleClose),
666            just("[").to(Token::BracketOpen),
667            just("]").to(Token::BracketClose),
668            just("(").to(Token::ParenOpen),
669            just(")").to(Token::ParenClose),
670            just("{").to(Token::BraceOpen),
671            just("}").to(Token::BraceClose),
672            just("::").to(Token::ColonColon),
673            just(":").to(Token::Colon),
674            just("&").to(Token::And),
675            just("*").to(Token::Star),
676            just("#").to(Token::Sharp),
677            just("+").to(Token::Plus),
678            just("=").to(Token::Eq),
679            just("?").to(Token::Question),
680            just(",").to(Token::Comma),
681            just(";").to(Token::Semicolon),
682        ]),
683        text::ident().map(Token::ident_or_kw),
684        text::int(10).map(|x: &str| Token::Number(x.parse().unwrap())),
685        just('"')
686            .ignore_then(none_of('"').repeated().to_slice().map(Token::Str))
687            .then_ignore(just('"')),
688    ));
689
690    let comment = just("//")
691        .then(any().and_is(just('\n').not()).repeated())
692        .padded();
693
694    token
695        .map_with(|tok, extra| (tok, extra.span()))
696        .padded_by(comment.repeated())
697        .padded()
698        .repeated()
699        .collect()
700}
701
702fn file_parser<'a>()
703-> impl Parser<'a, ParserInput<'a>, ParsedZngFile<'a>, extra::Err<Rich<'a, Token<'a>, Span>>> + Clone
704{
705    item().repeated().collect::<Vec<_>>().map(ParsedZngFile)
706}
707
708fn rust_type<'a>()
709-> Boxed<'a, 'a, ParserInput<'a>, ParsedRustType<'a>, extra::Err<Rich<'a, Token<'a>, Span>>> {
710    let as_scalar = |s: &str, head: char| -> Option<u32> {
711        let s = s.strip_prefix(head)?;
712        s.parse().ok()
713    };
714
715    let scalar = select! {
716        Token::Ident("bool") => PrimitiveRustType::Bool,
717        Token::Ident("str") => PrimitiveRustType::Str,
718        Token::Ident("ZngurCppOpaqueOwnedObject") => PrimitiveRustType::ZngurCppOpaqueOwnedObject,
719        Token::Ident("usize") => PrimitiveRustType::Usize,
720        Token::Ident(c) if as_scalar(c, 'u').is_some() => PrimitiveRustType::Uint(as_scalar(c, 'u').unwrap()),
721        Token::Ident(c) if as_scalar(c, 'i').is_some() => PrimitiveRustType::Int(as_scalar(c, 'i').unwrap()),
722        Token::Ident(c) if as_scalar(c, 'f').is_some() => PrimitiveRustType::Float(as_scalar(c, 'f').unwrap()),
723    }.map(ParsedRustType::Primitive);
724
725    recursive(|parser| {
726        let parser = parser.boxed();
727        let pg = rust_path_and_generics(parser.clone());
728        let adt = pg.clone().map(ParsedRustType::Adt);
729
730        let dyn_trait = just(Token::KwDyn)
731            .ignore_then(rust_trait(parser.clone()))
732            .then(
733                just(Token::Plus)
734                    .ignore_then(select! {
735                        Token::Ident(c) => c,
736                    })
737                    .repeated()
738                    .collect::<Vec<_>>(),
739            )
740            .map(|(x, y)| ParsedRustType::Dyn(x, y));
741        let boxed = just(Token::Ident("Box"))
742            .then(rust_generics(parser.clone()))
743            .map(|(_, x)| {
744                assert_eq!(x.len(), 1);
745                ParsedRustType::Boxed(Box::new(x.into_iter().next().unwrap().right().unwrap()))
746            });
747        let unit = just(Token::ParenOpen)
748            .then(just(Token::ParenClose))
749            .map(|_| ParsedRustType::Tuple(vec![]));
750        let tuple = parser
751            .clone()
752            .separated_by(just(Token::Comma))
753            .allow_trailing()
754            .collect::<Vec<_>>()
755            .delimited_by(just(Token::ParenOpen), just(Token::ParenClose))
756            .map(|xs| ParsedRustType::Tuple(xs));
757        let slice = parser
758            .clone()
759            .map(|x| ParsedRustType::Slice(Box::new(x)))
760            .delimited_by(just(Token::BracketOpen), just(Token::BracketClose));
761        let reference = just(Token::And)
762            .ignore_then(
763                just(Token::KwMut)
764                    .to(Mutability::Mut)
765                    .or(empty().to(Mutability::Not)),
766            )
767            .then(parser.clone())
768            .map(|(m, x)| ParsedRustType::Ref(m, Box::new(x)));
769        let raw_ptr = just(Token::Star)
770            .ignore_then(
771                just(Token::KwMut)
772                    .to(Mutability::Mut)
773                    .or(just(Token::KwConst).to(Mutability::Not)),
774            )
775            .then(parser)
776            .map(|(m, x)| ParsedRustType::Raw(m, Box::new(x)));
777        choice((
778            scalar, boxed, unit, tuple, slice, adt, reference, raw_ptr, dyn_trait,
779        ))
780    })
781    .boxed()
782}
783
784fn rust_generics<'a>(
785    rust_type: Boxed<
786        'a,
787        'a,
788        ParserInput<'a>,
789        ParsedRustType<'a>,
790        extra::Err<Rich<'a, Token<'a>, Span>>,
791    >,
792) -> impl Parser<
793    'a,
794    ParserInput<'a>,
795    Vec<Either<(&'a str, ParsedRustType<'a>), ParsedRustType<'a>>>,
796    extra::Err<Rich<'a, Token<'a>, Span>>,
797> + Clone {
798    let named_generic = select! {
799        Token::Ident(c) => c,
800    }
801    .then_ignore(just(Token::Eq))
802    .then(rust_type.clone())
803    .map(Either::Left);
804    just(Token::ColonColon).repeated().at_most(1).ignore_then(
805        named_generic
806            .or(rust_type.clone().map(Either::Right))
807            .separated_by(just(Token::Comma))
808            .allow_trailing()
809            .collect::<Vec<_>>()
810            .delimited_by(just(Token::AngleOpen), just(Token::AngleClose)),
811    )
812}
813
814fn rust_path_and_generics<'a>(
815    rust_type: Boxed<
816        'a,
817        'a,
818        ParserInput<'a>,
819        ParsedRustType<'a>,
820        extra::Err<Rich<'a, Token<'a>, Span>>,
821    >,
822) -> impl Parser<
823    'a,
824    ParserInput<'a>,
825    ParsedRustPathAndGenerics<'a>,
826    extra::Err<Rich<'a, Token<'a>, Span>>,
827> + Clone {
828    let generics = rust_generics(rust_type.clone());
829    path()
830        .then(generics.clone().repeated().at_most(1).collect::<Vec<_>>())
831        .map(|x| {
832            let generics = x.1.into_iter().next().unwrap_or_default();
833            let (named_generics, generics) = generics.into_iter().partition_map(|x| x);
834            ParsedRustPathAndGenerics {
835                path: x.0,
836                generics,
837                named_generics,
838            }
839        })
840}
841
842fn fn_args<'a>(
843    rust_type: Boxed<
844        'a,
845        'a,
846        ParserInput<'a>,
847        ParsedRustType<'a>,
848        extra::Err<Rich<'a, Token<'a>, Span>>,
849    >,
850) -> impl Parser<
851    'a,
852    ParserInput<'a>,
853    (Vec<ParsedRustType<'a>>, ParsedRustType<'a>),
854    extra::Err<Rich<'a, Token<'a>, Span>>,
855> + Clone {
856    rust_type
857        .clone()
858        .separated_by(just(Token::Comma))
859        .allow_trailing()
860        .collect::<Vec<_>>()
861        .delimited_by(just(Token::ParenOpen), just(Token::ParenClose))
862        .then(
863            just(Token::Arrow)
864                .ignore_then(rust_type)
865                .or(empty().to(ParsedRustType::Tuple(vec![]))),
866        )
867        .boxed()
868}
869
870fn spanned<'a, T>(
871    parser: impl Parser<'a, ParserInput<'a>, T, extra::Err<Rich<'a, Token<'a>, Span>>> + Clone,
872) -> impl Parser<'a, ParserInput<'a>, Spanned<T>, extra::Err<Rich<'a, Token<'a>, Span>>> + Clone {
873    parser.map_with(|inner, extra| Spanned {
874        inner,
875        span: extra.span(),
876    })
877}
878
879fn rust_trait<'a>(
880    rust_type: Boxed<
881        'a,
882        'a,
883        ParserInput<'a>,
884        ParsedRustType<'a>,
885        extra::Err<Rich<'a, Token<'a>, Span>>,
886    >,
887) -> impl Parser<'a, ParserInput<'a>, ParsedRustTrait<'a>, extra::Err<Rich<'a, Token<'a>, Span>>> + Clone
888{
889    let fn_trait = select! {
890        Token::Ident(c) => c,
891    }
892    .then(fn_args(rust_type.clone()))
893    .map(|x| ParsedRustTrait::Fn {
894        name: x.0,
895        inputs: x.1.0,
896        output: Box::new(x.1.1),
897    });
898
899    let rust_trait = fn_trait.or(rust_path_and_generics(rust_type).map(ParsedRustTrait::Normal));
900    rust_trait
901}
902
903fn method<'a>()
904-> impl Parser<'a, ParserInput<'a>, ParsedMethod<'a>, extra::Err<Rich<'a, Token<'a>, Span>>> + Clone
905{
906    just(Token::KwFn)
907        .ignore_then(select! {
908            Token::Ident(c) => c,
909        })
910        .then(
911            rust_type()
912                .separated_by(just(Token::Comma))
913                .collect::<Vec<_>>()
914                .delimited_by(just(Token::AngleOpen), just(Token::AngleClose))
915                .or(empty().to(vec![])),
916        )
917        .then(fn_args(rust_type()))
918        .map(|((name, generics), args)| {
919            let is_self = |c: &ParsedRustType<'_>| {
920                if let ParsedRustType::Adt(c) = c {
921                    c.path.start == ParsedPathStart::Relative
922                        && &c.path.segments == &["self"]
923                        && c.generics.is_empty()
924                } else {
925                    false
926                }
927            };
928            let (inputs, receiver) = match args.0.get(0) {
929                Some(x) if is_self(&x) => (args.0[1..].to_vec(), ZngurMethodReceiver::Move),
930                Some(ParsedRustType::Ref(m, x)) if is_self(&x) => {
931                    (args.0[1..].to_vec(), ZngurMethodReceiver::Ref(*m))
932                }
933                _ => (args.0, ZngurMethodReceiver::Static),
934            };
935            ParsedMethod {
936                name,
937                receiver,
938                generics,
939                inputs,
940                output: args.1,
941            }
942        })
943}
944
945fn type_item<'a>()
946-> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, extra::Err<Rich<'a, Token<'a>, Span>>> + Clone {
947    fn inner_item<'a>()
948    -> impl Parser<'a, ParserInput<'a>, ParsedTypeItem<'a>, extra::Err<Rich<'a, Token<'a>, Span>>>
949    + Clone {
950        let property_item = (spanned(select! {
951            Token::Ident(c) => c,
952        }))
953        .then_ignore(just(Token::Eq))
954        .then(select! {
955            Token::Number(c) => c,
956        });
957        let layout = just([Token::Sharp, Token::Ident("layout")])
958            .ignore_then(
959                property_item
960                    .separated_by(just(Token::Comma))
961                    .collect::<Vec<_>>()
962                    .delimited_by(just(Token::ParenOpen), just(Token::ParenClose)),
963            )
964            .map(ParsedLayoutPolicy::StackAllocated)
965            .or(just([Token::Sharp, Token::Ident("only_by_ref")]).to(ParsedLayoutPolicy::OnlyByRef))
966            .or(just([Token::Sharp, Token::Ident("heap_allocated")])
967                .to(ParsedLayoutPolicy::HeapAllocated))
968            .map_with(|x, extra| ParsedTypeItem::Layout(extra.span(), x))
969            .boxed();
970        let trait_item = select! {
971            Token::Ident("Debug") => ZngurWellknownTrait::Debug,
972            Token::Ident("Copy") => ZngurWellknownTrait::Copy,
973        }
974        .or(just(Token::Question)
975            .then(just(Token::Ident("Sized")))
976            .to(ZngurWellknownTrait::Unsized));
977        let traits = just(Token::Ident("wellknown_traits"))
978            .ignore_then(
979                spanned(trait_item)
980                    .separated_by(just(Token::Comma))
981                    .collect::<Vec<_>>()
982                    .delimited_by(just(Token::ParenOpen), just(Token::ParenClose)),
983            )
984            .map(ParsedTypeItem::Traits)
985            .boxed();
986        let constructor_args = rust_type()
987            .separated_by(just(Token::Comma))
988            .collect::<Vec<_>>()
989            .delimited_by(just(Token::ParenOpen), just(Token::ParenClose))
990            .map(ParsedConstructorArgs::Tuple)
991            .or((select! {
992                Token::Ident(c) => c,
993            })
994            .boxed()
995            .then_ignore(just(Token::Colon))
996            .then(rust_type())
997            .separated_by(just(Token::Comma))
998            .collect::<Vec<_>>()
999            .delimited_by(just(Token::BraceOpen), just(Token::BraceClose))
1000            .map(ParsedConstructorArgs::Named))
1001            .or(empty().to(ParsedConstructorArgs::Unit))
1002            .boxed();
1003        let constructor = just(Token::Ident("constructor")).ignore_then(
1004            (select! {
1005                Token::Ident(c) => Some(c),
1006            })
1007            .or(empty().to(None))
1008            .then(constructor_args)
1009            .map(|(name, args)| ParsedTypeItem::Constructor { name, args }),
1010        );
1011        let cpp_value = just(Token::Sharp)
1012            .then(just(Token::Ident("cpp_value")))
1013            .ignore_then(select! {
1014                Token::Str(c) => c,
1015            })
1016            .then(select! {
1017                Token::Str(c) => c,
1018            })
1019            .map(|x| ParsedTypeItem::CppValue {
1020                field: x.0,
1021                cpp_type: x.1,
1022            });
1023        let cpp_ref = just(Token::Sharp)
1024            .then(just(Token::Ident("cpp_ref")))
1025            .ignore_then(select! {
1026                Token::Str(c) => c,
1027            })
1028            .map(|x| ParsedTypeItem::CppRef { cpp_type: x });
1029        choice((
1030            layout,
1031            traits,
1032            constructor,
1033            cpp_value,
1034            cpp_ref,
1035            method()
1036                .then(
1037                    just(Token::KwUse)
1038                        .ignore_then(path())
1039                        .map(Some)
1040                        .or(empty().to(None)),
1041                )
1042                .then(
1043                    just(Token::Ident("deref"))
1044                        .ignore_then(rust_type())
1045                        .map(Some)
1046                        .or(empty().to(None)),
1047                )
1048                .map(|((data, use_path), deref)| ParsedTypeItem::Method {
1049                    deref,
1050                    use_path,
1051                    data,
1052                }),
1053        ))
1054        .then_ignore(just(Token::Semicolon))
1055    }
1056    just(Token::KwType)
1057        .ignore_then(spanned(rust_type()))
1058        .then(
1059            spanned(inner_item())
1060                .repeated()
1061                .collect::<Vec<_>>()
1062                .delimited_by(just(Token::BraceOpen), just(Token::BraceClose)),
1063        )
1064        .map(|(ty, items)| ParsedItem::Type { ty, items })
1065        .boxed()
1066}
1067
1068fn trait_item<'a>()
1069-> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, extra::Err<Rich<'a, Token<'a>, Span>>> + Clone {
1070    just(Token::KwTrait)
1071        .ignore_then(rust_trait(rust_type()))
1072        .then(
1073            method()
1074                .then_ignore(just(Token::Semicolon))
1075                .repeated()
1076                .collect::<Vec<_>>()
1077                .delimited_by(just(Token::BraceOpen), just(Token::BraceClose)),
1078        )
1079        .map(|(tr, methods)| ParsedItem::Trait { tr, methods })
1080        .boxed()
1081}
1082
1083fn fn_item<'a>()
1084-> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, extra::Err<Rich<'a, Token<'a>, Span>>> + Clone {
1085    method()
1086        .then_ignore(just(Token::Semicolon))
1087        .map(ParsedItem::Fn)
1088}
1089
1090fn additional_include_item<'a>()
1091-> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, extra::Err<Rich<'a, Token<'a>, Span>>> + Clone {
1092    just(Token::Sharp)
1093        .ignore_then(
1094            just(Token::Ident("cpp_additional_includes"))
1095                .ignore_then(select! {
1096                    Token::Str(c) => ParsedItem::CppAdditionalInclude(c),
1097                })
1098                .or(just(Token::Ident("convert_panic_to_exception"))
1099                    .to(ParsedItem::ConvertPanicToException)),
1100        )
1101        .boxed()
1102}
1103
1104fn extern_cpp_item<'a>()
1105-> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, extra::Err<Rich<'a, Token<'a>, Span>>> + Clone {
1106    let function = method()
1107        .then_ignore(just(Token::Semicolon))
1108        .map(ParsedExternCppItem::Function);
1109    let impl_block = just(Token::KwImpl)
1110        .ignore_then(
1111            rust_trait(rust_type())
1112                .then_ignore(just(Token::KwFor))
1113                .map(Some)
1114                .or(empty().to(None))
1115                .then(rust_type()),
1116        )
1117        .then(
1118            method()
1119                .then_ignore(just(Token::Semicolon))
1120                .repeated()
1121                .collect::<Vec<_>>()
1122                .delimited_by(just(Token::BraceOpen), just(Token::BraceClose)),
1123        )
1124        .map(|((tr, ty), methods)| ParsedExternCppItem::Impl { tr, ty, methods });
1125    just(Token::KwExtern)
1126        .then(just(Token::Str("C++")))
1127        .ignore_then(
1128            function
1129                .or(impl_block)
1130                .repeated()
1131                .collect::<Vec<_>>()
1132                .delimited_by(just(Token::BraceOpen), just(Token::BraceClose))
1133                .boxed(),
1134        )
1135        .map(ParsedItem::ExternCpp)
1136        .boxed()
1137}
1138
1139fn item<'a>()
1140-> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, extra::Err<Rich<'a, Token<'a>, Span>>> + Clone {
1141    recursive(|item| {
1142        choice((
1143            just(Token::KwMod)
1144                .ignore_then(path())
1145                .then(
1146                    item.repeated()
1147                        .collect::<Vec<_>>()
1148                        .delimited_by(just(Token::BraceOpen), just(Token::BraceClose)),
1149                )
1150                .map(|(path, items)| ParsedItem::Mod { path, items }),
1151            type_item(),
1152            trait_item(),
1153            extern_cpp_item(),
1154            fn_item(),
1155            additional_include_item(),
1156        ))
1157    })
1158    .boxed()
1159}
1160
1161fn path<'a>()
1162-> impl Parser<'a, ParserInput<'a>, ParsedPath<'a>, extra::Err<Rich<'a, Token<'a>, Span>>> + Clone {
1163    let start = choice((
1164        just(Token::ColonColon).to(ParsedPathStart::Absolute),
1165        just(Token::KwCrate)
1166            .then(just(Token::ColonColon))
1167            .to(ParsedPathStart::Crate),
1168        empty().to(ParsedPathStart::Relative),
1169    ));
1170    start
1171        .then(
1172            (select! {
1173                Token::Ident(c) => c,
1174            })
1175            .separated_by(just(Token::ColonColon))
1176            .at_least(1)
1177            .collect::<Vec<_>>(),
1178        )
1179        .or(just(Token::KwCrate).to((ParsedPathStart::Crate, vec![])))
1180        .map_with(|(start, segments), extra| ParsedPath {
1181            start,
1182            segments,
1183            span: extra.span(),
1184        })
1185        .boxed()
1186}