summaryrefslogtreecommitdiffstats
path: root/generic/tclCompCmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclCompCmds.c')
-rw-r--r--generic/tclCompCmds.c118
1 files changed, 95 insertions, 23 deletions
diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c
index 7046e54..3046841 100644
--- a/generic/tclCompCmds.c
+++ b/generic/tclCompCmds.c
@@ -480,23 +480,55 @@ TclCompileBreakCmd(
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
+ ExceptionRange *rangePtr;
+ ExceptionAux *auxPtr;
+
if (parsePtr->numWords != 1) {
return TCL_ERROR;
}
/*
+ * Find the innermost exception range that contains this command.
+ */
+
+ rangePtr = TclGetInnermostExceptionRange(envPtr, TCL_BREAK, &auxPtr);
+ if (rangePtr && rangePtr->type == LOOP_EXCEPTION_RANGE) {
+ int toPop = envPtr->currStackDepth - auxPtr->stackDepth;
+
+ /*
+ * Pop off the extra stack frames.
+ */
+
+ while (toPop > 0) {
+ TclEmitOpcode(INST_POP, envPtr);
+ TclAdjustStackDepth(1, envPtr);
+ toPop--;
+ }
+
+ if (envPtr->expandCount == auxPtr->expandTarget) {
+ /*
+ * Found the target! Also, no built-up expansion stack. No need
+ * for a nasty INST_BREAK here.
+ */
+
+ TclAddLoopBreakFixup(envPtr, auxPtr);
+ goto done;
+ }
+ }
+
+ /*
* Emit a break instruction.
*/
TclEmitOpcode(INST_BREAK, envPtr);
-#ifdef TCL_COMPILE_DEBUG
+
+ done:
/*
- * Instructions that raise exceptions don't really have to follow
- * the usual stack management rules. But the checker wants them
- * followed, so lie about stack usage to make it happy.
+ * Instructions that raise exceptions don't really have to follow the
+ * usual stack management rules, but the cleanup code does.
*/
+
TclAdjustStackDepth(1, envPtr);
-#endif
return TCL_OK;
}
@@ -602,7 +634,7 @@ TclCompileCatchCmd(
* uses.
*/
- range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
+ range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
/*
* If the body is a simple word, compile a BEGIN_CATCH instruction,
@@ -790,6 +822,9 @@ TclCompileContinueCmd(
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
+ ExceptionRange *rangePtr;
+ ExceptionAux *auxPtr;
+
/*
* There should be no argument after the "continue".
*/
@@ -799,11 +834,48 @@ TclCompileContinueCmd(
}
/*
+ * See if we can find a valid continueOffset (i.e., not -1) in the
+ * innermost containing exception range.
+ */
+
+ rangePtr = TclGetInnermostExceptionRange(envPtr, TCL_CONTINUE, &auxPtr);
+ if (rangePtr && rangePtr->type == LOOP_EXCEPTION_RANGE) {
+ int toPop = envPtr->currStackDepth - auxPtr->stackDepth;
+
+ /*
+ * Pop off the extra stack frames.
+ */
+
+ while (toPop > 0) {
+ TclEmitOpcode(INST_POP, envPtr);
+ TclAdjustStackDepth(1, envPtr);
+ toPop--;
+ }
+
+ if (envPtr->expandCount == auxPtr->expandTarget) {
+ /*
+ * Found the target! Also, no built-up expansion stack. No need
+ * for a nasty INST_CONTINUE here.
+ */
+
+ TclAddLoopContinueFixup(envPtr, auxPtr);
+ goto done;
+ }
+ }
+
+ /*
* Emit a continue instruction.
*/
TclEmitOpcode(INST_CONTINUE, envPtr);
- PushStringLiteral(envPtr, ""); /* Evil hack! */
+
+ done:
+ /*
+ * Instructions that raise exceptions don't really have to follow the
+ * usual stack management rules, but the cleanup code does.
+ */
+
+ TclAdjustStackDepth(1, envPtr);
return TCL_OK;
}
@@ -1256,7 +1328,7 @@ TclCompileDictMergeCmd(
* For each of the remaining dictionaries...
*/
- outLoop = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
+ outLoop = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
TclEmitInstInt4( INST_BEGIN_CATCH4, outLoop, envPtr);
ExceptionRangeStarts(envPtr, outLoop);
for (i=2 ; i<parsePtr->numWords ; i++) {
@@ -1469,7 +1541,7 @@ CompileDictEachCmd(
* started by Tcl_DictObjFirst above.
*/
- catchRange = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
+ catchRange = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
TclEmitInstInt4( INST_BEGIN_CATCH4, catchRange, envPtr);
ExceptionRangeStarts(envPtr, catchRange);
@@ -1487,7 +1559,7 @@ CompileDictEachCmd(
* Set up the loop exception targets.
*/
- loopRange = DeclareExceptionRange(envPtr, LOOP_EXCEPTION_RANGE);
+ loopRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
ExceptionRangeStarts(envPtr, loopRange);
/*
@@ -1535,6 +1607,7 @@ CompileDictEachCmd(
*/
ExceptionRangeTarget(envPtr, loopRange, breakOffset);
+ TclFinalizeLoopExceptionRange(envPtr, loopRange);
TclEmitInstInt1( INST_UNSET_SCALAR, 0, envPtr);
TclEmitInt4( infoIndex, envPtr);
TclEmitOpcode( INST_END_CATCH, envPtr);
@@ -1713,7 +1786,7 @@ TclCompileDictUpdateCmd(
TclEmitInstInt4( INST_DICT_UPDATE_START, dictIndex, envPtr);
TclEmitInt4( infoIndex, envPtr);
- range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
+ range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
TclEmitInstInt4( INST_BEGIN_CATCH4, range, envPtr);
ExceptionRangeStarts(envPtr, range);
@@ -2070,7 +2143,7 @@ TclCompileDictWithCmd(
* Now the body of the [dict with].
*/
- range = DeclareExceptionRange(envPtr, CATCH_EXCEPTION_RANGE);
+ range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
TclEmitInstInt4( INST_BEGIN_CATCH4, range, envPtr);
ExceptionRangeStarts(envPtr, range);
@@ -2352,15 +2425,6 @@ TclCompileForCmd(
}
/*
- * Create ExceptionRange records for the body and the "next" command. The
- * "next" command's ExceptionRange supports break but not continue (and
- * has a -1 continueOffset).
- */
-
- bodyRange = DeclareExceptionRange(envPtr, LOOP_EXCEPTION_RANGE);
- nextRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
-
- /*
* Inline compile the initial command.
*/
@@ -2386,6 +2450,7 @@ TclCompileForCmd(
* Compile the loop body.
*/
+ bodyRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
bodyCodeOffset = ExceptionRangeStarts(envPtr, bodyRange);
SetLineInformation(4);
CompileBody(envPtr, bodyTokenPtr, interp);
@@ -2394,9 +2459,13 @@ TclCompileForCmd(
TclEmitOpcode(INST_POP, envPtr);
/*
- * Compile the "next" subcommand.
+ * Compile the "next" subcommand. Note that this exception range will not
+ * have a continueOffset (other than -1) connected to it; it won't trap
+ * TCL_CONTINUE but rather just TCL_BREAK.
*/
+ nextRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
+ envPtr->exceptAuxArrayPtr[nextRange].supportsContinue = 0;
envPtr->currStackDepth = savedStackDepth;
nextCodeOffset = ExceptionRangeStarts(envPtr, nextRange);
SetLineInformation(3);
@@ -2444,6 +2513,8 @@ TclCompileForCmd(
ExceptionRangeTarget(envPtr, bodyRange, breakOffset);
ExceptionRangeTarget(envPtr, nextRange, breakOffset);
+ TclFinalizeLoopExceptionRange(envPtr, bodyRange);
+ TclFinalizeLoopExceptionRange(envPtr, nextRange);
/*
* The for command's result is an empty string.
@@ -2735,7 +2806,7 @@ CompileEachloopCmd(
* Create an exception record to handle [break] and [continue].
*/
- range = DeclareExceptionRange(envPtr, LOOP_EXCEPTION_RANGE);
+ range = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
/*
* Evaluate then store each value list in the associated temporary.
@@ -2841,6 +2912,7 @@ CompileEachloopCmd(
*/
ExceptionRangeTarget(envPtr, range, breakOffset);
+ TclFinalizeLoopExceptionRange(envPtr, range);
/*
* The command's result is an empty string if not collecting, or the