| 1 | use crate::core::*; |
| 2 | use crate::kw; |
| 3 | use crate::parser::{Cursor, Parse, Parser, Peek, Result}; |
| 4 | use crate::token::{Id, NameAnnotation, Span}; |
| 5 | |
| 6 | /// An `import` statement and entry in a WebAssembly module. |
| 7 | #[derive (Debug, Clone)] |
| 8 | pub struct Import<'a> { |
| 9 | /// Where this `import` was defined |
| 10 | pub span: Span, |
| 11 | /// The module that this statement is importing from |
| 12 | pub module: &'a str, |
| 13 | /// The name of the field in the module this statement imports from. |
| 14 | pub field: &'a str, |
| 15 | /// The item that's being imported. |
| 16 | pub item: ItemSig<'a>, |
| 17 | } |
| 18 | |
| 19 | impl<'a> Parse<'a> for Import<'a> { |
| 20 | fn parse(parser: Parser<'a>) -> Result<Self> { |
| 21 | let span: Span = parser.parse::<kw::import>()?.0; |
| 22 | let module: &str = parser.parse()?; |
| 23 | let field: &str = parser.parse()?; |
| 24 | let item: ItemSig<'_> = parser.parens(|p: Parser<'a>| p.parse())?; |
| 25 | Ok(Import { |
| 26 | span, |
| 27 | module, |
| 28 | field, |
| 29 | item, |
| 30 | }) |
| 31 | } |
| 32 | } |
| 33 | |
| 34 | #[derive (Debug, Clone)] |
| 35 | #[allow (missing_docs)] |
| 36 | pub struct ItemSig<'a> { |
| 37 | /// Where this item is defined in the source. |
| 38 | pub span: Span, |
| 39 | /// An optional identifier used during name resolution to refer to this item |
| 40 | /// from the rest of the module. |
| 41 | pub id: Option<Id<'a>>, |
| 42 | /// An optional name which, for functions, will be stored in the |
| 43 | /// custom `name` section. |
| 44 | pub name: Option<NameAnnotation<'a>>, |
| 45 | /// What kind of item this is. |
| 46 | pub kind: ItemKind<'a>, |
| 47 | } |
| 48 | |
| 49 | #[derive (Debug, Clone)] |
| 50 | #[allow (missing_docs)] |
| 51 | pub enum ItemKind<'a> { |
| 52 | Func(TypeUse<'a, FunctionType<'a>>), |
| 53 | Table(TableType<'a>), |
| 54 | Memory(MemoryType), |
| 55 | Global(GlobalType<'a>), |
| 56 | Tag(TagType<'a>), |
| 57 | } |
| 58 | |
| 59 | impl<'a> Parse<'a> for ItemSig<'a> { |
| 60 | fn parse(parser: Parser<'a>) -> Result<Self> { |
| 61 | let mut l = parser.lookahead1(); |
| 62 | if l.peek::<kw::func>()? { |
| 63 | let span = parser.parse::<kw::func>()?.0; |
| 64 | Ok(ItemSig { |
| 65 | span, |
| 66 | id: parser.parse()?, |
| 67 | name: parser.parse()?, |
| 68 | kind: ItemKind::Func(parser.parse()?), |
| 69 | }) |
| 70 | } else if l.peek::<kw::table>()? { |
| 71 | let span = parser.parse::<kw::table>()?.0; |
| 72 | Ok(ItemSig { |
| 73 | span, |
| 74 | id: parser.parse()?, |
| 75 | name: None, |
| 76 | kind: ItemKind::Table(parser.parse()?), |
| 77 | }) |
| 78 | } else if l.peek::<kw::memory>()? { |
| 79 | let span = parser.parse::<kw::memory>()?.0; |
| 80 | Ok(ItemSig { |
| 81 | span, |
| 82 | id: parser.parse()?, |
| 83 | name: None, |
| 84 | kind: ItemKind::Memory(parser.parse()?), |
| 85 | }) |
| 86 | } else if l.peek::<kw::global>()? { |
| 87 | let span = parser.parse::<kw::global>()?.0; |
| 88 | Ok(ItemSig { |
| 89 | span, |
| 90 | id: parser.parse()?, |
| 91 | name: None, |
| 92 | kind: ItemKind::Global(parser.parse()?), |
| 93 | }) |
| 94 | } else if l.peek::<kw::tag>()? { |
| 95 | let span = parser.parse::<kw::tag>()?.0; |
| 96 | Ok(ItemSig { |
| 97 | span, |
| 98 | id: parser.parse()?, |
| 99 | name: None, |
| 100 | kind: ItemKind::Tag(parser.parse()?), |
| 101 | }) |
| 102 | } else { |
| 103 | Err(l.error()) |
| 104 | } |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | /// A listing of a inline `(import "foo")` statement. |
| 109 | /// |
| 110 | /// Note that when parsing this type it is somewhat unconventional that it |
| 111 | /// parses its own surrounding parentheses. This is typically an optional type, |
| 112 | /// so it's so far been a bit nicer to have the optionality handled through |
| 113 | /// `Peek` rather than `Option<T>`. |
| 114 | #[derive (Debug, Copy, Clone)] |
| 115 | #[allow (missing_docs)] |
| 116 | pub struct InlineImport<'a> { |
| 117 | pub module: &'a str, |
| 118 | pub field: &'a str, |
| 119 | } |
| 120 | |
| 121 | impl<'a> Parse<'a> for InlineImport<'a> { |
| 122 | fn parse(parser: Parser<'a>) -> Result<Self> { |
| 123 | parser.parens(|p: Parser<'a>| { |
| 124 | p.parse::<kw::import>()?; |
| 125 | Ok(InlineImport { |
| 126 | module: p.parse()?, |
| 127 | field: p.parse()?, |
| 128 | }) |
| 129 | }) |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | impl Peek for InlineImport<'_> { |
| 134 | fn peek(cursor: Cursor<'_>) -> Result<bool> { |
| 135 | let cursor = match cursor.lparen()? { |
| 136 | Some(cursor) => cursor, |
| 137 | None => return Ok(false), |
| 138 | }; |
| 139 | let cursor = match cursor.keyword()? { |
| 140 | Some(("import" , cursor)) => cursor, |
| 141 | _ => return Ok(false), |
| 142 | }; |
| 143 | let cursor = match cursor.string()? { |
| 144 | Some((_, cursor)) => cursor, |
| 145 | None => return Ok(false), |
| 146 | }; |
| 147 | let cursor = match cursor.string()? { |
| 148 | Some((_, cursor)) => cursor, |
| 149 | None => return Ok(false), |
| 150 | }; |
| 151 | |
| 152 | Ok(cursor.rparen()?.is_some()) |
| 153 | } |
| 154 | |
| 155 | fn display() -> &'static str { |
| 156 | "inline import" |
| 157 | } |
| 158 | } |
| 159 | |