wast/component/
item_ref.rs

1use crate::parser::{Cursor, Parse, Parser, Peek, Result};
2use crate::token::Index;
3
4fn peek<K: Peek>(cursor: Cursor) -> Result<bool> {
5    // This is a little fancy because when parsing something like:
6    //
7    //      (type (component (type $foo)))
8    //
9    // we need to disambiguate that from
10    //
11    //      (type (component (type $foo (func))))
12    //
13    // where the first is a type reference and the second is an inline
14    // component type defining a type internally. The peek here not only
15    // peeks for `K` but also for the index and possibly trailing
16    // strings.
17
18    // Peek for the given keyword type
19    if !K::peek(cursor)? {
20        return Ok(false);
21    }
22
23    // Move past the given keyword
24    let cursor = match cursor.keyword()? {
25        Some((_, c)) => c,
26        _ => return Ok(false),
27    };
28
29    // Peek an id or integer index, followed by `)` or string to disambiguate
30    let cursor = match cursor.id()? {
31        Some((_, cursor)) => Some(cursor),
32        None => cursor.integer()?.map(|p| p.1),
33    };
34    Ok(match cursor {
35        Some(cursor) => cursor.rparen()?.is_some() || cursor.string()?.is_some(),
36        None => false,
37    })
38}
39
40/// Parses core item references.
41#[derive(Clone, Debug)]
42pub struct CoreItemRef<'a, K> {
43    /// The item kind being parsed.
44    pub kind: K,
45    /// The item or instance reference.
46    pub idx: Index<'a>,
47    /// Export name to resolve the item from.
48    pub export_name: Option<&'a str>,
49}
50
51impl<'a, K: Parse<'a>> Parse<'a> for CoreItemRef<'a, K> {
52    fn parse(parser: Parser<'a>) -> Result<Self> {
53        // This does not parse the surrounding `(` and `)` because
54        // core prefix is context dependent and only the caller knows if it should be
55        // present for core references; therefore, the caller parses the parens and any core prefix
56        let kind = parser.parse::<K>()?;
57        let idx = parser.parse()?;
58        let export_name = parser.parse()?;
59        Ok(Self {
60            kind,
61            idx,
62            export_name,
63        })
64    }
65}
66
67impl<'a, K: Peek> Peek for CoreItemRef<'a, K> {
68    fn peek(cursor: Cursor<'_>) -> Result<bool> {
69        peek::<K>(cursor)
70    }
71
72    fn display() -> &'static str {
73        "a core item reference"
74    }
75}
76
77/// Parses component item references.
78#[derive(Clone, Debug)]
79pub struct ItemRef<'a, K> {
80    /// The item kind being parsed.
81    pub kind: K,
82    /// The item or instance reference.
83    pub idx: Index<'a>,
84    /// Export names to resolve the item from.
85    pub export_names: Vec<&'a str>,
86}
87
88impl<'a, K: Parse<'a>> Parse<'a> for ItemRef<'a, K> {
89    fn parse(parser: Parser<'a>) -> Result<Self> {
90        let kind = parser.parse::<K>()?;
91        let idx = parser.parse()?;
92        let mut export_names = Vec::new();
93        while !parser.is_empty() {
94            export_names.push(parser.parse()?);
95        }
96        Ok(Self {
97            kind,
98            idx,
99            export_names,
100        })
101    }
102}
103
104impl<'a, K: Peek> Peek for ItemRef<'a, K> {
105    fn peek(cursor: Cursor<'_>) -> Result<bool> {
106        peek::<K>(cursor)
107    }
108
109    fn display() -> &'static str {
110        "a component item reference"
111    }
112}
113
114/// Convenience structure to parse `$f` or `(item $f)`.
115#[derive(Clone, Debug)]
116pub struct IndexOrRef<'a, K>(pub ItemRef<'a, K>);
117
118impl<'a, K> Parse<'a> for IndexOrRef<'a, K>
119where
120    K: Parse<'a> + Default,
121{
122    fn parse(parser: Parser<'a>) -> Result<Self> {
123        if parser.peek::<Index<'_>>()? {
124            Ok(IndexOrRef(ItemRef {
125                kind: K::default(),
126                idx: parser.parse()?,
127                export_names: Vec::new(),
128            }))
129        } else {
130            Ok(IndexOrRef(parser.parens(|p| p.parse())?))
131        }
132    }
133}
134
135/// Convenience structure to parse `$f` or `(item $f)`.
136#[derive(Clone, Debug)]
137pub struct IndexOrCoreRef<'a, K>(pub CoreItemRef<'a, K>);
138
139impl<'a, K> Parse<'a> for IndexOrCoreRef<'a, K>
140where
141    K: Parse<'a> + Default,
142{
143    fn parse(parser: Parser<'a>) -> Result<Self> {
144        if parser.peek::<Index<'_>>()? {
145            Ok(IndexOrCoreRef(CoreItemRef {
146                kind: K::default(),
147                idx: parser.parse()?,
148                export_name: None,
149            }))
150        } else {
151            Ok(IndexOrCoreRef(parser.parens(|p| p.parse())?))
152        }
153    }
154}