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