Skip to main content

wit_parser/
ast.rs

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