Coverage Report

Created: 2026-06-21 07:19

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