Skip to main content

wit_parser/
ast.rs

1use crate::ast::error::ParseError;
2use crate::{AccessorKind, ParseResult, UnresolvedPackage, UnresolvedPackageGroup};
3use alloc::borrow::Cow;
4use alloc::boxed::Box;
5use alloc::format;
6use alloc::string::{String, ToString};
7use alloc::vec::Vec;
8#[cfg(feature = "std")]
9use anyhow::Context as _;
10use core::fmt;
11use core::mem;
12use core::result::Result;
13use lex::{Span, Token, Tokenizer};
14use semver::Version;
15#[cfg(feature = "std")]
16use std::path::Path;
17
18pub mod error;
19pub mod lex;
20
21pub use resolve::Resolver;
22mod resolve;
23pub mod toposort;
24
25pub use lex::validate_id;
26
27/// Representation of a single WIT `*.wit` file and nested packages.
28struct PackageFile<'a> {
29    /// Optional `package foo:bar;` header
30    package_id: Option<PackageName<'a>>,
31    /// Other AST items.
32    decl_list: DeclList<'a>,
33}
34
35/// Maximum nesting depth of `package { ... }` scopes.
36const MAX_ITEM_DEPTH: usize = 100;
37
38impl<'a> PackageFile<'a> {
39    /// Parse a standalone file represented by `tokens`.
40    ///
41    /// This will optionally start with `package foo:bar;` and then will have a
42    /// list of ast items after it.
43    fn parse(tokens: &mut Tokenizer<'a>) -> ParseResult<Self> {
44        let mut package_name_tokens_peek = tokens.clone();
45        let docs = parse_docs(&mut package_name_tokens_peek)?;
46
47        // Parse `package foo:bar;` but throw it out if it's actually
48        // `package foo:bar { ... }` since that's an ast item instead.
49        let package_id = if package_name_tokens_peek.eat(Token::Package)? {
50            let name = PackageName::parse(&mut package_name_tokens_peek, docs)?;
51            if package_name_tokens_peek.eat(Token::Semicolon)? {
52                *tokens = package_name_tokens_peek;
53                Some(name)
54            } else {
55                None
56            }
57        } else {
58            None
59        };
60        let decl_list = DeclList::parse_until(tokens, None, 0)?;
61        Ok(PackageFile {
62            package_id,
63            decl_list,
64        })
65    }
66
67    /// Parse a nested package of the form `package foo:bar { ... }`
68    fn parse_nested(
69        tokens: &mut Tokenizer<'a>,
70        docs: Docs<'a>,
71        attributes: Vec<Attribute<'a>>,
72        depth: usize,
73    ) -> ParseResult<Self> {
74        let span = tokens.expect(Token::Package)?;
75        if !attributes.is_empty() {
76            return Err(ParseError::new_syntax(
77                span,
78                format!("cannot place attributes on nested packages"),
79            ));
80        }
81        if depth >= MAX_ITEM_DEPTH {
82            return Err(ParseError::new_syntax(span, "package nesting too deep"));
83        }
84        let package_id = PackageName::parse(tokens, docs)?;
85        tokens.expect(Token::LeftBrace)?;
86        let decl_list = DeclList::parse_until(tokens, Some(Token::RightBrace), depth + 1)?;
87        Ok(PackageFile {
88            package_id: Some(package_id),
89            decl_list,
90        })
91    }
92}
93
94/// Stores all of the declarations in a package's scope. In AST terms, this
95/// means everything except the `package` declaration that demarcates a package
96/// scope. In the traditional implicit format, these are all of the declarations
97/// non-`package` declarations in the file:
98///
99/// ```wit
100/// package foo:name;
101///
102/// /* START DECL LIST */
103/// // Some comment...
104/// interface i {}
105/// world w {}
106/// /* END DECL LIST */
107/// ```
108///
109/// In the nested package style, a [`DeclList`] is everything inside of each
110/// `package` element's brackets:
111///
112/// ```wit
113/// package foo:name {
114///   /* START FIRST DECL LIST */
115///   // Some comment...
116///   interface i {}
117///   world w {}
118///   /* END FIRST DECL LIST */
119/// }
120///
121/// package bar:name {
122///   /* START SECOND DECL LIST */
123///   // Some comment...
124///   interface i {}
125///   world w {}
126///   /* END SECOND DECL LIST */
127/// }
128/// ```
129#[derive(Default)]
130pub struct DeclList<'a> {
131    items: Vec<AstItem<'a>>,
132}
133
134impl<'a> DeclList<'a> {
135    fn parse_until(
136        tokens: &mut Tokenizer<'a>,
137        end: Option<Token>,
138        depth: usize,
139    ) -> ParseResult<DeclList<'a>> {
140        let mut items = Vec::new();
141        let mut docs = parse_docs(tokens)?;
142        loop {
143            match end {
144                Some(end) => {
145                    if tokens.eat(end)? {
146                        break;
147                    }
148                }
149                None => {
150                    if tokens.clone().next()?.is_none() {
151                        break;
152                    }
153                }
154            }
155            items.push(AstItem::parse(tokens, docs, depth)?);
156            docs = parse_docs(tokens)?;
157        }
158        Ok(DeclList { items })
159    }
160
161    fn for_each_path<'b>(
162        &'b self,
163        f: &mut dyn FnMut(
164            Option<&'b Id<'a>>,
165            &'b [Attribute<'a>],
166            &'b UsePath<'a>,
167            Option<&'b [UseName<'a>]>,
168            WorldOrInterface,
169        ) -> ParseResult<()>,
170    ) -> ParseResult<()> {
171        for item in self.items.iter() {
172            match item {
173                AstItem::World(world) => {
174                    // Visit imports here first before exports to help preserve
175                    // round-tripping of documents because printing a world puts
176                    // imports first but textually they can be listed with
177                    // exports first.
178                    let mut imports = Vec::new();
179                    let mut exports = Vec::new();
180                    for item in world.items.iter() {
181                        match item {
182                            WorldItem::Use(u) => f(
183                                None,
184                                &u.attributes,
185                                &u.from,
186                                Some(&u.names),
187                                WorldOrInterface::Interface,
188                            )?,
189                            WorldItem::Include(i) => f(
190                                Some(&world.name),
191                                &i.attributes,
192                                &i.from,
193                                None,
194                                WorldOrInterface::World,
195                            )?,
196                            WorldItem::Type(_) => {}
197                            WorldItem::Import(Import {
198                                kind, attributes, ..
199                            }) => imports.push((kind, attributes)),
200                            WorldItem::Export(Export {
201                                kind, attributes, ..
202                            }) => exports.push((kind, attributes)),
203                        }
204                    }
205
206                    let mut visit_kind =
207                        |kind: &'b ExternKind<'a>, attrs: &'b [Attribute<'a>]| match kind {
208                            ExternKind::Interface(_, items) => {
209                                for item in items {
210                                    match item {
211                                        InterfaceItem::Use(u) => f(
212                                            None,
213                                            &u.attributes,
214                                            &u.from,
215                                            Some(&u.names),
216                                            WorldOrInterface::Interface,
217                                        )?,
218                                        _ => {}
219                                    }
220                                }
221                                Ok(())
222                            }
223                            ExternKind::Path(path) | ExternKind::NamedPath(_, path) => {
224                                f(None, attrs, path, None, WorldOrInterface::Interface)
225                            }
226                            ExternKind::Func(..) => Ok(()),
227                        };
228
229                    for (kind, attrs) in imports {
230                        visit_kind(kind, attrs)?;
231                    }
232                    for (kind, attrs) in exports {
233                        visit_kind(kind, attrs)?;
234                    }
235                }
236                AstItem::Interface(i) => {
237                    for item in i.items.iter() {
238                        match item {
239                            InterfaceItem::Use(u) => f(
240                                Some(&i.name),
241                                &u.attributes,
242                                &u.from,
243                                Some(&u.names),
244                                WorldOrInterface::Interface,
245                            )?,
246                            _ => {}
247                        }
248                    }
249                }
250                AstItem::Use(u) => {
251                    // At the top-level, we don't know if this is a world or an interface
252                    // It is up to the resolver to decides how to handle this ambiguity.
253                    f(
254                        None,
255                        &u.attributes,
256                        &u.item,
257                        None,
258                        WorldOrInterface::Unknown,
259                    )?;
260                }
261
262                AstItem::Package(pkg) => pkg.decl_list.for_each_path(f)?,
263            }
264        }
265        Ok(())
266    }
267}
268
269enum AstItem<'a> {
270    Interface(Interface<'a>),
271    World(World<'a>),
272    Use(ToplevelUse<'a>),
273    Package(PackageFile<'a>),
274}
275
276impl<'a> AstItem<'a> {
277    fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>, depth: usize) -> ParseResult<Self> {
278        let attributes = Attribute::parse_list(tokens)?;
279        match tokens.clone().next()? {
280            Some((_span, Token::Interface)) => {
281                Interface::parse(tokens, docs, attributes).map(Self::Interface)
282            }
283            Some((_span, Token::World)) => World::parse(tokens, docs, attributes).map(Self::World),
284            Some((_span, Token::Use)) => ToplevelUse::parse(tokens, attributes).map(Self::Use),
285            Some((_span, Token::Package)) => {
286                PackageFile::parse_nested(tokens, docs, attributes, depth).map(Self::Package)
287            }
288            other => Err(err_expected(tokens, "`world`, `interface` or `use`", other).into()),
289        }
290    }
291}
292
293#[derive(Debug, Clone)]
294struct PackageName<'a> {
295    docs: Docs<'a>,
296    span: Span,
297    namespace: Id<'a>,
298    name: Id<'a>,
299    version: Option<(Span, Version)>,
300}
301
302impl<'a> PackageName<'a> {
303    fn parse(tokens: &mut Tokenizer<'a>, docs: Docs<'a>) -> ParseResult<Self> {
304        let namespace = parse_id(tokens)?;
305        tokens.expect(Token::Colon)?;
306        let name = parse_id(tokens)?;
307        let version = parse_opt_version(tokens)?;
308        Ok(PackageName {
309            docs,
310            span: Span::new(
311                namespace.span.start(),
312                version
313                    .as_ref()
314                    .map(|(s, _)| s.end())
315                    .unwrap_or(name.span.end()),
316            ),
317            namespace,
318            name,
319            version,
320        })
321    }
322
323    fn package_name(&self) -> crate::PackageName {
324        crate::PackageName {
325            namespace: self.namespace.name.to_string(),
326            name: self.name.name.to_string(),
327            version: self.version.as_ref().map(|(_, v)| v.clone()),
328        }
329    }
330}
331
332struct ToplevelUse<'a> {
333    span: Span,
334    attributes: Vec<Attribute<'a>>,
335    item: UsePath<'a>,
336    as_: Option<Id<'a>>,
337}
338
339impl<'a> ToplevelUse<'a> {
340    fn parse(tokens: &mut Tokenizer<'a>, attributes: Vec<Attribute<'a>>) -> ParseResult<Self> {
341        let span = tokens.expect(Token::Use)?;
342        let item = UsePath::parse(tokens)?;
343        let as_ = if tokens.eat(Token::As)? {
344            Some(parse_id(tokens)?)
345        } else {
346            None
347        };
348        tokens.expect_semicolon()?;
349        Ok(ToplevelUse {
350            span,
351            attributes,
352            item,
353            as_,
354        })
355    }
356}
357
358struct World<'a> {
359    docs: Docs<'a>,
360    attributes: Vec<Attribute<'a>>,
361    name: Id<'a>,
362    items: Vec<WorldItem<'a>>,
363}
364
365impl<'a> World<'a> {
366    fn parse(
367        tokens: &mut Tokenizer<'a>,
368        docs: Docs<'a>,
369        attributes: Vec<Attribute<'a>>,
370    ) -> ParseResult<Self> {
371        Attribute::reject_external_id(&attributes, "world declarations")?;
372        tokens.expect(Token::World)?;
373        let name = parse_id(tokens)?;
374        let items = Self::parse_items(tokens)?;
375        Ok(World {
376            docs,
377            attributes,
378            name,
379            items,
380        })
381    }
382
383    fn parse_items(tokens: &mut Tokenizer<'a>) -> ParseResult<Vec<WorldItem<'a>>> {
384        tokens.expect(Token::LeftBrace)?;
385        let mut items = Vec::new();
386        loop {
387            let docs = parse_docs(tokens)?;
388            if tokens.eat(Token::RightBrace)? {
389                break;
390            }
391            let attributes = Attribute::parse_list(tokens)?;
392            items.push(WorldItem::parse(tokens, docs, attributes)?);
393        }
394        Ok(items)
395    }
396}
397
398enum WorldItem<'a> {
399    Import(Import<'a>),
400    Export(Export<'a>),
401    Use(Use<'a>),
402    Type(TypeDef<'a>),
403    Include(Include<'a>),
404}
405
406impl<'a> WorldItem<'a> {
407    fn parse(
408        tokens: &mut Tokenizer<'a>,
409        docs: Docs<'a>,
410        attributes: Vec<Attribute<'a>>,
411    ) -> ParseResult<WorldItem<'a>> {
412        match tokens.clone().next()? {
413            Some((_span, Token::Import)) => {
414                Import::parse(tokens, docs, attributes).map(WorldItem::Import)
415            }
416            Some((_span, Token::Export)) => {
417                Export::parse(tokens, docs, attributes).map(WorldItem::Export)
418            }
419            Some((_span, Token::Use)) => Use::parse(tokens, attributes).map(WorldItem::Use),
420            Some((_span, Token::Type)) => {
421                TypeDef::parse(tokens, docs, attributes).map(WorldItem::Type)
422            }
423            Some((_span, Token::Flags)) => {
424                TypeDef::parse_flags(tokens, docs, attributes).map(WorldItem::Type)
425            }
426            Some((_span, Token::Resource)) => {
427                TypeDef::parse_resource(tokens, docs, attributes).map(WorldItem::Type)
428            }
429            Some((_span, Token::Record)) => {
430                TypeDef::parse_record(tokens, docs, attributes).map(WorldItem::Type)
431            }
432            Some((_span, Token::Variant)) => {
433                TypeDef::parse_variant(tokens, docs, attributes).map(WorldItem::Type)
434            }
435            Some((_span, Token::Enum)) => {
436                TypeDef::parse_enum(tokens, docs, attributes).map(WorldItem::Type)
437            }
438            Some((_span, Token::Include)) => {
439                Include::parse(tokens, attributes).map(WorldItem::Include)
440            }
441            other => Err(err_expected(
442                tokens,
443                "`import`, `export`, `include`, `use`, or type definition",
444                other,
445            )
446            .into()),
447        }
448    }
449}
450
451struct Import<'a> {
452    docs: Docs<'a>,
453    attributes: Vec<Attribute<'a>>,
454    kind: ExternKind<'a>,
455}
456
457impl<'a> Import<'a> {
458    fn parse(
459        tokens: &mut Tokenizer<'a>,
460        docs: Docs<'a>,
461        attributes: Vec<Attribute<'a>>,
462    ) -> ParseResult<Import<'a>> {
463        tokens.expect(Token::Import)?;
464        let kind = ExternKind::parse(tokens)?;
465        Ok(Import {
466            docs,
467            attributes,
468            kind,
469        })
470    }
471}
472
473struct Export<'a> {
474    docs: Docs<'a>,
475    attributes: Vec<Attribute<'a>>,
476    kind: ExternKind<'a>,
477}
478
479impl<'a> Export<'a> {
480    fn parse(
481        tokens: &mut Tokenizer<'a>,
482        docs: Docs<'a>,
483        attributes: Vec<Attribute<'a>>,
484    ) -> ParseResult<Export<'a>> {
485        tokens.expect(Token::Export)?;
486        let kind = ExternKind::parse(tokens)?;
487        Ok(Export {
488            docs,
489            attributes,
490            kind,
491        })
492    }
493}
494
495enum ExternKind<'a> {
496    Interface(Id<'a>, Vec<InterfaceItem<'a>>),
497    Path(UsePath<'a>),
498    Func(Id<'a>, Func<'a>),
499    /// `label: use-path` — a named import/export that implements an interface.
500    NamedPath(Id<'a>, UsePath<'a>),
501}
502
503impl<'a> ExternKind<'a> {
504    fn parse(tokens: &mut Tokenizer<'a>) -> ParseResult<ExternKind<'a>> {
505        // Create a copy of the token stream to test out if this is a function
506        // or an interface import. In those situations the token stream gets
507        // reset to the state of the clone and we continue down those paths.
508        //
509        // If neither a function nor an interface appears here though then the
510        // clone is thrown away and the original token stream is parsed for an
511        // interface. This will redo the original ID parse and the original
512        // colon parse, but that shouldn't be too bad perf-wise.
513        let mut clone = tokens.clone();
514        let id = parse_id(&mut clone)?;
515        if clone.eat(Token::Colon)? {
516            // import foo: async? func(...)
517            // import foo: get(...) / import foo: set(...)
518            if clone.clone().eat(Token::Func)?
519                || clone.clone().eat(Token::Async)?
520                || eat_accessor_token(&mut clone.clone())?.is_some()
521            {
522                *tokens = clone;
523                let ret = ExternKind::Func(id, Func::parse(tokens)?);
524                tokens.expect_semicolon()?;
525                return Ok(ret);
526            }
527
528            // import foo: interface { ... }
529            if clone.eat(Token::Interface)? {
530                *tokens = clone;
531                return Ok(ExternKind::Interface(id, Interface::parse_items(tokens)?));
532            }
533
534            // import label: use-path
535            // At this point we consumed `id:` on the clone but the next token
536            // is not `func`, `async`, or `interface`. This could be either:
537            //   import label: local-iface;          (NamedPath)
538            //   import label: pkg:name/iface;       (NamedPath with package path)
539            //   import ns:pkg/iface;                (regular fully-qualified Path)
540            //
541            // Disambiguate: if the next tokens are `id /`, then the colon was
542            // part of a fully-qualified `namespace:package/interface` name, not
543            // a label separator. Fall through to the Path parser in that case.
544            let mut peek = clone.clone();
545            let is_qualified_path =
546                parse_id(&mut peek).is_ok() && peek.clone().eat(Token::Slash).unwrap_or(false);
547            if !is_qualified_path {
548                *tokens = clone;
549                let path = UsePath::parse(tokens)?;
550                tokens.expect_semicolon()?;
551                return Ok(ExternKind::NamedPath(id, path));
552            }
553        }
554
555        // import foo
556        // import foo/bar
557        // import foo:bar/baz
558        let ret = ExternKind::Path(UsePath::parse(tokens)?);
559        tokens.expect_semicolon()?;
560        Ok(ret)
561    }
562
563    fn span(&self) -> Span {
564        match self {
565            ExternKind::Interface(id, _) => id.span,
566            ExternKind::Path(UsePath::Id(id)) => id.span,
567            ExternKind::Path(UsePath::Package { name, .. }) => name.span,
568            ExternKind::Func(id, _) => id.span,
569            ExternKind::NamedPath(id, _) => id.span,
570        }
571    }
572}
573
574struct Interface<'a> {
575    docs: Docs<'a>,
576    attributes: Vec<Attribute<'a>>,
577    name: Id<'a>,
578    items: Vec<InterfaceItem<'a>>,
579}
580
581impl<'a> Interface<'a> {
582    fn parse(
583        tokens: &mut Tokenizer<'a>,
584        docs: Docs<'a>,
585        attributes: Vec<Attribute<'a>>,
586    ) -> ParseResult<Self> {
587        Attribute::reject_external_id(&attributes, "interface declarations")?;
588        tokens.expect(Token::Interface)?;
589        let name = parse_id(tokens)?;
590        let items = Self::parse_items(tokens)?;
591        Ok(Interface {
592            docs,
593            attributes,
594            name,
595            items,
596        })
597    }
598
599    pub(super) fn parse_items(tokens: &mut Tokenizer<'a>) -> ParseResult<Vec<InterfaceItem<'a>>> {
600        tokens.expect(Token::LeftBrace)?;
601        let mut items = Vec::new();
602        loop {
603            let docs = parse_docs(tokens)?;
604            if tokens.eat(Token::RightBrace)? {
605                break;
606            }
607            let attributes = Attribute::parse_list(tokens)?;
608            items.push(InterfaceItem::parse(tokens, docs, attributes)?);
609        }
610        Ok(items)
611    }
612}
613
614#[derive(Debug)]
615pub enum WorldOrInterface {
616    World,
617    Interface,
618    Unknown,
619}
620
621enum InterfaceItem<'a> {
622    TypeDef(TypeDef<'a>),
623    Func(NamedFunc<'a>),
624    Use(Use<'a>),
625}
626
627struct Use<'a> {
628    attributes: Vec<Attribute<'a>>,
629    from: UsePath<'a>,
630    names: Vec<UseName<'a>>,
631}
632
633#[derive(Debug)]
634enum UsePath<'a> {
635    Id(Id<'a>),
636    Package { id: PackageName<'a>, name: Id<'a> },
637}
638
639impl<'a> UsePath<'a> {
640    fn parse(tokens: &mut Tokenizer<'a>) -> ParseResult<Self> {
641        let id = parse_id(tokens)?;
642        if tokens.eat(Token::Colon)? {
643            // `foo:bar/baz@1.0`
644            let namespace = id;
645            let pkg_name = parse_id(tokens)?;
646            tokens.expect(Token::Slash)?;
647            let name = parse_id(tokens)?;
648            let version = parse_opt_version(tokens)?;
649            Ok(UsePath::Package {
650                id: PackageName {
651                    docs: Default::default(),
652                    span: Span::new(namespace.span.start(), pkg_name.span.end()),
653                    namespace,
654                    name: pkg_name,
655                    version,
656                },
657                name,
658            })
659        } else {
660            // `foo`
661            Ok(UsePath::Id(id))
662        }
663    }
664
665    fn name(&self) -> &Id<'a> {
666        match self {
667            UsePath::Id(id) => id,
668            UsePath::Package { name, .. } => name,
669        }
670    }
671}
672
673struct UseName<'a> {
674    name: Id<'a>,
675    as_: Option<Id<'a>>,
676}
677
678impl<'a> Use<'a> {
679    fn parse(tokens: &mut Tokenizer<'a>, attributes: Vec<Attribute<'a>>) -> ParseResult<Self> {
680        tokens.expect(Token::Use)?;
681        let from = UsePath::parse(tokens)?;
682        tokens.expect(Token::Period)?;
683        tokens.expect(Token::LeftBrace)?;
684
685        let mut names = Vec::new();
686        while !tokens.eat(Token::RightBrace)? {
687            let mut name = UseName {
688                name: parse_id(tokens)?,
689                as_: None,
690            };
691            if tokens.eat(Token::As)? {
692                name.as_ = Some(parse_id(tokens)?);
693            }
694            names.push(name);
695            if !tokens.eat(Token::Comma)? {
696                tokens.expect(Token::RightBrace)?;
697                break;
698            }
699        }
700        tokens.expect_semicolon()?;
701        Ok(Use {
702            attributes,
703            from,
704            names,
705        })
706    }
707}
708
709struct Include<'a> {
710    from: UsePath<'a>,
711    attributes: Vec<Attribute<'a>>,
712    names: Vec<IncludeName<'a>>,
713}
714
715struct IncludeName<'a> {
716    name: Id<'a>,
717    as_: Id<'a>,
718}
719
720impl<'a> Include<'a> {
721    fn parse(tokens: &mut Tokenizer<'a>, attributes: Vec<Attribute<'a>>) -> ParseResult<Self> {
722        Attribute::reject_external_id(&attributes, "include statements")?;
723        tokens.expect(Token::Include)?;
724        let from = UsePath::parse(tokens)?;
725
726        let names = if tokens.eat(Token::With)? {
727            parse_list(
728                tokens,
729                Token::LeftBrace,
730                Token::RightBrace,
731                |_docs, tokens| {
732                    let name = parse_id(tokens)?;
733                    tokens.expect(Token::As)?;
734                    let as_ = parse_id(tokens)?;
735                    Ok(IncludeName { name, as_ })
736                },
737            )?
738        } else {
739            tokens.expect_semicolon()?;
740            Vec::new()
741        };
742
743        Ok(Include {
744            attributes,
745            from,
746            names,
747        })
748    }
749}
750
751#[derive(Debug, Clone)]
752pub struct Id<'a> {
753    name: &'a str,
754    span: Span,
755}
756
757impl<'a> From<&'a str> for Id<'a> {
758    fn from(s: &'a str) -> Id<'a> {
759        Id {
760            name: s.into(),
761            span: Default::default(),
762        }
763    }
764}
765
766#[derive(Debug, Clone)]
767pub struct Docs<'a> {
768    docs: Vec<Cow<'a, str>>,
769    span: Span,
770}
771
772impl<'a> Default for Docs<'a> {
773    fn default() -> Self {
774        Self {
775            docs: Default::default(),
776            span: Default::default(),
777        }
778    }
779}
780
781struct TypeDef<'a> {
782    docs: Docs<'a>,
783    attributes: Vec<Attribute<'a>>,
784    name: Id<'a>,
785    ty: Type<'a>,
786}
787
788enum Type<'a> {
789    Bool(Span),
790    U8(Span),
791    U16(Span),
792    U32(Span),
793    U64(Span),
794    S8(Span),
795    S16(Span),
796    S32(Span),
797    S64(Span),
798    F32(Span),
799    F64(Span),
800    Char(Span),
801    String(Span),
802    Name(Id<'a>),
803    List(List<'a>),
804    Map(Map<'a>),
805    FixedLengthList(FixedLengthList<'a>),
806    Handle(Handle<'a>),
807    Resource(Resource<'a>),
808    Record(Record<'a>),
809    Flags(Flags<'a>),
810    Variant(Variant<'a>),
811    Tuple(Tuple<'a>),
812    Enum(Enum<'a>),
813    Option(Option_<'a>),
814    Result(Result_<'a>),
815    Future(Future<'a>),
816    Stream(Stream<'a>),
817    ErrorContext(Span),
818}
819
820enum Handle<'a> {
821    Own { resource: Id<'a> },
822    Borrow { resource: Id<'a> },
823}
824
825impl Handle<'_> {
826    fn span(&self) -> Span {
827        match self {
828            Handle::Own { resource } | Handle::Borrow { resource } => resource.span,
829        }
830    }
831}
832
833struct Resource<'a> {
834    span: Span,
835    funcs: Vec<ResourceFunc<'a>>,
836}
837
838enum ResourceFunc<'a> {
839    Method(NamedFunc<'a>),
840    Static(NamedFunc<'a>),
841    Constructor(NamedFunc<'a>),
842}
843
844impl<'a> ResourceFunc<'a> {
845    fn parse(
846        docs: Docs<'a>,
847        attributes: Vec<Attribute<'a>>,
848        tokens: &mut Tokenizer<'a>,
849    ) -> ParseResult<Self> {
850        match tokens.clone().next()? {
851            Some((span, Token::Constructor)) => {
852                tokens.expect(Token::Constructor)?;
853                tokens.expect(Token::LeftParen)?;
854                let params = parse_list_trailer(tokens, Token::RightParen, |_docs, tokens| {
855                    let name = parse_id(tokens)?;
856                    tokens.expect(Token::Colon)?;
857                    let ty = Type::parse(tokens)?;
858                    Ok((name, ty))
859                })?;
860                let result = if tokens.eat(Token::RArrow)? {
861                    let ty = Type::parse(tokens)?;
862                    Some(ty)
863                } else {
864                    None
865                };
866                tokens.expect_semicolon()?;
867                Ok(ResourceFunc::Constructor(NamedFunc {
868                    docs,
869                    attributes,
870                    name: Id {
871                        span,
872                        name: "constructor",
873                    },
874                    func: Func {
875                        span,
876                        async_: false,
877                        accessor: None,
878                        params,
879                        result,
880                    },
881                }))
882            }
883            Some((_span, Token::Id | Token::ExplicitId)) => {
884                let name = parse_id(tokens)?;
885                tokens.expect(Token::Colon)?;
886                let ctor = if tokens.eat(Token::Static)? {
887                    ResourceFunc::Static
888                } else {
889                    ResourceFunc::Method
890                };
891                let func = Func::parse(tokens)?;
892                tokens.expect_semicolon()?;
893                Ok(ctor(NamedFunc {
894                    docs,
895                    attributes,
896                    name,
897                    func,
898                }))
899            }
900            other => Err(err_expected(tokens, "`constructor` or identifier", other).into()),
901        }
902    }
903
904    fn named_func(&self) -> &NamedFunc<'a> {
905        use ResourceFunc::*;
906        match self {
907            Method(f) | Static(f) | Constructor(f) => f,
908        }
909    }
910}
911
912struct Record<'a> {
913    span: Span,
914    fields: Vec<Field<'a>>,
915}
916
917struct Field<'a> {
918    docs: Docs<'a>,
919    name: Id<'a>,
920    ty: Type<'a>,
921}
922
923struct Flags<'a> {
924    span: Span,
925    flags: Vec<Flag<'a>>,
926}
927
928struct Flag<'a> {
929    docs: Docs<'a>,
930    name: Id<'a>,
931}
932
933struct Variant<'a> {
934    span: Span,
935    cases: Vec<Case<'a>>,
936}
937
938struct Case<'a> {
939    docs: Docs<'a>,
940    name: Id<'a>,
941    ty: Option<Type<'a>>,
942}
943
944struct Enum<'a> {
945    span: Span,
946    cases: Vec<EnumCase<'a>>,
947}
948
949struct EnumCase<'a> {
950    docs: Docs<'a>,
951    name: Id<'a>,
952}
953
954struct Option_<'a> {
955    span: Span,
956    ty: Box<Type<'a>>,
957}
958
959struct List<'a> {
960    span: Span,
961    ty: Box<Type<'a>>,
962}
963
964struct Map<'a> {
965    span: Span,
966    key: Box<Type<'a>>,
967    value: Box<Type<'a>>,
968}
969
970struct FixedLengthList<'a> {
971    span: Span,
972    ty: Box<Type<'a>>,
973    size: u32,
974}
975
976struct Future<'a> {
977    span: Span,
978    ty: Option<Box<Type<'a>>>,
979}
980
981struct Tuple<'a> {
982    span: Span,
983    types: Vec<Type<'a>>,
984}
985
986struct Result_<'a> {
987    span: Span,
988    ok: Option<Box<Type<'a>>>,
989    err: Option<Box<Type<'a>>>,
990}
991
992struct Stream<'a> {
993    span: Span,
994    ty: Option<Box<Type<'a>>>,
995}
996
997struct NamedFunc<'a> {
998    docs: Docs<'a>,
999    attributes: Vec<Attribute<'a>>,
1000    name: Id<'a>,
1001    func: Func<'a>,
1002}
1003
1004type ParamList<'a> = Vec<(Id<'a>, Type<'a>)>;
1005
1006struct Func<'a> {
1007    span: Span,
1008    async_: bool,
1009    accessor: Option<AccessorKind>,
1010    params: ParamList<'a>,
1011    result: Option<Type<'a>>,
1012}
1013
1014impl<'a> Func<'a> {
1015    fn parse(tokens: &mut Tokenizer<'a>) -> ParseResult<Func<'a>> {
1016        fn parse_params<'a>(
1017            tokens: &mut Tokenizer<'a>,
1018            left_paren: bool,
1019        ) -> ParseResult<ParamList<'a>> {
1020            if left_paren {
1021                tokens.expect(Token::LeftParen)?;
1022            };
1023            parse_list_trailer(tokens, Token::RightParen, |_docs, tokens| {
1024                let name = parse_id(tokens)?;
1025                tokens.expect(Token::Colon)?;
1026                let ty = Type::parse(tokens)?;
1027                Ok((name, ty))
1028            })
1029        }
1030
1031        let async_ = tokens.eat(Token::Async)?;
1032        let accessor = if async_ {
1033            None
1034        } else {
1035            eat_accessor_token(tokens)?
1036        };
1037        let (span, accessor) = match accessor {
1038            Some((span, accessor)) => (span, Some(accessor)),
1039            None => (tokens.expect(Token::Func)?, None),
1040        };
1041        let params = parse_params(tokens, true)?;
1042        let result = if tokens.eat(Token::RArrow)? {
1043            let ty = Type::parse(tokens)?;
1044            Some(ty)
1045        } else {
1046            None
1047        };
1048        Ok(Func {
1049            span,
1050            async_,
1051            accessor,
1052            params,
1053            result,
1054        })
1055    }
1056}
1057
1058fn eat_accessor_token(tokens: &mut Tokenizer<'_>) -> ParseResult<Option<(Span, AccessorKind)>> {
1059    let mut clone = tokens.clone();
1060    let (span, accessor) = match clone.next()? {
1061        Some((span, Token::Id)) => match clone.parse_id(span)? {
1062            "get" => (span, AccessorKind::Getter),
1063            "set" => (span, AccessorKind::Setter),
1064            _ => return Ok(None),
1065        },
1066        _ => return Ok(None),
1067    };
1068    if !clone.eat(Token::LeftParen)? {
1069        return Ok(None);
1070    }
1071    tokens.next()?; // consume "get" or "set" but not the paren
1072    Ok(Some((span, accessor)))
1073}
1074
1075impl<'a> InterfaceItem<'a> {
1076    fn parse(
1077        tokens: &mut Tokenizer<'a>,
1078        docs: Docs<'a>,
1079        attributes: Vec<Attribute<'a>>,
1080    ) -> ParseResult<InterfaceItem<'a>> {
1081        match tokens.clone().next()? {
1082            Some((_span, Token::Type)) => {
1083                TypeDef::parse(tokens, docs, attributes).map(InterfaceItem::TypeDef)
1084            }
1085            Some((_span, Token::Flags)) => {
1086                TypeDef::parse_flags(tokens, docs, attributes).map(InterfaceItem::TypeDef)
1087            }
1088            Some((_span, Token::Enum)) => {
1089                TypeDef::parse_enum(tokens, docs, attributes).map(InterfaceItem::TypeDef)
1090            }
1091            Some((_span, Token::Variant)) => {
1092                TypeDef::parse_variant(tokens, docs, attributes).map(InterfaceItem::TypeDef)
1093            }
1094            Some((_span, Token::Resource)) => {
1095                TypeDef::parse_resource(tokens, docs, attributes).map(InterfaceItem::TypeDef)
1096            }
1097            Some((_span, Token::Record)) => {
1098                TypeDef::parse_record(tokens, docs, attributes).map(InterfaceItem::TypeDef)
1099            }
1100            Some((_span, Token::Id)) | Some((_span, Token::ExplicitId)) => {
1101                NamedFunc::parse(tokens, docs, attributes).map(InterfaceItem::Func)
1102            }
1103            Some((_span, Token::Use)) => Use::parse(tokens, attributes).map(InterfaceItem::Use),
1104            other => Err(err_expected(tokens, "`type`, `resource` or `func`", other).into()),
1105        }
1106    }
1107}
1108
1109impl<'a> TypeDef<'a> {
1110    fn parse(
1111        tokens: &mut Tokenizer<'a>,
1112        docs: Docs<'a>,
1113        attributes: Vec<Attribute<'a>>,
1114    ) -> ParseResult<Self> {
1115        tokens.expect(Token::Type)?;
1116        let name = parse_id(tokens)?;
1117        tokens.expect(Token::Equals)?;
1118        let ty = Type::parse(tokens)?;
1119        tokens.expect_semicolon()?;
1120        Ok(TypeDef {
1121            docs,
1122            attributes,
1123            name,
1124            ty,
1125        })
1126    }
1127
1128    fn parse_flags(
1129        tokens: &mut Tokenizer<'a>,
1130        docs: Docs<'a>,
1131        attributes: Vec<Attribute<'a>>,
1132    ) -> ParseResult<Self> {
1133        tokens.expect(Token::Flags)?;
1134        let name = parse_id(tokens)?;
1135        let ty = Type::Flags(Flags {
1136            span: name.span,
1137            flags: parse_list(
1138                tokens,
1139                Token::LeftBrace,
1140                Token::RightBrace,
1141                |docs, tokens| {
1142                    let name = parse_id(tokens)?;
1143                    Ok(Flag { docs, name })
1144                },
1145            )?,
1146        });
1147        Ok(TypeDef {
1148            docs,
1149            attributes,
1150            name,
1151            ty,
1152        })
1153    }
1154
1155    fn parse_resource(
1156        tokens: &mut Tokenizer<'a>,
1157        docs: Docs<'a>,
1158        attributes: Vec<Attribute<'a>>,
1159    ) -> ParseResult<Self> {
1160        tokens.expect(Token::Resource)?;
1161        let name = parse_id(tokens)?;
1162        let mut funcs = Vec::new();
1163        if tokens.eat(Token::LeftBrace)? {
1164            while !tokens.eat(Token::RightBrace)? {
1165                let docs = parse_docs(tokens)?;
1166                let attributes = Attribute::parse_list(tokens)?;
1167                funcs.push(ResourceFunc::parse(docs, attributes, tokens)?);
1168            }
1169        } else {
1170            tokens.expect_semicolon()?;
1171        }
1172        let ty = Type::Resource(Resource {
1173            span: name.span,
1174            funcs,
1175        });
1176        Ok(TypeDef {
1177            docs,
1178            attributes,
1179            name,
1180            ty,
1181        })
1182    }
1183
1184    fn parse_record(
1185        tokens: &mut Tokenizer<'a>,
1186        docs: Docs<'a>,
1187        attributes: Vec<Attribute<'a>>,
1188    ) -> ParseResult<Self> {
1189        tokens.expect(Token::Record)?;
1190        let name = parse_id(tokens)?;
1191        let ty = Type::Record(Record {
1192            span: name.span,
1193            fields: parse_list(
1194                tokens,
1195                Token::LeftBrace,
1196                Token::RightBrace,
1197                |docs, tokens| {
1198                    let name = parse_id(tokens)?;
1199                    tokens.expect(Token::Colon)?;
1200                    let ty = Type::parse(tokens)?;
1201                    Ok(Field { docs, name, ty })
1202                },
1203            )?,
1204        });
1205        Ok(TypeDef {
1206            docs,
1207            attributes,
1208            name,
1209            ty,
1210        })
1211    }
1212
1213    fn parse_variant(
1214        tokens: &mut Tokenizer<'a>,
1215        docs: Docs<'a>,
1216        attributes: Vec<Attribute<'a>>,
1217    ) -> ParseResult<Self> {
1218        tokens.expect(Token::Variant)?;
1219        let name = parse_id(tokens)?;
1220        let ty = Type::Variant(Variant {
1221            span: name.span,
1222            cases: parse_list(
1223                tokens,
1224                Token::LeftBrace,
1225                Token::RightBrace,
1226                |docs, tokens| {
1227                    let name = parse_id(tokens)?;
1228                    let ty = if tokens.eat(Token::LeftParen)? {
1229                        let ty = Type::parse(tokens)?;
1230                        tokens.expect(Token::RightParen)?;
1231                        Some(ty)
1232                    } else {
1233                        None
1234                    };
1235                    Ok(Case { docs, name, ty })
1236                },
1237            )?,
1238        });
1239        Ok(TypeDef {
1240            docs,
1241            attributes,
1242            name,
1243            ty,
1244        })
1245    }
1246
1247    fn parse_enum(
1248        tokens: &mut Tokenizer<'a>,
1249        docs: Docs<'a>,
1250        attributes: Vec<Attribute<'a>>,
1251    ) -> ParseResult<Self> {
1252        tokens.expect(Token::Enum)?;
1253        let name = parse_id(tokens)?;
1254        let ty = Type::Enum(Enum {
1255            span: name.span,
1256            cases: parse_list(
1257                tokens,
1258                Token::LeftBrace,
1259                Token::RightBrace,
1260                |docs, tokens| {
1261                    let name = parse_id(tokens)?;
1262                    Ok(EnumCase { docs, name })
1263                },
1264            )?,
1265        });
1266        Ok(TypeDef {
1267            docs,
1268            attributes,
1269            name,
1270            ty,
1271        })
1272    }
1273}
1274
1275impl<'a> NamedFunc<'a> {
1276    fn parse(
1277        tokens: &mut Tokenizer<'a>,
1278        docs: Docs<'a>,
1279        attributes: Vec<Attribute<'a>>,
1280    ) -> ParseResult<Self> {
1281        let name = parse_id(tokens)?;
1282        tokens.expect(Token::Colon)?;
1283        let func = Func::parse(tokens)?;
1284        tokens.expect_semicolon()?;
1285        Ok(NamedFunc {
1286            docs,
1287            attributes,
1288            name,
1289            func,
1290        })
1291    }
1292}
1293
1294fn parse_id<'a>(tokens: &mut Tokenizer<'a>) -> ParseResult<Id<'a>> {
1295    match tokens.next()? {
1296        Some((span, Token::Id)) => Ok(Id {
1297            name: tokens.parse_id(span)?,
1298            span,
1299        }),
1300        Some((span, Token::ExplicitId)) => Ok(Id {
1301            name: tokens.parse_explicit_id(span)?,
1302            span,
1303        }),
1304        other => Err(err_expected(tokens, "an identifier or string", other)),
1305    }
1306}
1307
1308fn parse_opt_version(tokens: &mut Tokenizer<'_>) -> ParseResult<Option<(Span, Version)>> {
1309    if tokens.eat(Token::At)? {
1310        parse_version(tokens).map(Some)
1311    } else {
1312        Ok(None)
1313    }
1314}
1315
1316fn parse_version(tokens: &mut Tokenizer<'_>) -> ParseResult<(Span, Version)> {
1317    let start = tokens.expect(Token::Integer)?.start();
1318    tokens.expect(Token::Period)?;
1319    tokens.expect(Token::Integer)?;
1320    tokens.expect(Token::Period)?;
1321    let end = tokens.expect(Token::Integer)?.end();
1322    let mut span = Span::new(start, end);
1323    eat_ids(tokens, Token::Minus, &mut span)?;
1324    eat_ids(tokens, Token::Plus, &mut span)?;
1325    let string = tokens.get_span(span);
1326    let version =
1327        Version::parse(string).map_err(|e| ParseError::new_syntax(span, e.to_string()))?;
1328    return Ok((span, version));
1329
1330    // According to `semver.org` this is what we're parsing:
1331    //
1332    // ```ebnf
1333    // <pre-release> ::= <dot-separated pre-release identifiers>
1334    //
1335    // <dot-separated pre-release identifiers> ::= <pre-release identifier>
1336    //                                           | <pre-release identifier> "." <dot-separated pre-release identifiers>
1337    //
1338    // <build> ::= <dot-separated build identifiers>
1339    //
1340    // <dot-separated build identifiers> ::= <build identifier>
1341    //                                     | <build identifier> "." <dot-separated build identifiers>
1342    //
1343    // <pre-release identifier> ::= <alphanumeric identifier>
1344    //                            | <numeric identifier>
1345    //
1346    // <build identifier> ::= <alphanumeric identifier>
1347    //                      | <digits>
1348    //
1349    // <alphanumeric identifier> ::= <non-digit>
1350    //                             | <non-digit> <identifier characters>
1351    //                             | <identifier characters> <non-digit>
1352    //                             | <identifier characters> <non-digit> <identifier characters>
1353    //
1354    // <numeric identifier> ::= "0"
1355    //                        | <positive digit>
1356    //                        | <positive digit> <digits>
1357    //
1358    // <identifier characters> ::= <identifier character>
1359    //                           | <identifier character> <identifier characters>
1360    //
1361    // <identifier character> ::= <digit>
1362    //                          | <non-digit>
1363    //
1364    // <non-digit> ::= <letter>
1365    //               | "-"
1366    //
1367    // <digits> ::= <digit>
1368    //            | <digit> <digits>
1369    // ```
1370    //
1371    // This is loosely based on WIT syntax and an approximation is parsed here:
1372    //
1373    // * This function starts by parsing the optional leading `-` and `+` which
1374    //   indicates pre-release and build metadata.
1375    // * Afterwards all of $id, $integer, `-`, and `.` are chomped. The only
1376    //   exception here is that if `.` isn't followed by $id, $integer, or `-`
1377    //   then it's assumed that it's something like `use a:b@1.0.0-a.{...}`
1378    //   where the `.` is part of WIT syntax, not semver.
1379    //
1380    // Note that this additionally doesn't try to return any first-class errors.
1381    // Instead this bails out on something unrecognized for something else in
1382    // the system to return an error.
1383    fn eat_ids(
1384        tokens: &mut Tokenizer<'_>,
1385        prefix: Token,
1386        end: &mut Span,
1387    ) -> Result<(), lex::Error> {
1388        if !tokens.eat(prefix)? {
1389            return Ok(());
1390        }
1391        loop {
1392            let mut clone = tokens.clone();
1393            match clone.next()? {
1394                Some((span, Token::Id | Token::Integer | Token::Minus)) => {
1395                    end.set_end(span.end());
1396                    *tokens = clone;
1397                }
1398                Some((_span, Token::Period)) => match clone.next()? {
1399                    Some((span, Token::Id | Token::Integer | Token::Minus)) => {
1400                        end.set_end(span.end());
1401                        *tokens = clone;
1402                    }
1403                    _ => break Ok(()),
1404                },
1405                _ => break Ok(()),
1406            }
1407        }
1408    }
1409}
1410
1411fn parse_docs<'a>(tokens: &mut Tokenizer<'a>) -> Result<Docs<'a>, lex::Error> {
1412    let mut docs = Docs::default();
1413    let mut clone = tokens.clone();
1414    let mut started = false;
1415    while let Some((span, token)) = clone.next_raw()? {
1416        match token {
1417            Token::Whitespace => {}
1418            Token::Comment => {
1419                let comment = tokens.get_span(span);
1420                if !started {
1421                    docs.span.set_start(span.start());
1422                    started = true;
1423                }
1424                let trailing_ws = comment
1425                    .bytes()
1426                    .rev()
1427                    .take_while(|ch| ch.is_ascii_whitespace())
1428                    .count();
1429                docs.span.set_end(span.end() - (trailing_ws as u32));
1430                docs.docs.push(comment.into());
1431            }
1432            _ => break,
1433        };
1434        *tokens = clone.clone();
1435    }
1436    Ok(docs)
1437}
1438
1439/// Maximum nesting depth of types parsed with `Type::parse`, e.g.
1440/// `list<list<list<...>>>`.
1441const MAX_TYPE_DEPTH: usize = 100;
1442
1443impl<'a> Type<'a> {
1444    fn parse(tokens: &mut Tokenizer<'a>) -> ParseResult<Self> {
1445        Type::parse_at_depth(tokens, 0)
1446    }
1447
1448    fn parse_at_depth(tokens: &mut Tokenizer<'a>, depth: usize) -> ParseResult<Self> {
1449        let token = tokens.next()?;
1450        if depth >= MAX_TYPE_DEPTH {
1451            let span = match token {
1452                Some((span, _)) => span,
1453                None => tokens.eof_span(),
1454            };
1455            return Err(ParseError::new_syntax(span, "type nesting too deep"));
1456        }
1457        match token {
1458            Some((span, Token::U8)) => Ok(Type::U8(span)),
1459            Some((span, Token::U16)) => Ok(Type::U16(span)),
1460            Some((span, Token::U32)) => Ok(Type::U32(span)),
1461            Some((span, Token::U64)) => Ok(Type::U64(span)),
1462            Some((span, Token::S8)) => Ok(Type::S8(span)),
1463            Some((span, Token::S16)) => Ok(Type::S16(span)),
1464            Some((span, Token::S32)) => Ok(Type::S32(span)),
1465            Some((span, Token::S64)) => Ok(Type::S64(span)),
1466            Some((span, Token::F32)) => Ok(Type::F32(span)),
1467            Some((span, Token::F64)) => Ok(Type::F64(span)),
1468            Some((span, Token::Char)) => Ok(Type::Char(span)),
1469
1470            // tuple<T, U, ...>
1471            Some((span, Token::Tuple)) => {
1472                let types = parse_list(
1473                    tokens,
1474                    Token::LessThan,
1475                    Token::GreaterThan,
1476                    |_docs, tokens| Type::parse_at_depth(tokens, depth + 1),
1477                )?;
1478                Ok(Type::Tuple(Tuple { span, types }))
1479            }
1480
1481            Some((span, Token::Bool)) => Ok(Type::Bool(span)),
1482            Some((span, Token::String_)) => Ok(Type::String(span)),
1483
1484            // list<T>
1485            // list<T, N>
1486            Some((span, Token::List)) => {
1487                tokens.expect(Token::LessThan)?;
1488                let ty = Type::parse_at_depth(tokens, depth + 1)?;
1489                let size = if tokens.eat(Token::Comma)? {
1490                    let number = tokens.next()?;
1491                    if let Some((span, Token::Integer)) = number {
1492                        let size: u32 = tokens.get_span(span).parse().map_err(|e| {
1493                            ParseError::new_syntax(span, format!("invalid list size: {e}"))
1494                        })?;
1495                        Some(size)
1496                    } else {
1497                        return Err(err_expected(tokens, "fixed-length", number).into());
1498                    }
1499                } else {
1500                    None
1501                };
1502                tokens.expect(Token::GreaterThan)?;
1503                if let Some(size) = size {
1504                    Ok(Type::FixedLengthList(FixedLengthList {
1505                        span,
1506                        ty: Box::new(ty),
1507                        size,
1508                    }))
1509                } else {
1510                    Ok(Type::List(List {
1511                        span,
1512                        ty: Box::new(ty),
1513                    }))
1514                }
1515            }
1516
1517            // map<K, V>
1518            Some((span, Token::Map)) => {
1519                tokens.expect(Token::LessThan)?;
1520                let key = Type::parse_at_depth(tokens, depth + 1)?;
1521                tokens.expect(Token::Comma)?;
1522                let value = Type::parse_at_depth(tokens, depth + 1)?;
1523                tokens.expect(Token::GreaterThan)?;
1524                Ok(Type::Map(Map {
1525                    span,
1526                    key: Box::new(key),
1527                    value: Box::new(value),
1528                }))
1529            }
1530
1531            // option<T>
1532            Some((span, Token::Option_)) => {
1533                tokens.expect(Token::LessThan)?;
1534                let ty = Type::parse_at_depth(tokens, depth + 1)?;
1535                tokens.expect(Token::GreaterThan)?;
1536                Ok(Type::Option(Option_ {
1537                    span,
1538                    ty: Box::new(ty),
1539                }))
1540            }
1541
1542            // result<T, E>
1543            // result<_, E>
1544            // result<T>
1545            // result
1546            Some((span, Token::Result_)) => {
1547                let mut ok = None;
1548                let mut err = None;
1549
1550                if tokens.eat(Token::LessThan)? {
1551                    if tokens.eat(Token::Underscore)? {
1552                        tokens.expect(Token::Comma)?;
1553                        err = Some(Box::new(Type::parse_at_depth(tokens, depth + 1)?));
1554                    } else {
1555                        ok = Some(Box::new(Type::parse_at_depth(tokens, depth + 1)?));
1556                        if tokens.eat(Token::Comma)? {
1557                            err = Some(Box::new(Type::parse_at_depth(tokens, depth + 1)?));
1558                        }
1559                    };
1560                    tokens.expect(Token::GreaterThan)?;
1561                };
1562                Ok(Type::Result(Result_ { span, ok, err }))
1563            }
1564
1565            // future<T>
1566            // future
1567            Some((span, Token::Future)) => {
1568                let mut ty = None;
1569
1570                if tokens.eat(Token::LessThan)? {
1571                    ty = Some(Box::new(Type::parse_at_depth(tokens, depth + 1)?));
1572                    tokens.expect(Token::GreaterThan)?;
1573                };
1574                Ok(Type::Future(Future { span, ty }))
1575            }
1576
1577            // stream<T>
1578            // stream
1579            Some((span, Token::Stream)) => {
1580                let mut ty = None;
1581
1582                if tokens.eat(Token::LessThan)? {
1583                    ty = Some(Box::new(Type::parse_at_depth(tokens, depth + 1)?));
1584                    tokens.expect(Token::GreaterThan)?;
1585                };
1586                Ok(Type::Stream(Stream { span, ty }))
1587            }
1588
1589            // error-context
1590            Some((span, Token::ErrorContext)) => Ok(Type::ErrorContext(span)),
1591
1592            // own<T>
1593            Some((_span, Token::Own)) => {
1594                tokens.expect(Token::LessThan)?;
1595                let resource = parse_id(tokens)?;
1596                tokens.expect(Token::GreaterThan)?;
1597                Ok(Type::Handle(Handle::Own { resource }))
1598            }
1599
1600            // borrow<T>
1601            Some((_span, Token::Borrow)) => {
1602                tokens.expect(Token::LessThan)?;
1603                let resource = parse_id(tokens)?;
1604                tokens.expect(Token::GreaterThan)?;
1605                Ok(Type::Handle(Handle::Borrow { resource }))
1606            }
1607
1608            // `foo`
1609            Some((span, Token::Id)) => Ok(Type::Name(Id {
1610                name: tokens.parse_id(span)?.into(),
1611                span,
1612            })),
1613            // `%foo`
1614            Some((span, Token::ExplicitId)) => Ok(Type::Name(Id {
1615                name: tokens.parse_explicit_id(span)?.into(),
1616                span,
1617            })),
1618
1619            other => Err(err_expected(tokens, "a type", other).into()),
1620        }
1621    }
1622
1623    fn span(&self) -> Span {
1624        match self {
1625            Type::Bool(span)
1626            | Type::U8(span)
1627            | Type::U16(span)
1628            | Type::U32(span)
1629            | Type::U64(span)
1630            | Type::S8(span)
1631            | Type::S16(span)
1632            | Type::S32(span)
1633            | Type::S64(span)
1634            | Type::F32(span)
1635            | Type::F64(span)
1636            | Type::Char(span)
1637            | Type::String(span)
1638            | Type::ErrorContext(span) => *span,
1639            Type::Name(id) => id.span,
1640            Type::List(l) => l.span,
1641            Type::Map(m) => m.span,
1642            Type::FixedLengthList(l) => l.span,
1643            Type::Handle(h) => h.span(),
1644            Type::Resource(r) => r.span,
1645            Type::Record(r) => r.span,
1646            Type::Flags(f) => f.span,
1647            Type::Variant(v) => v.span,
1648            Type::Tuple(t) => t.span,
1649            Type::Enum(e) => e.span,
1650            Type::Option(o) => o.span,
1651            Type::Result(r) => r.span,
1652            Type::Future(f) => f.span,
1653            Type::Stream(s) => s.span,
1654        }
1655    }
1656}
1657
1658fn parse_list<'a, T>(
1659    tokens: &mut Tokenizer<'a>,
1660    start: Token,
1661    end: Token,
1662    parse: impl FnMut(Docs<'a>, &mut Tokenizer<'a>) -> ParseResult<T>,
1663) -> ParseResult<Vec<T>> {
1664    tokens.expect(start)?;
1665    parse_list_trailer(tokens, end, parse)
1666}
1667
1668fn parse_list_trailer<'a, T>(
1669    tokens: &mut Tokenizer<'a>,
1670    end: Token,
1671    mut parse: impl FnMut(Docs<'a>, &mut Tokenizer<'a>) -> ParseResult<T>,
1672) -> ParseResult<Vec<T>> {
1673    let mut items = Vec::new();
1674    loop {
1675        // get docs before we skip them to try to eat the end token
1676        let docs = parse_docs(tokens)?;
1677
1678        // if we found an end token then we're done
1679        if tokens.eat(end)? {
1680            break;
1681        }
1682
1683        let item = parse(docs, tokens)?;
1684        items.push(item);
1685
1686        // if there's no trailing comma then this is required to be the end,
1687        // otherwise we go through the loop to try to get another item
1688        if !tokens.eat(Token::Comma)? {
1689            tokens.expect(end)?;
1690            break;
1691        }
1692    }
1693    Ok(items)
1694}
1695
1696fn err_expected(
1697    tokens: &Tokenizer<'_>,
1698    expected: &'static str,
1699    found: Option<(Span, Token)>,
1700) -> ParseError {
1701    match found {
1702        Some((span, token)) => ParseError::new_syntax(
1703            span,
1704            format!("expected {}, found {}", expected, token.describe()),
1705        ),
1706        None => {
1707            ParseError::new_syntax(tokens.eof_span(), format!("expected {expected}, found eof"))
1708        }
1709    }
1710}
1711
1712enum Attribute<'a> {
1713    Since { span: Span, version: Version },
1714    Unstable { span: Span, feature: Id<'a> },
1715    Deprecated { span: Span, version: Version },
1716    ExternalId { span: Span, id: String },
1717}
1718
1719impl<'a> Attribute<'a> {
1720    fn parse_list(tokens: &mut Tokenizer<'a>) -> ParseResult<Vec<Attribute<'a>>> {
1721        let mut ret = Vec::new();
1722        while tokens.eat(Token::At)? {
1723            let id = parse_id(tokens)?;
1724            let attr = match id.name {
1725                "since" => {
1726                    tokens.expect(Token::LeftParen)?;
1727                    eat_id(tokens, "version")?;
1728                    tokens.expect(Token::Equals)?;
1729                    let (_span, version) = parse_version(tokens)?;
1730                    tokens.expect(Token::RightParen)?;
1731                    Attribute::Since {
1732                        span: id.span,
1733                        version,
1734                    }
1735                }
1736                "unstable" => {
1737                    tokens.expect(Token::LeftParen)?;
1738                    eat_id(tokens, "feature")?;
1739                    tokens.expect(Token::Equals)?;
1740                    let feature = parse_id(tokens)?;
1741                    tokens.expect(Token::RightParen)?;
1742                    Attribute::Unstable {
1743                        span: id.span,
1744                        feature,
1745                    }
1746                }
1747                "deprecated" => {
1748                    tokens.expect(Token::LeftParen)?;
1749                    eat_id(tokens, "version")?;
1750                    tokens.expect(Token::Equals)?;
1751                    let (_span, version) = parse_version(tokens)?;
1752                    tokens.expect(Token::RightParen)?;
1753                    Attribute::Deprecated {
1754                        span: id.span,
1755                        version,
1756                    }
1757                }
1758                "external-id" => {
1759                    tokens.expect(Token::LeftParen)?;
1760                    let span = tokens.expect(Token::StringLiteral)?;
1761                    tokens.expect(Token::RightParen)?;
1762                    Attribute::ExternalId {
1763                        span: id.span,
1764                        id: tokens.string_literal(span)?,
1765                    }
1766                }
1767                other => {
1768                    return Err(ParseError::new_syntax(
1769                        id.span,
1770                        format!("unknown attribute `{other}`"),
1771                    ));
1772                }
1773            };
1774            ret.push(attr);
1775        }
1776        Ok(ret)
1777    }
1778
1779    /// Returns an error if `attrs` contains an `@external-id` attribute.
1780    ///
1781    /// This is used for items which accept other attributes, such as feature
1782    /// gates, but have no place to record an `@external-id` in the resolved
1783    /// representation of a package, so it would otherwise be silently
1784    /// dropped.
1785    fn reject_external_id(attrs: &[Attribute<'a>], what: &str) -> ParseResult<()> {
1786        for attr in attrs {
1787            if let Attribute::ExternalId { span, .. } = attr {
1788                return Err(ParseError::new_syntax(
1789                    *span,
1790                    format!("@external-id is not allowed on {what}"),
1791                ));
1792            }
1793        }
1794        Ok(())
1795    }
1796}
1797
1798fn eat_id(tokens: &mut Tokenizer<'_>, expected: &str) -> ParseResult<Span> {
1799    let id = parse_id(tokens)?;
1800    if id.name != expected {
1801        return Err(ParseError::new_syntax(
1802            id.span,
1803            format!("expected `{expected}`, found `{}`", id.name),
1804        ));
1805    }
1806    Ok(id.span)
1807}
1808
1809/// A listing of source files which are used to get parsed into an
1810/// [`UnresolvedPackage`].
1811///
1812/// [`UnresolvedPackage`]: crate::UnresolvedPackage
1813#[derive(Clone, Default, Debug, PartialEq, Eq)]
1814pub struct SourceMap {
1815    sources: Vec<Source>,
1816    offset: u32,
1817}
1818
1819#[derive(Clone, Debug, PartialEq, Eq)]
1820struct Source {
1821    offset: u32,
1822    path: String,
1823    contents: String,
1824}
1825
1826impl SourceMap {
1827    /// Creates a new empty source map.
1828    pub fn new() -> SourceMap {
1829        SourceMap::default()
1830    }
1831
1832    /// Reads the file `path` on the filesystem and appends its contents to this
1833    /// [`SourceMap`].
1834    #[cfg(feature = "std")]
1835    pub fn push_file(&mut self, path: &Path) -> anyhow::Result<()> {
1836        let contents = std::fs::read_to_string(path)
1837            .with_context(|| format!("failed to read file {path:?}"))?;
1838        self.push(path, contents);
1839        Ok(())
1840    }
1841
1842    /// Reads all `*.wit` files in the directory `path` (non-recursively) and
1843    /// appends their contents to this [`SourceMap`].
1844    ///
1845    /// Subdirectories, non-`*.wit` files, and symlinks to directories are
1846    /// ignored. Note that a `deps` subdirectory is not probed here; that is
1847    /// handled by [`crate::Resolve::push_dir`].
1848    #[cfg(feature = "std")]
1849    pub fn push_dir(&mut self, path: &Path) -> anyhow::Result<()> {
1850        let cx = || format!("failed to read directory {path:?}");
1851        for entry in path.read_dir().with_context(&cx)? {
1852            let entry = entry.with_context(&cx)?;
1853            let entry_path = entry.path();
1854            let ty = entry.file_type().with_context(&cx)?;
1855            if ty.is_dir() {
1856                continue;
1857            }
1858            if ty.is_symlink() {
1859                if entry_path.is_dir() {
1860                    continue;
1861                }
1862            }
1863            let filename = match entry_path.file_name().and_then(|s| s.to_str()) {
1864                Some(name) => name,
1865                None => continue,
1866            };
1867            if !filename.ends_with(".wit") {
1868                continue;
1869            }
1870            self.push_file(&entry_path)?;
1871        }
1872        Ok(())
1873    }
1874
1875    /// Appends the given contents with the given path into this source map.
1876    ///
1877    /// The `path` provided is not read from the filesystem and is instead only
1878    /// used during error messages. Each file added to a [`SourceMap`] is
1879    /// used to create the final parsed package namely by unioning all the
1880    /// interfaces and worlds defined together. Note that each file has its own
1881    /// personal namespace, however, for top-level `use` and such.
1882    #[cfg(feature = "std")]
1883    pub fn push(&mut self, path: &Path, contents: impl Into<String>) {
1884        self.push_str(&path.display().to_string(), contents);
1885    }
1886
1887    /// Appends the given contents with the given source name into this source map.
1888    ///
1889    /// The `path` provided is not read from the filesystem and is instead only
1890    /// used during error messages. Each file added to a [`SourceMap`] is
1891    /// used to create the final parsed package namely by unioning all the
1892    /// interfaces and worlds defined together. Note that each file has its own
1893    /// personal namespace, however, for top-level `use` and such.
1894    pub fn push_str(&mut self, path: &str, contents: impl Into<String>) {
1895        let mut contents = contents.into();
1896        // Guarantee that there's at least one character in these contents by
1897        // appending a single newline to the end. This is excluded from
1898        // tokenization below so it's only here to ensure that spans which point
1899        // one byte beyond the end of a file (eof) point to the same original
1900        // file.
1901        contents.push('\n');
1902        let new_offset = self.offset + u32::try_from(contents.len()).unwrap();
1903        self.sources.push(Source {
1904            offset: self.offset,
1905            path: path.to_string(),
1906            contents,
1907        });
1908        self.offset = new_offset;
1909    }
1910
1911    /// Appends all sources from another `SourceMap` into this one.
1912    ///
1913    /// Returns the byte offset that should be added to all `Span.start` and
1914    /// `Span.end` values from the appended source map to make them valid
1915    /// in the combined source map.
1916    pub fn append(&mut self, other: SourceMap) -> u32 {
1917        let base = self.offset;
1918        for mut source in other.sources {
1919            source.offset += base;
1920            self.sources.push(source);
1921        }
1922        self.offset += other.offset;
1923        base
1924    }
1925
1926    /// Parses the files added to this source map into a
1927    /// [`UnresolvedPackageGroup`].
1928    ///
1929    /// On failure returns `Err((self, e))` so the caller can use the source
1930    /// map for error formatting if needed.
1931    pub fn parse(self) -> Result<UnresolvedPackageGroup, (Self, ParseError)> {
1932        match self.parse_inner() {
1933            Ok((main, nested)) => Ok(UnresolvedPackageGroup {
1934                main,
1935                nested,
1936                source_map: self,
1937            }),
1938            Err(e) => Err((self, e)),
1939        }
1940    }
1941
1942    fn parse_inner(&self) -> ParseResult<(UnresolvedPackage, Vec<UnresolvedPackage>)> {
1943        let mut nested = Vec::new();
1944        let mut resolver = Resolver::default();
1945        let mut srcs = self.sources.iter().collect::<Vec<_>>();
1946        srcs.sort_by_key(|src| &src.path);
1947
1948        // Parse each source file individually. A tokenizer is created here
1949        // from settings and then `PackageFile` is used to parse the whole
1950        // stream of tokens.
1951        for src in srcs {
1952            let mut tokens = Tokenizer::new(
1953                // chop off the forcibly appended `\n` character when
1954                // passing through the source to get tokenized.
1955                &src.contents[..src.contents.len() - 1],
1956                src.offset,
1957            )?;
1958            let mut file = PackageFile::parse(&mut tokens)?;
1959
1960            // Filter out any nested packages and resolve them separately.
1961            // Nested packages have only a single "file" so only one item
1962            // is pushed into a `Resolver`. Note that a nested `Resolver`
1963            // is used here, not the outer one.
1964            //
1965            // Note that filtering out `Package` items is required due to
1966            // how the implementation of disallowing nested packages in
1967            // nested packages currently works.
1968            for item in mem::take(&mut file.decl_list.items) {
1969                match item {
1970                    AstItem::Package(nested_pkg) => {
1971                        let mut resolve = Resolver::default();
1972                        resolve.push(nested_pkg)?;
1973                        nested.push(resolve.resolve()?);
1974                    }
1975                    other => file.decl_list.items.push(other),
1976                }
1977            }
1978
1979            // With nested packages handled push this file into the resolver.
1980            resolver.push(file)?;
1981        }
1982
1983        Ok((resolver.resolve()?, nested))
1984    }
1985
1986    pub(crate) fn highlight_span(&self, span: Span, err: impl fmt::Display) -> Option<String> {
1987        if !span.is_known() {
1988            return None;
1989        }
1990        Some(self.highlight_err(span.start(), Some(span.end()), err))
1991    }
1992
1993    fn highlight_err(&self, start: u32, end: Option<u32>, err: impl fmt::Display) -> String {
1994        let src = self.source_for_offset(start);
1995        let start = src.to_relative_offset(start);
1996        let end = end.map(|end| src.to_relative_offset(end));
1997        let (line, col) = src.linecol(start);
1998        let snippet = src.contents.lines().nth(line).unwrap_or("");
1999        let line = line + 1;
2000        let col = col + 1;
2001
2002        // If the snippet is too large then don't overload output on a terminal
2003        // for example and instead just print the error. This also sidesteps
2004        // Rust's restriction that `>0$` below has to be less than `u16::MAX`.
2005        if snippet.len() > 500 {
2006            return format!("{}:{line}:{col}: {err}", src.path);
2007        }
2008        let mut msg = format!(
2009            "\
2010{err}
2011     --> {file}:{line}:{col}
2012      |
2013 {line:4} | {snippet}
2014      | {marker:>0$}",
2015            col,
2016            file = src.path,
2017            marker = "^",
2018        );
2019        if let Some(end) = end {
2020            if let Some(s) = src.contents.get(start..end) {
2021                for _ in s.chars().skip(1) {
2022                    msg.push('-');
2023                }
2024            }
2025        }
2026        return msg;
2027    }
2028
2029    /// Resolves a global `span` to a location within a single source file.
2030    ///
2031    /// Returns the path the source was registered with and the span's byte
2032    /// range (UTF-8) relative to that file's contents. Returns `None` if
2033    /// `span` is unknown or does not fall within any source in this map.
2034    pub fn resolve_span(&self, span: Span) -> Option<SpanLocation<'_>> {
2035        if !span.is_known() || span.start() >= self.offset {
2036            return None;
2037        }
2038        let src = self.source_for_offset(span.start());
2039        // Exclude the synthetic `\n` appended by `push_str` so that spans
2040        // pointing at eof resolve to an empty range at the end of the file.
2041        let len = src.contents.len() - 1;
2042        let start = src.to_relative_offset(span.start()).min(len);
2043        let end = usize::try_from(span.end().saturating_sub(src.offset))
2044            .unwrap()
2045            .clamp(start, len);
2046        Some(SpanLocation {
2047            path: &src.path,
2048            range: start..end,
2049        })
2050    }
2051
2052    /// Renders a span as a human-readable location string (e.g., "file.wit:10:5").
2053    pub fn render_location(&self, span: Span) -> String {
2054        if !span.is_known() {
2055            return "<unknown>".to_string();
2056        }
2057        let start = span.start();
2058        let src = self.source_for_offset(start);
2059        let rel_start = src.to_relative_offset(start);
2060        let (line, col) = src.linecol(rel_start);
2061        format!(
2062            "{file}:{line}:{col}",
2063            file = src.path,
2064            line = line + 1,
2065            col = col + 1,
2066        )
2067    }
2068
2069    fn source_for_offset(&self, start: u32) -> &Source {
2070        let i = match self.sources.binary_search_by_key(&start, |src| src.offset) {
2071            Ok(i) => i,
2072            Err(i) => i - 1,
2073        };
2074        &self.sources[i]
2075    }
2076
2077    /// Returns an iterator over all filenames added to this source map.
2078    #[cfg(feature = "std")]
2079    pub fn source_files(&self) -> impl Iterator<Item = &Path> {
2080        self.sources.iter().map(|src| Path::new(&src.path))
2081    }
2082
2083    /// Returns an iterator over all source names added to this source map.
2084    pub fn source_names(&self) -> impl Iterator<Item = &str> {
2085        self.sources.iter().map(|src| src.path.as_str())
2086    }
2087}
2088
2089/// A [`Span`] resolved to a location within a single source file.
2090#[derive(Clone, Debug, PartialEq, Eq)]
2091pub struct SpanLocation<'a> {
2092    /// The path of the source, as it was registered with the [`SourceMap`].
2093    pub path: &'a str,
2094    /// The byte range (UTF-8) within the file's contents.
2095    pub range: core::ops::Range<usize>,
2096}
2097
2098impl Source {
2099    fn to_relative_offset(&self, offset: u32) -> usize {
2100        usize::try_from(offset - self.offset).unwrap()
2101    }
2102
2103    fn linecol(&self, relative_offset: usize) -> (usize, usize) {
2104        let mut cur = 0;
2105        // Use split_terminator instead of lines so that if there is a `\r`,
2106        // it is included in the offset calculation. The `+1` values below
2107        // account for the `\n`.
2108        for (i, line) in self.contents.split_terminator('\n').enumerate() {
2109            if cur + line.len() + 1 > relative_offset {
2110                return (i, relative_offset - cur);
2111            }
2112            cur += line.len() + 1;
2113        }
2114        (self.contents.lines().count(), 0)
2115    }
2116}
2117
2118pub enum ParsedUsePath {
2119    Name(String),
2120    Package(crate::PackageName, String),
2121}
2122
2123pub fn parse_use_path(s: &str) -> anyhow::Result<ParsedUsePath> {
2124    let mut tokens = Tokenizer::new(s, 0)?;
2125    let path = UsePath::parse(&mut tokens)?;
2126    if tokens.next()?.is_some() {
2127        anyhow::bail!("trailing tokens in path specifier");
2128    }
2129    Ok(match path {
2130        UsePath::Id(id) => ParsedUsePath::Name(id.name.to_string()),
2131        UsePath::Package { id, name } => {
2132            ParsedUsePath::Package(id.package_name(), name.name.to_string())
2133        }
2134    })
2135}
2136
2137#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
2138#[cfg_attr(
2139    feature = "serde",
2140    derive(serde_derive::Serialize, serde_derive::Deserialize)
2141)]
2142#[cfg_attr(feature = "serde", serde(into = "String", try_from = "String"))]
2143/// The fully-qualified name of a Component Model item (function,
2144/// type, or resource) as can be defined by wit. An item is optionally in a
2145/// package, the package optionally has a version, and the item is optionally
2146/// inside a namespace.
2147///
2148/// The syntax for an ItemName always uses the package version as a suffix, if
2149/// it is given. The following tests show examples of the syntax for ItemName:
2150/// ```rust
2151/// # use wit_parser::{ItemName, PackageName};
2152/// assert_eq!(
2153///     "foo".parse::<ItemName>().unwrap(),
2154///     ItemName {
2155///         package: None,
2156///         interface: None,
2157///         name: "foo".to_owned()
2158///     }
2159/// );
2160/// assert_eq!(
2161///     "foo.bar".parse::<ItemName>().unwrap(),
2162///     ItemName {
2163///         package: None,
2164///         interface: Some("foo".to_owned()),
2165///         name: "bar".to_owned()
2166///     }
2167/// );
2168/// assert_eq!(
2169///     "foo:bar/baz".parse::<ItemName>().unwrap(),
2170///     ItemName {
2171///         package: Some(PackageName {
2172///             namespace: "foo".to_owned(),
2173///             name: "bar".to_owned(),
2174///             version: None
2175///         }),
2176///         interface: None,
2177///         name: "baz".to_owned()
2178///     }
2179/// );
2180/// assert_eq!(
2181///     "foo:bar/baz@0.1.0".parse::<ItemName>().unwrap(),
2182///     ItemName {
2183///         package: Some(PackageName {
2184///             namespace: "foo".to_owned(),
2185///             name: "bar".to_owned(),
2186///             version: Some("0.1.0".parse().unwrap())
2187///         }),
2188///         interface: None,
2189///         name: "baz".to_owned()
2190///     }
2191/// );
2192/// assert_eq!(
2193///     "foo:bar/baz.bat".parse::<ItemName>().unwrap(),
2194///     ItemName {
2195///         package: Some(PackageName {
2196///             namespace: "foo".to_owned(),
2197///             name: "bar".to_owned(),
2198///             version: None
2199///         }),
2200///         interface: Some("baz".to_owned()),
2201///         name: "bat".to_owned()
2202///     }
2203/// );
2204/// assert_eq!(
2205///     "foo:bar/baz.bat@0.1.0".parse::<ItemName>().unwrap(),
2206///     ItemName {
2207///         package: Some(PackageName {
2208///             namespace: "foo".to_owned(),
2209///             name: "bar".to_owned(),
2210///             version: Some("0.1.0".parse().unwrap()),
2211///         }),
2212///         interface: Some("baz".to_owned()),
2213///         name: "bat".to_owned()
2214///     }
2215/// );
2216/// assert!("foo@0.1.0".parse::<ItemName>().is_err());
2217/// assert!("foo:bar@0.1.0".parse::<ItemName>().is_err());
2218/// assert!("foo:bar/baz@0.1.0.bat".parse::<ItemName>().is_err());
2219/// assert!("foo.bar@0.1.0".parse::<ItemName>().is_err());
2220/// assert!("foo@0.1.0.bar".parse::<ItemName>().is_err());
2221/// ```
2222///
2223/// Parse this from a string using its [`FromStr`](core::str::FromStr) or
2224/// [`TryFrom<String>`](core::convert::TryFrom) impls.
2225/// [`Display`](core::fmt::Display) to render to the same string syntax.
2226pub struct ItemName {
2227    pub package: Option<crate::PackageName>,
2228    pub interface: Option<String>,
2229    pub name: String,
2230}
2231impl ItemName {
2232    /// Get the name of the component instance containing this item, if any.
2233    /// The instance name will be formed like:
2234    /// "namespace.packagename/interfacename@0.1.0"
2235    /// ```rust
2236    /// # use wit_parser::ItemName;
2237    /// assert_eq!(
2238    ///     "foo".parse::<ItemName>().unwrap().instance_name(),
2239    ///     None,
2240    /// );
2241    /// assert_eq!(
2242    ///     "foo.bar".parse::<ItemName>().unwrap().instance_name(),
2243    ///     Some("foo".to_owned())
2244    /// );
2245    /// assert_eq!(
2246    ///     "foo:bar/baz.bat@0.1.0".parse::<ItemName>().unwrap().instance_name(),
2247    ///     Some("foo:bar/baz@0.1.0".to_owned())
2248    /// );
2249    /// ```
2250    pub fn instance_name(&self) -> Option<String> {
2251        if self.package.is_none() && self.interface.is_none() {
2252            return None;
2253        }
2254        let mut s = String::new();
2255        if let Some(crate::PackageName {
2256            namespace, name, ..
2257        }) = &self.package
2258        {
2259            s.push_str(&format!("{namespace}:{name}/"));
2260        }
2261        if let Some(name) = &self.interface {
2262            s.push_str(&format!("{name}"));
2263        }
2264        if let Some(crate::PackageName {
2265            version: Some(version),
2266            ..
2267        }) = &self.package
2268        {
2269            s.push_str(&format!("@{version}"));
2270        }
2271        Some(s)
2272    }
2273}
2274impl core::str::FromStr for ItemName {
2275    type Err = anyhow::Error;
2276    fn from_str(s: &str) -> anyhow::Result<ItemName> {
2277        let mut tokens = Tokenizer::new(s, 0)?;
2278
2279        let id = parse_id(&mut tokens)?;
2280        let (package, name) = if tokens.eat(Token::Colon)? {
2281            let name = parse_id(&mut tokens)?;
2282            tokens.expect(Token::Slash)?;
2283            (Some((id, name)), parse_id(&mut tokens)?)
2284        } else {
2285            (None, id)
2286        };
2287        let interface;
2288        let name = if tokens.eat(Token::Period)? {
2289            interface = Some(name.name.to_string());
2290            parse_id(&mut tokens)?
2291        } else {
2292            interface = None;
2293            name
2294        };
2295
2296        let package = package
2297            .map(|(namespace, name)| -> anyhow::Result<crate::PackageName> {
2298                let version = parse_opt_version(&mut tokens)?;
2299                Ok(PackageName {
2300                    docs: Docs::default(),
2301                    span: Span::new(
2302                        namespace.span.start(),
2303                        version
2304                            .as_ref()
2305                            .map(|(s, _)| s.end())
2306                            .unwrap_or(name.span.end()),
2307                    ),
2308                    namespace,
2309                    name,
2310                    version,
2311                }
2312                .package_name())
2313            })
2314            .transpose()?;
2315
2316        if tokens.next()?.is_some() {
2317            anyhow::bail!("trailing tokens in item name specifier");
2318        }
2319        Ok(ItemName {
2320            package,
2321            interface,
2322            name: name.name.to_string(),
2323        })
2324    }
2325}
2326impl core::convert::TryFrom<String> for ItemName {
2327    type Error = anyhow::Error;
2328    fn try_from(s: String) -> anyhow::Result<ItemName> {
2329        s.parse()
2330    }
2331}
2332impl fmt::Display for ItemName {
2333    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2334        if let Some(crate::PackageName {
2335            namespace, name, ..
2336        }) = &self.package
2337        {
2338            write!(f, "{namespace}:{name}/")?;
2339        }
2340        if let Some(int) = &self.interface {
2341            write!(f, "{int}.")?;
2342        }
2343        write!(f, "{}", self.name)?;
2344        if let Some(crate::PackageName {
2345            version: Some(version),
2346            ..
2347        }) = &self.package
2348        {
2349            write!(f, "@{version}")?;
2350        }
2351        Ok(())
2352    }
2353}
2354impl From<ItemName> for String {
2355    fn from(m: ItemName) -> String {
2356        m.to_string()
2357    }
2358}
2359
2360#[cfg(test)]
2361mod item_name_test {
2362    use super::{ItemName, Version};
2363    use crate::PackageName;
2364    use alloc::borrow::ToOwned;
2365
2366    fn assert_round_trip(s: &str) {
2367        use alloc::string::ToString;
2368        let i = s.parse::<ItemName>().unwrap();
2369        assert_eq!(i.to_string(), s);
2370    }
2371
2372    #[test]
2373    fn bare() {
2374        assert_eq!(
2375            "bare-kebab-name".parse::<ItemName>().unwrap(),
2376            ItemName {
2377                package: None,
2378                interface: None,
2379                name: "bare-kebab-name".to_owned()
2380            }
2381        );
2382        assert_round_trip("bare-kebab-name");
2383        // Invalid to have a version without a package name
2384        assert!("bare-kebab-name@0.1.0".parse::<ItemName>().is_err());
2385    }
2386    #[test]
2387    fn in_interface() {
2388        assert_eq!(
2389            "foo.bar".parse::<ItemName>().unwrap(),
2390            ItemName {
2391                package: None,
2392                interface: Some("foo".to_owned()),
2393                name: "bar".to_owned()
2394            }
2395        );
2396        assert_round_trip("foo.bar");
2397        // Invalid to have a version without a package name
2398        assert!("foo.bar@0.1.0".parse::<ItemName>().is_err());
2399    }
2400    #[test]
2401    fn in_package() {
2402        assert_eq!(
2403            "foo:bar/baz.bat".parse::<ItemName>().unwrap(),
2404            ItemName {
2405                package: Some(PackageName {
2406                    namespace: "foo".to_owned(),
2407                    name: "bar".to_owned(),
2408                    version: None
2409                }),
2410                interface: Some("baz".to_owned()),
2411                name: "bat".to_owned()
2412            }
2413        );
2414        assert_round_trip("foo:bar/baz.bat");
2415        assert_eq!(
2416            "foo:bar/baz.bat@0.1.0".parse::<ItemName>().unwrap(),
2417            ItemName {
2418                package: Some(PackageName {
2419                    namespace: "foo".to_owned(),
2420                    name: "bar".to_owned(),
2421                    version: Some(Version::parse("0.1.0").unwrap()),
2422                }),
2423                interface: Some("baz".to_owned()),
2424                name: "bat".to_owned()
2425            }
2426        );
2427        assert_round_trip("foo:bar/baz.bat@0.1.0");
2428        assert_eq!(
2429            "foo:bar/baz".parse::<ItemName>().unwrap(),
2430            ItemName {
2431                package: Some(PackageName {
2432                    namespace: "foo".to_owned(),
2433                    name: "bar".to_owned(),
2434                    version: None
2435                }),
2436                interface: None,
2437                name: "baz".to_owned()
2438            }
2439        );
2440        assert_round_trip("foo:bar/baz@0.1.0");
2441        assert_eq!(
2442            "foo:bar/baz@0.1.0".parse::<ItemName>().unwrap(),
2443            ItemName {
2444                package: Some(PackageName {
2445                    namespace: "foo".to_owned(),
2446                    name: "bar".to_owned(),
2447                    version: Some(Version::parse("0.1.0").unwrap()),
2448                }),
2449                interface: None,
2450                name: "baz".to_owned()
2451            }
2452        );
2453    }
2454}