Skip to content
This repository was archived by the owner on May 20, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions crates/wast/src/ast/expr.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::ast::{self, kw};
use crate::ast::{self, kw, RefType};
use crate::parser::{Parse, Parser, Result};
use std::mem;

Expand Down Expand Up @@ -411,8 +411,8 @@ instructions! {
TableSize(TableArg<'a>) : [0xfc, 0x10] : "table.size",
TableGrow(TableArg<'a>) : [0xfc, 0x0f] : "table.grow",

RefNull : [0xd0] : "ref.null",
RefIsNull : [0xd1] : "ref.is_null",
RefNull(RefType<'a>) : [0xd0] : "ref.null",
RefIsNull(RefType<'a>) : [0xd1] : "ref.is_null",
RefHost(u32) : [0xff] : "ref.host", // only used in test harness
RefFunc(ast::Index<'a>) : [0xd2] : "ref.func",

Expand Down
2 changes: 2 additions & 0 deletions crates/wast/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,8 @@ pub mod kw {
custom_keyword!(exn);
custom_keyword!(exnref);
custom_keyword!(export);
custom_keyword!(r#extern = "extern");
custom_keyword!(externref);
custom_keyword!(eq);
custom_keyword!(eqref);
custom_keyword!(f32);
Expand Down
12 changes: 8 additions & 4 deletions crates/wast/src/ast/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,23 +208,27 @@ impl<'a> ElemPayload<'a> {
let func = parser.parens(|p| match p.parse::<Option<kw::item>>()? {
Some(_) => {
if parser.peek::<ast::LParen>() {
parser.parens(parse_ref_func)
parser.parens(|p| parse_ref_func(p, ty))
} else {
parse_ref_func(parser)
parse_ref_func(parser, ty)
}
}
None => parse_ref_func(p),
None => parse_ref_func(parser, ty),
})?;
exprs.push(func);
}
Ok(ElemPayload::Exprs { exprs, ty })
}
}

fn parse_ref_func<'a>(parser: Parser<'a>) -> Result<Option<ast::Index<'a>>> {
fn parse_ref_func<'a>(parser: Parser<'a>, ty: ast::TableElemType) -> Result<Option<ast::Index<'a>>> {
let mut l = parser.lookahead1();
if l.peek::<kw::ref_null>() {
parser.parse::<kw::ref_null>()?;
let null_ty: ast::RefType = parser.parse()?;
if null_ty != ty.into() {
return Err(parser.error("elem segment item doesn't match elem segment type"));
}
Ok(None)
} else if l.peek::<kw::ref_func>() {
parser.parse::<kw::ref_func>()?;
Expand Down
147 changes: 90 additions & 57 deletions crates/wast/src/ast/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,7 @@ pub enum ValType<'a> {
V128,
I8,
I16,
Funcref,
Anyref,
Nullref,
Exnref,
Ref(ast::Index<'a>),
Optref(ast::Index<'a>),
Eqref,
I31ref,
Ref(RefType<'a>),
Rtt(ast::Index<'a>),
}

Expand Down Expand Up @@ -49,52 +42,27 @@ impl<'a> Parse<'a> for ValType<'a> {
Ok(ValType::I16)
} else if l.peek::<kw::funcref>() {
parser.parse::<kw::funcref>()?;
Ok(ValType::Funcref)
Ok(ValType::Ref(RefType::Func))
} else if l.peek::<kw::anyfunc>() {
parser.parse::<kw::anyfunc>()?;
Ok(ValType::Funcref)
Ok(ValType::Ref(RefType::Func))
} else if l.peek::<kw::externref>() {
parser.parse::<kw::externref>()?;
Ok(ValType::Ref(RefType::Extern))
} else if l.peek::<kw::anyref>() {
// Parse `anyref` as an alias of `externref` until all tests are
// ported to use the new name
parser.parse::<kw::anyref>()?;
Ok(ValType::Anyref)
} else if l.peek::<kw::nullref>() {
parser.parse::<kw::nullref>()?;
Ok(ValType::Nullref)
Ok(ValType::Ref(RefType::Extern))
} else if l.peek::<ast::LParen>() {
parser.parens(|p| {
let mut l = parser.lookahead1();
if l.peek::<kw::r#ref>() {
p.parse::<kw::r#ref>()?;

let mut l = parser.lookahead1();
if l.peek::<kw::func>() {
parser.parse::<kw::func>()?;
Ok(ValType::Funcref)
} else if l.peek::<kw::any>() {
parser.parse::<kw::any>()?;
Ok(ValType::Anyref)
} else if l.peek::<kw::null>() {
parser.parse::<kw::null>()?;
Ok(ValType::Nullref)
} else if l.peek::<kw::exn>() {
parser.parse::<kw::exn>()?;
Ok(ValType::Exnref)
} else if l.peek::<kw::eq>() {
parser.parse::<kw::eq>()?;
Ok(ValType::Eqref)
} else if l.peek::<kw::i31>() {
parser.parse::<kw::i31>()?;
Ok(ValType::I31ref)
} else if l.peek::<kw::opt>() {
parser.parse::<kw::opt>()?;
Ok(ValType::Optref(parser.parse()?))
} else if l.peek::<ast::Index>() {
Ok(ValType::Ref(parser.parse()?))
} else {
Err(l.error())
}
Ok(ValType::Ref(p.parse()?))
} else if l.peek::<kw::optref>() {
p.parse::<kw::optref>()?;
Ok(ValType::Optref(parser.parse()?))
Ok(ValType::Ref(RefType::OptType(parser.parse()?)))
} else if l.peek::<kw::rtt>() {
p.parse::<kw::rtt>()?;
Ok(ValType::Rtt(parser.parse()?))
Expand All @@ -104,13 +72,80 @@ impl<'a> Parse<'a> for ValType<'a> {
})
} else if l.peek::<kw::exnref>() {
parser.parse::<kw::exnref>()?;
Ok(ValType::Exnref)
Ok(ValType::Ref(RefType::Exn))
} else if l.peek::<kw::eqref>() {
parser.parse::<kw::eqref>()?;
Ok(ValType::Eqref)
Ok(ValType::Ref(RefType::Eq))
} else if l.peek::<kw::i31ref>() {
parser.parse::<kw::i31ref>()?;
Ok(ValType::I31ref)
Ok(ValType::Ref(RefType::I31))
} else {
Err(l.error())
}
}
}

/// The reference value types for a wasm module.
#[allow(missing_docs)]
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
pub enum RefType<'a> {
/// An untyped function reference: funcref. This is part of the reference
/// types proposal.
Func,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mind adding a few comments to the variants here? The first two I think are reference-types proposal types, the next is exception handling, and everything else is the gc proposal, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's the case. I've added some comments explaining the types.

/// A reference to any host value: externref. This was originally known as
/// anyref when it was the supertype of all reference value types. This is
/// part of the reference types proposal.
Extern,
/// A reference to an exception: exnref. This is part of the exception
/// handling proposal.
Exn,
/// A reference that has an identity that can be compared: eqref. This is
/// part of the GC proposal.
Eq,
/// An unboxed 31-bit integer: i31ref. This may be going away if there is no common
/// supertype of all reference types. Part of the GC proposal.
I31,
/// A reference to a function, struct, or array: ref T. This is part of the
/// GC proposal.
Type(ast::Index<'a>),
/// A nullable reference to a function, struct, or array: optref T. This is
/// part of the GC proposal.
OptType(ast::Index<'a>),
}

impl<'a> From<TableElemType> for RefType<'a> {
fn from(elem: TableElemType) -> Self {
match elem {
TableElemType::Funcref => RefType::Func,
TableElemType::Externref => RefType::Extern,
TableElemType::Exnref => RefType::Exn,
}
}
}

impl<'a> Parse<'a> for RefType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::func>() {
parser.parse::<kw::func>()?;
Ok(RefType::Func)
} else if l.peek::<kw::r#extern>() {
parser.parse::<kw::r#extern>()?;
Ok(RefType::Extern)
} else if l.peek::<kw::exn>() {
parser.parse::<kw::exn>()?;
Ok(RefType::Exn)
} else if l.peek::<kw::eq>() {
parser.parse::<kw::eq>()?;
Ok(RefType::Eq)
} else if l.peek::<kw::i31>() {
parser.parse::<kw::i31>()?;
Ok(RefType::I31)
} else if l.peek::<kw::opt>() {
parser.parse::<kw::opt>()?;
Ok(RefType::OptType(parser.parse()?))
} else if l.peek::<ast::Index>() {
Ok(RefType::Type(parser.parse()?))
} else {
Err(l.error())
}
Expand Down Expand Up @@ -146,16 +181,12 @@ impl<'a> Parse<'a> for GlobalType<'a> {
}

/// List of different kinds of table types we can have.
///
/// Currently there's only one, a `funcref`.
#[derive(Copy, Clone, Debug)]
pub enum TableElemType {
/// An element for a table that is a list of functions.
Funcref,
/// An element for a table that is a list of `anyref` values.
Anyref,
/// An element for a table that is a list of `nullref` values.
Nullref,
/// An element for a table that is a list of `externref` values.
Externref,
/// An element for a table that is a list of `exnref` values.
Exnref,
}
Expand All @@ -172,11 +203,13 @@ impl<'a> Parse<'a> for TableElemType {
parser.parse::<kw::funcref>()?;
Ok(TableElemType::Funcref)
} else if l.peek::<kw::anyref>() {
// Parse `anyref` as an alias of `externref` until all tests are
// ported to use the new name
parser.parse::<kw::anyref>()?;
Ok(TableElemType::Anyref)
} else if l.peek::<kw::nullref>() {
parser.parse::<kw::nullref>()?;
Ok(TableElemType::Nullref)
Ok(TableElemType::Externref)
} else if l.peek::<kw::externref>() {
parser.parse::<kw::externref>()?;
Ok(TableElemType::Externref)
} else if l.peek::<kw::exnref>() {
parser.parse::<kw::exnref>()?;
Ok(TableElemType::Exnref)
Expand All @@ -190,7 +223,7 @@ impl Peek for TableElemType {
fn peek(cursor: Cursor<'_>) -> bool {
kw::funcref::peek(cursor)
|| kw::anyref::peek(cursor)
|| kw::nullref::peek(cursor)
|| kw::externref::peek(cursor)
|| /* legacy */ kw::anyfunc::peek(cursor)
|| kw::exnref::peek(cursor)
}
Expand Down
44 changes: 26 additions & 18 deletions crates/wast/src/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,24 +250,33 @@ impl<'a> Encode for ValType<'a> {
ValType::V128 => e.push(0x7b),
ValType::I8 => e.push(0x7a),
ValType::I16 => e.push(0x79),
ValType::Funcref => e.push(0x70),
ValType::Anyref => e.push(0x6f),
ValType::Nullref => e.push(0x6e),
ValType::Ref(index) => {
e.push(0x6d);
ValType::Ref(ty) => {
ty.encode(e);
}
ValType::Rtt(index) => {
e.push(0x69);
index.encode(e);
}
ValType::Optref(index) => {
e.push(0x6c);
}
}
}

impl<'a> Encode for RefType<'a> {
fn encode(&self, e: &mut Vec<u8>) {
match self {
RefType::Func => e.push(0x70),
RefType::Extern => e.push(0x6f),
RefType::Eq => e.push(0x6b),
RefType::I31 => e.push(0x6a),
RefType::Exn => e.push(0x68),
RefType::Type(index) => {
e.push(0x6d);
index.encode(e);
}
ValType::Eqref => e.push(0x6b),
ValType::I31ref => e.push(0x6a),
ValType::Rtt(index) => {
e.push(0x69);
RefType::OptType(index) => {
e.push(0x6c);
index.encode(e);
}
ValType::Exnref => e.push(0x68),
}
}
}
Expand Down Expand Up @@ -329,10 +338,9 @@ impl Encode for TableType {
impl Encode for TableElemType {
fn encode(&self, e: &mut Vec<u8>) {
match self {
TableElemType::Funcref => ValType::Funcref.encode(e),
TableElemType::Anyref => ValType::Anyref.encode(e),
TableElemType::Nullref => ValType::Nullref.encode(e),
TableElemType::Exnref => ValType::Exnref.encode(e),
TableElemType::Funcref => RefType::Func.encode(e),
TableElemType::Externref => RefType::Extern.encode(e),
TableElemType::Exnref => RefType::Exn.encode(e),
}
}
}
Expand Down Expand Up @@ -517,15 +525,15 @@ impl Encode for ElemPayload<'_> {
fn encode(&self, e: &mut Vec<u8>) {
match self {
ElemPayload::Indices(v) => v.encode(e),
ElemPayload::Exprs { exprs, .. } => {
ElemPayload::Exprs { exprs, ty } => {
exprs.len().encode(e);
for idx in exprs {
match idx {
Some(idx) => {
Instruction::RefFunc(*idx).encode(e);
}
None => {
Instruction::RefNull.encode(e);
Instruction::RefNull((*ty).into()).encode(e);
}
}
Instruction::End(None).encode(e);
Expand Down
17 changes: 16 additions & 1 deletion crates/wast/src/resolve/names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,20 @@ impl<'a> Resolver<'a> {

fn resolve_valtype(&self, ty: &mut ValType<'a>) -> Result<(), Error> {
match ty {
ValType::Ref(i) | ValType::Optref(i) | ValType::Rtt(i) => {
ValType::Ref(ty) => self.resolve_reftype(ty)?,
ValType::Rtt(i) => {
self.ns(Ns::Type)
.resolve(i)
.map_err(|id| self.resolve_error(id, "type"))?;
}
_ => {}
}
Ok(())
}

fn resolve_reftype(&self, ty: &mut RefType<'a>) -> Result<(), Error> {
match ty {
RefType::Type(i) | RefType::OptType(i) => {
self.ns(Ns::Type)
.resolve(i)
.map_err(|id| self.resolve_error(id, "type"))?;
Expand Down Expand Up @@ -548,6 +561,8 @@ impl<'a, 'b> ExprResolver<'a, 'b> {
self.resolver.resolve_valtype(&mut s.to)
}

RefNull(ty) | RefIsNull(ty) => self.resolver.resolve_reftype(ty),

_ => Ok(()),
}
}
Expand Down
1 change: 0 additions & 1 deletion tests/regression/gc-struct.wat
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,5 @@
(func
struct.narrow i32 f32
struct.narrow anyref funcref
struct.narrow anyref nullref
)
)
Loading