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