diff options
author | Thomas Lively <tlively@google.com> | 2023-12-14 10:27:53 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-14 10:27:53 -0800 |
commit | bdd96e8c21d23a57a99dcca9d4d802ff471243c3 (patch) | |
tree | bca67e3db39d12835263086ac200f44a658ee3a4 | |
parent | 7adc82b5da6ad2b36d2f335af6619601ccc8e36b (diff) | |
download | binaryen-bdd96e8c21d23a57a99dcca9d4d802ff471243c3.tar.gz binaryen-bdd96e8c21d23a57a99dcca9d4d802ff471243c3.tar.bz2 binaryen-bdd96e8c21d23a57a99dcca9d4d802ff471243c3.zip |
[Parser] Parse explicit exports (#6179)
-rw-r--r-- | src/parser/contexts.h | 13 | ||||
-rw-r--r-- | src/parser/parsers.h | 55 | ||||
-rw-r--r-- | src/parser/wat-parser.cpp | 10 | ||||
-rw-r--r-- | test/lit/wat-kitchen-sink.wast | 18 |
4 files changed, 93 insertions, 3 deletions
diff --git a/src/parser/contexts.h b/src/parser/contexts.h index 3ed455043..e09f8bbd0 100644 --- a/src/parser/contexts.h +++ b/src/parser/contexts.h @@ -548,6 +548,9 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx { std::vector<DefPos> dataDefs; std::vector<DefPos> tagDefs; + // Positions of export definitions. + std::vector<Index> exportDefs; + // Positions of typeuses that might implicitly define new types. std::vector<Index> implicitTypeDefs; @@ -684,6 +687,11 @@ struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx { ImportNames* import, TypeUseT type, Index pos); + + Result<> addExport(Index pos, Ok, Name, ExternalKind) { + exportDefs.push_back(pos); + return Ok{}; + } }; // Phase 2: Parse type definitions into a TypeBuilder. @@ -1265,6 +1273,11 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> { Result<> addData(Name, Name* mem, std::optional<ExprT> offset, DataStringT, Index pos); + Result<> addExport(Index, Name value, Name name, ExternalKind kind) { + wasm.addExport(builder.makeExport(name, value, kind)); + return Ok{}; + } + Result<Index> addScratchLocal(Index pos, Type type) { if (!func) { return in.err(pos, diff --git a/src/parser/parsers.h b/src/parser/parsers.h index dc86e0d60..54644cafc 100644 --- a/src/parser/parsers.h +++ b/src/parser/parsers.h @@ -194,6 +194,7 @@ template<typename Ctx> MaybeResult<> func(Ctx&); template<typename Ctx> MaybeResult<> table(Ctx&); template<typename Ctx> MaybeResult<> memory(Ctx&); template<typename Ctx> MaybeResult<> global(Ctx&); +template<typename Ctx> MaybeResult<> export_(Ctx&); template<typename Ctx> MaybeResult<typename Ctx::ExprT> maybeElemexpr(Ctx&); template<typename Ctx> Result<typename Ctx::ElemListT> elemlist(Ctx&, bool); template<typename Ctx> MaybeResult<> elem(Ctx&); @@ -2371,6 +2372,56 @@ template<typename Ctx> MaybeResult<> global(Ctx& ctx) { return Ok{}; } +// export ::= '(' 'export' nm:name exportdesc ')' +// exportdesc ::= '(' 'func' x:funcidx ')' +// | '(' 'table' x:tableidx ')' +// | '(' 'memory' x:memidx ')' +// | '(' 'global' x:globalidx ')' +// | '(' 'tag' x:tagidx ')' +template<typename Ctx> MaybeResult<> export_(Ctx& ctx) { + auto pos = ctx.in.getPos(); + if (!ctx.in.takeSExprStart("export"sv)) { + return {}; + } + + auto name = ctx.in.takeName(); + if (!name) { + return ctx.in.err("expected export name"); + } + + if (ctx.in.takeSExprStart("func"sv)) { + auto idx = funcidx(ctx); + CHECK_ERR(idx); + CHECK_ERR(ctx.addExport(pos, *idx, *name, ExternalKind::Function)); + } else if (ctx.in.takeSExprStart("table"sv)) { + auto idx = tableidx(ctx); + CHECK_ERR(idx); + CHECK_ERR(ctx.addExport(pos, *idx, *name, ExternalKind::Table)); + } else if (ctx.in.takeSExprStart("memory"sv)) { + auto idx = memidx(ctx); + CHECK_ERR(idx); + CHECK_ERR(ctx.addExport(pos, *idx, *name, ExternalKind::Memory)); + } else if (ctx.in.takeSExprStart("global"sv)) { + auto idx = globalidx(ctx); + CHECK_ERR(idx); + CHECK_ERR(ctx.addExport(pos, *idx, *name, ExternalKind::Global)); + } else if (ctx.in.takeSExprStart("tag"sv)) { + auto idx = tagidx(ctx); + CHECK_ERR(idx); + CHECK_ERR(ctx.addExport(pos, *idx, *name, ExternalKind::Tag)); + } else { + return ctx.in.err("expected export description"); + } + + if (!ctx.in.takeRParen()) { + return ctx.in.err("expected end of export description"); + } + if (!ctx.in.takeRParen()) { + return ctx.in.err("expected end of export"); + } + return Ok{}; +} + // elemexpr ::= '(' 'item' expr ')' | '(' instr ')' template<typename Ctx> MaybeResult<typename Ctx::ExprT> maybeElemexpr(Ctx& ctx) { @@ -2611,6 +2662,10 @@ template<typename Ctx> MaybeResult<> modulefield(Ctx& ctx) { CHECK_ERR(res); return Ok{}; } + if (auto res = export_(ctx)) { + CHECK_ERR(res); + return Ok{}; + } if (auto res = elem(ctx)) { CHECK_ERR(res); return Ok{}; diff --git a/src/parser/wat-parser.cpp b/src/parser/wat-parser.cpp index cc0f582fc..95dfa1405 100644 --- a/src/parser/wat-parser.cpp +++ b/src/parser/wat-parser.cpp @@ -178,6 +178,16 @@ Result<> parseModule(Module& wasm, std::string_view input) { CHECK_ERR(parsed); assert(parsed); } + + // Parse exports. + // TODO: It would be more technically correct to interleave these properly + // with the implicit inline exports in other module field definitions. + for (auto pos : decls.exportDefs) { + WithPosition with(ctx, pos); + auto parsed = export_(ctx); + CHECK_ERR(parsed); + assert(parsed); + } } return Ok{}; diff --git a/test/lit/wat-kitchen-sink.wast b/test/lit/wat-kitchen-sink.wast index 98795e5ee..4368a1cb2 100644 --- a/test/lit/wat-kitchen-sink.wast +++ b/test/lit/wat-kitchen-sink.wast @@ -354,9 +354,7 @@ ;; CHECK: (tag $tag-pair (param i32 i64)) (tag $tag-pair (param i32 i64)) - ;; functions - (func) - + ;; explicit exports ;; CHECK: (export "g1" (global $g1)) ;; CHECK: (export "g1.1" (global $g1)) @@ -377,6 +375,20 @@ ;; CHECK: (export "t0.1" (tag $imported)) + ;; CHECK: (export "exported-func" (func $fimport$0)) + (export "exported-func" (func 0)) + ;; CHECK: (export "exported-table" (table $timport$0)) + (export "exported-table" (table 0)) + ;; CHECK: (export "exported-memory" (memory $mimport$0)) + (export "exported-memory" (memory 0)) + ;; CHECK: (export "exported-global" (global $g1)) + (export "exported-global" (global 0)) + ;; CHECK: (export "exported-tag" (tag $imported)) + (export "exported-tag" (tag 0)) + + ;; functions + (func) + ;; CHECK: (func $1 (type $void) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) |