1use std::{collections::HashMap, fmt::Display, path::Component};
2
3#[cfg(not(test))]
4use std::process::exit;
5
6use ariadne::{Color, Label, Report, ReportKind, sources};
7use chumsky::prelude::*;
8use itertools::{Either, Itertools};
9
10use zngur_def::{
11 AdditionalIncludes, ConvertPanicToException, CppRef, CppStackOwned, CppValue, Import,
12 LayoutPolicy, Merge, MergeFailure, ModuleImport, Mutability, PrimitiveRustType,
13 RustPathAndGenerics, RustTrait, RustType, ZngurConstructor, ZngurExternCppFn,
14 ZngurExternCppImpl, ZngurField, ZngurFn, ZngurMethod, ZngurMethodDetails, ZngurMethodReceiver,
15 ZngurSpec, ZngurTrait, ZngurType, ZngurWellknownTrait,
16};
17
18pub type Span = SimpleSpan<usize>;
19
20#[derive(Debug)]
22pub struct ParseResult {
23 pub spec: ZngurSpec,
25 pub processed_files: Vec<std::path::PathBuf>,
27}
28
29#[cfg(test)]
30mod tests;
31
32pub mod cfg;
33mod conditional;
34
35use crate::{
36 cfg::{CfgConditional, RustCfgProvider},
37 conditional::{Condition, ConditionalItem, NItems, conditional_item},
38};
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub struct Spanned<T> {
42 inner: T,
43 span: Span,
44}
45
46type ParserInput<'a> = chumsky::input::MappedInput<
47 Token<'a>,
48 Span,
49 &'a [(Token<'a>, Span)],
50 Box<
51 dyn for<'x> Fn(
52 &'x (Token<'_>, chumsky::span::SimpleSpan),
53 ) -> (&'x Token<'x>, &'x SimpleSpan),
54 >,
55>;
56
57#[derive(Default)]
58pub struct UnstableFeatures {
59 pub cfg_match: bool,
60 pub cfg_if: bool,
61}
62
63#[derive(Default)]
64pub struct ZngParserState {
65 pub unstable_features: UnstableFeatures,
66}
67
68type ZngParserExtra<'a> =
69 extra::Full<Rich<'a, Token<'a>, Span>, extra::SimpleState<ZngParserState>, ()>;
70
71type BoxedZngParser<'a, Item> = chumsky::Boxed<'a, 'a, ParserInput<'a>, Item, ZngParserExtra<'a>>;
72
73pub(crate) trait ZngParser<'a, Item>:
75 Parser<'a, ParserInput<'a>, Item, ZngParserExtra<'a>> + Clone
76{
77}
78impl<'a, T, Item> ZngParser<'a, Item> for T where
79 T: Parser<'a, ParserInput<'a>, Item, ZngParserExtra<'a>> + Clone
80{
81}
82
83#[derive(Debug)]
84pub struct ParsedZngFile<'a>(Vec<ParsedItem<'a>>);
85
86#[derive(Debug)]
87pub struct ProcessedZngFile<'a> {
88 aliases: Vec<ParsedAlias<'a>>,
89 items: Vec<ProcessedItem<'a>>,
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
93enum ParsedPathStart {
94 Absolute,
95 Relative,
96 Crate,
97}
98
99#[derive(Debug, Clone, PartialEq, Eq)]
100struct ParsedPath<'a> {
101 start: ParsedPathStart,
102 segments: Vec<&'a str>,
103 span: Span,
104}
105
106#[derive(Debug, Clone)]
107struct Scope<'a> {
108 aliases: Vec<ParsedAlias<'a>>,
109 base: Vec<String>,
110}
111
112impl<'a> Scope<'a> {
113 fn new_root(aliases: Vec<ParsedAlias<'a>>) -> Scope<'a> {
115 Scope {
116 aliases,
117 base: Vec::new(),
118 }
119 }
120
121 fn resolve_path(&self, path: ParsedPath<'a>) -> Vec<String> {
123 if let Some(expanded_alias) = self
125 .aliases
126 .iter()
127 .find_map(|alias| alias.expand(&path, &self.base))
128 {
129 expanded_alias
130 } else {
131 path.to_zngur(&self.base)
132 }
133 }
134
135 fn simple_relative_path(&self, relative_item_name: &str) -> Vec<String> {
137 self.base
138 .iter()
139 .cloned()
140 .chain(Some(relative_item_name.to_string()))
141 .collect()
142 }
143
144 fn sub_scope(&self, new_aliases: &[ParsedAlias<'a>], nested_path: ParsedPath<'a>) -> Scope<'_> {
145 let base = nested_path.to_zngur(&self.base);
146 let mut mod_aliases = new_aliases.to_vec();
147 mod_aliases.extend_from_slice(&self.aliases);
148
149 Scope {
150 aliases: mod_aliases,
151 base,
152 }
153 }
154}
155
156impl ParsedPath<'_> {
157 fn to_zngur(self, base: &[String]) -> Vec<String> {
158 match self.start {
159 ParsedPathStart::Absolute => self.segments.into_iter().map(|x| x.to_owned()).collect(),
160 ParsedPathStart::Relative => base
161 .iter()
162 .map(|x| x.as_str())
163 .chain(self.segments)
164 .map(|x| x.to_owned())
165 .collect(),
166 ParsedPathStart::Crate => ["crate"]
167 .into_iter()
168 .chain(self.segments)
169 .map(|x| x.to_owned())
170 .collect(),
171 }
172 }
173
174 fn matches_alias(&self, alias: &ParsedAlias<'_>) -> bool {
175 match self.start {
176 ParsedPathStart::Absolute | ParsedPathStart::Crate => false,
177 ParsedPathStart::Relative => self
178 .segments
179 .first()
180 .is_some_and(|part| *part == alias.name),
181 }
182 }
183}
184
185#[derive(Debug, Clone, PartialEq, Eq)]
186pub struct ParsedAlias<'a> {
187 name: &'a str,
188 path: ParsedPath<'a>,
189 span: Span,
190}
191
192impl ParsedAlias<'_> {
193 fn expand(&self, path: &ParsedPath<'_>, base: &[String]) -> Option<Vec<String>> {
194 if path.matches_alias(self) {
195 match self.path.start {
196 ParsedPathStart::Absolute => Some(
197 self.path
198 .segments
199 .iter()
200 .chain(path.segments.iter().skip(1))
201 .map(|seg| (*seg).to_owned())
202 .collect(),
203 ),
204 ParsedPathStart::Crate => Some(
205 ["crate"]
206 .into_iter()
207 .chain(self.path.segments.iter().cloned())
208 .chain(path.segments.iter().skip(1).cloned())
209 .map(|seg| (*seg).to_owned())
210 .collect(),
211 ),
212 ParsedPathStart::Relative => Some(
213 base.iter()
214 .map(|x| x.as_str())
215 .chain(self.path.segments.iter().cloned())
216 .chain(path.segments.iter().skip(1).cloned())
217 .map(|seg| (*seg).to_owned())
218 .collect(),
219 ),
220 }
221 } else {
222 None
223 }
224 }
225}
226
227#[derive(Debug, Clone, PartialEq, Eq)]
228struct ParsedImportPath {
229 path: std::path::PathBuf,
230 span: Span,
231}
232
233#[derive(Debug, Clone, PartialEq, Eq)]
234enum ParsedItem<'a> {
235 ConvertPanicToException(Span),
236 CppAdditionalInclude(&'a str),
237 UnstableFeature(&'a str),
238 Mod {
239 path: ParsedPath<'a>,
240 items: Vec<ParsedItem<'a>>,
241 },
242 Type {
243 ty: Spanned<ParsedRustType<'a>>,
244 items: Vec<Spanned<ParsedTypeItem<'a>>>,
245 },
246 Trait {
247 tr: Spanned<ParsedRustTrait<'a>>,
248 methods: Vec<ParsedMethod<'a>>,
249 },
250 Fn(Spanned<ParsedMethod<'a>>),
251 ExternCpp(Vec<ParsedExternCppItem<'a>>),
252 Alias(ParsedAlias<'a>),
253 Import(ParsedImportPath),
254 ModuleImport {
255 path: std::path::PathBuf,
256 span: Span,
257 },
258 MatchOnCfg(Condition<CfgConditional<'a>, ParsedItem<'a>, NItems>),
259}
260
261#[derive(Debug, Clone, PartialEq, Eq)]
262enum ProcessedItem<'a> {
263 ConvertPanicToException(Span),
264 CppAdditionalInclude(&'a str),
265 Mod {
266 path: ParsedPath<'a>,
267 items: Vec<ProcessedItem<'a>>,
268 aliases: Vec<ParsedAlias<'a>>,
269 },
270 Type {
271 ty: Spanned<ParsedRustType<'a>>,
272 items: Vec<Spanned<ParsedTypeItem<'a>>>,
273 },
274 Trait {
275 tr: Spanned<ParsedRustTrait<'a>>,
276 methods: Vec<ParsedMethod<'a>>,
277 },
278 Fn(Spanned<ParsedMethod<'a>>),
279 ExternCpp(Vec<ParsedExternCppItem<'a>>),
280 Import(ParsedImportPath),
281 ModuleImport {
282 path: std::path::PathBuf,
283 span: Span,
284 },
285}
286
287#[derive(Debug, Clone, PartialEq, Eq)]
288enum ParsedExternCppItem<'a> {
289 Function {
290 is_safe: bool,
291 method: Spanned<ParsedMethod<'a>>,
292 },
293 Impl {
294 tr: Option<ParsedRustTrait<'a>>,
295 ty: Spanned<ParsedRustType<'a>>,
296 methods: Vec<(bool, ParsedMethod<'a>)>,
297 },
298}
299
300#[derive(Debug, Clone, PartialEq, Eq)]
301enum ParsedConstructorArgs<'a> {
302 Unit,
303 Tuple(Vec<ParsedRustType<'a>>),
304 Named(Vec<(&'a str, ParsedRustType<'a>)>),
305}
306
307#[derive(Debug, Clone, PartialEq, Eq)]
308enum ParsedLayoutPolicy<'a> {
309 StackAllocated(Vec<(Spanned<&'a str>, usize)>),
310 Conservative(Vec<(Spanned<&'a str>, usize)>),
311 HeapAllocated,
312 OnlyByRef,
313}
314
315#[derive(Debug, Clone, PartialEq, Eq)]
316enum ParsedTypeItem<'a> {
317 Layout(Span, ParsedLayoutPolicy<'a>),
318 Traits(Vec<Spanned<ZngurWellknownTrait>>),
319 Constructor {
320 name: Option<&'a str>,
321 args: ParsedConstructorArgs<'a>,
322 },
323 Field {
324 name: String,
325 ty: ParsedRustType<'a>,
326 offset: Option<usize>,
327 },
328 Method {
329 data: ParsedMethod<'a>,
330 use_path: Option<ParsedPath<'a>>,
331 deref: Option<ParsedRustType<'a>>,
332 },
333 CppValue {
334 field: &'a str,
335 cpp_type: &'a str,
336 },
337 CppRef {
338 cpp_type: &'a str,
339 },
340 CppStackOwned {
341 cpp_type: &'a str,
342 props: Vec<(Spanned<&'a str>, usize)>,
343 },
344 MatchOnCfg(Condition<CfgConditional<'a>, ParsedTypeItem<'a>, NItems>),
345}
346
347#[derive(Debug, Clone, PartialEq, Eq)]
348struct ParsedMethod<'a> {
349 name: &'a str,
350 receiver: ZngurMethodReceiver,
351 generics: Vec<ParsedRustType<'a>>,
352 inputs: Vec<ParsedRustType<'a>>,
353 output: ParsedRustType<'a>,
354}
355
356impl ParsedMethod<'_> {
357 fn to_zngur(self, scope: &Scope<'_>) -> ZngurMethod {
358 ZngurMethod {
359 name: self.name.to_owned(),
360 generics: self
361 .generics
362 .into_iter()
363 .map(|x| x.to_zngur(scope))
364 .collect(),
365 receiver: self.receiver,
366 inputs: self.inputs.into_iter().map(|x| x.to_zngur(scope)).collect(),
367 output: self.output.to_zngur(scope),
368 is_safe: true,
369 }
370 }
371}
372
373fn checked_merge<T, U>(src: T, dst: &mut U, span: Span, ctx: &mut ParseContext)
374where
375 T: Merge<U>,
376{
377 match src.merge(dst) {
378 Ok(()) => {}
379 Err(e) => match e {
380 MergeFailure::Conflict(s) => {
381 ctx.add_error_str(&s, span);
382 }
383 },
384 }
385}
386
387impl ProcessedItem<'_> {
388 fn add_to_zngur_spec(self, r: &mut ZngurSpec, scope: &Scope<'_>, ctx: &mut ParseContext) {
389 match self {
390 ProcessedItem::Mod {
391 path,
392 items,
393 aliases,
394 } => {
395 let sub_scope = scope.sub_scope(&aliases, path);
396 for item in items {
397 item.add_to_zngur_spec(r, &sub_scope, ctx);
398 }
399 }
400 ProcessedItem::Import(path) => {
401 if path.path.is_absolute() {
402 ctx.add_error_str("Absolute paths imports are not supported.", path.span)
403 }
404 match path.path.components().next() {
405 Some(Component::CurDir) | Some(Component::ParentDir) => {
406 r.imports.push(Import(path.path));
407 }
408 _ => ctx.add_error_str(
409 "Module import is not supported. Use a relative path instead.",
410 path.span,
411 ),
412 }
413 }
414 ProcessedItem::ModuleImport { path, span: _ } => {
415 r.imported_modules.push(ModuleImport { path: path.clone() });
416 }
417 ProcessedItem::Type { ty, items } => {
418 if ty.inner == ParsedRustType::Tuple(vec![]) {
419 ctx.add_error_str(
421 "Unit type is declared implicitly. Remove this entirely.",
422 ty.span,
423 );
424 }
425
426 let mut methods = vec![];
427 let mut constructors = vec![];
428 let mut fields = vec![];
429 let mut wellknown_traits = vec![];
430 let mut layout = None;
431 let mut layout_span = None;
432 let mut cpp_value = None;
433 let mut cpp_ref = None;
434 let mut cpp_stack_owned = None;
435 let mut to_process = items;
436 to_process.reverse(); let check_size_align = |props: Vec<(Spanned<&str>, usize)>| {
438 let mut size = None;
439 let mut align = None;
440 let mut errors = vec![];
441 for (key, value) in props {
442 match key.inner {
443 "size" => size = Some(value),
444 "align" => align = Some(value),
445 _ => errors.push(("Unknown property", key.span)),
446 }
447 }
448 if size.is_none() {
449 errors.push(("Size is not declared for this type", ty.span));
450 }
451 if align.is_none() {
452 errors.push(("Align is not declared for this type", ty.span));
453 }
454 if errors.is_empty() {
455 Ok((size.unwrap(), align.unwrap()))
456 } else {
457 Err(errors)
458 }
459 };
460 while let Some(item) = to_process.pop() {
461 let item_span = item.span;
462 let item = item.inner;
463 match item {
464 ParsedTypeItem::Layout(span, p) => {
465 layout = Some(match p {
466 ParsedLayoutPolicy::StackAllocated(p) => {
467 match check_size_align(p) {
468 Ok((size, align)) => {
469 LayoutPolicy::StackAllocated { size, align }
470 }
471 Err(errs) => {
472 for (msg, span) in errs {
473 ctx.add_error_str(msg, span);
474 }
475 continue;
476 }
477 }
478 }
479 ParsedLayoutPolicy::Conservative(p) => match check_size_align(p) {
480 Ok((size, align)) => LayoutPolicy::Conservative { size, align },
481 Err(errs) => {
482 for (msg, span) in errs {
483 ctx.add_error_str(msg, span);
484 }
485 continue;
486 }
487 },
488 ParsedLayoutPolicy::HeapAllocated => LayoutPolicy::HeapAllocated,
489 ParsedLayoutPolicy::OnlyByRef => LayoutPolicy::OnlyByRef,
490 });
491 match layout_span {
492 Some(_) => {
493 ctx.add_error_str("Duplicate layout policy found", span);
494 }
495 None => layout_span = Some(span),
496 }
497 }
498 ParsedTypeItem::Traits(tr) => {
499 wellknown_traits.extend(tr);
500 }
501 ParsedTypeItem::Constructor { name, args } => {
502 constructors.push(ZngurConstructor {
503 name: name.map(|x| x.to_owned()),
504 inputs: match args {
505 ParsedConstructorArgs::Unit => vec![],
506 ParsedConstructorArgs::Tuple(t) => t
507 .into_iter()
508 .enumerate()
509 .map(|(i, t)| (i.to_string(), t.to_zngur(scope)))
510 .collect(),
511 ParsedConstructorArgs::Named(t) => t
512 .into_iter()
513 .map(|(i, t)| (i.to_owned(), t.to_zngur(scope)))
514 .collect(),
515 },
516 })
517 }
518 ParsedTypeItem::Field { name, ty, offset } => {
519 fields.push(ZngurField {
520 name: name.to_owned(),
521 ty: ty.to_zngur(scope),
522 offset,
523 });
524 }
525 ParsedTypeItem::Method {
526 data,
527 use_path,
528 deref,
529 } => {
530 let deref = deref.and_then(|x| {
531 let deref_type = x.to_zngur(scope);
532 let receiver_mutability = match data.receiver {
533 ZngurMethodReceiver::Ref(mutability) => mutability,
534 ZngurMethodReceiver::Static | ZngurMethodReceiver::Move => {
535 ctx.add_error_str(
536 "Deref needs reference receiver",
537 item_span,
538 );
539 return None;
540 }
541 };
542 Some((deref_type, receiver_mutability))
543 });
544 methods.push(ZngurMethodDetails {
545 data: data.to_zngur(scope),
546 use_path: use_path.map(|x| scope.resolve_path(x)),
547 deref,
548 });
549 }
550 ParsedTypeItem::CppValue { field, cpp_type } => {
551 cpp_value = Some(CppValue(field.to_owned(), cpp_type.to_owned()));
552 }
553 ParsedTypeItem::CppRef { cpp_type } => {
554 match layout_span {
555 Some(span) => {
556 ctx.add_error_str("Duplicate layout policy found", span);
557 continue;
558 }
559 None => {
560 layout = Some(LayoutPolicy::ZERO_SIZED_TYPE);
561 layout_span = Some(item_span);
562 }
563 }
564 cpp_ref = Some(CppRef(cpp_type.to_owned()));
565 }
566 ParsedTypeItem::CppStackOwned { cpp_type, props } => {
567 let (size, align) = match check_size_align(props) {
568 Ok(x) => x,
569 Err(errs) => {
570 for (msg, span) in errs {
571 ctx.add_error_str(msg, span);
572 }
573 continue;
574 }
575 };
576 cpp_stack_owned = Some(CppStackOwned {
577 cpp_type: cpp_type.to_owned(),
578 size,
579 align,
580 });
581 layout = Some(LayoutPolicy::StackAllocated { size, align });
582 }
583 ParsedTypeItem::MatchOnCfg(match_) => {
584 let result = match_.eval(ctx);
585 if let Some(result) = result {
586 to_process.extend(result);
587 }
588 }
589 }
590 }
591 let is_unsized = wellknown_traits
592 .iter()
593 .find(|x| x.inner == ZngurWellknownTrait::Unsized)
594 .cloned();
595 let is_copy = wellknown_traits
596 .iter()
597 .find(|x| x.inner == ZngurWellknownTrait::Copy)
598 .cloned();
599 let mut wt = wellknown_traits
600 .into_iter()
601 .map(|x| x.inner)
602 .collect::<Vec<_>>();
603 if is_copy.is_none() && is_unsized.is_none() {
604 wt.push(ZngurWellknownTrait::Drop);
605 }
606 if let Some(is_unsized) = is_unsized {
607 if let Some(span) = layout_span {
608 ctx.add_report(
609 Report::build(
610 ReportKind::Error,
611 ctx.filename().to_string(),
612 span.start,
613 )
614 .with_message("Duplicate layout policy found for unsized type.")
615 .with_label(
616 Label::new((ctx.filename().to_string(), span.start..span.end))
617 .with_message(
618 "Unsized types have implicit layout policy, remove this.",
619 )
620 .with_color(Color::Red),
621 )
622 .with_label(
623 Label::new((
624 ctx.filename().to_string(),
625 is_unsized.span.start..is_unsized.span.end,
626 ))
627 .with_message("Type declared as unsized here.")
628 .with_color(Color::Blue),
629 )
630 .finish(),
631 )
632 }
633 layout = Some(LayoutPolicy::OnlyByRef);
634 }
635 if let Some(layout) = layout {
636 checked_merge(
637 ZngurType {
638 ty: ty.inner.to_zngur(scope),
639 layout,
640 methods,
641 wellknown_traits: wt,
642 constructors,
643 fields,
644 cpp_value,
645 cpp_ref,
646 cpp_stack_owned,
647 },
648 r,
649 ty.span,
650 ctx,
651 );
652 } else {
653 ctx.add_error_str(
654 "No layout policy found for this type. \
655Use one of `#layout(size = X, align = Y)`, `#heap_allocated` or `#only_by_ref`.",
656 ty.span,
657 );
658 };
659 }
660 ProcessedItem::Trait { tr, methods } => {
661 checked_merge(
662 ZngurTrait {
663 tr: tr.inner.to_zngur(scope),
664 methods: methods.into_iter().map(|m| m.to_zngur(scope)).collect(),
665 },
666 r,
667 tr.span,
668 ctx,
669 );
670 }
671 ProcessedItem::Fn(f) => {
672 let method = f.inner.to_zngur(scope);
673 checked_merge(
674 ZngurFn {
675 path: RustPathAndGenerics {
676 path: scope.simple_relative_path(&method.name),
677 generics: method.generics,
678 named_generics: vec![],
679 },
680 inputs: method.inputs,
681 output: method.output,
682 },
683 r,
684 f.span,
685 ctx,
686 );
687 }
688 ProcessedItem::ExternCpp(items) => {
689 for item in items {
690 match item {
691 ParsedExternCppItem::Function { is_safe, method } => {
692 let span = method.span;
693 let method = method.inner.to_zngur(scope);
694 checked_merge(
695 ZngurExternCppFn {
696 name: method.name.to_string(),
697 inputs: method.inputs,
698 output: method.output,
699 is_safe,
700 },
701 r,
702 span,
703 ctx,
704 );
705 }
706 ParsedExternCppItem::Impl { tr, ty, methods } => {
707 checked_merge(
708 ZngurExternCppImpl {
709 tr: tr.map(|x| x.to_zngur(scope)),
710 ty: ty.inner.to_zngur(scope),
711 methods: methods
712 .into_iter()
713 .map(|(is_safe, x)| {
714 let mut m = x.to_zngur(scope);
715 m.is_safe = is_safe;
716 m
717 })
718 .collect(),
719 },
720 r,
721 ty.span,
722 ctx,
723 );
724 }
725 }
726 }
727 }
728 ProcessedItem::CppAdditionalInclude(s) => {
729 match AdditionalIncludes(s.to_owned()).merge(r) {
730 Ok(()) => {}
731 Err(_) => {
732 unreachable!() }
734 }
735 }
736 ProcessedItem::ConvertPanicToException(span) => {
737 if ctx.depth > 0 {
738 ctx.add_error_str(
739 "Using `#convert_panic_to_exception` in imported zngur files is not supported. This directive can only be used in the main zngur file.",
740 span,
741 );
742 return;
743 }
744 match ConvertPanicToException(true).merge(r) {
745 Ok(()) => {}
746 Err(_) => {
747 unreachable!() }
749 }
750 }
751 }
752 }
753}
754
755#[derive(Debug, Clone, PartialEq, Eq)]
756enum ParsedRustType<'a> {
757 Primitive(PrimitiveRustType),
758 Ref(Mutability, Box<ParsedRustType<'a>>),
759 Raw(Mutability, Box<ParsedRustType<'a>>),
760 Boxed(Box<ParsedRustType<'a>>),
761 Slice(Box<ParsedRustType<'a>>),
762 Dyn(ParsedRustTrait<'a>, Vec<&'a str>),
763 Impl(ParsedRustTrait<'a>, Vec<&'a str>),
764 Tuple(Vec<ParsedRustType<'a>>),
765 Adt(ParsedRustPathAndGenerics<'a>),
766}
767
768impl ParsedRustType<'_> {
769 fn to_zngur(self, scope: &Scope<'_>) -> RustType {
770 match self {
771 ParsedRustType::Primitive(s) => RustType::Primitive(s),
772 ParsedRustType::Ref(m, s) => RustType::Ref(m, Box::new(s.to_zngur(scope))),
773 ParsedRustType::Raw(m, s) => RustType::Raw(m, Box::new(s.to_zngur(scope))),
774 ParsedRustType::Boxed(s) => RustType::Boxed(Box::new(s.to_zngur(scope))),
775 ParsedRustType::Slice(s) => RustType::Slice(Box::new(s.to_zngur(scope))),
776 ParsedRustType::Dyn(tr, bounds) => RustType::Dyn(
777 tr.to_zngur(scope),
778 bounds.into_iter().map(|x| x.to_owned()).collect(),
779 ),
780 ParsedRustType::Impl(tr, bounds) => RustType::Impl(
781 tr.to_zngur(scope),
782 bounds.into_iter().map(|x| x.to_owned()).collect(),
783 ),
784 ParsedRustType::Tuple(v) => {
785 RustType::Tuple(v.into_iter().map(|s| s.to_zngur(scope)).collect())
786 }
787 ParsedRustType::Adt(s) => RustType::Adt(s.to_zngur(scope)),
788 }
789 }
790}
791
792#[derive(Debug, Clone, PartialEq, Eq)]
793enum ParsedRustTrait<'a> {
794 Normal(ParsedRustPathAndGenerics<'a>),
795 Fn {
796 name: &'a str,
797 inputs: Vec<ParsedRustType<'a>>,
798 output: Box<ParsedRustType<'a>>,
799 },
800}
801
802impl ParsedRustTrait<'_> {
803 fn to_zngur(self, scope: &Scope<'_>) -> RustTrait {
804 match self {
805 ParsedRustTrait::Normal(s) => RustTrait::Normal(s.to_zngur(scope)),
806 ParsedRustTrait::Fn {
807 name,
808 inputs,
809 output,
810 } => RustTrait::Fn {
811 name: name.to_owned(),
812 inputs: inputs.into_iter().map(|s| s.to_zngur(scope)).collect(),
813 output: Box::new(output.to_zngur(scope)),
814 },
815 }
816 }
817}
818
819#[derive(Debug, Clone, PartialEq, Eq)]
820struct ParsedRustPathAndGenerics<'a> {
821 path: ParsedPath<'a>,
822 generics: Vec<ParsedRustType<'a>>,
823 named_generics: Vec<(&'a str, ParsedRustType<'a>)>,
824}
825
826impl ParsedRustPathAndGenerics<'_> {
827 fn to_zngur(self, scope: &Scope<'_>) -> RustPathAndGenerics {
828 RustPathAndGenerics {
829 path: scope.resolve_path(self.path),
830 generics: self
831 .generics
832 .into_iter()
833 .map(|x| x.to_zngur(scope))
834 .collect(),
835 named_generics: self
836 .named_generics
837 .into_iter()
838 .map(|(name, x)| (name.to_owned(), x.to_zngur(scope)))
839 .collect(),
840 }
841 }
842}
843
844struct ParseContext<'a, 'b> {
845 path: std::path::PathBuf,
846 text: &'a str,
847 depth: usize,
848 reports: Vec<Report<'b, (String, std::ops::Range<usize>)>>,
849 source_cache: std::collections::HashMap<std::path::PathBuf, String>,
850 processed_files: Vec<std::path::PathBuf>,
852 cfg_provider: Box<dyn RustCfgProvider>,
853}
854
855impl<'a, 'b> ParseContext<'a, 'b> {
856 fn new(path: std::path::PathBuf, text: &'a str, cfg: Box<dyn RustCfgProvider>) -> Self {
857 let processed_files = vec![path.clone()];
858 Self {
859 path,
860 text,
861 depth: 0,
862 reports: Vec::new(),
863 source_cache: HashMap::new(),
864 processed_files,
865 cfg_provider: cfg,
866 }
867 }
868
869 fn with_depth(
870 path: std::path::PathBuf,
871 text: &'a str,
872 depth: usize,
873 cfg: Box<dyn RustCfgProvider>,
874 ) -> Self {
875 let processed_files = vec![path.clone()];
876 Self {
877 path,
878 text,
879 depth,
880 reports: Vec::new(),
881 source_cache: HashMap::new(),
882 processed_files,
883 cfg_provider: cfg,
884 }
885 }
886
887 fn filename(&self) -> &str {
888 self.path.file_name().unwrap().to_str().unwrap()
889 }
890
891 fn add_report(&mut self, report: Report<'b, (String, std::ops::Range<usize>)>) {
892 self.reports.push(report);
893 }
894 fn add_errors<'err_src>(&mut self, errs: impl Iterator<Item = Rich<'err_src, String>>) {
895 let filename = self.filename().to_string();
896 self.reports.extend(errs.map(|e| {
897 Report::build(ReportKind::Error, &filename, e.span().start)
898 .with_message(e.to_string())
899 .with_label(
900 Label::new((filename.clone(), e.span().into_range()))
901 .with_message(e.reason().to_string())
902 .with_color(Color::Red),
903 )
904 .with_labels(e.contexts().map(|(label, span)| {
905 Label::new((filename.clone(), span.into_range()))
906 .with_message(format!("while parsing this {}", label))
907 .with_color(Color::Yellow)
908 }))
909 .finish()
910 }));
911 }
912
913 fn add_error_str(&mut self, error: &str, span: Span) {
914 self.add_errors([Rich::custom(span, error)].into_iter());
915 }
916
917 fn consume_from(&mut self, mut other: ParseContext<'_, 'b>) {
918 self.processed_files.append(&mut other.processed_files);
920 if other.has_errors() {
921 self.reports.extend(other.reports);
922 self.source_cache.insert(other.path, other.text.to_string());
923 self.source_cache.extend(other.source_cache);
924 }
925 }
926
927 fn has_errors(&self) -> bool {
928 !self.reports.is_empty()
929 }
930
931 #[cfg(test)]
932 fn emit_ariadne_errors(&self) -> ! {
933 let mut r = Vec::<u8>::new();
934 for err in &self.reports {
935 err.write(
936 sources(
937 [(self.filename().to_string(), self.text)]
938 .into_iter()
939 .chain(
940 self.source_cache
941 .iter()
942 .map(|(path, text)| {
943 (
944 path.file_name().unwrap().to_str().unwrap().to_string(),
945 text.as_str(),
946 )
947 })
948 .collect::<Vec<_>>()
949 .into_iter(),
950 ),
951 ),
952 &mut r,
953 )
954 .unwrap();
955 }
956 std::panic::resume_unwind(Box::new(tests::ErrorText(
957 String::from_utf8(strip_ansi_escapes::strip(r)).unwrap(),
958 )));
959 }
960
961 #[cfg(not(test))]
962 fn emit_ariadne_errors(&self) -> ! {
963 for err in &self.reports {
964 err.eprint(sources(
965 [(self.filename().to_string(), self.text)]
966 .into_iter()
967 .chain(
968 self.source_cache
969 .iter()
970 .map(|(path, text)| {
971 (
972 path.file_name().unwrap().to_str().unwrap().to_string(),
973 text.as_str(),
974 )
975 })
976 .collect::<Vec<_>>()
977 .into_iter(),
978 ),
979 ))
980 .unwrap();
981 }
982 exit(101);
983 }
984
985 fn get_config_provider(&self) -> &dyn RustCfgProvider {
986 self.cfg_provider.as_ref()
987 }
988}
989
990pub trait ImportResolver {
992 fn resolve_import(
993 &self,
994 cwd: &std::path::Path,
995 relpath: &std::path::Path,
996 ) -> Result<String, String>;
997}
998
999struct DefaultImportResolver;
1001
1002impl ImportResolver for DefaultImportResolver {
1003 fn resolve_import(
1004 &self,
1005 cwd: &std::path::Path,
1006 relpath: &std::path::Path,
1007 ) -> Result<String, String> {
1008 let path = cwd
1009 .join(relpath)
1010 .canonicalize()
1011 .map_err(|e| e.to_string())?;
1012 std::fs::read_to_string(path).map_err(|e| e.to_string())
1013 }
1014}
1015
1016impl<'a> ParsedZngFile<'a> {
1017 fn parse_into(zngur: &mut ZngurSpec, ctx: &mut ParseContext, resolver: &impl ImportResolver) {
1018 let (tokens, errs) = lexer().parse(ctx.text).into_output_errors();
1019 let Some(tokens) = tokens else {
1020 ctx.add_errors(errs.into_iter().map(|e| e.map_token(|c| c.to_string())));
1021 ctx.emit_ariadne_errors();
1022 };
1023 let tokens: ParserInput<'_> = tokens.as_slice().map(
1024 (ctx.text.len()..ctx.text.len()).into(),
1025 Box::new(|(t, s)| (t, s)),
1026 );
1027 let (ast, errs) = file_parser()
1028 .map_with(|ast, extra| (ast, extra.span()))
1029 .parse_with_state(tokens, &mut extra::SimpleState(ZngParserState::default()))
1030 .into_output_errors();
1031 let Some(ast) = ast else {
1032 ctx.add_errors(errs.into_iter().map(|e| e.map_token(|c| c.to_string())));
1033 ctx.emit_ariadne_errors();
1034 };
1035
1036 let (aliases, items) = partition_parsed_items(
1037 ast.0
1038 .0
1039 .into_iter()
1040 .map(|item| process_parsed_item(item, ctx)),
1041 );
1042 ProcessedZngFile::new(aliases, items).into_zngur_spec(zngur, ctx);
1043
1044 if let Some(dirname) = ctx.path.to_owned().parent() {
1045 for import in std::mem::take(&mut zngur.imports) {
1046 match resolver.resolve_import(dirname, &import.0) {
1047 Ok(text) => {
1048 let mut nested_ctx = ParseContext::with_depth(
1049 dirname.join(&import.0),
1050 &text,
1051 ctx.depth + 1,
1052 ctx.get_config_provider().clone_box(),
1053 );
1054 Self::parse_into(zngur, &mut nested_ctx, resolver);
1055 ctx.consume_from(nested_ctx);
1056 }
1057 Err(_) => {
1058 ctx.add_report(
1062 Report::build(ReportKind::Error, ctx.filename(), 0)
1063 .with_message(format!(
1064 "Import path not found: {}",
1065 import.0.display()
1066 ))
1067 .finish(),
1068 );
1069 }
1070 }
1071 }
1072 }
1073 }
1074
1075 pub fn parse(path: std::path::PathBuf, cfg: Box<dyn RustCfgProvider>) -> ParseResult {
1077 let mut zngur = ZngurSpec::default();
1078 zngur.rust_cfg.extend(cfg.get_cfg_pairs());
1079 let text = std::fs::read_to_string(&path).unwrap();
1080 let mut ctx = ParseContext::new(path.clone(), &text, cfg.clone_box());
1081 Self::parse_into(&mut zngur, &mut ctx, &DefaultImportResolver);
1082 if ctx.has_errors() {
1083 ctx.add_report(
1085 Report::build(
1086 ReportKind::Custom("cfg values", ariadne::Color::Green),
1087 path.file_name().unwrap_or_default().to_string_lossy(),
1088 0,
1089 )
1090 .with_message(
1091 cfg.get_cfg_pairs()
1092 .into_iter()
1093 .map(|(key, value)| match value {
1094 Some(value) => format!("{key}=\"{value}\""),
1095 None => key,
1096 })
1097 .join("\n")
1098 .to_string(),
1099 )
1100 .finish(),
1101 );
1102 ctx.emit_ariadne_errors();
1103 }
1104 ParseResult {
1105 spec: zngur,
1106 processed_files: ctx.processed_files,
1107 }
1108 }
1109
1110 pub fn parse_str(text: &str, cfg: impl RustCfgProvider + 'static) -> ParseResult {
1112 let mut zngur = ZngurSpec::default();
1113 let mut ctx = ParseContext::new(std::path::PathBuf::from("test.zng"), text, Box::new(cfg));
1114 Self::parse_into(&mut zngur, &mut ctx, &DefaultImportResolver);
1115 if ctx.has_errors() {
1116 ctx.emit_ariadne_errors();
1117 }
1118 ParseResult {
1119 spec: zngur,
1120 processed_files: ctx.processed_files,
1121 }
1122 }
1123
1124 #[cfg(test)]
1125 pub(crate) fn parse_str_with_resolver(
1126 text: &str,
1127 cfg: impl RustCfgProvider + 'static,
1128 resolver: &impl ImportResolver,
1129 ) -> ParseResult {
1130 let mut zngur = ZngurSpec::default();
1131 let mut ctx = ParseContext::new(std::path::PathBuf::from("test.zng"), text, Box::new(cfg));
1132 Self::parse_into(&mut zngur, &mut ctx, resolver);
1133 if ctx.has_errors() {
1134 ctx.emit_ariadne_errors();
1135 }
1136 ParseResult {
1137 spec: zngur,
1138 processed_files: ctx.processed_files,
1139 }
1140 }
1141}
1142
1143pub(crate) enum ProcessedItemOrAlias<'a> {
1144 Ignore,
1145 Processed(ProcessedItem<'a>),
1146 Alias(ParsedAlias<'a>),
1147 ChildItems(Vec<ProcessedItemOrAlias<'a>>),
1148}
1149
1150fn process_parsed_item<'a>(
1151 item: ParsedItem<'a>,
1152 ctx: &mut ParseContext,
1153) -> ProcessedItemOrAlias<'a> {
1154 use ProcessedItemOrAlias as Ret;
1155 match item {
1156 ParsedItem::Alias(alias) => Ret::Alias(alias),
1157 ParsedItem::ConvertPanicToException(span) => {
1158 Ret::Processed(ProcessedItem::ConvertPanicToException(span))
1159 }
1160 ParsedItem::UnstableFeature(_) => {
1161 Ret::Ignore
1163 }
1164 ParsedItem::CppAdditionalInclude(inc) => {
1165 Ret::Processed(ProcessedItem::CppAdditionalInclude(inc))
1166 }
1167 ParsedItem::Mod { path, items } => {
1168 let (aliases, items) = partition_parsed_items(
1169 items.into_iter().map(|item| process_parsed_item(item, ctx)),
1170 );
1171 Ret::Processed(ProcessedItem::Mod {
1172 path,
1173 items,
1174 aliases,
1175 })
1176 }
1177 ParsedItem::Type { ty, items } => Ret::Processed(ProcessedItem::Type { ty, items }),
1178 ParsedItem::Trait { tr, methods } => Ret::Processed(ProcessedItem::Trait { tr, methods }),
1179 ParsedItem::Fn(method) => Ret::Processed(ProcessedItem::Fn(method)),
1180 ParsedItem::ExternCpp(items) => Ret::Processed(ProcessedItem::ExternCpp(items)),
1181 ParsedItem::Import(path) => Ret::Processed(ProcessedItem::Import(path)),
1182 ParsedItem::ModuleImport { path, span } => {
1183 Ret::Processed(ProcessedItem::ModuleImport { path, span })
1184 }
1185 ParsedItem::MatchOnCfg(match_) => Ret::ChildItems(
1186 match_
1187 .eval(ctx)
1188 .unwrap_or_default() .into_iter()
1190 .map(|item| item.inner)
1191 .collect(),
1192 ),
1193 }
1194}
1195
1196fn partition_parsed_items<'a>(
1197 items: impl IntoIterator<Item = ProcessedItemOrAlias<'a>>,
1198) -> (Vec<ParsedAlias<'a>>, Vec<ProcessedItem<'a>>) {
1199 let mut aliases = Vec::new();
1200 let mut processed = Vec::new();
1201 for item in items.into_iter() {
1202 match item {
1203 ProcessedItemOrAlias::Ignore => continue,
1204 ProcessedItemOrAlias::Processed(p) => processed.push(p),
1205 ProcessedItemOrAlias::Alias(a) => aliases.push(a),
1206 ProcessedItemOrAlias::ChildItems(children) => {
1207 let (child_aliases, child_items) = partition_parsed_items(children);
1208 aliases.extend(child_aliases);
1209 processed.extend(child_items);
1210 }
1211 }
1212 }
1213 (aliases, processed)
1214}
1215
1216impl<'a> ProcessedZngFile<'a> {
1217 fn new(aliases: Vec<ParsedAlias<'a>>, items: Vec<ProcessedItem<'a>>) -> Self {
1218 ProcessedZngFile { aliases, items }
1219 }
1220
1221 fn into_zngur_spec(self, zngur: &mut ZngurSpec, ctx: &mut ParseContext) {
1222 let root_scope = Scope::new_root(self.aliases);
1223
1224 for item in self.items {
1225 item.add_to_zngur_spec(zngur, &root_scope, ctx);
1226 }
1227 }
1228}
1229
1230#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1231enum Token<'a> {
1232 Arrow,
1233 ArrowArm,
1234 AngleOpen,
1235 AngleClose,
1236 BracketOpen,
1237 BracketClose,
1238 Colon,
1239 ColonColon,
1240 ParenOpen,
1241 ParenClose,
1242 BraceOpen,
1243 BraceClose,
1244 And,
1245 Star,
1246 Sharp,
1247 Plus,
1248 Eq,
1249 Question,
1250 Comma,
1251 Semicolon,
1252 Pipe,
1253 Underscore,
1254 Dot,
1255 Bang,
1256 KwAs,
1257 KwAsync,
1258 KwDyn,
1259 KwUse,
1260 KwFor,
1261 KwMod,
1262 KwCrate,
1263 KwType,
1264 KwTrait,
1265 KwFn,
1266 KwMut,
1267 KwConst,
1268 KwExtern,
1269 KwImpl,
1270 KwImport,
1271 KwMerge,
1272 KwIf,
1273 KwElse,
1274 KwMatch,
1275 KwSafe,
1276 KwUnsafe,
1277 Ident(&'a str),
1278 Str(&'a str),
1279 Number(usize),
1280}
1281
1282impl<'a> Token<'a> {
1283 fn ident_or_kw(ident: &'a str) -> Self {
1284 match ident {
1285 "as" => Token::KwAs,
1286 "async" => Token::KwAsync,
1287 "dyn" => Token::KwDyn,
1288 "mod" => Token::KwMod,
1289 "type" => Token::KwType,
1290 "trait" => Token::KwTrait,
1291 "crate" => Token::KwCrate,
1292 "fn" => Token::KwFn,
1293 "mut" => Token::KwMut,
1294 "const" => Token::KwConst,
1295 "use" => Token::KwUse,
1296 "for" => Token::KwFor,
1297 "extern" => Token::KwExtern,
1298 "impl" => Token::KwImpl,
1299 "import" => Token::KwImport,
1300 "merge" => Token::KwMerge,
1301 "if" => Token::KwIf,
1302 "else" => Token::KwElse,
1303 "match" => Token::KwMatch,
1304 "safe" => Token::KwSafe,
1305 "unsafe" => Token::KwUnsafe,
1306 x => Token::Ident(x),
1307 }
1308 }
1309}
1310
1311impl Display for Token<'_> {
1312 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1313 match self {
1314 Token::Arrow => write!(f, "->"),
1315 Token::ArrowArm => write!(f, "=>"),
1316 Token::AngleOpen => write!(f, "<"),
1317 Token::AngleClose => write!(f, ">"),
1318 Token::BracketOpen => write!(f, "["),
1319 Token::BracketClose => write!(f, "]"),
1320 Token::ParenOpen => write!(f, "("),
1321 Token::ParenClose => write!(f, ")"),
1322 Token::BraceOpen => write!(f, "{{"),
1323 Token::BraceClose => write!(f, "}}"),
1324 Token::Colon => write!(f, ":"),
1325 Token::ColonColon => write!(f, "::"),
1326 Token::And => write!(f, "&"),
1327 Token::Star => write!(f, "*"),
1328 Token::Sharp => write!(f, "#"),
1329 Token::Plus => write!(f, "+"),
1330 Token::Eq => write!(f, "="),
1331 Token::Question => write!(f, "?"),
1332 Token::Comma => write!(f, ","),
1333 Token::Semicolon => write!(f, ";"),
1334 Token::Pipe => write!(f, "|"),
1335 Token::Underscore => write!(f, "_"),
1336 Token::Dot => write!(f, "."),
1337 Token::Bang => write!(f, "!"),
1338 Token::KwAs => write!(f, "as"),
1339 Token::KwAsync => write!(f, "async"),
1340 Token::KwDyn => write!(f, "dyn"),
1341 Token::KwUse => write!(f, "use"),
1342 Token::KwFor => write!(f, "for"),
1343 Token::KwMod => write!(f, "mod"),
1344 Token::KwCrate => write!(f, "crate"),
1345 Token::KwType => write!(f, "type"),
1346 Token::KwTrait => write!(f, "trait"),
1347 Token::KwFn => write!(f, "fn"),
1348 Token::KwMut => write!(f, "mut"),
1349 Token::KwConst => write!(f, "const"),
1350 Token::KwExtern => write!(f, "extern"),
1351 Token::KwImpl => write!(f, "impl"),
1352 Token::KwImport => write!(f, "import"),
1353 Token::KwMerge => write!(f, "merge"),
1354 Token::KwIf => write!(f, "if"),
1355 Token::KwElse => write!(f, "else"),
1356 Token::KwMatch => write!(f, "match"),
1357 Token::KwSafe => write!(f, "safe"),
1358 Token::KwUnsafe => write!(f, "unsafe"),
1359 Token::Ident(i) => write!(f, "{i}"),
1360 Token::Number(n) => write!(f, "{n}"),
1361 Token::Str(s) => write!(f, r#""{s}""#),
1362 }
1363 }
1364}
1365
1366fn lexer<'src>()
1367-> impl Parser<'src, &'src str, Vec<(Token<'src>, Span)>, extra::Err<Rich<'src, char, Span>>> {
1368 let token = choice((
1369 choice([
1370 just("->").to(Token::Arrow),
1371 just("=>").to(Token::ArrowArm),
1372 just("<").to(Token::AngleOpen),
1373 just(">").to(Token::AngleClose),
1374 just("[").to(Token::BracketOpen),
1375 just("]").to(Token::BracketClose),
1376 just("(").to(Token::ParenOpen),
1377 just(")").to(Token::ParenClose),
1378 just("{").to(Token::BraceOpen),
1379 just("}").to(Token::BraceClose),
1380 just("::").to(Token::ColonColon),
1381 just(":").to(Token::Colon),
1382 just("&").to(Token::And),
1383 just("*").to(Token::Star),
1384 just("#").to(Token::Sharp),
1385 just("+").to(Token::Plus),
1386 just("=").to(Token::Eq),
1387 just("?").to(Token::Question),
1388 just(",").to(Token::Comma),
1389 just(";").to(Token::Semicolon),
1390 just("|").to(Token::Pipe),
1391 just("_").to(Token::Underscore),
1392 just(".").to(Token::Dot),
1393 just("!").to(Token::Bang),
1394 ]),
1395 text::ident().map(Token::ident_or_kw),
1396 text::int(10).map(|x: &str| Token::Number(x.parse().unwrap())),
1397 just('"')
1398 .ignore_then(none_of('"').repeated().to_slice().map(Token::Str))
1399 .then_ignore(just('"')),
1400 ));
1401
1402 let comment = just("//")
1403 .then(any().and_is(just('\n').not()).repeated())
1404 .padded();
1405
1406 token
1407 .map_with(|tok, extra| (tok, extra.span()))
1408 .padded_by(comment.repeated())
1409 .padded()
1410 .repeated()
1411 .collect()
1412}
1413
1414fn alias<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone {
1415 just(Token::KwUse)
1416 .ignore_then(path())
1417 .then_ignore(just(Token::KwAs))
1418 .then(select! {
1419 Token::Ident(c) => c,
1420 })
1421 .then_ignore(just(Token::Semicolon))
1422 .map_with(|(path, name), extra| {
1423 ParsedItem::Alias(ParsedAlias {
1424 name,
1425 path,
1426 span: extra.span(),
1427 })
1428 })
1429 .boxed()
1430}
1431
1432fn file_parser<'a>()
1433-> impl Parser<'a, ParserInput<'a>, ParsedZngFile<'a>, ZngParserExtra<'a>> + Clone {
1434 item().repeated().collect::<Vec<_>>().map(ParsedZngFile)
1435}
1436
1437fn rust_type<'a>() -> Boxed<'a, 'a, ParserInput<'a>, ParsedRustType<'a>, ZngParserExtra<'a>> {
1438 let as_scalar = |s: &str, head: char| -> Option<u32> {
1439 let s = s.strip_prefix(head)?;
1440 s.parse().ok()
1441 };
1442
1443 let scalar = select! {
1444 Token::Ident("bool") => PrimitiveRustType::Bool,
1445 Token::Ident("str") => PrimitiveRustType::Str,
1446 Token::Ident("char") => PrimitiveRustType::Char,
1447 Token::Ident("usize") => PrimitiveRustType::Usize,
1448 Token::Ident(c) if as_scalar(c, 'u').is_some() => PrimitiveRustType::Uint(as_scalar(c, 'u').unwrap()),
1449 Token::Ident(c) if as_scalar(c, 'i').is_some() => PrimitiveRustType::Int(as_scalar(c, 'i').unwrap()),
1450 Token::Ident(c) if as_scalar(c, 'f').is_some() => PrimitiveRustType::Float(as_scalar(c, 'f').unwrap()),
1451 }.map(ParsedRustType::Primitive);
1452
1453 recursive(|parser| {
1454 let parser = parser.boxed();
1455 let pg = rust_path_and_generics(parser.clone());
1456 let adt = pg.clone().map(ParsedRustType::Adt);
1457
1458 let dyn_trait = just(Token::KwDyn)
1459 .or(just(Token::KwImpl))
1460 .then(rust_trait(parser.clone()))
1461 .then(
1462 just(Token::Plus)
1463 .ignore_then(select! {
1464 Token::Ident(c) => c,
1465 })
1466 .repeated()
1467 .collect::<Vec<_>>(),
1468 )
1469 .map(|((token, first), rest)| match token {
1470 Token::KwDyn => ParsedRustType::Dyn(first, rest),
1471 Token::KwImpl => ParsedRustType::Impl(first, rest),
1472 _ => unreachable!(),
1473 });
1474 let boxed = just(Token::Ident("Box"))
1475 .then(rust_generics(parser.clone()))
1476 .map(|(_, x)| {
1477 assert_eq!(x.len(), 1);
1478 ParsedRustType::Boxed(Box::new(x.into_iter().next().unwrap().right().unwrap()))
1479 });
1480 let unit = just(Token::ParenOpen)
1481 .then(just(Token::ParenClose))
1482 .map(|_| ParsedRustType::Tuple(vec![]));
1483 let tuple = parser
1484 .clone()
1485 .separated_by(just(Token::Comma))
1486 .allow_trailing()
1487 .collect::<Vec<_>>()
1488 .delimited_by(just(Token::ParenOpen), just(Token::ParenClose))
1489 .map(|xs| ParsedRustType::Tuple(xs));
1490 let slice = parser
1491 .clone()
1492 .map(|x| ParsedRustType::Slice(Box::new(x)))
1493 .delimited_by(just(Token::BracketOpen), just(Token::BracketClose));
1494 let reference = just(Token::And)
1495 .ignore_then(
1496 just(Token::KwMut)
1497 .to(Mutability::Mut)
1498 .or(empty().to(Mutability::Not)),
1499 )
1500 .then(parser.clone())
1501 .map(|(m, x)| ParsedRustType::Ref(m, Box::new(x)));
1502 let raw_ptr = just(Token::Star)
1503 .ignore_then(
1504 just(Token::KwMut)
1505 .to(Mutability::Mut)
1506 .or(just(Token::KwConst).to(Mutability::Not)),
1507 )
1508 .then(parser)
1509 .map(|(m, x)| ParsedRustType::Raw(m, Box::new(x)));
1510 choice((
1511 scalar, boxed, unit, tuple, slice, adt, reference, raw_ptr, dyn_trait,
1512 ))
1513 })
1514 .boxed()
1515}
1516
1517fn rust_generics<'a>(
1518 rust_type: Boxed<'a, 'a, ParserInput<'a>, ParsedRustType<'a>, ZngParserExtra<'a>>,
1519) -> impl Parser<
1520 'a,
1521 ParserInput<'a>,
1522 Vec<Either<(&'a str, ParsedRustType<'a>), ParsedRustType<'a>>>,
1523 ZngParserExtra<'a>,
1524> + Clone {
1525 let named_generic = select! {
1526 Token::Ident(c) => c,
1527 }
1528 .then_ignore(just(Token::Eq))
1529 .then(rust_type.clone())
1530 .map(Either::Left);
1531 just(Token::ColonColon).repeated().at_most(1).ignore_then(
1532 named_generic
1533 .or(rust_type.clone().map(Either::Right))
1534 .separated_by(just(Token::Comma))
1535 .allow_trailing()
1536 .collect::<Vec<_>>()
1537 .delimited_by(just(Token::AngleOpen), just(Token::AngleClose)),
1538 )
1539}
1540
1541fn rust_path_and_generics<'a>(
1542 rust_type: Boxed<'a, 'a, ParserInput<'a>, ParsedRustType<'a>, ZngParserExtra<'a>>,
1543) -> impl Parser<'a, ParserInput<'a>, ParsedRustPathAndGenerics<'a>, ZngParserExtra<'a>> + Clone {
1544 let generics = rust_generics(rust_type.clone());
1545 path()
1546 .then(generics.clone().repeated().at_most(1).collect::<Vec<_>>())
1547 .map(|x| {
1548 let generics = x.1.into_iter().next().unwrap_or_default();
1549 let (named_generics, generics) = generics.into_iter().partition_map(|x| x);
1550 ParsedRustPathAndGenerics {
1551 path: x.0,
1552 generics,
1553 named_generics,
1554 }
1555 })
1556}
1557
1558fn fn_args<'a>(
1559 rust_type: Boxed<'a, 'a, ParserInput<'a>, ParsedRustType<'a>, ZngParserExtra<'a>>,
1560) -> impl Parser<'a, ParserInput<'a>, (Vec<ParsedRustType<'a>>, ParsedRustType<'a>), ZngParserExtra<'a>>
1561+ Clone {
1562 rust_type
1563 .clone()
1564 .separated_by(just(Token::Comma))
1565 .allow_trailing()
1566 .collect::<Vec<_>>()
1567 .delimited_by(just(Token::ParenOpen), just(Token::ParenClose))
1568 .then(
1569 just(Token::Arrow)
1570 .ignore_then(rust_type)
1571 .or(empty().to(ParsedRustType::Tuple(vec![]))),
1572 )
1573 .boxed()
1574}
1575
1576fn spanned<'a, T>(
1577 parser: impl Parser<'a, ParserInput<'a>, T, ZngParserExtra<'a>> + Clone,
1578) -> impl Parser<'a, ParserInput<'a>, Spanned<T>, ZngParserExtra<'a>> + Clone {
1579 parser.map_with(|inner, extra| Spanned {
1580 inner,
1581 span: extra.span(),
1582 })
1583}
1584
1585fn rust_trait<'a>(
1586 rust_type: Boxed<'a, 'a, ParserInput<'a>, ParsedRustType<'a>, ZngParserExtra<'a>>,
1587) -> impl Parser<'a, ParserInput<'a>, ParsedRustTrait<'a>, ZngParserExtra<'a>> + Clone {
1588 let fn_trait = select! {
1589 Token::Ident(c) => c,
1590 }
1591 .then(fn_args(rust_type.clone()))
1592 .map(|x| ParsedRustTrait::Fn {
1593 name: x.0,
1594 inputs: x.1.0,
1595 output: Box::new(x.1.1),
1596 });
1597
1598 let rust_trait = fn_trait.or(rust_path_and_generics(rust_type).map(ParsedRustTrait::Normal));
1599 rust_trait
1600}
1601
1602fn method<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedMethod<'a>, ZngParserExtra<'a>> + Clone {
1603 spanned(just(Token::KwAsync))
1604 .or_not()
1605 .then_ignore(just(Token::KwFn))
1606 .then(select! {
1607 Token::Ident(c) => c,
1608 })
1609 .then(
1610 rust_type()
1611 .separated_by(just(Token::Comma))
1612 .collect::<Vec<_>>()
1613 .delimited_by(just(Token::AngleOpen), just(Token::AngleClose))
1614 .or(empty().to(vec![])),
1615 )
1616 .then(fn_args(rust_type()))
1617 .map(|(((opt_async, name), generics), args)| {
1618 let is_self = |c: &ParsedRustType<'_>| {
1619 if let ParsedRustType::Adt(c) = c {
1620 c.path.start == ParsedPathStart::Relative
1621 && &c.path.segments == &["self"]
1622 && c.generics.is_empty()
1623 } else {
1624 false
1625 }
1626 };
1627 let (inputs, receiver) = match args.0.get(0) {
1628 Some(x) if is_self(&x) => (args.0[1..].to_vec(), ZngurMethodReceiver::Move),
1629 Some(ParsedRustType::Ref(m, x)) if is_self(&x) => {
1630 (args.0[1..].to_vec(), ZngurMethodReceiver::Ref(*m))
1631 }
1632 _ => (args.0, ZngurMethodReceiver::Static),
1633 };
1634 let mut output = args.1;
1635 if let Some(async_kw) = opt_async {
1636 output = ParsedRustType::Impl(
1637 ParsedRustTrait::Normal(ParsedRustPathAndGenerics {
1638 path: ParsedPath {
1639 start: ParsedPathStart::Absolute,
1640 segments: vec!["std", "future", "Future"],
1641 span: async_kw.span,
1642 },
1643 generics: vec![],
1644 named_generics: vec![("Output", output)],
1645 }),
1646 vec![],
1647 )
1648 }
1649 ParsedMethod {
1650 name,
1651 receiver,
1652 generics,
1653 inputs,
1654 output,
1655 }
1656 })
1657}
1658
1659fn inner_type_item<'a>()
1660-> impl Parser<'a, ParserInput<'a>, ParsedTypeItem<'a>, ZngParserExtra<'a>> + Clone {
1661 let property_item = (spanned(select! {
1662 Token::Ident(c) => c,
1663 }))
1664 .then_ignore(just(Token::Eq))
1665 .then(select! {
1666 Token::Number(c) => c,
1667 });
1668 let layout = just([Token::Sharp, Token::Ident("layout")])
1669 .ignore_then(
1670 property_item
1671 .clone()
1672 .separated_by(just(Token::Comma))
1673 .collect::<Vec<_>>()
1674 .delimited_by(just(Token::ParenOpen), just(Token::ParenClose)),
1675 )
1676 .map(ParsedLayoutPolicy::StackAllocated)
1677 .or(just([Token::Sharp, Token::Ident("layout_conservative")])
1678 .ignore_then(
1679 property_item
1680 .clone()
1681 .separated_by(just(Token::Comma))
1682 .collect::<Vec<_>>()
1683 .delimited_by(just(Token::ParenOpen), just(Token::ParenClose)),
1684 )
1685 .map(ParsedLayoutPolicy::Conservative))
1686 .or(just([Token::Sharp, Token::Ident("only_by_ref")]).to(ParsedLayoutPolicy::OnlyByRef))
1687 .or(just([Token::Sharp, Token::Ident("heap_allocated")])
1688 .to(ParsedLayoutPolicy::HeapAllocated))
1689 .map_with(|x, extra| ParsedTypeItem::Layout(extra.span(), x))
1690 .boxed();
1691 let trait_item = select! {
1692 Token::Ident("Debug") => ZngurWellknownTrait::Debug,
1693 Token::Ident("Copy") => ZngurWellknownTrait::Copy,
1694 }
1695 .or(just(Token::Question)
1696 .then(just(Token::Ident("Sized")))
1697 .to(ZngurWellknownTrait::Unsized));
1698 let traits = just(Token::Ident("wellknown_traits"))
1699 .ignore_then(
1700 spanned(trait_item)
1701 .separated_by(just(Token::Comma))
1702 .collect::<Vec<_>>()
1703 .delimited_by(just(Token::ParenOpen), just(Token::ParenClose)),
1704 )
1705 .map(ParsedTypeItem::Traits)
1706 .boxed();
1707 let constructor_args = rust_type()
1708 .separated_by(just(Token::Comma))
1709 .collect::<Vec<_>>()
1710 .delimited_by(just(Token::ParenOpen), just(Token::ParenClose))
1711 .map(ParsedConstructorArgs::Tuple)
1712 .or((select! {
1713 Token::Ident(c) => c,
1714 })
1715 .boxed()
1716 .then_ignore(just(Token::Colon))
1717 .then(rust_type())
1718 .separated_by(just(Token::Comma))
1719 .collect::<Vec<_>>()
1720 .delimited_by(just(Token::BraceOpen), just(Token::BraceClose))
1721 .map(ParsedConstructorArgs::Named))
1722 .or(empty().to(ParsedConstructorArgs::Unit))
1723 .boxed();
1724 let constructor = just(Token::Ident("constructor")).ignore_then(
1725 (select! {
1726 Token::Ident(c) => Some(c),
1727 })
1728 .or(empty().to(None))
1729 .then(constructor_args)
1730 .map(|(name, args)| ParsedTypeItem::Constructor { name, args }),
1731 );
1732 let field = just(Token::Ident("field")).ignore_then(
1733 (select! {
1734 Token::Ident(c) => c.to_owned(),
1735 Token::Number(c) => c.to_string(),
1736 })
1737 .then(
1738 just(Token::Ident("offset"))
1739 .then(just(Token::Eq))
1740 .ignore_then(select! {
1741 Token::Number(c) => Some(c),
1742 Token::Ident("auto") => None,
1743 })
1744 .then(
1745 just(Token::Comma)
1746 .then(just(Token::KwType))
1747 .then(just(Token::Eq))
1748 .ignore_then(rust_type()),
1749 )
1750 .delimited_by(just(Token::ParenOpen), just(Token::ParenClose)),
1751 )
1752 .map(|(name, (offset, ty))| ParsedTypeItem::Field { name, ty, offset }),
1753 );
1754 let cpp_value = just(Token::Sharp)
1755 .then(just(Token::Ident("cpp_value")))
1756 .ignore_then(select! {
1757 Token::Str(c) => c,
1758 })
1759 .then(select! {
1760 Token::Str(c) => c,
1761 })
1762 .map(|x| ParsedTypeItem::CppValue {
1763 field: x.0,
1764 cpp_type: x.1,
1765 });
1766 let cpp_ref = just(Token::Sharp)
1767 .then(just(Token::Ident("cpp_ref")))
1768 .ignore_then(select! {
1769 Token::Str(c) => c,
1770 })
1771 .map(|x| ParsedTypeItem::CppRef { cpp_type: x });
1772 let cpp_stack_owned = just(Token::Sharp)
1773 .then(just(Token::Ident("cpp_stack_owned")))
1774 .ignore_then(select! {
1775 Token::Str(c) => c,
1776 })
1777 .then(
1778 property_item
1779 .clone()
1780 .separated_by(just(Token::Comma))
1781 .collect::<Vec<_>>()
1782 .delimited_by(just(Token::ParenOpen), just(Token::ParenClose)),
1783 )
1784 .map(|(cpp_type, props)| ParsedTypeItem::CppStackOwned { cpp_type, props });
1785 recursive(|item| {
1786 let inner_item = choice((
1787 layout,
1788 traits,
1789 constructor,
1790 field,
1791 cpp_value,
1792 cpp_ref,
1793 cpp_stack_owned,
1794 method()
1795 .then(
1796 just(Token::KwUse)
1797 .ignore_then(path())
1798 .map(Some)
1799 .or(empty().to(None)),
1800 )
1801 .then(
1802 just(Token::Ident("deref"))
1803 .ignore_then(rust_type())
1804 .map(Some)
1805 .or(empty().to(None)),
1806 )
1807 .map(|((data, use_path), deref)| ParsedTypeItem::Method {
1808 deref,
1809 use_path,
1810 data,
1811 }),
1812 ));
1813
1814 let match_stmt =
1815 conditional_item::<_, CfgConditional<'a>, NItems>(item).map(ParsedTypeItem::MatchOnCfg);
1816
1817 choice((match_stmt, inner_item.then_ignore(just(Token::Semicolon))))
1818 })
1819}
1820
1821fn type_item<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone {
1822 just(Token::KwType)
1823 .ignore_then(spanned(rust_type()))
1824 .then(
1825 spanned(inner_type_item())
1826 .repeated()
1827 .collect::<Vec<_>>()
1828 .delimited_by(just(Token::BraceOpen), just(Token::BraceClose)),
1829 )
1830 .map(|(ty, items)| ParsedItem::Type { ty, items })
1831 .boxed()
1832}
1833
1834fn trait_item<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone
1835{
1836 just(Token::KwTrait)
1837 .ignore_then(spanned(rust_trait(rust_type())))
1838 .then(
1839 method()
1840 .then_ignore(just(Token::Semicolon))
1841 .repeated()
1842 .collect::<Vec<_>>()
1843 .delimited_by(just(Token::BraceOpen), just(Token::BraceClose)),
1844 )
1845 .map(|(tr, methods)| ParsedItem::Trait { tr, methods })
1846 .boxed()
1847}
1848
1849fn fn_item<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone {
1850 spanned(method())
1851 .then_ignore(just(Token::Semicolon))
1852 .map(ParsedItem::Fn)
1853}
1854
1855fn additional_include_item<'a>()
1856-> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone {
1857 just(Token::Sharp)
1858 .ignore_then(choice((
1859 just(Token::Ident("cpp_additional_includes")).ignore_then(select! {
1860 Token::Str(c) => ParsedItem::CppAdditionalInclude(c),
1861 }),
1862 just(Token::Ident("convert_panic_to_exception"))
1863 .map_with(|_, extra| ParsedItem::ConvertPanicToException(extra.span())),
1864 )))
1865 .boxed()
1866}
1867
1868fn extern_cpp_item<'a>()
1869-> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone {
1870 let safety = choice((
1871 just(Token::KwSafe).to(true),
1872 just(Token::KwUnsafe).to(false),
1873 ));
1874 let function = safety
1875 .clone()
1876 .then(spanned(method()))
1877 .then_ignore(just(Token::Semicolon))
1878 .map(|(is_safe, method)| ParsedExternCppItem::Function { is_safe, method });
1879 let impl_block = just(Token::KwImpl)
1880 .ignore_then(
1881 rust_trait(rust_type())
1882 .then_ignore(just(Token::KwFor))
1883 .map(Some)
1884 .or(empty().to(None))
1885 .then(spanned(rust_type())),
1886 )
1887 .then(
1888 safety
1889 .then(method())
1890 .then_ignore(just(Token::Semicolon))
1891 .repeated()
1892 .collect::<Vec<_>>()
1893 .delimited_by(just(Token::BraceOpen), just(Token::BraceClose)),
1894 )
1895 .map(|((tr, ty), methods)| ParsedExternCppItem::Impl { tr, ty, methods });
1896 just(Token::KwExtern)
1897 .then(just(Token::Str("C++")))
1898 .ignore_then(
1899 function
1900 .or(impl_block)
1901 .repeated()
1902 .collect::<Vec<_>>()
1903 .delimited_by(just(Token::BraceOpen), just(Token::BraceClose))
1904 .boxed(),
1905 )
1906 .map(ParsedItem::ExternCpp)
1907 .boxed()
1908}
1909
1910fn unstable_feature<'a>()
1911-> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone {
1912 just([Token::Sharp, Token::Ident("unstable")]).ignore_then(
1913 select! { Token::Ident(feat) => feat }
1914 .delimited_by(just(Token::ParenOpen), just(Token::ParenClose))
1915 .try_map_with(|feat, e| match feat {
1916 "cfg_match" => {
1917 let ctx: &mut extra::SimpleState<ZngParserState> = e.state();
1918 ctx.unstable_features.cfg_match = true;
1919 Ok(ParsedItem::UnstableFeature("cfg_match"))
1920 }
1921 "cfg_if" => {
1922 let ctx: &mut extra::SimpleState<ZngParserState> = e.state();
1923 ctx.unstable_features.cfg_if = true;
1924 Ok(ParsedItem::UnstableFeature("cfg_if"))
1925 }
1926 _ => Err(Rich::custom(
1927 e.span(),
1928 format!("unknown unstable feature '{feat}'"),
1929 )),
1930 }),
1931 )
1932}
1933
1934fn item<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone {
1935 recursive(|item| {
1936 choice((
1937 unstable_feature(),
1938 just(Token::KwMod)
1939 .ignore_then(path())
1940 .then(
1941 item.clone()
1942 .repeated()
1943 .collect::<Vec<_>>()
1944 .delimited_by(just(Token::BraceOpen), just(Token::BraceClose)),
1945 )
1946 .map(|(path, items)| ParsedItem::Mod { path, items }),
1947 type_item(),
1948 trait_item(),
1949 extern_cpp_item(),
1950 fn_item(),
1951 additional_include_item(),
1952 import_item(),
1953 module_import_item(),
1954 alias(),
1955 conditional_item::<_, CfgConditional<'a>, NItems>(item).map(ParsedItem::MatchOnCfg),
1956 ))
1957 })
1958 .boxed()
1959}
1960
1961fn import_item<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone
1962{
1963 just(Token::KwMerge)
1964 .ignore_then(select! {
1965 Token::Str(path) => path,
1966 })
1967 .then_ignore(just(Token::Semicolon))
1968 .map_with(|path, extra| {
1969 ParsedItem::Import(ParsedImportPath {
1970 path: std::path::PathBuf::from(path),
1971 span: extra.span(),
1972 })
1973 })
1974 .boxed()
1975}
1976
1977fn module_import_item<'a>()
1978-> impl Parser<'a, ParserInput<'a>, ParsedItem<'a>, ZngParserExtra<'a>> + Clone {
1979 just(Token::KwImport)
1980 .ignore_then(select! { Token::Str(path) => path })
1981 .then_ignore(just(Token::Semicolon))
1982 .map_with(|path, extra| ParsedItem::ModuleImport {
1983 path: std::path::PathBuf::from(path),
1984 span: extra.span(),
1985 })
1986 .boxed()
1987}
1988
1989fn path<'a>() -> impl Parser<'a, ParserInput<'a>, ParsedPath<'a>, ZngParserExtra<'a>> + Clone {
1990 let start = choice((
1991 just(Token::ColonColon).to(ParsedPathStart::Absolute),
1992 just(Token::KwCrate)
1993 .then(just(Token::ColonColon))
1994 .to(ParsedPathStart::Crate),
1995 empty().to(ParsedPathStart::Relative),
1996 ));
1997
1998 start
1999 .then(
2000 (select! {
2001 Token::Ident(c) => c,
2002 })
2003 .separated_by(just(Token::ColonColon))
2004 .at_least(1)
2005 .collect::<Vec<_>>(),
2006 )
2007 .or(just(Token::KwCrate).to((ParsedPathStart::Crate, vec![])))
2008 .map_with(|(start, segments), extra| ParsedPath {
2009 start,
2010 segments,
2011 span: extra.span(),
2012 })
2013 .boxed()
2014}
2015
2016impl<'a> conditional::BodyItem for crate::ParsedTypeItem<'a> {
2017 type Processed = Self;
2018
2019 fn process(self, _ctx: &mut ParseContext) -> Self::Processed {
2020 self
2021 }
2022}
2023
2024impl<'a> conditional::BodyItem for crate::ParsedItem<'a> {
2025 type Processed = ProcessedItemOrAlias<'a>;
2026
2027 fn process(self, ctx: &mut ParseContext) -> Self::Processed {
2028 crate::process_parsed_item(self, ctx)
2029 }
2030}