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 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 {
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}