diff options
Diffstat (limited to 'src/parser/parsers.h')
-rw-r--r-- | src/parser/parsers.h | 192 |
1 files changed, 174 insertions, 18 deletions
diff --git a/src/parser/parsers.h b/src/parser/parsers.h index 9201314dc..f16cca2b5 100644 --- a/src/parser/parsers.h +++ b/src/parser/parsers.h @@ -56,6 +56,7 @@ template<typename Ctx> Result<typename Ctx::BlockTypeT> blocktype(Ctx&); template<typename Ctx> MaybeResult<> block(Ctx&, bool); template<typename Ctx> MaybeResult<> ifelse(Ctx&, bool); template<typename Ctx> MaybeResult<> loop(Ctx&, bool); +template<typename Ctx> MaybeResult<> trycatch(Ctx&, bool); template<typename Ctx> Result<> makeUnreachable(Ctx&, Index); template<typename Ctx> Result<> makeNop(Ctx&, Index); template<typename Ctx> Result<> makeBinary(Ctx&, Index, BinaryOp op); @@ -113,9 +114,6 @@ template<typename Ctx> Result<> makeTableSize(Ctx&, Index); template<typename Ctx> Result<> makeTableGrow(Ctx&, Index); template<typename Ctx> Result<> makeTableFill(Ctx&, Index); template<typename Ctx> Result<> makeTableCopy(Ctx&, Index); -template<typename Ctx> Result<> makeTry(Ctx&, Index); -template<typename Ctx> -Result<> makeTryOrCatchBody(Ctx&, Index, Type type, bool isTry); template<typename Ctx> Result<> makeThrow(Ctx&, Index); template<typename Ctx> Result<> makeRethrow(Ctx&, Index); template<typename Ctx> Result<> makeTupleMake(Ctx&, Index); @@ -173,7 +171,8 @@ template<typename Ctx> Result<typename Ctx::MemoryIdxT> memidx(Ctx&); template<typename Ctx> MaybeResult<typename Ctx::MemoryIdxT> maybeMemuse(Ctx&); template<typename Ctx> Result<typename Ctx::GlobalIdxT> globalidx(Ctx&); template<typename Ctx> Result<typename Ctx::LocalIdxT> localidx(Ctx&); -template<typename Ctx> Result<typename Ctx::LabelIdxT> labelidx(Ctx&); +template<typename Ctx> +Result<typename Ctx::LabelIdxT> labelidx(Ctx&, bool inDelegate = false); template<typename Ctx> Result<typename Ctx::TagIdxT> tagidx(Ctx&); template<typename Ctx> Result<typename Ctx::TypeUseT> typeuse(Ctx&); MaybeResult<ImportNames> inlineImport(ParseInput&); @@ -573,6 +572,9 @@ template<typename Ctx> MaybeResult<> foldedBlockinstr(Ctx& ctx) { if (auto i = loop(ctx, true)) { return i; } + if (auto i = trycatch(ctx, true)) { + return i; + } // TODO: Other block instructions return {}; } @@ -587,6 +589,9 @@ template<typename Ctx> MaybeResult<> unfoldedBlockinstr(Ctx& ctx) { if (auto i = loop(ctx, false)) { return i; } + if (auto i = trycatch(ctx, false)) { + return i; + } // TODO: Other block instructions return {}; } @@ -619,7 +624,9 @@ template<typename Ctx> MaybeResult<> instr(Ctx& ctx) { // Check for valid strings that are not instructions. if (auto tok = ctx.in.peek()) { if (auto keyword = tok->getKeyword()) { - if (keyword == "end"sv || keyword == "then"sv || keyword == "else"sv) { + if (keyword == "end"sv || keyword == "then"sv || keyword == "else"sv || + keyword == "catch"sv || keyword == "catch_all"sv || + keyword == "delegate"sv) { return {}; } } @@ -860,7 +867,7 @@ template<typename Ctx> MaybeResult<> ifelse(Ctx& ctx, bool folded) { return ctx.visitEnd(); } -// loop ::= 'loop' label blocktype instr* end id? +// loop ::= 'loop' label blocktype instr* 'end' id? // | '(' 'loop' label blocktype instr* ')' template<typename Ctx> MaybeResult<> loop(Ctx& ctx, bool folded) { auto pos = ctx.in.getPos(); @@ -895,6 +902,163 @@ template<typename Ctx> MaybeResult<> loop(Ctx& ctx, bool folded) { return ctx.visitEnd(); } +// trycatch ::= 'try' label blocktype instr* ('catch' id? tagidx instr*)* +// ('catch_all' id? instr*)? 'end' id? +// | '(' 'try' label blocktype '(' 'do' instr* ')' +// ('(' 'catch' tagidx instr* ')')* +// ('(' 'catch_all' instr* ')')? ')' +// | 'try' label blocktype instr* 'deledate' label +// | '(' 'try' label blocktype '(' 'do' instr* ')' +// '(' 'delegate' label ')' ')' +template<typename Ctx> MaybeResult<> trycatch(Ctx& ctx, bool folded) { + auto pos = ctx.in.getPos(); + + if ((folded && !ctx.in.takeSExprStart("try"sv)) || + (!folded && !ctx.in.takeKeyword("try"sv))) { + return {}; + } + + auto label = ctx.in.takeID(); + + auto type = blocktype(ctx); + CHECK_ERR(type); + + CHECK_ERR(ctx.makeTry(pos, label, *type)); + + if (folded) { + if (!ctx.in.takeSExprStart("do"sv)) { + return ctx.in.err("expected 'do' in try"); + } + } + + CHECK_ERR(instrs(ctx)); + + if (folded) { + if (!ctx.in.takeRParen()) { + return ctx.in.err("expected ')' at end of do"); + } + } + + if ((folded && ctx.in.takeSExprStart("delegate")) || + (!folded && ctx.in.takeKeyword("delegate"))) { + auto delegatePos = ctx.in.getPos(); + + auto label = labelidx(ctx, true); + CHECK_ERR(label); + + if (folded) { + if (!ctx.in.takeRParen()) { + return ctx.in.err("expected ')' at end of delegate"); + } + if (!ctx.in.takeRParen()) { + return ctx.in.err("expected ')' at end of try"); + } + } + + CHECK_ERR(ctx.visitDelegate(delegatePos, *label)); + return Ok{}; + } + + while (true) { + auto catchPos = ctx.in.getPos(); + + if ((folded && !ctx.in.takeSExprStart("catch"sv)) || + (!folded && !ctx.in.takeKeyword("catch"sv))) { + break; + } + + // It can be ambiguous whether the name after `catch` is intended to be the + // optional ID or the tag identifier. For example: + // + // (tag $t) + // (func $ambiguous + // try $t + // catch $t + // end + // ) + // + // When parsing the `catch`, the parser first tries to parse an optional ID + // that must match the label of the `try`, and it succeeds because it sees + // `$t` after the catch. However, when it then tries to parse the mandatory + // tag index, it fails because the next token is `end`. The problem is that + // the `$t` after the `catch` was the tag name and there was no optional ID + // after all. The parser sets `parseID = false` and resets to just after the + // `catch`, and now it skips parsing the optional ID so it correctly parses + // the `$t` as a tag name. + bool parseID = !folded; + auto afterCatchPos = ctx.in.getPos(); + while (true) { + if (!folded && parseID) { + auto id = ctx.in.takeID(); + if (id && id != label) { + // Instead of returning an error, retry without the ID. + parseID = false; + ctx.in.lexer.setIndex(afterCatchPos); + continue; + } + } + + auto tag = tagidx(ctx); + if (parseID && tag.getErr()) { + // Instead of returning an error, retry without the ID. + parseID = false; + ctx.in.lexer.setIndex(afterCatchPos); + continue; + } + CHECK_ERR(tag); + + CHECK_ERR(ctx.visitCatch(catchPos, *tag)); + + CHECK_ERR(instrs(ctx)); + + if (folded) { + if (!ctx.in.takeRParen()) { + return ctx.in.err("expected ')' at end of catch"); + } + } + break; + } + } + + if ((folded && ctx.in.takeSExprStart("catch_all"sv)) || + (!folded && ctx.in.takeKeyword("catch_all"sv))) { + auto catchPos = ctx.in.getPos(); + + if (!folded) { + auto id = ctx.in.takeID(); + if (id && id != label) { + return ctx.in.err("catch_all label does not match try label"); + } + } + + CHECK_ERR(ctx.visitCatchAll(catchPos)); + + CHECK_ERR(instrs(ctx)); + + if (folded) { + if (!ctx.in.takeRParen()) { + return ctx.in.err("expected ')' at end of catch_all"); + } + } + } + + if (folded) { + if (!ctx.in.takeRParen()) { + return ctx.in.err("expected ')' at end of try"); + } + } else { + if (!ctx.in.takeKeyword("end"sv)) { + return ctx.in.err("expected 'end' at end of try"); + } + + auto id = ctx.in.takeID(); + if (id && id != label) { + return ctx.in.err("end label does not match try label"); + } + } + return ctx.visitEnd(); +} + template<typename Ctx> Result<> makeUnreachable(Ctx& ctx, Index pos) { return ctx.makeUnreachable(pos); } @@ -1266,15 +1430,6 @@ template<typename Ctx> Result<> makeTableCopy(Ctx& ctx, Index pos) { return ctx.in.err("unimplemented instruction"); } -template<typename Ctx> Result<> makeTry(Ctx& ctx, Index pos) { - return ctx.in.err("unimplemented instruction"); -} - -template<typename Ctx> -Result<> makeTryOrCatchBody(Ctx& ctx, Index pos, Type type, bool isTry) { - return ctx.in.err("unimplemented instruction"); -} - template<typename Ctx> Result<> makeThrow(Ctx& ctx, Index pos) { auto tag = tagidx(ctx); CHECK_ERR(tag); @@ -1621,12 +1776,13 @@ template<typename Ctx> Result<typename Ctx::LocalIdxT> localidx(Ctx& ctx) { // labelidx ::= x:u32 => x // | v:id => x (if labels[x] = v) -template<typename Ctx> Result<typename Ctx::LabelIdxT> labelidx(Ctx& ctx) { +template<typename Ctx> +Result<typename Ctx::LabelIdxT> labelidx(Ctx& ctx, bool inDelegate) { if (auto x = ctx.in.takeU32()) { - return ctx.getLabelFromIdx(*x); + return ctx.getLabelFromIdx(*x, inDelegate); } if (auto id = ctx.in.takeID()) { - return ctx.getLabelFromName(*id); + return ctx.getLabelFromName(*id, inDelegate); } return ctx.in.err("expected label index or identifier"); } |