summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2023-12-14 10:27:53 -0800
committerGitHub <noreply@github.com>2023-12-14 10:27:53 -0800
commitbdd96e8c21d23a57a99dcca9d4d802ff471243c3 (patch)
treebca67e3db39d12835263086ac200f44a658ee3a4
parent7adc82b5da6ad2b36d2f335af6619601ccc8e36b (diff)
downloadbinaryen-bdd96e8c21d23a57a99dcca9d4d802ff471243c3.tar.gz
binaryen-bdd96e8c21d23a57a99dcca9d4d802ff471243c3.tar.bz2
binaryen-bdd96e8c21d23a57a99dcca9d4d802ff471243c3.zip
[Parser] Parse explicit exports (#6179)
-rw-r--r--src/parser/contexts.h13
-rw-r--r--src/parser/parsers.h55
-rw-r--r--src/parser/wat-parser.cpp10
-rw-r--r--test/lit/wat-kitchen-sink.wast18
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: )