summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wasm/wat-parser.cpp141
-rw-r--r--test/lit/wat-kitchen-sink.wast44
2 files changed, 120 insertions, 65 deletions
diff --git a/src/wasm/wat-parser.cpp b/src/wasm/wat-parser.cpp
index 54aa1dc7d..b81a92464 100644
--- a/src/wasm/wat-parser.cpp
+++ b/src/wasm/wat-parser.cpp
@@ -296,6 +296,7 @@ struct ParseDeclsCtx {
// At this stage we only look at types to find implicit type definitions,
// which are inserted directly in to the context. We cannot materialize or
// validate any types because we don't know what types exist yet.
+ using IndexT = Ok;
using HeapTypeT = Ok;
using TypeT = Ok;
using ParamsT = Ok;
@@ -329,6 +330,7 @@ inline constexpr bool parsingDecls = std::is_same_v<Ctx, ParseDeclsCtx>;
// Phase 2: Parse type definitions into a TypeBuilder.
struct ParseTypeDefsCtx {
+ using IndexT = Index;
using HeapTypeT = HeapType;
using TypeT = Type;
using ParamsT = std::vector<NameType>;
@@ -364,6 +366,7 @@ inline constexpr bool parsingTypeDefs = std::is_same_v<Ctx, ParseTypeDefsCtx>;
struct ParseModuleTypesCtx {
// In this phase we have constructed all the types, so we can materialize and
// validate them when they are used.
+ using IndexT = Index;
using HeapTypeT = HeapType;
using TypeT = Type;
using ParamsT = std::vector<NameType>;
@@ -420,10 +423,15 @@ MaybeResult<typename Ctx::ArrayT> arraytype(Ctx&, ParseInput&);
// Modules
template<typename Ctx>
+MaybeResult<typename Ctx::IndexT> maybeTypeidx(Ctx& ctx, ParseInput& in);
+template<typename Ctx>
Result<typename Ctx::HeapTypeT> typeidx(Ctx&, ParseInput&);
MaybeResult<ImportNames> inlineImport(ParseInput&);
Result<std::vector<Name>> inlineExports(ParseInput&);
-template<typename Ctx> MaybeResult<> strtype(Ctx&, ParseInput&);
+template<typename Ctx> Result<> strtype(Ctx&, ParseInput&);
+template<typename Ctx>
+MaybeResult<typename Ctx::ModuleNameT> subtype(Ctx&, ParseInput&);
+template<typename Ctx> MaybeResult<> deftype(Ctx&, ParseInput&);
template<typename Ctx> MaybeResult<> global(Ctx&, ParseInput&);
MaybeResult<> modulefield(ParseDeclsCtx&, ParseInput&);
Result<> module(ParseDeclsCtx&, ParseInput&);
@@ -811,35 +819,43 @@ Result<typename Ctx::GlobalTypeT> globaltype(Ctx& ctx, ParseInput& in) {
// typeidx ::= x:u32 => x
// | v:id => x (if types[x] = v)
template<typename Ctx>
-Result<typename Ctx::HeapTypeT> typeidx(Ctx& ctx, ParseInput& in) {
- [[maybe_unused]] Index index;
+MaybeResult<typename Ctx::IndexT> maybeTypeidx(Ctx& ctx, ParseInput& in) {
if (auto x = in.takeU32()) {
- index = *x;
- } else if (auto id = in.takeID()) {
- if constexpr (!parsingDecls<Ctx>) {
+ RETURN_OR_OK(*x);
+ }
+ if (auto id = in.takeID()) {
+ if constexpr (parsingDecls<Ctx>) {
+ return Ok{};
+ } else {
auto it = ctx.typeIndices.find(*id);
if (it == ctx.typeIndices.end()) {
return in.err("unknown type identifier");
}
- index = it->second;
+ return it->second;
}
- } else {
- return in.err("expected type index or identifier");
}
+ return {};
+}
- if constexpr (parsingDecls<Ctx>) {
- return Ok{};
- } else if constexpr (parsingTypeDefs<Ctx>) {
- if (index >= ctx.builder.size()) {
- return in.err("type index out of bounds");
- }
- return ctx.builder[index];
- } else {
- if (index >= ctx.types.size()) {
- return in.err("type index out of bounds");
+template<typename Ctx>
+Result<typename Ctx::HeapTypeT> typeidx(Ctx& ctx, ParseInput& in) {
+ if (auto index = maybeTypeidx(ctx, in)) {
+ CHECK_ERR(index);
+ if constexpr (parsingDecls<Ctx>) {
+ return Ok{};
+ } else if constexpr (parsingTypeDefs<Ctx>) {
+ if (*index >= ctx.builder.size()) {
+ return in.err("type index out of bounds");
+ }
+ return ctx.builder[*index];
+ } else {
+ if (*index >= ctx.types.size()) {
+ return in.err("type index out of bounds");
+ }
+ return ctx.types[*index];
}
- return ctx.types[index];
}
+ return in.err("expected type index or identifier");
}
// ('(' 'import' mod:name nm:name ')')?
@@ -877,30 +893,18 @@ Result<std::vector<Name>> inlineExports(ParseInput& in) {
return exports;
}
-// strtype ::= '(' 'type' id? ft:functype ')' => ft
-// | '(' 'type' id? st:structtype ')' => st
-// | '(' 'type' id? at:arraytype ')' => at
-template<typename Ctx> MaybeResult<> strtype(Ctx& ctx, ParseInput& in) {
- [[maybe_unused]] auto start = in.getPos();
-
- if (!in.takeSExprStart("type"sv)) {
- return {};
- }
-
- Name name;
- if (auto id = in.takeID()) {
- name = *id;
- if constexpr (parsingTypeDefs<Ctx>) {
- ctx.names[ctx.index].name = name;
- }
- }
-
+// strtype ::= ft:functype => ft
+// | st:structtype => st
+// | at:arraytype => at
+template<typename Ctx> Result<> strtype(Ctx& ctx, ParseInput& in) {
if (auto type = functype(ctx, in)) {
CHECK_ERR(type);
if constexpr (parsingTypeDefs<Ctx>) {
ctx.builder[ctx.index] = *type;
}
- } else if (auto type = structtype(ctx, in)) {
+ return Ok{};
+ }
+ if (auto type = structtype(ctx, in)) {
CHECK_ERR(type);
if constexpr (parsingTypeDefs<Ctx>) {
auto& [fieldNames, str] = *type;
@@ -911,13 +915,53 @@ template<typename Ctx> MaybeResult<> strtype(Ctx& ctx, ParseInput& in) {
}
}
}
- } else if (auto type = arraytype(ctx, in)) {
+ return Ok{};
+ }
+ if (auto type = arraytype(ctx, in)) {
CHECK_ERR(type);
if constexpr (parsingTypeDefs<Ctx>) {
ctx.builder[ctx.index] = *type;
}
+ return Ok{};
+ }
+ return in.err("expected type description");
+}
+
+// subtype ::= '(' 'type' id? '(' 'sub' typeidx? strtype ')' ')'
+// | '(' 'type' id? strtype ')'
+template<typename Ctx> MaybeResult<> subtype(Ctx& ctx, ParseInput& in) {
+ [[maybe_unused]] auto start = in.getPos();
+
+ if (!in.takeSExprStart("type"sv)) {
+ return {};
+ }
+
+ Name name;
+ if (auto id = in.takeID()) {
+ name = *id;
+ if constexpr (parsingTypeDefs<Ctx>) {
+ ctx.names[ctx.index].name = name;
+ }
+ }
+
+ if (in.takeSExprStart("sub"sv)) {
+ if (auto super = maybeTypeidx(ctx, in)) {
+ CHECK_ERR(super);
+ if constexpr (parsingTypeDefs<Ctx>) {
+ if (*super >= ctx.builder.size()) {
+ return in.err("supertype index out of bounds");
+ }
+ ctx.builder[ctx.index].subTypeOf(ctx.builder[*super]);
+ }
+ }
+
+ CHECK_ERR(strtype(ctx, in));
+
+ if (!in.takeRParen()) {
+ return in.err("expected end of subtype definition");
+ }
} else {
- return in.err("expected type description");
+ CHECK_ERR(strtype(ctx, in));
}
if (!in.takeRParen()) {
@@ -927,16 +971,16 @@ template<typename Ctx> MaybeResult<> strtype(Ctx& ctx, ParseInput& in) {
if constexpr (parsingDecls<Ctx>) {
ctx.typeDefs.push_back({name, start});
}
+
return Ok{};
}
-// subtype ::= '(' 'sub' typeidx? strtype ')'
-// | strtype
-// TODO
-
// deftype ::= '(' 'rec' subtype* ')'
// | subtype
-// TODO:
+template<typename Ctx> MaybeResult<> deftype(Ctx& ctx, ParseInput& in) {
+ // TODO: rec
+ return subtype(ctx, in);
+}
// global ::= '(' 'global' id? ('(' 'export' name ')')* gt:globaltype e:expr ')'
// | '(' 'global' id? '(' 'import' mod:name nm:name ')'
@@ -998,8 +1042,7 @@ MaybeResult<> modulefield(ParseDeclsCtx& ctx, ParseInput& in) {
if (auto t = in.peek(); !t || t->isRParen()) {
return {};
}
- // TODO: Replace strtype with deftype.
- if (auto res = strtype(ctx, in)) {
+ if (auto res = deftype(ctx, in)) {
CHECK_ERR(res);
return Ok{};
}
@@ -1140,7 +1183,7 @@ Result<> parseModule(Module& wasm, std::string_view input) {
{
TypeBuilder builder(decls.typeDefs.size());
ParseTypeDefsCtx ctx(builder, *typeIndices);
- CHECK_ERR(parseDefs(ctx, input, decls.typeDefs, strtype));
+ CHECK_ERR(parseDefs(ctx, input, decls.typeDefs, deftype));
auto built = builder.build();
if (auto* err = built.getError()) {
std::stringstream msg;
diff --git a/test/lit/wat-kitchen-sink.wast b/test/lit/wat-kitchen-sink.wast
index 1520003a6..315cb172c 100644
--- a/test/lit/wat-kitchen-sink.wast
+++ b/test/lit/wat-kitchen-sink.wast
@@ -1,43 +1,49 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
-;; RUN: wasm-opt --new-wat-parser -all %s -S -o - | filecheck %s
+;; RUN: wasm-opt --new-wat-parser --hybrid -all %s -S -o - | filecheck %s
(module $parse
;; types
- ;; CHECK: (type $s0 (struct ))
+ ;; CHECK: (type $s0 (struct_subtype data))
- ;; CHECK: (type $void (func))
+ ;; CHECK: (type $void (func_subtype func))
(type $void (func))
- ;; CHECK: (type $many (func (param i32 i64 f32 f64) (result anyref (ref func))))
+ ;; CHECK: (type $many (func_subtype (param i32 i64 f32 f64) (result anyref (ref func)) func))
(type $many (func (param $x i32) (param i64 f32) (param) (param $y f64)
(result anyref (ref func))))
- (type $s0 (struct))
+ (type $s0 (sub (struct)))
(type $s1 (struct (field)))
- ;; CHECK: (type $s2 (struct (field i32)))
+ ;; CHECK: (type $s2 (struct_subtype (field i32) data))
(type $s2 (struct i32))
- ;; CHECK: (type $s3 (struct (field i64)))
+ ;; CHECK: (type $s3 (struct_subtype (field i64) data))
(type $s3 (struct (field i64)))
- ;; CHECK: (type $s4 (struct (field $x f32)))
+ ;; CHECK: (type $s4 (struct_subtype (field $x f32) data))
(type $s4 (struct (field $x f32)))
- ;; CHECK: (type $s5 (struct (field i32) (field i64)))
+ ;; CHECK: (type $s5 (struct_subtype (field i32) (field i64) data))
(type $s5 (struct i32 i64))
- ;; CHECK: (type $s6 (struct (field i64) (field f32)))
+ ;; CHECK: (type $s6 (struct_subtype (field i64) (field f32) data))
(type $s6 (struct (field i64 f32)))
- ;; CHECK: (type $s7 (struct (field $x f32) (field $y f64)))
+ ;; CHECK: (type $s7 (struct_subtype (field $x f32) (field $y f64) data))
(type $s7 (struct (field $x f32) (field $y f64)))
- ;; CHECK: (type $s8 (struct (field i32) (field i64) (field $z f32) (field f64) (field (mut i32))))
+ ;; CHECK: (type $s8 (struct_subtype (field i32) (field i64) (field $z f32) (field f64) (field (mut i32)) data))
(type $s8 (struct i32 (field) i64 (field $z f32) (field f64 (mut i32))))
- ;; CHECK: (type $a0 (array i32))
+ ;; CHECK: (type $a0 (array_subtype i32 data))
(type $a0 (array i32))
- ;; CHECK: (type $a1 (array i64))
+ ;; CHECK: (type $a1 (array_subtype i64 data))
(type $a1 (array (field i64)))
- ;; CHECK: (type $a2 (array (mut f32)))
+ ;; CHECK: (type $a2 (array_subtype (mut f32) data))
(type $a2 (array (mut f32)))
- ;; CHECK: (type $a3 (array (mut f64)))
+ ;; CHECK: (type $a3 (array_subtype (mut f64) data))
(type $a3 (array (field $x (mut f64))))
+ ;; CHECK: (type $subvoid (func_subtype $void))
+ (type $subvoid (sub 0 (func)))
+
+ ;; CHECK: (type $submany (func_subtype (param i32 i64 f32 f64) (result anyref (ref func)) $many))
+ (type $submany (sub $many (func (param i32 i64 f32 f64) (result anyref (ref func)))))
+
;; globals
(global $g1 (export "g1") (export "g1.1") (import "mod" "g1") i32)
(global $g2 (import "mod" "g2") (mut i64))
@@ -59,6 +65,8 @@
(global $a1 (import "mod" "a1") (mut (ref $a1)))
(global $a2 (import "mod" "a2") (mut (ref $a2)))
(global $a3 (import "mod" "a3") (mut (ref $a3)))
+ (global $sub0 (import "mod" "sub0") (mut (ref $subvoid)))
+ (global $sub1 (import "mod" "sub1") (mut (ref $submany)))
)
;; CHECK: (import "mod" "g1" (global $g1 i32))
@@ -94,6 +102,10 @@
;; CHECK: (import "mod" "a3" (global $a3 (mut (ref $a3))))
+;; CHECK: (import "mod" "sub0" (global $sub0 (mut (ref $subvoid))))
+
+;; CHECK: (import "mod" "sub1" (global $sub1 (mut (ref $submany))))
+
;; CHECK: (export "g1" (global $g1))
;; CHECK: (export "g1.1" (global $g1))