diff options
Diffstat (limited to 'generic/tclCompCmds.c')
-rw-r--r-- | generic/tclCompCmds.c | 118 |
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 |