summaryrefslogtreecommitdiffstats
path: root/generic/tclEnsemble.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclEnsemble.c')
-rw-r--r--generic/tclEnsemble.c64
1 files changed, 53 insertions, 11 deletions
diff --git a/generic/tclEnsemble.c b/generic/tclEnsemble.c
index ad11785..473c4bb 100644
--- a/generic/tclEnsemble.c
+++ b/generic/tclEnsemble.c
@@ -2749,15 +2749,9 @@ TclCompileEnsemble(
int ourResult = TCL_ERROR;
unsigned numBytes;
const char *word;
+ DefineLineInformation;
Tcl_IncrRefCount(replaced);
-
- /*
- * This is where we return to if we are parsing multiple nested compiled
- * ensembles. [info object] is such a beast.
- */
-
- checkNextWord:
if (parsePtr->numWords < depth + 1) {
goto failed;
}
@@ -2769,6 +2763,12 @@ TclCompileEnsemble(
goto failed;
}
+ /*
+ * This is where we return to if we are parsing multiple nested compiled
+ * ensembles. [info object] is such a beast.
+ */
+
+ checkNextWord:
word = tokenPtr[1].start;
numBytes = tokenPtr[1].size;
@@ -2979,6 +2979,17 @@ TclCompileEnsemble(
if (cmdPtr->compileProc == TclCompileEnsemble) {
tokenPtr = TokenAfter(tokenPtr);
+ if (parsePtr->numWords < depth + 1
+ || tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
+ /*
+ * Too hard because the user has done something unpleasant like
+ * omitting the sub-ensemble's command name or used a non-constant
+ * name for a sub-ensemble's command name; we respond by bailing
+ * out completely (this is a rare case). [Bug 6d2f249a01]
+ */
+
+ goto cleanup;
+ }
ensemble = (Tcl_Command) cmdPtr;
goto checkNextWord;
}
@@ -2998,6 +3009,23 @@ TclCompileEnsemble(
}
/*
+ * Throw out any line information generated by the failed compile attempt.
+ */
+
+ while (mapPtr->nuloc - 1 > eclIndex) {
+ mapPtr->nuloc--;
+ ckfree(mapPtr->loc[mapPtr->nuloc].line);
+ mapPtr->loc[mapPtr->nuloc].line = NULL;
+ }
+
+ /*
+ * Reset the index of next command. Toss out any from failed nested
+ * partial compiles.
+ */
+
+ envPtr->numCommands = mapPtr->nuloc;
+
+ /*
* Failed to do a full compile for some reason. Try to do a direct invoke
* instead of going through the ensemble lookup process again.
*/
@@ -3009,8 +3037,24 @@ TclCompileEnsemble(
cmdPtr = oldCmdPtr;
depth--;
}
- (void) Tcl_ListObjReplace(NULL, replaced, depth, 2, 0, NULL);
}
+ /*
+ * The length of the "replaced" list must be depth-1. Trim back
+ * any extra elements that might have been appended by failing
+ * pathways above.
+ */
+ (void) Tcl_ListObjReplace(NULL, replaced, depth-1, INT_MAX, 0, NULL);
+
+ /*
+ * TODO: Reconsider whether we ought to call CompileToInvokedCommand()
+ * when depth==1. In that case we are choosing to emit the
+ * INST_INVOKE_REPLACE bytecode when there is in fact no replacing
+ * to be done. It would be equally functional and presumably more
+ * performant to fall through to cleanup below, return TCL_ERROR,
+ * and let the compiler harness emit the INST_INVOKE_STK
+ * implementation for us.
+ */
+
CompileToInvokedCommand(interp, parsePtr, replaced, cmdPtr, envPtr);
ourResult = TCL_OK;
}
@@ -3179,9 +3223,7 @@ CompileToInvokedCommand(
* Do the replacing dispatch.
*/
- TclEmitInstInt4(INST_INVOKE_REPLACE, parsePtr->numWords, envPtr);
- TclEmitInt1(numWords+1, envPtr);
- TclAdjustStackDepth(-1, envPtr); /* Correction to stack depth calcs. */
+ TclEmitInvoke(envPtr, INST_INVOKE_REPLACE, parsePtr->numWords,numWords+1);
}
/*