diff options
-rw-r--r-- | src/wasm/wat-parser.cpp | 141 | ||||
-rw-r--r-- | test/lit/wat-kitchen-sink.wast | 44 |
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)) |