@@ -56,6 +56,7 @@ template<typename Ctx> Result<typename Ctx::BlockTypeT> blocktype(Ctx&);
5656template <typename Ctx> MaybeResult<> block (Ctx&, bool );
5757template <typename Ctx> MaybeResult<> ifelse (Ctx&, bool );
5858template <typename Ctx> MaybeResult<> loop (Ctx&, bool );
59+ template <typename Ctx> MaybeResult<> trycatch (Ctx&, bool );
5960template <typename Ctx> Result<> makeUnreachable (Ctx&, Index);
6061template <typename Ctx> Result<> makeNop (Ctx&, Index);
6162template <typename Ctx> Result<> makeBinary (Ctx&, Index, BinaryOp op);
@@ -113,9 +114,6 @@ template<typename Ctx> Result<> makeTableSize(Ctx&, Index);
113114template <typename Ctx> Result<> makeTableGrow (Ctx&, Index);
114115template <typename Ctx> Result<> makeTableFill (Ctx&, Index);
115116template <typename Ctx> Result<> makeTableCopy (Ctx&, Index);
116- template <typename Ctx> Result<> makeTry (Ctx&, Index);
117- template <typename Ctx>
118- Result<> makeTryOrCatchBody (Ctx&, Index, Type type, bool isTry);
119117template <typename Ctx> Result<> makeThrow (Ctx&, Index);
120118template <typename Ctx> Result<> makeRethrow (Ctx&, Index);
121119template <typename Ctx> Result<> makeTupleMake (Ctx&, Index);
@@ -173,7 +171,8 @@ template<typename Ctx> Result<typename Ctx::MemoryIdxT> memidx(Ctx&);
173171template <typename Ctx> MaybeResult<typename Ctx::MemoryIdxT> maybeMemuse (Ctx&);
174172template <typename Ctx> Result<typename Ctx::GlobalIdxT> globalidx (Ctx&);
175173template <typename Ctx> Result<typename Ctx::LocalIdxT> localidx (Ctx&);
176- template <typename Ctx> Result<typename Ctx::LabelIdxT> labelidx (Ctx&);
174+ template <typename Ctx>
175+ Result<typename Ctx::LabelIdxT> labelidx (Ctx&, bool inDelegate = false );
177176template <typename Ctx> Result<typename Ctx::TagIdxT> tagidx (Ctx&);
178177template <typename Ctx> Result<typename Ctx::TypeUseT> typeuse (Ctx&);
179178MaybeResult<ImportNames> inlineImport (ParseInput&);
@@ -573,6 +572,9 @@ template<typename Ctx> MaybeResult<> foldedBlockinstr(Ctx& ctx) {
573572 if (auto i = loop (ctx, true )) {
574573 return i;
575574 }
575+ if (auto i = trycatch (ctx, true )) {
576+ return i;
577+ }
576578 // TODO: Other block instructions
577579 return {};
578580}
@@ -587,6 +589,9 @@ template<typename Ctx> MaybeResult<> unfoldedBlockinstr(Ctx& ctx) {
587589 if (auto i = loop (ctx, false )) {
588590 return i;
589591 }
592+ if (auto i = trycatch (ctx, false )) {
593+ return i;
594+ }
590595 // TODO: Other block instructions
591596 return {};
592597}
@@ -619,7 +624,9 @@ template<typename Ctx> MaybeResult<> instr(Ctx& ctx) {
619624 // Check for valid strings that are not instructions.
620625 if (auto tok = ctx.in .peek ()) {
621626 if (auto keyword = tok->getKeyword ()) {
622- if (keyword == " end" sv || keyword == " then" sv || keyword == " else" sv) {
627+ if (keyword == " end" sv || keyword == " then" sv || keyword == " else" sv ||
628+ keyword == " catch" sv || keyword == " catch_all" sv ||
629+ keyword == " delegate" sv) {
623630 return {};
624631 }
625632 }
@@ -860,7 +867,7 @@ template<typename Ctx> MaybeResult<> ifelse(Ctx& ctx, bool folded) {
860867 return ctx.visitEnd ();
861868}
862869
863- // loop ::= 'loop' label blocktype instr* end id?
870+ // loop ::= 'loop' label blocktype instr* ' end' id?
864871// | '(' 'loop' label blocktype instr* ')'
865872template <typename Ctx> MaybeResult<> loop (Ctx& ctx, bool folded) {
866873 auto pos = ctx.in .getPos ();
@@ -895,6 +902,163 @@ template<typename Ctx> MaybeResult<> loop(Ctx& ctx, bool folded) {
895902 return ctx.visitEnd ();
896903}
897904
905+ // trycatch ::= 'try' label blocktype instr* ('catch' id? tagidx instr*)*
906+ // ('catch_all' id? instr*)? 'end' id?
907+ // | '(' 'try' label blocktype '(' 'do' instr* ')'
908+ // ('(' 'catch' tagidx instr* ')')*
909+ // ('(' 'catch_all' instr* ')')? ')'
910+ // | 'try' label blocktype instr* 'deledate' label
911+ // | '(' 'try' label blocktype '(' 'do' instr* ')'
912+ // '(' 'delegate' label ')' ')'
913+ template <typename Ctx> MaybeResult<> trycatch (Ctx& ctx, bool folded) {
914+ auto pos = ctx.in .getPos ();
915+
916+ if ((folded && !ctx.in .takeSExprStart (" try" sv)) ||
917+ (!folded && !ctx.in .takeKeyword (" try" sv))) {
918+ return {};
919+ }
920+
921+ auto label = ctx.in .takeID ();
922+
923+ auto type = blocktype (ctx);
924+ CHECK_ERR (type);
925+
926+ CHECK_ERR (ctx.makeTry (pos, label, *type));
927+
928+ if (folded) {
929+ if (!ctx.in .takeSExprStart (" do" sv)) {
930+ return ctx.in .err (" expected 'do' in try" );
931+ }
932+ }
933+
934+ CHECK_ERR (instrs (ctx));
935+
936+ if (folded) {
937+ if (!ctx.in .takeRParen ()) {
938+ return ctx.in .err (" expected ')' at end of do" );
939+ }
940+ }
941+
942+ if ((folded && ctx.in .takeSExprStart (" delegate" )) ||
943+ (!folded && ctx.in .takeKeyword (" delegate" ))) {
944+ auto delegatePos = ctx.in .getPos ();
945+
946+ auto label = labelidx (ctx, true );
947+ CHECK_ERR (label);
948+
949+ if (folded) {
950+ if (!ctx.in .takeRParen ()) {
951+ return ctx.in .err (" expected ')' at end of delegate" );
952+ }
953+ if (!ctx.in .takeRParen ()) {
954+ return ctx.in .err (" expected ')' at end of try" );
955+ }
956+ }
957+
958+ CHECK_ERR (ctx.visitDelegate (delegatePos, *label));
959+ return Ok{};
960+ }
961+
962+ while (true ) {
963+ auto catchPos = ctx.in .getPos ();
964+
965+ if ((folded && !ctx.in .takeSExprStart (" catch" sv)) ||
966+ (!folded && !ctx.in .takeKeyword (" catch" sv))) {
967+ break ;
968+ }
969+
970+ // It can be ambiguous whether the name after `catch` is intended to be the
971+ // optional ID or the tag identifier. For example:
972+ //
973+ // (tag $t)
974+ // (func $ambiguous
975+ // try $t
976+ // catch $t
977+ // end
978+ // )
979+ //
980+ // When parsing the `catch`, the parser first tries to parse an optional ID
981+ // that must match the label of the `try`, and it succeeds because it sees
982+ // `$t` after the catch. However, when it then tries to parse the mandatory
983+ // tag index, it fails because the next token is `end`. The problem is that
984+ // the `$t` after the `catch` was the tag name and there was no optional ID
985+ // after all. The parser sets `parseID = false` and resets to just after the
986+ // `catch`, and now it skips parsing the optional ID so it correctly parses
987+ // the `$t` as a tag name.
988+ bool parseID = !folded;
989+ auto afterCatchPos = ctx.in .getPos ();
990+ while (true ) {
991+ if (!folded && parseID) {
992+ auto id = ctx.in .takeID ();
993+ if (id && id != label) {
994+ // Instead of returning an error, retry without the ID.
995+ parseID = false ;
996+ ctx.in .lexer .setIndex (afterCatchPos);
997+ continue ;
998+ }
999+ }
1000+
1001+ auto tag = tagidx (ctx);
1002+ if (parseID && tag.getErr ()) {
1003+ // Instead of returning an error, retry without the ID.
1004+ parseID = false ;
1005+ ctx.in .lexer .setIndex (afterCatchPos);
1006+ continue ;
1007+ }
1008+ CHECK_ERR (tag);
1009+
1010+ CHECK_ERR (ctx.visitCatch (catchPos, *tag));
1011+
1012+ CHECK_ERR (instrs (ctx));
1013+
1014+ if (folded) {
1015+ if (!ctx.in .takeRParen ()) {
1016+ return ctx.in .err (" expected ')' at end of catch" );
1017+ }
1018+ }
1019+ break ;
1020+ }
1021+ }
1022+
1023+ if ((folded && ctx.in .takeSExprStart (" catch_all" sv)) ||
1024+ (!folded && ctx.in .takeKeyword (" catch_all" sv))) {
1025+ auto catchPos = ctx.in .getPos ();
1026+
1027+ if (!folded) {
1028+ auto id = ctx.in .takeID ();
1029+ if (id && id != label) {
1030+ return ctx.in .err (" catch_all label does not match try label" );
1031+ }
1032+ }
1033+
1034+ CHECK_ERR (ctx.visitCatchAll (catchPos));
1035+
1036+ CHECK_ERR (instrs (ctx));
1037+
1038+ if (folded) {
1039+ if (!ctx.in .takeRParen ()) {
1040+ return ctx.in .err (" expected ')' at end of catch_all" );
1041+ }
1042+ }
1043+ }
1044+
1045+ if (folded) {
1046+ if (!ctx.in .takeRParen ()) {
1047+ return ctx.in .err (" expected ')' at end of try" );
1048+ }
1049+ } else {
1050+ if (!ctx.in .takeKeyword (" end" sv)) {
1051+ return ctx.in .err (" expected 'end' at end of try" );
1052+ }
1053+
1054+ auto id = ctx.in .takeID ();
1055+ if (id && id != label) {
1056+ return ctx.in .err (" end label does not match try label" );
1057+ }
1058+ }
1059+ return ctx.visitEnd ();
1060+ }
1061+
8981062template <typename Ctx> Result<> makeUnreachable (Ctx& ctx, Index pos) {
8991063 return ctx.makeUnreachable (pos);
9001064}
@@ -1266,15 +1430,6 @@ template<typename Ctx> Result<> makeTableCopy(Ctx& ctx, Index pos) {
12661430 return ctx.in .err (" unimplemented instruction" );
12671431}
12681432
1269- template <typename Ctx> Result<> makeTry (Ctx& ctx, Index pos) {
1270- return ctx.in .err (" unimplemented instruction" );
1271- }
1272-
1273- template <typename Ctx>
1274- Result<> makeTryOrCatchBody (Ctx& ctx, Index pos, Type type, bool isTry) {
1275- return ctx.in .err (" unimplemented instruction" );
1276- }
1277-
12781433template <typename Ctx> Result<> makeThrow (Ctx& ctx, Index pos) {
12791434 auto tag = tagidx (ctx);
12801435 CHECK_ERR (tag);
@@ -1621,12 +1776,13 @@ template<typename Ctx> Result<typename Ctx::LocalIdxT> localidx(Ctx& ctx) {
16211776
16221777// labelidx ::= x:u32 => x
16231778// | v:id => x (if labels[x] = v)
1624- template <typename Ctx> Result<typename Ctx::LabelIdxT> labelidx (Ctx& ctx) {
1779+ template <typename Ctx>
1780+ Result<typename Ctx::LabelIdxT> labelidx (Ctx& ctx, bool inDelegate) {
16251781 if (auto x = ctx.in .takeU32 ()) {
1626- return ctx.getLabelFromIdx (*x);
1782+ return ctx.getLabelFromIdx (*x, inDelegate );
16271783 }
16281784 if (auto id = ctx.in .takeID ()) {
1629- return ctx.getLabelFromName (*id);
1785+ return ctx.getLabelFromName (*id, inDelegate );
16301786 }
16311787 return ctx.in .err (" expected label index or identifier" );
16321788}
0 commit comments