diff --git a/lib/Translation/ForthToMLIR/ForthToMLIR.cpp b/lib/Translation/ForthToMLIR/ForthToMLIR.cpp index aebb7e8..d12d2a8 100644 --- a/lib/Translation/ForthToMLIR/ForthToMLIR.cpp +++ b/lib/Translation/ForthToMLIR/ForthToMLIR.cpp @@ -763,7 +763,11 @@ LogicalResult ForthParser::parseBody(Value &stack) { builder.create(loc, mergeBlock, ValueRange{stack}); // Pop the false-path block (from IF) - this becomes else-body start. + if (cfStack.empty()) + return emitError("ELSE without matching IF"); auto [tag, joinBlock] = cfStack.pop_back_val(); + if (tag != CFTag::Orig) + return emitError("ELSE without matching IF"); // Push merge block for THEN to pick up. cfStack.push_back({CFTag::Orig, mergeBlock}); @@ -777,7 +781,11 @@ LogicalResult ForthParser::parseBody(Value &stack) { consume(); // Pop the join/merge block. + if (cfStack.empty()) + return emitError("THEN without matching IF"); auto [tag, joinBlock] = cfStack.pop_back_val(); + if (tag != CFTag::Orig) + return emitError("THEN without matching IF"); // Branch from current block to join. builder.create(loc, joinBlock, ValueRange{stack}); @@ -810,7 +818,11 @@ LogicalResult ForthParser::parseBody(Value &stack) { auto [s1, flag] = emitPopFlag(loc, stack); + if (cfStack.empty()) + return emitError("UNTIL without matching BEGIN"); auto [tag, loopBlock] = cfStack.pop_back_val(); + if (tag != CFTag::Dest) + return emitError("UNTIL without matching BEGIN"); auto *exitBlock = createStackBlock(parentRegion, loc); @@ -829,7 +841,11 @@ LogicalResult ForthParser::parseBody(Value &stack) { auto [s1, flag] = emitPopFlag(loc, stack); + if (cfStack.empty()) + return emitError("WHILE without matching BEGIN"); auto [tag, loopBlock] = cfStack.pop_back_val(); + if (tag != CFTag::Dest) + return emitError("WHILE without matching BEGIN"); auto *bodyBlock = createStackBlock(parentRegion, loc); auto *exitBlock = createStackBlock(parentRegion, loc); @@ -851,13 +867,21 @@ LogicalResult ForthParser::parseBody(Value &stack) { consume(); // Pop loop header (from WHILE's re-push). + if (cfStack.empty()) + return emitError("REPEAT without matching WHILE"); auto [destTag, loopBlock] = cfStack.pop_back_val(); + if (destTag != CFTag::Dest) + return emitError("REPEAT without matching WHILE"); // Branch back to loop header. builder.create(loc, loopBlock, ValueRange{stack}); // Pop exit block (from WHILE). + if (cfStack.empty()) + return emitError("REPEAT without matching WHILE"); auto [origTag, exitBlock] = cfStack.pop_back_val(); + if (origTag != CFTag::Orig) + return emitError("REPEAT without matching WHILE"); // Continue after exit. builder.setInsertionPointToStart(exitBlock); @@ -1007,6 +1031,11 @@ LogicalResult ForthParser::parseBody(Value &stack) { } } + if (!cfStack.empty()) { + cfStack.clear(); + return emitError("unclosed control flow (missing THEN, REPEAT, or UNTIL?)"); + } + return success(); } diff --git a/test/Translation/Forth/begin-begin-repeat-mismatch-error.forth b/test/Translation/Forth/begin-begin-repeat-mismatch-error.forth new file mode 100644 index 0000000..d9d7b7d --- /dev/null +++ b/test/Translation/Forth/begin-begin-repeat-mismatch-error.forth @@ -0,0 +1,4 @@ +\ RUN: %not %warpforth-translate --forth-to-mlir %s 2>&1 | %FileCheck %s +\ CHECK: REPEAT without matching WHILE +\! kernel main +BEGIN BEGIN REPEAT diff --git a/test/Translation/Forth/begin-then-mismatch-error.forth b/test/Translation/Forth/begin-then-mismatch-error.forth new file mode 100644 index 0000000..16a1708 --- /dev/null +++ b/test/Translation/Forth/begin-then-mismatch-error.forth @@ -0,0 +1,4 @@ +\ RUN: %not %warpforth-translate --forth-to-mlir %s 2>&1 | %FileCheck %s +\ CHECK: THEN without matching IF +\! kernel main +BEGIN THEN diff --git a/test/Translation/Forth/else-without-if-error.forth b/test/Translation/Forth/else-without-if-error.forth new file mode 100644 index 0000000..7179e26 --- /dev/null +++ b/test/Translation/Forth/else-without-if-error.forth @@ -0,0 +1,4 @@ +\ RUN: %not %warpforth-translate --forth-to-mlir %s 2>&1 | %FileCheck %s +\ CHECK: ELSE without matching IF +\! kernel main +ELSE diff --git a/test/Translation/Forth/if-repeat-mismatch-error.forth b/test/Translation/Forth/if-repeat-mismatch-error.forth new file mode 100644 index 0000000..70b62c9 --- /dev/null +++ b/test/Translation/Forth/if-repeat-mismatch-error.forth @@ -0,0 +1,4 @@ +\ RUN: %not %warpforth-translate --forth-to-mlir %s 2>&1 | %FileCheck %s +\ CHECK: REPEAT without matching WHILE +\! kernel main +1 IF REPEAT diff --git a/test/Translation/Forth/if-until-mismatch-error.forth b/test/Translation/Forth/if-until-mismatch-error.forth new file mode 100644 index 0000000..16f4283 --- /dev/null +++ b/test/Translation/Forth/if-until-mismatch-error.forth @@ -0,0 +1,4 @@ +\ RUN: %not %warpforth-translate --forth-to-mlir %s 2>&1 | %FileCheck %s +\ CHECK: UNTIL without matching BEGIN +\! kernel main +IF UNTIL diff --git a/test/Translation/Forth/repeat-without-while-error.forth b/test/Translation/Forth/repeat-without-while-error.forth new file mode 100644 index 0000000..8728fae --- /dev/null +++ b/test/Translation/Forth/repeat-without-while-error.forth @@ -0,0 +1,4 @@ +\ RUN: %not %warpforth-translate --forth-to-mlir %s 2>&1 | %FileCheck %s +\ CHECK: REPEAT without matching WHILE +\! kernel main +REPEAT diff --git a/test/Translation/Forth/then-without-if-error.forth b/test/Translation/Forth/then-without-if-error.forth new file mode 100644 index 0000000..8c8ada6 --- /dev/null +++ b/test/Translation/Forth/then-without-if-error.forth @@ -0,0 +1,4 @@ +\ RUN: %not %warpforth-translate --forth-to-mlir %s 2>&1 | %FileCheck %s +\ CHECK: THEN without matching IF +\! kernel main +THEN diff --git a/test/Translation/Forth/unclosed-begin-while-error.forth b/test/Translation/Forth/unclosed-begin-while-error.forth new file mode 100644 index 0000000..1d56b55 --- /dev/null +++ b/test/Translation/Forth/unclosed-begin-while-error.forth @@ -0,0 +1,4 @@ +\ RUN: %not %warpforth-translate --forth-to-mlir %s 2>&1 | %FileCheck %s +\ CHECK: unclosed control flow (missing THEN, REPEAT, or UNTIL?) +\! kernel main +BEGIN 1 WHILE 42 diff --git a/test/Translation/Forth/unclosed-if-error.forth b/test/Translation/Forth/unclosed-if-error.forth new file mode 100644 index 0000000..7a156d4 --- /dev/null +++ b/test/Translation/Forth/unclosed-if-error.forth @@ -0,0 +1,4 @@ +\ RUN: %not %warpforth-translate --forth-to-mlir %s 2>&1 | %FileCheck %s +\ CHECK: unclosed control flow (missing THEN, REPEAT, or UNTIL?) +\! kernel main +1 IF 42 diff --git a/test/Translation/Forth/until-without-begin-error.forth b/test/Translation/Forth/until-without-begin-error.forth new file mode 100644 index 0000000..576d10f --- /dev/null +++ b/test/Translation/Forth/until-without-begin-error.forth @@ -0,0 +1,4 @@ +\ RUN: %not %warpforth-translate --forth-to-mlir %s 2>&1 | %FileCheck %s +\ CHECK: UNTIL without matching BEGIN +\! kernel main +UNTIL diff --git a/test/Translation/Forth/while-without-begin-error.forth b/test/Translation/Forth/while-without-begin-error.forth new file mode 100644 index 0000000..e26bac0 --- /dev/null +++ b/test/Translation/Forth/while-without-begin-error.forth @@ -0,0 +1,4 @@ +\ RUN: %not %warpforth-translate --forth-to-mlir %s 2>&1 | %FileCheck %s +\ CHECK: WHILE without matching BEGIN +\! kernel main +WHILE