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