diff options
Diffstat (limited to 'src/wasm')
-rw-r--r-- | src/wasm/wat-parser.cpp | 918 |
1 files changed, 890 insertions, 28 deletions
diff --git a/src/wasm/wat-parser.cpp b/src/wasm/wat-parser.cpp index bb756159b..aa059b1db 100644 --- a/src/wasm/wat-parser.cpp +++ b/src/wasm/wat-parser.cpp @@ -48,8 +48,8 @@ // before we parse instructions because they determine the types of instructions // such as global.get and ref.func. // -// In the fifth and final phase, not yet implemented, parses the remaining -// contents of all module elements, including instructions. +// The fifth and final phase parses the remaining contents of all module +// elements, including instructions. // // Each phase of parsing gets its own context type that is passed to the // individual parsing functions. There is a parsing function for each element of @@ -127,6 +127,16 @@ struct ParseInput { return {}; } + std::optional<std::string_view> takeKeyword() { + if (auto t = peek()) { + if (auto keyword = t->getKeyword()) { + ++lexer; + return *keyword; + } + } + return {}; + } + bool takeKeyword(std::string_view expected) { if (auto t = peek()) { if (auto keyword = t->getKeyword()) { @@ -308,6 +318,10 @@ struct ParseDeclsCtx { using ArrayT = Ok; using GlobalTypeT = Ok; + using InstrT = Ok; + using InstrsT = Ok; + using ExprT = Ok; + // Declared module elements are inserted into the module, but their bodies are // not filled out until later parsing phases. Module& wasm; @@ -342,6 +356,10 @@ struct ParseTypeDefsCtx { using StructT = std::pair<std::vector<Name>, Struct>; using ArrayT = Array; + using InstrT = Ok; + using InstrsT = Ok; + using ExprT = Ok; + // We update slots in this builder as we parse type definitions. TypeBuilder& builder; @@ -374,6 +392,10 @@ struct ParseModuleTypesCtx { using ResultsT = std::vector<Type>; using GlobalTypeT = GlobalType; + using InstrT = Ok; + using InstrsT = Ok; + using ExprT = Ok; + Module& wasm; const std::vector<HeapType>& types; @@ -394,7 +416,38 @@ template<typename Ctx> inline constexpr bool parsingModuleTypes = std::is_same_v<Ctx, ParseModuleTypesCtx>; -// TODO: Phase 5: ParseDefsCtx +// Phase 5: Parse module element definitions, including instructions. +struct ParseDefsCtx { + using IndexT = Index; + using TypeT = Type; + using HeapTypeT = HeapType; + // TODO: This could be Ok, but then we wouldn't be able to use RETURN_OR_OK. + using GlobalTypeT = GlobalType; + + using InstrT = Expression*; + using InstrsT = std::vector<Expression*>; + using ExprT = Expression*; + + Module& wasm; + + Builder builder; + + const std::vector<HeapType>& types; + + // Map heap type names to their indices. + const IndexMap& typeIndices; + + // The index of the current module element. + Index index = 0; + + ParseDefsCtx(Module& wasm, + const std::vector<HeapType>& types, + const IndexMap& typeIndices) + : wasm(wasm), builder(wasm), types(types), typeIndices(typeIndices) {} +}; + +template<typename Ctx> +inline constexpr bool parsingDefs = std::is_same_v<Ctx, ParseDefsCtx>; // ================ // Parser Functions @@ -421,6 +474,205 @@ template<typename Ctx> MaybeResult<typename Ctx::StructT> structtype(Ctx&, ParseInput&); template<typename Ctx> MaybeResult<typename Ctx::ArrayT> arraytype(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::GlobalTypeT> globaltype(Ctx&, ParseInput&); + +// Instructions +template<typename Ctx> +MaybeResult<typename Ctx::InstrT> instr(Ctx&, ParseInput&); +template<typename Ctx> Result<typename Ctx::InstrsT> instrs(Ctx&, ParseInput&); +template<typename Ctx> Result<typename Ctx::ExprT> expr(Ctx&, ParseInput&); +template<typename Ctx> Result<typename Ctx::InstrT> makeUnreachable(Ctx&); +template<typename Ctx> Result<typename Ctx::InstrT> makeNop(Ctx&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeBinary(Ctx&, ParseInput&, BinaryOp op); +template<typename Ctx> +Result<typename Ctx::InstrT> makeUnary(Ctx&, ParseInput&, UnaryOp op); +template<typename Ctx> +Result<typename Ctx::InstrT> makeSelect(Ctx&, ParseInput&); +template<typename Ctx> Result<typename Ctx::InstrT> makeDrop(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeMemorySize(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeMemoryGrow(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeLocalGet(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeLocalTee(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeLocalSet(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeGlobalGet(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeGlobalSet(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeBlock(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeThenOrElse(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeConst(Ctx&, ParseInput&, Type type); +template<typename Ctx> +Result<typename Ctx::InstrT> +makeLoad(Ctx&, ParseInput&, Type type, bool isAtomic); +template<typename Ctx> +Result<typename Ctx::InstrT> +makeStore(Ctx&, ParseInput&, Type type, bool isAtomic); +template<typename Ctx> +Result<typename Ctx::InstrT> +makeAtomicRMWOrCmpxchg(Ctx&, ParseInput&, Type type); +template<typename Ctx> +Result<typename Ctx::InstrT> +makeAtomicRMW(Ctx&, ParseInput&, Type type, uint8_t bytes, const char* extra); +template<typename Ctx> +Result<typename Ctx::InstrT> makeAtomicCmpxchg( + Ctx&, ParseInput&, Type type, uint8_t bytes, const char* extra); +template<typename Ctx> +Result<typename Ctx::InstrT> makeAtomicWait(Ctx&, ParseInput&, Type type); +template<typename Ctx> +Result<typename Ctx::InstrT> makeAtomicNotify(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeAtomicFence(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> +makeSIMDExtract(Ctx&, ParseInput&, SIMDExtractOp op, size_t lanes); +template<typename Ctx> +Result<typename Ctx::InstrT> +makeSIMDReplace(Ctx&, ParseInput&, SIMDReplaceOp op, size_t lanes); +template<typename Ctx> +Result<typename Ctx::InstrT> makeSIMDShuffle(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> +makeSIMDTernary(Ctx&, ParseInput&, SIMDTernaryOp op); +template<typename Ctx> +Result<typename Ctx::InstrT> makeSIMDShift(Ctx&, ParseInput&, SIMDShiftOp op); +template<typename Ctx> +Result<typename Ctx::InstrT> makeSIMDLoad(Ctx&, ParseInput&, SIMDLoadOp op); +template<typename Ctx> +Result<typename Ctx::InstrT> +makeSIMDLoadStoreLane(Ctx&, ParseInput&, SIMDLoadStoreLaneOp op); +template<typename Ctx> +Result<typename Ctx::InstrT> makeMemoryInit(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeDataDrop(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeMemoryCopy(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeMemoryFill(Ctx&, ParseInput&); +template<typename Ctx> Result<typename Ctx::InstrT> makePush(Ctx&, ParseInput&); +template<typename Ctx> Result<typename Ctx::InstrT> makePop(Ctx&, ParseInput&); +template<typename Ctx> Result<typename Ctx::InstrT> makeIf(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> +makeMaybeBlock(Ctx&, ParseInput&, size_t i, Type type); +template<typename Ctx> Result<typename Ctx::InstrT> makeLoop(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeCall(Ctx&, ParseInput&, bool isReturn); +template<typename Ctx> +Result<typename Ctx::InstrT> makeCallIndirect(Ctx&, ParseInput&, bool isReturn); +template<typename Ctx> +Result<typename Ctx::InstrT> makeBreak(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeBreakTable(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeReturn(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefNull(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefIs(Ctx&, ParseInput&, RefIsOp op); +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefFunc(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefEq(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeTableGet(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeTableSet(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeTableSize(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeTableGrow(Ctx&, ParseInput&); +template<typename Ctx> Result<typename Ctx::InstrT> makeTry(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> +makeTryOrCatchBody(Ctx&, ParseInput&, Type type, bool isTry); +template<typename Ctx> +Result<typename Ctx::InstrT> makeThrow(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeRethrow(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeTupleMake(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeTupleExtract(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeCallRef(Ctx&, ParseInput&, bool isReturn); +template<typename Ctx> +Result<typename Ctx::InstrT> makeI31New(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeI31Get(Ctx&, ParseInput&, bool signed_); +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefTest(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefTestStatic(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefCast(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefCastStatic(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefCastNopStatic(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeBrOn(Ctx&, ParseInput&, BrOnOp op); +template<typename Ctx> +Result<typename Ctx::InstrT> makeBrOnStatic(Ctx&, ParseInput&, BrOnOp op); +template<typename Ctx> +Result<typename Ctx::InstrT> makeRttCanon(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeRttSub(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeRttFreshSub(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeStructNew(Ctx&, ParseInput&, bool default_); +template<typename Ctx> +Result<typename Ctx::InstrT> +makeStructNewStatic(Ctx&, ParseInput&, bool default_); +template<typename Ctx> +Result<typename Ctx::InstrT> +makeStructGet(Ctx&, ParseInput&, bool signed_ = false); +template<typename Ctx> +Result<typename Ctx::InstrT> makeStructSet(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeArrayNew(Ctx&, ParseInput&, bool default_); +template<typename Ctx> +Result<typename Ctx::InstrT> +makeArrayNewStatic(Ctx&, ParseInput&, bool default_); +template<typename Ctx> +Result<typename Ctx::InstrT> makeArrayInit(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeArrayInitStatic(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> +makeArrayGet(Ctx&, ParseInput&, bool signed_ = false); +template<typename Ctx> +Result<typename Ctx::InstrT> makeArraySet(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeArrayLen(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeArrayCopy(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefAs(Ctx&, ParseInput&, RefAsOp op); +template<typename Ctx> +Result<typename Ctx::InstrT> makeStringNew(Ctx&, ParseInput&, StringNewOp op); +template<typename Ctx> +Result<typename Ctx::InstrT> makeStringConst(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> +makeStringMeasure(Ctx&, ParseInput&, StringMeasureOp op); +template<typename Ctx> +Result<typename Ctx::InstrT> +makeStringEncode(Ctx&, ParseInput&, StringEncodeOp op); +template<typename Ctx> +Result<typename Ctx::InstrT> makeStringConcat(Ctx&, ParseInput&); +template<typename Ctx> +Result<typename Ctx::InstrT> makeStringEq(Ctx&, ParseInput&); // Modules template<typename Ctx> @@ -813,6 +1065,602 @@ Result<typename Ctx::GlobalTypeT> globaltype(Ctx& ctx, ParseInput& in) { RETURN_OR_OK((GlobalType{Immutable, *type})); } +// ============ +// Instructions +// ============ + +template<typename Ctx> +MaybeResult<typename Ctx::InstrT> instr(Ctx& ctx, ParseInput& in) { + auto keyword = in.takeKeyword(); + if (!keyword) { + return {}; + } + + auto op = *keyword; + +#define NEW_INSTRUCTION_PARSER +#define NEW_WAT_PARSER +#include <gen-s-parser.inc> +} + +template<typename Ctx> +Result<typename Ctx::InstrsT> instrs(Ctx& ctx, ParseInput& in) { + // TODO: Folded instructions. + std::vector<Expression*> insts; + while (auto inst = instr(ctx, in)) { + CHECK_ERR(inst); + if constexpr (parsingDefs<Ctx>) { + insts.push_back(*inst); + } + } + if constexpr (parsingDefs<Ctx>) { + return insts; + } else { + return Ok{}; + } +} + +template<typename Ctx> +Result<typename Ctx::ExprT> expr(Ctx& ctx, ParseInput& in) { + auto insts = instrs(ctx, in); + CHECK_ERR(insts); + if constexpr (parsingDefs<Ctx>) { + switch (insts->size()) { + case 0: + return ctx.builder.makeNop(); + case 1: + return insts->front(); + default: + return ctx.builder.makeBlock(*insts); + } + } else { + return Ok{}; + } +} + +template<typename Ctx> Result<typename Ctx::InstrT> makeUnreachable(Ctx& ctx) { + if constexpr (parsingDefs<Ctx>) { + return ctx.builder.makeUnreachable(); + } else { + return Ok{}; + } +} + +template<typename Ctx> Result<typename Ctx::InstrT> makeNop(Ctx& ctx) { + if constexpr (parsingDefs<Ctx>) { + return ctx.builder.makeNop(); + } else { + return Ok{}; + } +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeBinary(Ctx& ctx, ParseInput& in, BinaryOp op) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeUnary(Ctx& ctx, ParseInput& in, UnaryOp op) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeSelect(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeDrop(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeMemorySize(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeMemoryGrow(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeLocalGet(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeLocalTee(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeLocalSet(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeGlobalGet(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeGlobalSet(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeBlock(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeThenOrElse(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeConst(Ctx& ctx, ParseInput& in, Type type) { + assert(type.isBasic()); + switch (type.getBasic()) { + case Type::i32: + if (auto c = in.takeI32()) { + if constexpr (parsingDefs<Ctx>) { + return ctx.builder.makeConst(Literal(*c)); + } else { + return Ok{}; + } + } + return in.err("expected i32"); + case Type::i64: + if (auto c = in.takeI64()) { + if constexpr (parsingDefs<Ctx>) { + return ctx.builder.makeConst(Literal(*c)); + } else { + return Ok{}; + } + } + return in.err("expected i64"); + case Type::f32: + if (auto f = in.takeF32()) { + if constexpr (parsingDefs<Ctx>) { + return ctx.builder.makeConst(Literal(*f)); + } else { + return Ok{}; + } + } + return in.err("expected f32"); + case Type::f64: + if (auto f = in.takeF64()) { + if constexpr (parsingDefs<Ctx>) { + return ctx.builder.makeConst(Literal(*f)); + } else { + return Ok{}; + } + } + return in.err("expected f64"); + case Type::v128: + return in.err("unimplemented instruction"); + case Type::none: + case Type::unreachable: + case Type::funcref: + case Type::anyref: + case Type::eqref: + case Type::i31ref: + case Type::dataref: + break; + } + WASM_UNREACHABLE("unexpected type"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeLoad(Ctx& ctx, ParseInput& in, Type type, bool isAtomic) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeStore(Ctx& ctx, ParseInput& in, Type type, bool isAtomic) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeAtomicRMWOrCmpxchg(Ctx& ctx, ParseInput& in, Type type) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeAtomicRMW( + Ctx& ctx, ParseInput& in, Type type, uint8_t bytes, const char* extra) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeAtomicCmpxchg( + Ctx& ctx, ParseInput& in, Type type, uint8_t bytes, const char* extra) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeAtomicWait(Ctx& ctx, ParseInput& in, Type type) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeAtomicNotify(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeAtomicFence(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeSIMDExtract(Ctx& ctx, ParseInput& in, SIMDExtractOp op, size_t lanes) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeSIMDReplace(Ctx& ctx, ParseInput& in, SIMDReplaceOp op, size_t lanes) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeSIMDShuffle(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeSIMDTernary(Ctx& ctx, ParseInput& in, SIMDTernaryOp op) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeSIMDShift(Ctx& ctx, ParseInput& in, SIMDShiftOp op) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeSIMDLoad(Ctx& ctx, ParseInput& in, SIMDLoadOp op) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeSIMDLoadStoreLane(Ctx& ctx, ParseInput& in, SIMDLoadStoreLaneOp op) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeMemoryInit(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeDataDrop(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeMemoryCopy(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeMemoryFill(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makePush(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makePop(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeIf(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeMaybeBlock(Ctx& ctx, ParseInput& in, size_t i, Type type) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeLoop(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeCall(Ctx& ctx, ParseInput& in, bool isReturn) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeCallIndirect(Ctx& ctx, ParseInput& in, bool isReturn) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeBreak(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeBreakTable(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeReturn(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefNull(Ctx& ctx, ParseInput& in) { + auto t = heaptype(ctx, in); + CHECK_ERR(t); + if constexpr (parsingDefs<Ctx>) { + return ctx.builder.makeRefNull(*t); + } else { + return Ok{}; + } +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefIs(Ctx& ctx, ParseInput& in, RefIsOp op) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefFunc(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefEq(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeTableGet(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeTableSet(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeTableSize(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeTableGrow(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeTry(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeTryOrCatchBody(Ctx& ctx, ParseInput& in, Type type, bool isTry) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeThrow(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeRethrow(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeTupleMake(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeTupleExtract(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeCallRef(Ctx& ctx, ParseInput& in, bool isReturn) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeI31New(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeI31Get(Ctx& ctx, ParseInput& in, bool signed_) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefTest(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefTestStatic(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefCast(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefCastStatic(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefCastNopStatic(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeBrOn(Ctx& ctx, ParseInput& in, BrOnOp op) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeBrOnStatic(Ctx& ctx, ParseInput& in, BrOnOp op) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeRttCanon(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeRttSub(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeRttFreshSub(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeStructNew(Ctx& ctx, ParseInput& in, bool default_) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeStructNewStatic(Ctx& ctx, ParseInput& in, bool default_) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeStructGet(Ctx& ctx, ParseInput& in, bool signed_) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeStructSet(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeArrayNew(Ctx& ctx, ParseInput& in, bool default_) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeArrayNewStatic(Ctx& ctx, ParseInput& in, bool default_) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeArrayInit(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeArrayInitStatic(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeArrayGet(Ctx& ctx, ParseInput& in, bool signed_) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeArraySet(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeArrayLen(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeArrayCopy(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeRefAs(Ctx& ctx, ParseInput& in, RefAsOp op) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeStringNew(Ctx& ctx, ParseInput& in, StringNewOp op) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeStringConst(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeStringMeasure(Ctx& ctx, ParseInput& in, StringMeasureOp op) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeStringEncode(Ctx& ctx, ParseInput& in, StringEncodeOp op) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeStringConcat(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeStringEq(Ctx& ctx, ParseInput& in) { + return in.err("unimplemented instruction"); +} + // ======= // Modules // ======= @@ -1035,28 +1883,37 @@ template<typename Ctx> MaybeResult<> global(Ctx& ctx, ParseInput& in) { auto type = globaltype(ctx, in); CHECK_ERR(type); - if (import) { - if (!in.takeRParen()) { - return in.err("expected end of global"); - } + std::optional<typename Ctx::ExprT> exp; + if (!import) { + auto e = expr(ctx, in); + CHECK_ERR(e); + *exp = *e; + } - if constexpr (parsingDecls<Ctx>) { - if (ctx.hasNonImport) { - return in.err("import after non-import"); - } - auto g = addGlobalDecl(ctx, in, name, *import); - CHECK_ERR(g); - CHECK_ERR(addExports(in, ctx.wasm, *g, *exports, ExternalKind::Global)); - ctx.globalDefs.push_back({name, pos}); - } else if constexpr (parsingModuleTypes<Ctx>) { - auto& g = ctx.wasm.globals[ctx.index]; - g->mutable_ = type->mutability; - g->type = type->type; + if (!in.takeRParen()) { + return in.err("expected end of global"); + } + + if constexpr (parsingDecls<Ctx>) { + if (ctx.hasNonImport) { + return in.err("import after non-import"); + } + auto imp = import ? std::make_optional(*import) : std::nullopt; + auto g = addGlobalDecl(ctx, in, name, imp); + CHECK_ERR(g); + CHECK_ERR(addExports(in, ctx.wasm, *g, *exports, ExternalKind::Global)); + ctx.globalDefs.push_back({name, pos}); + } else if constexpr (parsingModuleTypes<Ctx>) { + auto& g = ctx.wasm.globals[ctx.index]; + g->mutable_ = type->mutability; + g->type = type->type; + } else if constexpr (parsingDefs<Ctx>) { + if (!import) { + ctx.wasm.globals[ctx.index]->init = *exp; } - return Ok{}; } - return in.err("TODO: non-imported globals"); + return Ok{}; } // modulefield ::= deftype @@ -1236,13 +2093,18 @@ Result<> parseModule(Module& wasm, std::string_view input) { // TODO: Parse implicit type definitions. - // Parse module-level types. - ParseModuleTypesCtx ctx(wasm, types, *typeIndices); - CHECK_ERR(parseDefs(ctx, input, decls.globalDefs, global)); - - // TODO: Parse types of other module elements. - - // TODO: Parse definitions. + { + // Parse module-level types. + ParseModuleTypesCtx ctx(wasm, types, *typeIndices); + CHECK_ERR(parseDefs(ctx, input, decls.globalDefs, global)); + // TODO: Parse types of other module elements. + } + { + // Parse definitions. + // TODO: Parallelize this. + ParseDefsCtx ctx(wasm, types, *typeIndices); + CHECK_ERR(parseDefs(ctx, input, decls.globalDefs, global)); + } return Ok{}; } |