summaryrefslogtreecommitdiff
path: root/src/parser/parsers.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser/parsers.h')
-rw-r--r--src/parser/parsers.h267
1 files changed, 265 insertions, 2 deletions
diff --git a/src/parser/parsers.h b/src/parser/parsers.h
index f16cca2b5..2bf9915eb 100644
--- a/src/parser/parsers.h
+++ b/src/parser/parsers.h
@@ -39,6 +39,7 @@ template<typename Ctx> MaybeResult<typename Ctx::ArrayT> arraytype(Ctx&);
template<typename Ctx> Result<typename Ctx::LimitsT> limits32(Ctx&);
template<typename Ctx> Result<typename Ctx::LimitsT> limits64(Ctx&);
template<typename Ctx> Result<typename Ctx::MemTypeT> memtype(Ctx&);
+template<typename Ctx> Result<typename Ctx::TableTypeT> tabletype(Ctx&);
template<typename Ctx> Result<typename Ctx::GlobalTypeT> globaltype(Ctx&);
// Instructions
@@ -165,7 +166,11 @@ template<typename Ctx> MaybeResult<Index> maybeTypeidx(Ctx& ctx);
template<typename Ctx> Result<typename Ctx::HeapTypeT> typeidx(Ctx&);
template<typename Ctx>
Result<typename Ctx::FieldIdxT> fieldidx(Ctx&, typename Ctx::HeapTypeT);
+template<typename Ctx> MaybeResult<typename Ctx::FuncIdxT> maybeFuncidx(Ctx&);
template<typename Ctx> Result<typename Ctx::FuncIdxT> funcidx(Ctx&);
+template<typename Ctx> MaybeResult<typename Ctx::TableIdxT> maybeTableidx(Ctx&);
+template<typename Ctx> Result<typename Ctx::TableIdxT> tableidx(Ctx&);
+template<typename Ctx> MaybeResult<typename Ctx::TableIdxT> maybeTableuse(Ctx&);
template<typename Ctx> MaybeResult<typename Ctx::MemoryIdxT> maybeMemidx(Ctx&);
template<typename Ctx> Result<typename Ctx::MemoryIdxT> memidx(Ctx&);
template<typename Ctx> MaybeResult<typename Ctx::MemoryIdxT> maybeMemuse(Ctx&);
@@ -182,8 +187,12 @@ template<typename Ctx> MaybeResult<typename Ctx::ModuleNameT> subtype(Ctx&);
template<typename Ctx> MaybeResult<> deftype(Ctx&);
template<typename Ctx> MaybeResult<typename Ctx::LocalsT> locals(Ctx&);
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<typename Ctx::ExprT> maybeElemexpr(Ctx&);
+template<typename Ctx> Result<typename Ctx::ElemListT> elemlist(Ctx&, bool);
+template<typename Ctx> MaybeResult<> elem(Ctx&);
template<typename Ctx> Result<typename Ctx::DataStringT> datastring(Ctx&);
template<typename Ctx> MaybeResult<> data(Ctx&);
template<typename Ctx> MaybeResult<> tag(Ctx&);
@@ -539,6 +548,18 @@ template<typename Ctx> Result<typename Ctx::MemTypeT> memtype(Ctx& ctx) {
return ctx.makeMemType(type, *limits, shared);
}
+// tabletype ::= limits32 reftype
+template<typename Ctx> Result<typename Ctx::TableTypeT> tabletype(Ctx& ctx) {
+ auto limits = limits32(ctx);
+ CHECK_ERR(limits);
+ auto type = reftype(ctx);
+ CHECK_ERR(type);
+ if (!type) {
+ return ctx.in.err("expected reftype");
+ }
+ return ctx.makeTableType(*limits, *type);
+}
+
// globaltype ::= t:valtype => const t
// | '(' 'mut' t:valtype ')' => var t
template<typename Ctx> Result<typename Ctx::GlobalTypeT> globaltype(Ctx& ctx) {
@@ -626,7 +647,7 @@ template<typename Ctx> MaybeResult<> instr(Ctx& ctx) {
if (auto keyword = tok->getKeyword()) {
if (keyword == "end"sv || keyword == "then"sv || keyword == "else"sv ||
keyword == "catch"sv || keyword == "catch_all"sv ||
- keyword == "delegate"sv) {
+ keyword == "delegate"sv || keyword == "ref"sv) {
return {};
}
}
@@ -1693,16 +1714,60 @@ Result<typename Ctx::FieldIdxT> fieldidx(Ctx& ctx,
// funcidx ::= x:u32 => x
// | v:id => x (if t.funcs[x] = v)
-template<typename Ctx> Result<typename Ctx::FuncIdxT> funcidx(Ctx& ctx) {
+template<typename Ctx>
+MaybeResult<typename Ctx::FuncIdxT> maybeFuncidx(Ctx& ctx) {
if (auto x = ctx.in.takeU32()) {
return ctx.getFuncFromIdx(*x);
}
if (auto id = ctx.in.takeID()) {
return ctx.getFuncFromName(*id);
}
+ return {};
+}
+
+template<typename Ctx> Result<typename Ctx::FuncIdxT> funcidx(Ctx& ctx) {
+ if (auto idx = maybeFuncidx(ctx)) {
+ CHECK_ERR(idx);
+ return *idx;
+ }
return ctx.in.err("expected function index or identifier");
}
+// tableidx ::= x:u23 => x
+// | v:id => x (if tables[x] = v)
+template<typename Ctx>
+MaybeResult<typename Ctx::TableIdxT> maybeTableidx(Ctx& ctx) {
+ if (auto x = ctx.in.takeU32()) {
+ return ctx.getTableFromIdx(*x);
+ }
+ if (auto id = ctx.in.takeID()) {
+ return ctx.getTableFromName(*id);
+ }
+ return {};
+}
+
+template<typename Ctx> Result<typename Ctx::TableIdxT> tableidx(Ctx& ctx) {
+ if (auto idx = maybeTableidx(ctx)) {
+ CHECK_ERR(idx);
+ return *idx;
+ }
+ return ctx.in.err("expected table index or identifier");
+}
+
+// tableuse ::= '(' 'table' x:tableidx ')'
+template<typename Ctx>
+MaybeResult<typename Ctx::TableIdxT> maybeTableuse(Ctx& ctx) {
+ if (!ctx.in.takeSExprStart("table"sv)) {
+ return {};
+ }
+ auto idx = tableidx(ctx);
+ CHECK_ERR(idx);
+ if (!ctx.in.takeRParen()) {
+ return ctx.in.err("Expected end of memory use");
+ }
+ return *idx;
+}
+
// memidx ::= x:u32 => x
// | v:id => x (if memories[x] = v)
template<typename Ctx>
@@ -2031,6 +2096,82 @@ template<typename Ctx> MaybeResult<> func(Ctx& ctx) {
return Ok{};
}
+// table ::= '(' 'table' id? ('(' 'export' name ')')*
+// '(' 'import' mod:name nm:name ')'? tabletype ')'
+// | '(' 'table' id? ('(' 'export' name ')')*
+// reftype '(' 'elem' (elemexpr* | funcidx*) ')' ')'
+template<typename Ctx> MaybeResult<> table(Ctx& ctx) {
+ auto pos = ctx.in.getPos();
+ if (!ctx.in.takeSExprStart("table"sv)) {
+ return {};
+ }
+
+ Name name;
+ if (auto id = ctx.in.takeID()) {
+ name = *id;
+ }
+
+ auto exports = inlineExports(ctx.in);
+ CHECK_ERR(exports);
+
+ auto import = inlineImport(ctx.in);
+ CHECK_ERR(import);
+
+ // Reftype if we have inline elements.
+ auto type = reftype(ctx);
+ CHECK_ERR(type);
+
+ std::optional<typename Ctx::TableTypeT> ttype;
+ std::optional<typename Ctx::ElemListT> elems;
+ if (type) {
+ // We should have inline elements.
+ if (!ctx.in.takeSExprStart("elem"sv)) {
+ return ctx.in.err("expected table limits or inline elements");
+ }
+ if (import) {
+ return ctx.in.err("imported tables cannot have inline elements");
+ }
+
+ auto list = ctx.makeElemList(*type);
+ bool foundElem = false;
+ while (auto elem = maybeElemexpr(ctx)) {
+ CHECK_ERR(elem);
+ ctx.appendElem(list, *elem);
+ foundElem = true;
+ }
+
+ // If there were no elemexprs, then maybe we have funcidxs instead.
+ if (!foundElem) {
+ while (auto func = maybeFuncidx(ctx)) {
+ CHECK_ERR(func);
+ ctx.appendFuncElem(list, *func);
+ }
+ }
+
+ if (!ctx.in.takeRParen()) {
+ return ctx.in.err("expected end of inline elems");
+ }
+ ttype = ctx.makeTableType(ctx.getLimitsFromElems(list), *type);
+ elems = std::move(list);
+ } else {
+ auto tabtype = tabletype(ctx);
+ CHECK_ERR(tabtype);
+ ttype = *tabtype;
+ }
+
+ if (!ctx.in.takeRParen()) {
+ return ctx.in.err("expected end of table declaration");
+ }
+
+ CHECK_ERR(ctx.addTable(name, *exports, import.getPtr(), *ttype, pos));
+
+ if (elems) {
+ CHECK_ERR(ctx.addImplicitElems(*type, std::move(*elems)));
+ }
+
+ return Ok{};
+}
+
// mem ::= '(' 'memory' id? ('(' 'export' name ')')*
// ('(' 'data' b:datastring ')' | memtype) ')'
// | '(' 'memory' id? ('(' 'export' name ')')*
@@ -2122,6 +2263,120 @@ template<typename Ctx> MaybeResult<> global(Ctx& ctx) {
return Ok{};
}
+// elemexpr ::= '(' 'item' expr ')' | '(' instr ')'
+template<typename Ctx>
+MaybeResult<typename Ctx::ExprT> maybeElemexpr(Ctx& ctx) {
+ MaybeResult<typename Ctx::ExprT> result;
+ if (ctx.in.takeSExprStart("item"sv)) {
+ result = expr(ctx);
+ } else if (ctx.in.takeLParen()) {
+ // TODO: `instr` should included both folded and unfolded instrs.
+ if (auto inst = instr(ctx)) {
+ CHECK_ERR(inst);
+ } else {
+ return ctx.in.err("expected instruction");
+ }
+ result = ctx.makeExpr();
+ } else {
+ return {};
+ }
+ CHECK_ERR(result);
+ if (!ctx.in.takeRParen()) {
+ return ctx.in.err("expected end of element expression");
+ }
+ return result;
+}
+
+// elemlist ::= reftype elemexpr* | 'func' funcidx*
+// | funcidx* (iff the tableuse is omitted)
+template<typename Ctx>
+Result<typename Ctx::ElemListT> elemlist(Ctx& ctx, bool legacy) {
+ if (auto type = reftype(ctx)) {
+ auto res = ctx.makeElemList(*type);
+ while (auto elem = maybeElemexpr(ctx)) {
+ CHECK_ERR(elem);
+ ctx.appendElem(res, *elem);
+ }
+ return res;
+ } else if (ctx.in.takeKeyword("func"sv) || legacy) {
+ auto res = ctx.makeFuncElemList();
+ while (auto func = maybeFuncidx(ctx)) {
+ CHECK_ERR(func);
+ ctx.appendFuncElem(res, *func);
+ }
+ return res;
+ }
+ return ctx.in.err("expected element list");
+}
+
+// elem ::= '(' 'elem' id? x:tableuse? ('(' ('offset' e:expr | e:instr) ')')?
+// elemlist ')'
+// | '(' 'elem' id? 'declare' elemlist ')'
+template<typename Ctx> MaybeResult<> elem(Ctx& ctx) {
+ auto pos = ctx.in.getPos();
+ if (!ctx.in.takeSExprStart("elem"sv)) {
+ return {};
+ }
+
+ Name name;
+ if (auto id = ctx.in.takeID()) {
+ name = *id;
+ }
+
+ bool isDeclare = false;
+ MaybeResult<typename Ctx::TableIdxT> table;
+ std::optional<typename Ctx::ExprT> offset;
+
+ if (ctx.in.takeKeyword("declare"sv)) {
+ isDeclare = true;
+ } else {
+ table = maybeTableuse(ctx);
+ CHECK_ERR(table);
+
+ if (ctx.in.takeSExprStart("offset")) {
+ auto off = expr(ctx);
+ CHECK_ERR(off);
+ offset = *off;
+ } else {
+ // This may be an abbreviated offset instruction or it may be the
+ // beginning of the elemlist.
+ auto beforeLParen = ctx.in.getPos();
+ if (ctx.in.takeLParen()) {
+ if (auto inst = instr(ctx)) {
+ CHECK_ERR(inst);
+ auto off = ctx.makeExpr();
+ CHECK_ERR(off);
+ offset = *off;
+ } else {
+ // This must be the beginning of the elemlist instead.
+ ctx.in.lexer.setIndex(beforeLParen);
+ }
+ }
+ }
+ if (offset && !ctx.in.takeRParen()) {
+ return ctx.in.err("expected end of offset expression");
+ }
+ }
+
+ // If there is no explicit tableuse, we can use the legacy elemlist format.
+ bool legacy = !table;
+ auto elems = elemlist(ctx, legacy);
+ CHECK_ERR(elems);
+
+ if (!ctx.in.takeRParen()) {
+ return ctx.in.err("expected end of element segment");
+ }
+
+ if (isDeclare) {
+ CHECK_ERR(ctx.addDeclareElem(name, std::move(*elems), pos));
+ } else {
+ CHECK_ERR(
+ ctx.addElem(name, table.getPtr(), offset, std::move(*elems), pos));
+ }
+
+ return Ok{};
+}
+
// datastring ::= (b:string)* => concat(b*)
template<typename Ctx> Result<typename Ctx::DataStringT> datastring(Ctx& ctx) {
auto data = ctx.makeDataString();
@@ -2236,6 +2491,10 @@ template<typename Ctx> MaybeResult<> modulefield(Ctx& ctx) {
CHECK_ERR(res);
return Ok{};
}
+ if (auto res = table(ctx)) {
+ CHECK_ERR(res);
+ return Ok{};
+ }
if (auto res = memory(ctx)) {
CHECK_ERR(res);
return Ok{};
@@ -2244,6 +2503,10 @@ template<typename Ctx> MaybeResult<> modulefield(Ctx& ctx) {
CHECK_ERR(res);
return Ok{};
}
+ if (auto res = elem(ctx)) {
+ CHECK_ERR(res);
+ return Ok{};
+ }
if (auto res = data(ctx)) {
CHECK_ERR(res);
return Ok{};