Compare commits

...
Author SHA1 Message Date
dkf 7319a7803b precondition was wrong, and needed to flush part of the string/internal rep 2013-12-29 18:48:09 +00:00
dkf 7a36091c38 use the new instruction 2013-12-29 16:59:15 +00:00
dkf 4ee64245d2 completed instruction implementation 2013-12-28 17:21:39 +00:00
dkf 24707208d7 interim commit; not yet working 2013-12-24 18:57:46 +00:00
dkf cbfb4c7624 merge trunk 2013-12-23 18:32:17 +00:00
mig 724d7b20d4 Added new tools for managing and verifying the stack depth during compilation. Used it in some spots in the compiler and in TclCompileCatchCommand. 2013-12-23 11:28:12 +00:00
mig c339e59205 remove unnecessary messing around INST_CONTINUE and INST_BREAK: local continue/break are already converted to jumps, so that these are either caught or returned - in either case, the stacks are cleaned up properly by TEBC itself. 2013-12-22 14:11:46 +00:00
mig 9b9e35d814 remove duplicate statement in previous commit 2013-12-22 13:03:19 +00:00
mig 0065bfd6bc fix stack counting bug in new catch compiler, commit 62a51cdb45. 2013-12-22 12:52:39 +00:00
mig 6bde9d5683 remove INST_TRY_CVT_TO_NUMERIC when it is known not be necessary (cherrypick from mig-optimize) 2013-12-20 21:59:28 +00:00
jan.nijtmans f324306fb2 Add TclRegisterLiteral() to internal stub table (from "mig-optimize" branch, looks like a good idea anyway) 2013-12-19 14:35:50 +00:00
dgp b23b38a551 [0b874c344d] Fix for nested coroutines ability to stitch together multiple
parts of the CmdFrame chain traversed by [info frame].
2013-12-18 18:23:20 +00:00
dkf f1a1245d74 simple compilation of [string replace] 2013-12-12 09:57:38 +00:00
dkf 03b5a36e45 merge trunk; document added instructions 2013-12-12 09:13:39 +00:00
dkf 19de6f5858 merge trunk 2013-12-12 08:09:45 +00:00
dkf 2127f0af03 merge trunk 2013-12-06 09:33:14 +00:00
dkf cdc8943683 merge trunk 2013-11-19 13:02:05 +00:00
dkf 1be1a5dfa4 merge trunk 2013-11-14 10:25:33 +00:00
dkf efa791f58b merge trunk 2013-10-29 20:08:41 +00:00
dkf bc84019495 Now do [string toupper], [string tolower] and [string totitle]. Only handles the no-indices case; that's the only case anyone actually commonly uses. 2013-10-29 20:07:56 +00:00
dkf 504122c70e merge trunk 2013-10-27 08:32:38 +00:00
dkf 9cc416d585 General [concat] compilation. 2013-10-26 08:25:02 +00:00
dkf f663a0f78d Change name of instruction to make way for future changes. 2013-10-26 07:50:08 +00:00
dkf edff530f8d First step in compiling [concat]: the trivial cases. 2013-10-24 07:21:14 +00:00
dkf cc5f831d90 Stack depth calculation correction. 2013-10-23 08:33:40 +00:00
dkf 054a071db5 merge fixes from trunk 2013-10-22 17:36:22 +00:00
dkf 2ffe17a9b3 Fix for assemble.test; problem was a total assumption failure caused by way that the assembler works. 2013-10-22 17:34:55 +00:00
dkf 345c194b8e corrected trace printing 2013-10-22 09:18:19 +00:00
dkf e1e7fafd59 merge trunk 2013-10-20 18:44:22 +00:00
dkf a1ae407099 Factor out some knowledge of immediate index encoding. 2013-10-06 13:21:10 +00:00
dkf e1e4f33ee4 merge trunk 2013-10-05 13:58:48 +00:00
dkf d9b2d9628a Added 'linsert' compiler. Factored out constant list index parser. 2013-10-05 13:53:30 +00:00
dkf 7fc9ecd5ab cleaner and faster 'string trim' 2013-10-03 13:32:06 +00:00
dkf 638b28b372 merge trunk 2013-10-03 08:54:01 +00:00
dkf 066dd2cb10 Expand subset of lreplace functionality that is compiled. 2013-10-02 08:46:29 +00:00
dkf 93595c68aa First attempt at [string trim] compilation. 2013-09-30 03:00:06 +00:00
dkf 324cc442eb merge trunk 2013-09-30 01:05:48 +00:00
dkf 967d113043 merge trunk 2013-02-04 22:02:53 +00:00
173 changed files with 1299 additions and 341 deletions
Executable → Regular
View File
Executable → Regular
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
+17 -33
View File
@@ -246,8 +246,6 @@ static void BBEmitInstInt4(AssemblyEnv* assemEnvPtr, int tblIdx,
int opnd, int count);
static void BBEmitInst1or4(AssemblyEnv* assemEnvPtr, int tblIdx,
int param, int count);
static void BBEmitInvoke1or4(AssemblyEnv* assemEnvPtr, int tblIdx,
int param, int count);
static void BBEmitOpcode(AssemblyEnv* assemEnvPtr, int tblIdx,
int count);
static int BuildExceptionRanges(AssemblyEnv* assemEnvPtr);
@@ -351,7 +349,8 @@ static const TalInstDesc TalInstructionTable[] = {
{"bitnot", ASSEM_1BYTE, INST_BITNOT, 1, 1},
{"bitor", ASSEM_1BYTE, INST_BITOR, 2, 1},
{"bitxor", ASSEM_1BYTE, INST_BITXOR, 2, 1},
{"concat", ASSEM_CONCAT1, INST_CONCAT1, INT_MIN,1},
{"concat", ASSEM_CONCAT1, INST_STR_CONCAT1, INT_MIN,1},
{"concatStk", ASSEM_LIST, INST_CONCAT_STK, INT_MIN,1},
{"coroName", ASSEM_1BYTE, INST_COROUTINE_NAME, 0, 1},
{"currentNamespace",ASSEM_1BYTE, INST_NS_CURRENT, 0, 1},
{"dictAppend", ASSEM_LVT4, INST_DICT_APPEND, 2, 1},
@@ -454,7 +453,11 @@ static const TalInstDesc TalInstructionTable[] = {
| INST_STORE_ARRAY4), 2, 1},
{"storeArrayStk", ASSEM_1BYTE, INST_STORE_ARRAY_STK, 3, 1},
{"storeStk", ASSEM_1BYTE, INST_STORE_STK, 2, 1},
{"strLower", ASSEM_1BYTE, INST_STR_LOWER, 1, 1},
{"strTitle", ASSEM_1BYTE, INST_STR_TITLE, 1, 1},
{"strUpper", ASSEM_1BYTE, INST_STR_UPPER, 1, 1},
{"strcmp", ASSEM_1BYTE, INST_STR_CMP, 2, 1},
{"strcat", ASSEM_CONCAT1, INST_STR_CONCAT1, INT_MIN,1},
{"streq", ASSEM_1BYTE, INST_STR_EQ, 2, 1},
{"strfind", ASSEM_1BYTE, INST_STR_FIND, 2, 1},
{"strindex", ASSEM_1BYTE, INST_STR_INDEX, 2, 1},
@@ -464,6 +467,9 @@ static const TalInstDesc TalInstructionTable[] = {
{"strneq", ASSEM_1BYTE, INST_STR_NEQ, 2, 1},
{"strrange", ASSEM_1BYTE, INST_STR_RANGE, 3, 1},
{"strrfind", ASSEM_1BYTE, INST_STR_FIND_LAST, 2, 1},
{"strtrim", ASSEM_1BYTE, INST_STR_TRIM, 2, 1},
{"strtrimLeft", ASSEM_1BYTE, INST_STR_TRIM_LEFT, 2, 1},
{"strtrimRight", ASSEM_1BYTE, INST_STR_TRIM_RIGHT, 2, 1},
{"sub", ASSEM_1BYTE, INST_SUB, 2, 1},
{"tclooClass", ASSEM_1BYTE, INST_TCLOO_CLASS, 1, 1},
{"tclooIsObject", ASSEM_1BYTE, INST_TCLOO_IS_OBJECT, 1, 1},
@@ -495,6 +501,7 @@ static const unsigned char NonThrowingByteCodes[] = {
INST_PUSH1, INST_PUSH4, INST_POP, INST_DUP, /* 1-4 */
INST_JUMP1, INST_JUMP4, /* 34-35 */
INST_END_CATCH, INST_PUSH_RESULT, INST_PUSH_RETURN_CODE, /* 70-72 */
INST_LIST, /* 79 */
INST_OVER, /* 95 */
INST_PUSH_RETURN_OPTIONS, /* 108 */
INST_REVERSE, /* 126 */
@@ -504,7 +511,10 @@ static const unsigned char NonThrowingByteCodes[] = {
INST_COROUTINE_NAME, /* 149 */
INST_NS_CURRENT, /* 151 */
INST_INFO_LEVEL_NUM, /* 152 */
INST_RESOLVE_COMMAND /* 154 */
INST_RESOLVE_COMMAND, /* 154 */
INST_STR_TRIM, INST_STR_TRIM_LEFT, INST_STR_TRIM_RIGHT, /* 166-168 */
INST_CONCAT_STK, /* 169 */
INST_STR_UPPER, INST_STR_LOWER, INST_STR_TITLE /* 170-172 */
};
/*
@@ -681,13 +691,10 @@ BBEmitInstInt4(
/*
*-----------------------------------------------------------------------------
*
* BBEmitInst1or4, BBEmitInvoke1or4 --
* BBEmitInst1or4 --
*
* Emits a 1- or 4-byte operation according to the magnitude of the
* operand. The Invoke variant generates wrapping stack-balance
* management if necessary (which is not normally required in assembled
* code, as loop exception ranges, expansions, breaks and continues can't
* be issued currently).
* operand.
*
*-----------------------------------------------------------------------------
*/
@@ -719,29 +726,6 @@ BBEmitInst1or4(
TclUpdateAtCmdStart(op, envPtr);
BBUpdateStackReqs(bbPtr, tblIdx, count);
}
static void
BBEmitInvoke1or4(
AssemblyEnv* assemEnvPtr, /* Assembly environment */
int tblIdx, /* Index in TalInstructionTable of op */
int param, /* Variable-length parameter */
int count) /* Arity if variadic */
{
CompileEnv* envPtr = assemEnvPtr->envPtr;
/* Compilation environment */
BasicBlock* bbPtr = assemEnvPtr->curr_bb;
/* Current basic block */
int op = TalInstructionTable[tblIdx].tclInstCode;
if (param <= 0xff) {
op >>= 8;
} else {
op &= 0xff;
}
TclEmitInvoke(envPtr, op, param);
TclUpdateAtCmdStart(op, envPtr);
BBUpdateStackReqs(bbPtr, tblIdx, count);
}
/*
*-----------------------------------------------------------------------------
@@ -1478,7 +1462,7 @@ AssembleOneLine(
goto cleanup;
}
BBEmitInvoke1or4(assemEnvPtr, tblIdx, opnd, opnd);
BBEmitInst1or4(assemEnvPtr, tblIdx, opnd, opnd);
break;
case ASSEM_JUMP:
+2 -2
View File
@@ -211,7 +211,7 @@ static const CmdInfo builtInCmds[] = {
{"case", Tcl_CaseObjCmd, NULL, NULL, CMD_IS_SAFE},
#endif
{"catch", Tcl_CatchObjCmd, TclCompileCatchCmd, TclNRCatchObjCmd, CMD_IS_SAFE},
{"concat", Tcl_ConcatObjCmd, NULL, NULL, CMD_IS_SAFE},
{"concat", Tcl_ConcatObjCmd, TclCompileConcatCmd, NULL, CMD_IS_SAFE},
{"continue", Tcl_ContinueObjCmd, TclCompileContinueCmd, NULL, CMD_IS_SAFE},
{"coroutine", NULL, NULL, TclNRCoroutineObjCmd, CMD_IS_SAFE},
{"error", Tcl_ErrorObjCmd, TclCompileErrorCmd, NULL, CMD_IS_SAFE},
@@ -227,7 +227,7 @@ static const CmdInfo builtInCmds[] = {
{"lappend", Tcl_LappendObjCmd, TclCompileLappendCmd, NULL, CMD_IS_SAFE},
{"lassign", Tcl_LassignObjCmd, TclCompileLassignCmd, NULL, CMD_IS_SAFE},
{"lindex", Tcl_LindexObjCmd, TclCompileLindexCmd, NULL, CMD_IS_SAFE},
{"linsert", Tcl_LinsertObjCmd, NULL, NULL, CMD_IS_SAFE},
{"linsert", Tcl_LinsertObjCmd, TclCompileLinsertCmd, NULL, CMD_IS_SAFE},
{"list", Tcl_ListObjCmd, TclCompileListCmd, NULL, CMD_IS_SAFE|CMD_COMPILES_EXPANDED},
{"llength", Tcl_LlengthObjCmd, TclCompileLlengthCmd, NULL, CMD_IS_SAFE},
{"lmap", Tcl_LmapObjCmd, TclCompileLmapCmd, TclNRLmapCmd, CMD_IS_SAFE},
+9 -7
View File
@@ -35,6 +35,8 @@ static int UniCharIsHexDigit(int character);
/*
* Default set of characters to trim in [string trim] and friends. This is a
* UTF-8 literal string containing all Unicode space characters [TIP #413]
*
* Synch with tclCompCmdsSZ.c
*/
#define DEFAULT_TRIM_SET \
@@ -3337,14 +3339,14 @@ TclInitStringCmd(
{"match", StringMatchCmd, TclCompileStringMatchCmd, NULL, NULL, 0},
{"range", StringRangeCmd, TclCompileStringRangeCmd, NULL, NULL, 0},
{"repeat", StringReptCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
{"replace", StringRplcCmd, NULL, NULL, NULL, 0},
{"replace", StringRplcCmd, TclCompileStringReplaceCmd, NULL, NULL, 0},
{"reverse", StringRevCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0},
{"tolower", StringLowerCmd, TclCompileBasic1To3ArgCmd, NULL, NULL, 0},
{"toupper", StringUpperCmd, TclCompileBasic1To3ArgCmd, NULL, NULL, 0},
{"totitle", StringTitleCmd, TclCompileBasic1To3ArgCmd, NULL, NULL, 0},
{"trim", StringTrimCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
{"trimleft", StringTrimLCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
{"trimright", StringTrimRCmd, TclCompileBasic1Or2ArgCmd, NULL, NULL, 0},
{"tolower", StringLowerCmd, TclCompileStringToLowerCmd, NULL, NULL, 0},
{"toupper", StringUpperCmd, TclCompileStringToUpperCmd, NULL, NULL, 0},
{"totitle", StringTitleCmd, TclCompileStringToTitleCmd, NULL, NULL, 0},
{"trim", StringTrimCmd, TclCompileStringTrimCmd, NULL, NULL, 0},
{"trimleft", StringTrimLCmd, TclCompileStringTrimLCmd, NULL, NULL, 0},
{"trimright", StringTrimRCmd, TclCompileStringTrimRCmd, NULL, NULL, 0},
{"wordend", StringEndCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
{"wordstart", StringStartCmd, TclCompileBasic2ArgCmd, NULL, NULL, 0},
{NULL, NULL, NULL, NULL, NULL, 0}
+115 -15
View File
@@ -65,6 +65,13 @@ const AuxDataType tclDictUpdateInfoType = {
FreeDictUpdateInfo, /* freeProc */
PrintDictUpdateInfo /* printProc */
};
/*
* The definition of what whitespace is stripped when [concat]enating. Must be
* kept in synch with tclUtil.c
*/
#define CONCAT_WS " \f\v\r\t\n"
/*
*----------------------------------------------------------------------
@@ -489,17 +496,14 @@ TclCompileBreakCmd(
TclCleanupStackForBreakContinue(envPtr, auxPtr);
TclAddLoopBreakFixup(envPtr, auxPtr);
TclAdjustStackDepth(1, envPtr);
} else {
/*
* Emit a real break.
*/
PushStringLiteral(envPtr, "");
TclEmitOpcode(INST_DUP, envPtr);
TclEmitInstInt4(INST_RETURN_IMM, TCL_BREAK, envPtr);
TclEmitInt4(0, envPtr);
TclEmitOpcode(INST_BREAK, envPtr);
}
TclAdjustStackDepth(1, envPtr);
return TCL_OK;
}
@@ -533,9 +537,10 @@ TclCompileCatchCmd(
{
JumpFixup jumpFixup;
Tcl_Token *cmdTokenPtr, *resultNameTokenPtr, *optsNameTokenPtr;
int resultIndex, optsIndex, range;
int resultIndex, optsIndex, range, dropScript = 0;
DefineLineInformation; /* TIP #280 */
int depth = TclGetStackDepth(envPtr);
/*
* If syntax does not match what we expect for [catch], do not compile.
* Let runtime checks determine if syntax has changed.
@@ -608,16 +613,19 @@ TclCompileCatchCmd(
TclEmitOpcode( INST_DUP, envPtr);
TclEmitInvoke(envPtr, INST_EVAL_STK);
/* drop the script */
dropScript = 1;
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
TclEmitOpcode( INST_POP, envPtr);
}
ExceptionRangeEnds(envPtr, range);
/*
* Emit the "no errors" epilogue: push "0" (TCL_OK) as the catch result,
* and jump around the "error case" code.
*/
TclCheckStackDepth(depth+1, envPtr);
PushStringLiteral(envPtr, "0");
TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
@@ -626,8 +634,14 @@ TclCompileCatchCmd(
* return code.
*/
TclAdjustStackDepth(-2, envPtr);
ExceptionRangeTarget(envPtr, range, catchOffset);
TclSetStackDepth(depth + dropScript, envPtr);
if (dropScript) {
TclEmitOpcode( INST_POP, envPtr);
}
/* Stack at this point is empty */
TclEmitOpcode( INST_PUSH_RESULT, envPtr);
TclEmitOpcode( INST_PUSH_RETURN_CODE, envPtr);
@@ -676,6 +690,94 @@ TclCompileCatchCmd(
}
TclEmitOpcode( INST_POP, envPtr);
TclCheckStackDepth(depth+1, envPtr);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileConcatCmd --
*
* Procedure called to compile the "concat" command.
*
* Results:
* Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
* evaluation to runtime.
*
* Side effects:
* Instructions are added to envPtr to execute the "concat" command at
* runtime.
*
*----------------------------------------------------------------------
*/
int
TclCompileConcatCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to defintion of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Obj *objPtr, *listObj;
Tcl_Token *tokenPtr;
int i;
/* TODO: Consider compiling expansion case. */
if (parsePtr->numWords == 1) {
/*
* [concat] without arguments just pushes an empty object.
*/
PushStringLiteral(envPtr, "");
return TCL_OK;
}
/*
* Test if all arguments are compile-time known. If they are, we can
* implement with a simple push.
*/
listObj = Tcl_NewObj();
for (i = 1, tokenPtr = parsePtr->tokenPtr; i < parsePtr->numWords; i++) {
tokenPtr = TokenAfter(tokenPtr);
objPtr = Tcl_NewObj();
if (!TclWordKnownAtCompileTime(tokenPtr, objPtr)) {
Tcl_DecrRefCount(objPtr);
Tcl_DecrRefCount(listObj);
listObj = NULL;
break;
}
(void) Tcl_ListObjAppendElement(NULL, listObj, objPtr);
}
if (listObj != NULL) {
Tcl_Obj **objs;
const char *bytes;
int len;
Tcl_ListObjGetElements(NULL, listObj, &len, &objs);
objPtr = Tcl_ConcatObj(len, objs);
Tcl_DecrRefCount(listObj);
bytes = Tcl_GetStringFromObj(objPtr, &len);
PushLiteral(envPtr, bytes, len);
Tcl_DecrRefCount(objPtr);
return TCL_OK;
}
/*
* General case: runtime concat.
*/
for (i = 1, tokenPtr = parsePtr->tokenPtr; i < parsePtr->numWords; i++) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, i);
}
TclEmitInstInt4( INST_CONCAT_STK, i-1, envPtr);
return TCL_OK;
}
@@ -730,17 +832,14 @@ TclCompileContinueCmd(
TclCleanupStackForBreakContinue(envPtr, auxPtr);
TclAddLoopContinueFixup(envPtr, auxPtr);
TclAdjustStackDepth(1, envPtr);
} else {
/*
* Emit a real continue.
*/
PushStringLiteral(envPtr, "");
TclEmitOpcode(INST_DUP, envPtr);
TclEmitInstInt4(INST_RETURN_IMM, TCL_CONTINUE, envPtr);
TclEmitInt4(0, envPtr);
TclEmitOpcode(INST_CONTINUE, envPtr);
}
TclAdjustStackDepth(1, envPtr);
return TCL_OK;
}
@@ -1673,7 +1772,7 @@ TclCompileDictAppendCmd(
tokenPtr = TokenAfter(tokenPtr);
}
if (parsePtr->numWords > 4) {
TclEmitInstInt1(INST_CONCAT1, parsePtr->numWords-3, envPtr);
TclEmitInstInt1(INST_STR_CONCAT1, parsePtr->numWords-3, envPtr);
}
/*
@@ -2276,6 +2375,7 @@ TclCompileForCmd(
SetLineInformation(2);
TclCompileExprWords(interp, testTokenPtr, 1, envPtr);
TclClearNumConversion(envPtr);
jumpDist = CurrentOffset(envPtr) - bodyCodeOffset;
if (jumpDist > 127) {
@@ -3005,7 +3105,7 @@ TclCompileFormatCmd(
* Do the concatenation, which produces the result.
*/
TclEmitInstInt1(INST_CONCAT1, i, envPtr);
TclEmitInstInt1(INST_STR_CONCAT1, i, envPtr);
} else {
/*
* EVIL HACK! Force there to be a string representation in the case
+313 -148
View File
@@ -28,6 +28,58 @@ static void CompileReturnInternal(CompileEnv *envPtr,
static int IndexTailVarIfKnown(Tcl_Interp *interp,
Tcl_Token *varTokenPtr, CompileEnv *envPtr);
#define INDEX_END (-2)
/*
*----------------------------------------------------------------------
*
* GetIndexFromToken --
*
* Parse a token and get the encoded version of the index (as understood
* by TEBC), assuming it is at all knowable at compile time. Only handles
* indices that are integers or 'end' or 'end-integer'.
*
* Returns:
* TCL_OK if parsing succeeded, and TCL_ERROR if it failed.
*
* Side effects:
* Sets *index to the index value if successful.
*
*----------------------------------------------------------------------
*/
static inline int
GetIndexFromToken(
Tcl_Token *tokenPtr,
int *index)
{
Tcl_Obj *tmpObj = Tcl_NewObj();
int result, idx;
if (!TclWordKnownAtCompileTime(tokenPtr, tmpObj)) {
Tcl_DecrRefCount(tmpObj);
return TCL_ERROR;
}
result = TclGetIntFromObj(NULL, tmpObj, &idx);
if (result == TCL_OK) {
if (idx < 0) {
result = TCL_ERROR;
}
} else {
result = TclGetIntForIndexM(NULL, tmpObj, INDEX_END, &idx);
if (result == TCL_OK && idx > INDEX_END) {
result = TCL_ERROR;
}
}
Tcl_DecrRefCount(tmpObj);
if (result == TCL_OK) {
*index = idx;
}
return result;
}
/*
*----------------------------------------------------------------------
@@ -229,6 +281,7 @@ TclCompileIfCmd(
SetLineInformation(wordIdx);
Tcl_ResetResult(interp);
TclCompileExprWords(interp, testTokenPtr, 1, envPtr);
TclClearNumConversion(envPtr);
if (jumpFalseFixupArray.next >= jumpFalseFixupArray.end) {
TclExpandJumpFixupArray(&jumpFalseFixupArray);
}
@@ -478,6 +531,7 @@ TclCompileIncrCmd(
} else {
SetLineInformation(2);
CompileTokens(envPtr, incrTokenPtr, interp);
TclClearNumConversion(envPtr);
}
} else { /* No incr amount given so use 1. */
haveImmValue = 1;
@@ -1027,7 +1081,7 @@ TclCompileLassignCmd(
*/
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx, envPtr);
TclEmitInt4( -2 /* == "end" */, envPtr);
TclEmitInt4( INDEX_END, envPtr);
return TCL_OK;
}
@@ -1060,7 +1114,7 @@ TclCompileLindexCmd(
CompileEnv *envPtr) /* Holds resulting instructions. */
{
Tcl_Token *idxTokenPtr, *valTokenPtr;
int i, numWords = parsePtr->numWords;
int i, idx, numWords = parsePtr->numWords;
DefineLineInformation; /* TIP #280 */
/*
@@ -1078,45 +1132,27 @@ TclCompileLindexCmd(
}
idxTokenPtr = TokenAfter(valTokenPtr);
if (idxTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
Tcl_Obj *tmpObj;
int idx, result;
tmpObj = Tcl_NewStringObj(idxTokenPtr[1].start, idxTokenPtr[1].size);
result = TclGetIntFromObj(NULL, tmpObj, &idx);
if (result == TCL_OK) {
if (idx < 0) {
result = TCL_ERROR;
}
} else {
result = TclGetIntForIndexM(NULL, tmpObj, -2, &idx);
if (result == TCL_OK && idx > -2) {
result = TCL_ERROR;
}
}
TclDecrRefCount(tmpObj);
if (result == TCL_OK) {
/*
* All checks have been completed, and we have exactly one of
* these constructs:
* lindex <arbitraryValue> <posInt>
* lindex <arbitraryValue> end-<posInt>
* This is best compiled as a push of the arbitrary value followed
* by an "immediate lindex" which is the most efficient variety.
*/
CompileWord(envPtr, valTokenPtr, interp, 1);
TclEmitInstInt4( INST_LIST_INDEX_IMM, idx, envPtr);
return TCL_OK;
}
if (GetIndexFromToken(idxTokenPtr, &idx) == TCL_OK) {
/*
* If the conversion failed or the value was negative, we just keep on
* going with the more complex compilation.
* All checks have been completed, and we have exactly one of these
* constructs:
* lindex <arbitraryValue> <posInt>
* lindex <arbitraryValue> end-<posInt>
* This is best compiled as a push of the arbitrary value followed by
* an "immediate lindex" which is the most efficient variety.
*/
CompileWord(envPtr, valTokenPtr, interp, 1);
TclEmitInstInt4( INST_LIST_INDEX_IMM, idx, envPtr);
return TCL_OK;
}
/*
* If the value was not known at compile time, the conversion failed or
* the value was negative, we just keep on going with the more complex
* compilation.
*/
/*
* Push the operands onto the stack.
*/
@@ -1263,7 +1299,7 @@ TclCompileListCmd(
if (concat && numWords == 2) {
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
TclEmitInt4( -2, envPtr);
TclEmitInt4( INDEX_END, envPtr);
}
return TCL_OK;
}
@@ -1330,8 +1366,7 @@ TclCompileLrangeCmd(
{
Tcl_Token *tokenPtr, *listTokenPtr;
DefineLineInformation; /* TIP #280 */
Tcl_Obj *tmpObj;
int idx1, idx2, result;
int idx1, idx2;
if (parsePtr->numWords != 4) {
return TCL_ERROR;
@@ -1339,56 +1374,18 @@ TclCompileLrangeCmd(
listTokenPtr = TokenAfter(parsePtr->tokenPtr);
/*
* Parse the first index. Will only compile if it is constant and not an
* Parse the indices. Will only compile if both are constants and not an
* _integer_ less than zero (since we reserve negative indices here for
* end-relative indexing).
* end-relative indexing) or an end-based index greater than 'end' itself.
*/
tokenPtr = TokenAfter(listTokenPtr);
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
if (GetIndexFromToken(tokenPtr, &idx1) != TCL_OK) {
return TCL_ERROR;
}
tmpObj = Tcl_NewStringObj(tokenPtr[1].start, tokenPtr[1].size);
result = TclGetIntFromObj(NULL, tmpObj, &idx1);
if (result == TCL_OK) {
if (idx1 < 0) {
result = TCL_ERROR;
}
} else {
result = TclGetIntForIndexM(NULL, tmpObj, -2, &idx1);
if (result == TCL_OK && idx1 > -2) {
result = TCL_ERROR;
}
}
TclDecrRefCount(tmpObj);
if (result != TCL_OK) {
return TCL_ERROR;
}
/*
* Parse the second index. Will only compile if it is constant and not an
* _integer_ less than zero (since we reserve negative indices here for
* end-relative indexing).
*/
tokenPtr = TokenAfter(tokenPtr);
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
return TCL_ERROR;
}
tmpObj = Tcl_NewStringObj(tokenPtr[1].start, tokenPtr[1].size);
result = TclGetIntFromObj(NULL, tmpObj, &idx2);
if (result == TCL_OK) {
if (idx2 < 0) {
result = TCL_ERROR;
}
} else {
result = TclGetIntForIndexM(NULL, tmpObj, -2, &idx2);
if (result == TCL_OK && idx2 > -2) {
result = TCL_ERROR;
}
}
TclDecrRefCount(tmpObj);
if (result != TCL_OK) {
if (GetIndexFromToken(tokenPtr, &idx2) != TCL_OK) {
return TCL_ERROR;
}
@@ -1404,16 +1401,95 @@ TclCompileLrangeCmd(
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileLinsertCmd --
*
* How to compile the "linsert" command. We only bother with the case
* where the index is constant.
*
*----------------------------------------------------------------------
*/
int
TclCompileLinsertCmd(
Tcl_Interp *interp, /* Tcl interpreter for context. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the
* command. */
Command *cmdPtr, /* Points to defintion of command being
* compiled. */
CompileEnv *envPtr) /* Holds the resulting instructions. */
{
Tcl_Token *tokenPtr, *listTokenPtr;
DefineLineInformation; /* TIP #280 */
int idx, i;
if (parsePtr->numWords < 3) {
return TCL_ERROR;
}
listTokenPtr = TokenAfter(parsePtr->tokenPtr);
/*
* Parse the index. Will only compile if it is constant and not an
* _integer_ less than zero (since we reserve negative indices here for
* end-relative indexing) or an end-based index greater than 'end' itself.
*/
tokenPtr = TokenAfter(listTokenPtr);
if (GetIndexFromToken(tokenPtr, &idx) != TCL_OK) {
return TCL_ERROR;
}
/*
* There are four main cases. If there are no values to insert, this is
* just a confirm-listiness check. If the index is '0', this is a prepend.
* If the index is 'end' (== INDEX_END), this is an append. Otherwise,
* this is a splice (== split, insert values as list, concat-3).
*/
CompileWord(envPtr, listTokenPtr, interp, 1);
if (parsePtr->numWords == 3) {
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
TclEmitInt4( INDEX_END, envPtr);
return TCL_OK;
}
for (i=3 ; i<parsePtr->numWords ; i++) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, i);
}
TclEmitInstInt4( INST_LIST, i-3, envPtr);
if (idx == 0 /*start*/) {
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
} else if (idx == INDEX_END /*end*/) {
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
} else {
if (idx < 0) {
idx++;
}
TclEmitInstInt4( INST_OVER, 1, envPtr);
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
TclEmitInt4( idx-1, envPtr);
TclEmitInstInt4( INST_REVERSE, 3, envPtr);
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx, envPtr);
TclEmitInt4( INDEX_END, envPtr);
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* TclCompileLreplaceCmd --
*
* How to compile the "lreplace" command. We only bother with the case
* where there are no elements to insert and where both the 'first' and
* 'last' arguments are constant and one can be deterined to be at the
* end of the list. (This is the case that could also be written with
* "lrange".)
* where the indices are constant.
*
*----------------------------------------------------------------------
*/
@@ -1430,100 +1506,189 @@ TclCompileLreplaceCmd(
Tcl_Token *tokenPtr, *listTokenPtr;
DefineLineInformation; /* TIP #280 */
Tcl_Obj *tmpObj;
int idx1, idx2, result, guaranteedDropAll = 0;
int idx1, idx2, i, offset;
if (parsePtr->numWords != 4) {
if (parsePtr->numWords < 4) {
return TCL_ERROR;
}
listTokenPtr = TokenAfter(parsePtr->tokenPtr);
/*
* Parse the first index. Will only compile if it is constant and not an
* Parse the indices. Will only compile if both are constants and not an
* _integer_ less than zero (since we reserve negative indices here for
* end-relative indexing).
* end-relative indexing) or an end-based index greater than 'end' itself.
*/
tokenPtr = TokenAfter(listTokenPtr);
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
if (GetIndexFromToken(tokenPtr, &idx1) != TCL_OK) {
return TCL_ERROR;
}
tmpObj = Tcl_NewStringObj(tokenPtr[1].start, tokenPtr[1].size);
result = TclGetIntFromObj(NULL, tmpObj, &idx1);
if (result == TCL_OK) {
if (idx1 < 0) {
result = TCL_ERROR;
}
} else {
result = TclGetIntForIndexM(NULL, tmpObj, -2, &idx1);
if (result == TCL_OK && idx1 > -2) {
result = TCL_ERROR;
}
}
TclDecrRefCount(tmpObj);
if (result != TCL_OK) {
return TCL_ERROR;
}
/*
* Parse the second index. Will only compile if it is constant and not an
* _integer_ less than zero (since we reserve negative indices here for
* end-relative indexing).
*/
tokenPtr = TokenAfter(tokenPtr);
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
return TCL_ERROR;
}
tmpObj = Tcl_NewStringObj(tokenPtr[1].start, tokenPtr[1].size);
result = TclGetIntFromObj(NULL, tmpObj, &idx2);
if (result == TCL_OK) {
if (idx2 < 0) {
result = TCL_ERROR;
}
} else {
result = TclGetIntForIndexM(NULL, tmpObj, -2, &idx2);
if (result == TCL_OK && idx2 > -2) {
result = TCL_ERROR;
}
}
TclDecrRefCount(tmpObj);
if (result != TCL_OK) {
if (GetIndexFromToken(tokenPtr, &idx2) != TCL_OK) {
return TCL_ERROR;
}
/*
* Sanity check: can only issue when we're removing a range at one or
* other end of the list. If we're at one end or the other, convert the
* indices into the equivalent for an [lrange].
* Work out what this [lreplace] is actually doing.
*/
tmpObj = NULL;
CompileWord(envPtr, listTokenPtr, interp, 1);
if (parsePtr->numWords == 4) {
if (idx1 == 0) {
if (idx2 == INDEX_END) {
goto dropAll;
}
idx1 = idx2 + 1;
idx2 = INDEX_END;
goto dropEnd;
} else if (idx2 == INDEX_END) {
idx2 = idx1 - 1;
idx1 = 0;
goto dropEnd;
} else {
if (idx1 > 0) {
tmpObj = Tcl_NewIntObj(idx1);
Tcl_IncrRefCount(tmpObj);
}
goto dropRange;
}
}
tokenPtr = TokenAfter(tokenPtr);
for (i=4 ; i<parsePtr->numWords ; i++) {
CompileWord(envPtr, tokenPtr, interp, i);
tokenPtr = TokenAfter(tokenPtr);
}
TclEmitInstInt4( INST_LIST, i - 4, envPtr);
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
if (idx1 == 0) {
if (idx2 == -2) {
guaranteedDropAll = 1;
if (idx2 == INDEX_END) {
goto replaceAll;
}
idx1 = idx2 + 1;
idx2 = -2;
} else if (idx2 == -2) {
idx2 = INDEX_END;
goto replaceHead;
} else if (idx2 == INDEX_END) {
idx2 = idx1 - 1;
idx1 = 0;
goto replaceTail;
} else {
return TCL_ERROR;
if (idx1 > 0 && idx2 > 0 && idx2 < idx1) {
idx2 = idx1 - 1;
} else if (idx1 < 0 && idx2 < 0 && idx2 < idx1) {
idx2 = idx1 - 1;
}
if (idx1 > 0) {
tmpObj = Tcl_NewIntObj(idx1);
Tcl_IncrRefCount(tmpObj);
}
goto replaceRange;
}
/*
* Issue instructions. It's not safe to skip doing the LIST_RANGE, as
* we've not proved that the 'list' argument is really a list. Not that it
* is worth trying to do that given current knowledge.
* Issue instructions to perform the operations relating to configurations
* that just drop. The only argument pushed on the stack is the list to
* operate on.
*/
CompileWord(envPtr, listTokenPtr, interp, 1);
if (guaranteedDropAll) {
dropAll:
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
TclEmitOpcode( INST_POP, envPtr);
PushStringLiteral(envPtr, "");
goto done;
dropEnd:
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx1, envPtr);
TclEmitInt4( idx2, envPtr);
goto done;
dropRange:
if (tmpObj != NULL) {
TclEmitOpcode( INST_DUP, envPtr);
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
TclEmitOpcode( INST_POP, envPtr);
PushStringLiteral(envPtr, "");
} else {
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx1, envPtr);
TclEmitInt4( idx2, envPtr);
TclEmitPush(TclAddLiteralObj(envPtr, tmpObj, NULL), envPtr);
TclEmitOpcode( INST_GT, envPtr);
offset = CurrentOffset(envPtr);
TclEmitInstInt1( INST_JUMP_TRUE1, 0, envPtr);
TclEmitPush(TclAddLiteralObj(envPtr, Tcl_ObjPrintf(
"list doesn't contain element %d", idx1), NULL), envPtr);
CompileReturnInternal(envPtr, INST_RETURN_IMM, TCL_ERROR, 0,
Tcl_ObjPrintf("-errorcode {TCL OPERATION LREPLACE BADIDX}"));
TclStoreInt1AtPtr(CurrentOffset(envPtr) - offset,
envPtr->codeStart + offset + 1);
TclAdjustStackDepth(-1, envPtr);
}
TclEmitOpcode( INST_DUP, envPtr);
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
TclEmitInt4( idx1 - 1, envPtr);
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx2 + 1, envPtr);
TclEmitInt4( INDEX_END, envPtr);
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
goto done;
/*
* Issue instructions to perform the operations relating to configurations
* that do real replacement. All arguments are pushed and assembled into a
* pair: the list of values to replace with, and the list to do the
* surgery on.
*/
replaceAll:
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
TclEmitOpcode( INST_POP, envPtr);
goto done;
replaceHead:
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx1, envPtr);
TclEmitInt4( idx2, envPtr);
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
goto done;
replaceTail:
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx1, envPtr);
TclEmitInt4( idx2, envPtr);
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
goto done;
replaceRange:
if (tmpObj != NULL) {
TclEmitOpcode( INST_DUP, envPtr);
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
TclEmitPush(TclAddLiteralObj(envPtr, tmpObj, NULL), envPtr);
TclEmitOpcode( INST_GT, envPtr);
offset = CurrentOffset(envPtr);
TclEmitInstInt1( INST_JUMP_TRUE1, 0, envPtr);
TclEmitPush(TclAddLiteralObj(envPtr, Tcl_ObjPrintf(
"list doesn't contain element %d", idx1), NULL), envPtr);
CompileReturnInternal(envPtr, INST_RETURN_IMM, TCL_ERROR, 0,
Tcl_ObjPrintf("-errorcode {TCL OPERATION LREPLACE BADIDX}"));
TclStoreInt1AtPtr(CurrentOffset(envPtr) - offset,
envPtr->codeStart + offset + 1);
TclAdjustStackDepth(-1, envPtr);
}
TclEmitOpcode( INST_DUP, envPtr);
TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
TclEmitInt4( idx1 - 1, envPtr);
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
TclEmitInstInt4( INST_LIST_RANGE_IMM, idx2 + 1, envPtr);
TclEmitInt4( INDEX_END, envPtr);
TclEmitInstInt4( INST_REVERSE, 3, envPtr);
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
TclEmitInstInt4( INST_REVERSE, 2, envPtr);
TclEmitOpcode( INST_LIST_CONCAT, envPtr);
goto done;
/*
* Clean up the allocated memory.
*/
done:
if (tmpObj != NULL) {
Tcl_DecrRefCount(tmpObj);
}
return TCL_OK;
}
+374 -48
View File
@@ -101,6 +101,59 @@ const AuxDataType tclJumptableInfoType = {
if ((idx)<256) {OP1(STORE_SCALAR1,(idx));} else {OP4(STORE_SCALAR4,(idx));}
#define INVOKE(name) \
TclEmitInvoke(envPtr,INST_##name)
#define INDEX_END (-2)
/*
*----------------------------------------------------------------------
*
* GetIndexFromToken --
*
* Parse a token and get the encoded version of the index (as understood
* by TEBC), assuming it is at all knowable at compile time. Only handles
* indices that are integers or 'end' or 'end-integer'.
*
* Returns:
* TCL_OK if parsing succeeded, and TCL_ERROR if it failed.
*
* Side effects:
* Sets *index to the index value if successful.
*
*----------------------------------------------------------------------
*/
static inline int
GetIndexFromToken(
Tcl_Token *tokenPtr,
int *index)
{
Tcl_Obj *tmpObj = Tcl_NewObj();
int result, idx;
if (!TclWordKnownAtCompileTime(tokenPtr, tmpObj)) {
Tcl_DecrRefCount(tmpObj);
return TCL_ERROR;
}
result = TclGetIntFromObj(NULL, tmpObj, &idx);
if (result == TCL_OK) {
if (idx < 0) {
result = TCL_ERROR;
}
} else {
result = TclGetIntForIndexM(NULL, tmpObj, INDEX_END, &idx);
if (result == TCL_OK && idx > INDEX_END) {
result = TCL_ERROR;
}
}
Tcl_DecrRefCount(tmpObj);
if (result == TCL_OK) {
*index = idx;
}
return result;
}
/*
*----------------------------------------------------------------------
@@ -565,8 +618,7 @@ TclCompileStringRangeCmd(
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *stringTokenPtr, *fromTokenPtr, *toTokenPtr;
Tcl_Obj *tmpObj;
int idx1, idx2, result;
int idx1, idx2;
if (parsePtr->numWords != 4) {
return TCL_ERROR;
@@ -576,50 +628,13 @@ TclCompileStringRangeCmd(
toTokenPtr = TokenAfter(fromTokenPtr);
/*
* Parse the first index. Will only compile if it is constant and not an
* _integer_ less than zero (since we reserve negative indices here for
* end-relative indexing).
* Parse the two indices.
*/
tmpObj = Tcl_NewObj();
result = TCL_ERROR;
if (TclWordKnownAtCompileTime(fromTokenPtr, tmpObj)) {
if (TclGetIntFromObj(NULL, tmpObj, &idx1) == TCL_OK) {
if (idx1 >= 0) {
result = TCL_OK;
}
} else if (TclGetIntForIndexM(NULL, tmpObj, -2, &idx1) == TCL_OK) {
if (idx1 <= -2) {
result = TCL_OK;
}
}
}
TclDecrRefCount(tmpObj);
if (result != TCL_OK) {
if (GetIndexFromToken(fromTokenPtr, &idx1) != TCL_OK) {
goto nonConstantIndices;
}
/*
* Parse the second index. Will only compile if it is constant and not an
* _integer_ less than zero (since we reserve negative indices here for
* end-relative indexing).
*/
tmpObj = Tcl_NewObj();
result = TCL_ERROR;
if (TclWordKnownAtCompileTime(toTokenPtr, tmpObj)) {
if (TclGetIntFromObj(NULL, tmpObj, &idx2) == TCL_OK) {
if (idx2 >= 0) {
result = TCL_OK;
}
} else if (TclGetIntForIndexM(NULL, tmpObj, -2, &idx2) == TCL_OK) {
if (idx2 <= -2) {
result = TCL_OK;
}
}
}
TclDecrRefCount(tmpObj);
if (result != TCL_OK) {
if (GetIndexFromToken(toTokenPtr, &idx2) != TCL_OK) {
goto nonConstantIndices;
}
@@ -642,6 +657,316 @@ TclCompileStringRangeCmd(
OP( STR_RANGE);
return TCL_OK;
}
int
TclCompileStringReplaceCmd(
Tcl_Interp *interp, /* Tcl interpreter for context. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the
* command. */
Command *cmdPtr, /* Points to defintion of command being
* compiled. */
CompileEnv *envPtr) /* Holds the resulting instructions. */
{
Tcl_Token *tokenPtr, *valueTokenPtr, *replacementTokenPtr = NULL;
DefineLineInformation; /* TIP #280 */
int idx1, idx2;
if (parsePtr->numWords < 4 || parsePtr->numWords > 5) {
return TCL_ERROR;
}
valueTokenPtr = TokenAfter(parsePtr->tokenPtr);
if (parsePtr->numWords == 5) {
tokenPtr = TokenAfter(valueTokenPtr);
tokenPtr = TokenAfter(tokenPtr);
replacementTokenPtr = TokenAfter(tokenPtr);
}
/*
* Parse the indices. Will only compile special cases if both are
* constants and not an _integer_ less than zero (since we reserve
* negative indices here for end-relative indexing) or an end-based index
* greater than 'end' itself.
*/
tokenPtr = TokenAfter(valueTokenPtr);
if (GetIndexFromToken(tokenPtr, &idx1) != TCL_OK) {
goto genericReplace;
}
tokenPtr = TokenAfter(tokenPtr);
if (GetIndexFromToken(tokenPtr, &idx2) != TCL_OK) {
goto genericReplace;
}
/*
* We handle these replacements specially: first character (where
* idx1=idx2=0) and suffixes (where idx1=idx2=INDEX_END). Anything else
* and the semantics get rather screwy.
*/
if (idx1 == 0 && idx2 == 0) {
int notEq, end;
/*
* Just working with the first character.
*/
CompileWord(envPtr, valueTokenPtr, interp, 1);
if (replacementTokenPtr == NULL) {
/* Drop first */
OP44( STR_RANGE_IMM, 1, INDEX_END);
return TCL_OK;
}
/* Replace first */
CompileWord(envPtr, replacementTokenPtr, interp, 4);
OP4( OVER, 1);
PUSH( "");
OP( STR_EQ);
JUMP1( JUMP_FALSE, notEq);
OP( POP);
JUMP1( JUMP, end);
FIXJUMP1(notEq);
TclAdjustStackDepth(1, envPtr);
OP4( REVERSE, 2);
OP44( STR_RANGE_IMM, 1, INDEX_END);
OP1( STR_CONCAT1, 2);
FIXJUMP1(end);
return TCL_OK;
} else if (idx1 == INDEX_END && idx2 == INDEX_END) {
int notEq, end;
/*
* Just working with the last character.
*/
CompileWord(envPtr, valueTokenPtr, interp, 1);
if (replacementTokenPtr == NULL) {
/* Drop last */
OP44( STR_RANGE_IMM, 0, INDEX_END-1);
return TCL_OK;
}
/* Replace last */
CompileWord(envPtr, replacementTokenPtr, interp, 4);
OP4( OVER, 1);
PUSH( "");
OP( STR_EQ);
JUMP1( JUMP_FALSE, notEq);
OP( POP);
JUMP1( JUMP, end);
FIXJUMP1(notEq);
TclAdjustStackDepth(1, envPtr);
OP4( REVERSE, 2);
OP44( STR_RANGE_IMM, 0, INDEX_END-1);
OP4( REVERSE, 2);
OP1( STR_CONCAT1, 2);
FIXJUMP1(end);
return TCL_OK;
} else {
/*
* Need to process indices at runtime. This could be because the
* indices are not constants, or because we need to resolve them to
* absolute indices to work out if a replacement is going to happen.
* In any case, to runtime it is.
*/
genericReplace:
CompileWord(envPtr, valueTokenPtr, interp, 1);
tokenPtr = TokenAfter(valueTokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 3);
if (replacementTokenPtr != NULL) {
CompileWord(envPtr, replacementTokenPtr, interp, 4);
} else {
PUSH( "");
}
OP( STR_REPLACE);
return TCL_OK;
}
}
/*
* Synch with tclCmdMZ.c
*/
#define DEFAULT_TRIM_SET \
"\x09\x0a\x0b\x0c\x0d " /* ASCII */\
"\xc0\x80" /* nul (U+0000) */\
"\xc2\x85" /* next line (U+0085) */\
"\xc2\xa0" /* non-breaking space (U+00a0) */\
"\xe1\x9a\x80" /* ogham space mark (U+1680) */ \
"\xe1\xa0\x8e" /* mongolian vowel separator (U+180e) */\
"\xe2\x80\x80" /* en quad (U+2000) */\
"\xe2\x80\x81" /* em quad (U+2001) */\
"\xe2\x80\x82" /* en space (U+2002) */\
"\xe2\x80\x83" /* em space (U+2003) */\
"\xe2\x80\x84" /* three-per-em space (U+2004) */\
"\xe2\x80\x85" /* four-per-em space (U+2005) */\
"\xe2\x80\x86" /* six-per-em space (U+2006) */\
"\xe2\x80\x87" /* figure space (U+2007) */\
"\xe2\x80\x88" /* punctuation space (U+2008) */\
"\xe2\x80\x89" /* thin space (U+2009) */\
"\xe2\x80\x8a" /* hair space (U+200a) */\
"\xe2\x80\x8b" /* zero width space (U+200b) */\
"\xe2\x80\xa8" /* line separator (U+2028) */\
"\xe2\x80\xa9" /* paragraph separator (U+2029) */\
"\xe2\x80\xaf" /* narrow no-break space (U+202f) */\
"\xe2\x81\x9f" /* medium mathematical space (U+205f) */\
"\xe2\x81\xa0" /* word joiner (U+2060) */\
"\xe3\x80\x80" /* ideographic space (U+3000) */\
"\xef\xbb\xbf" /* zero width no-break space (U+feff) */
int
TclCompileStringTrimLCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to defintion of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
if (parsePtr->numWords != 2 && parsePtr->numWords != 3) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
if (parsePtr->numWords == 3) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
} else {
PushLiteral(envPtr, DEFAULT_TRIM_SET, strlen(DEFAULT_TRIM_SET));
}
OP( STR_TRIM_LEFT);
return TCL_OK;
}
int
TclCompileStringTrimRCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to defintion of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
if (parsePtr->numWords != 2 && parsePtr->numWords != 3) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
if (parsePtr->numWords == 3) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
} else {
PushLiteral(envPtr, DEFAULT_TRIM_SET, strlen(DEFAULT_TRIM_SET));
}
OP( STR_TRIM_RIGHT);
return TCL_OK;
}
int
TclCompileStringTrimCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to defintion of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
if (parsePtr->numWords != 2 && parsePtr->numWords != 3) {
return TCL_ERROR;
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
if (parsePtr->numWords == 3) {
tokenPtr = TokenAfter(tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 2);
} else {
PushLiteral(envPtr, DEFAULT_TRIM_SET, strlen(DEFAULT_TRIM_SET));
}
OP( STR_TRIM);
return TCL_OK;
}
int
TclCompileStringToUpperCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to defintion of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
if (parsePtr->numWords != 2) {
return TclCompileBasic1To3ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
OP( STR_UPPER);
return TCL_OK;
}
int
TclCompileStringToLowerCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to defintion of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
if (parsePtr->numWords != 2) {
return TclCompileBasic1To3ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
OP( STR_LOWER);
return TCL_OK;
}
int
TclCompileStringToTitleCmd(
Tcl_Interp *interp, /* Used for error reporting. */
Tcl_Parse *parsePtr, /* Points to a parse structure for the command
* created by Tcl_ParseCommand. */
Command *cmdPtr, /* Points to defintion of command being
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
DefineLineInformation; /* TIP #280 */
Tcl_Token *tokenPtr;
if (parsePtr->numWords != 2) {
return TclCompileBasic1To3ArgCmd(interp, parsePtr, cmdPtr, envPtr);
}
tokenPtr = TokenAfter(parsePtr->tokenPtr);
CompileWord(envPtr, tokenPtr, interp, 1);
OP( STR_TITLE);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
@@ -752,7 +1077,7 @@ TclSubstCompile(
/*
* Tricky point! If the first token does not result in a *guaranteed* push
* of a Tcl_Obj on the stack, we must push an empty object. Otherwise it
* is possible to get to an INST_CONCAT1 or INST_DONE without enough
* is possible to get to an INST_STR_CONCAT1 or INST_DONE without enough
* values on the stack, resulting in a crash. Thanks to Joe Mistachkin for
* identifying a script that could trigger this case.
*/
@@ -817,11 +1142,11 @@ TclSubstCompile(
}
while (count > 255) {
OP1( CONCAT1, 255);
OP1( STR_CONCAT1, 255);
count -= 254;
}
if (count > 1) {
OP1( CONCAT1, count);
OP1( STR_CONCAT1, count);
count = 1;
}
@@ -941,7 +1266,7 @@ TclSubstCompile(
(int) (CurrentOffset(envPtr) - okFixup.codeOffset));
}
if (count > 1) {
OP1(CONCAT1, count);
OP1(STR_CONCAT1, count);
count = 1;
}
@@ -954,11 +1279,11 @@ TclSubstCompile(
}
while (count > 255) {
OP1( CONCAT1, 255);
OP1( STR_CONCAT1, 255);
count -= 254;
}
if (count > 1) {
OP1( CONCAT1, count);
OP1( STR_CONCAT1, count);
}
Tcl_FreeParse(&parse);
@@ -3071,6 +3396,7 @@ TclCompileWhileCmd(
}
SetLineInformation(1);
TclCompileExprWords(interp, testTokenPtr, 1, envPtr);
TclClearNumConversion(envPtr);
jumpDist = CurrentOffset(envPtr) - bodyCodeOffset;
if (jumpDist > 127) {
+91 -20
View File
@@ -63,7 +63,7 @@ InstructionDesc const tclInstructionTable[] = {
/* Pop the topmost stack object */
{"dup", 1, +1, 0, {OPERAND_NONE}},
/* Duplicate the topmost stack object and push the result */
{"concat1", 2, INT_MIN, 1, {OPERAND_UINT1}},
{"strcat", 2, INT_MIN, 1, {OPERAND_UINT1}},
/* Concatenate the top op1 items and push result */
{"invokeStk1", 2, INT_MIN, 1, {OPERAND_UINT1}},
/* Invoke command named objv[0]; <objc,objv> = <op1,top op1> */
@@ -546,15 +546,70 @@ InstructionDesc const tclInstructionTable[] = {
* until the matching stack depth is reached. */
/* New foreach implementation */
{"foreach_start", 5, +2, 1, {OPERAND_AUX4}},
{"foreach_start", 5, +2, 1, {OPERAND_AUX4}},
/* Initialize execution of a foreach loop. Operand is aux data index
* of the ForeachInfo structure for the foreach command. It pushes 2
* elements which hold runtime params for foreach_step, they are later
* dropped by foreach_end together with the value lists. */
{"foreach_step", 1, 0, 0, {OPERAND_NONE}},
/* "Step" or begin next iteration of foreach loop. */
{"foreach_end", 1, 0, 0, {OPERAND_NONE}},
{"lmap_collect", 1, -1, 0, {OPERAND_NONE}},
* dropped by foreach_end together with the value lists. NOTE that the
* iterator-tracker and info reference must not be passed to bytecodes
* that handle normal Tcl values. NOTE that this instruction jumps to
* the foreach_step instruction paired with it; the stack info below
* is only nominal.
* Stack: ... listObjs... => ... listObjs... iterTracker info */
{"foreach_step", 1, 0, 0, {OPERAND_NONE}},
/* "Step" or begin next iteration of foreach loop. Assigns to foreach
* iteration variables. May jump to straight after the foreach_start
* that pushed the iterTracker and info values. MUST be followed
* immediately by a foreach_end.
* Stack: ... listObjs... iterTracker info =>
* ... listObjs... iterTracker info */
{"foreach_end", 1, 0, 0, {OPERAND_NONE}},
/* Clean up a foreach loop by dropping the info value, the tracker
* value and the lists that were being iterated over.
* Stack: ... listObjs... iterTracker info => ... */
{"lmap_collect", 1, -1, 0, {OPERAND_NONE}},
/* Appends the value at the top of the stack to the list located on
* the stack the "other side" of the foreach-related values.
* Stack: ... collector listObjs... iterTracker info value =>
* ... collector listObjs... iterTracker info */
{"strtrim", 1, -1, 0, {OPERAND_NONE}},
/* [string trim] core: removes the characters (designated by the value
* at the top of the stack) from both ends of the string and pushes
* the resulting string.
* Stack: ... string charset => ... trimmedString */
{"strtrimLeft", 1, -1, 0, {OPERAND_NONE}},
/* [string trimleft] core: removes the characters (designated by the
* value at the top of the stack) from the left of the string and
* pushes the resulting string.
* Stack: ... string charset => ... trimmedString */
{"strtrimRight", 1, -1, 0, {OPERAND_NONE}},
/* [string trimright] core: removes the characters (designated by the
* value at the top of the stack) from the right of the string and
* pushes the resulting string.
* Stack: ... string charset => ... trimmedString */
{"concatStk", 5, INT_MIN, 1, {OPERAND_UINT4}},
/* Wrapper round Tcl_ConcatObj(), used for [concat] and [eval]. opnd
* is number of values to concatenate.
* Operation: push concat(stk1 stk2 ... stktop) */
{"strUpper", 1, 0, 0, {OPERAND_NONE}},
/* [string toupper] core: converts whole string to upper case using
* the default (extended "C" locale) rules.
* Stack: ... string => ... newString */
{"strLower", 1, 0, 0, {OPERAND_NONE}},
/* [string tolower] core: converts whole string to upper case using
* the default (extended "C" locale) rules.
* Stack: ... string => ... newString */
{"strTitle", 1, 0, 0, {OPERAND_NONE}},
/* [string totitle] core: converts whole string to upper case using
* the default (extended "C" locale) rules.
* Stack: ... string => ... newString */
{"strReplace", 1, -3, 0, {OPERAND_NONE}},
/* [string replace] core: replaces a non-empty range of one string
* with the contents of another.
* Stack: ... string fromIdx toIdx replacement => ... newString */
{NULL, 0, 0, 0, {OPERAND_NONE}}
};
@@ -1722,7 +1777,7 @@ TclCompileInvocation(
int numWords,
CompileEnv *envPtr)
{
int wordIdx = 0;
int wordIdx = 0, depth = TclGetStackDepth(envPtr);
DefineLineInformation;
if (cmdObj) {
@@ -1755,6 +1810,7 @@ TclCompileInvocation(
} else {
TclEmitInvoke(envPtr, INST_INVOKE_STK4, wordIdx);
}
TclCheckStackDepth(depth+1, envPtr);
}
static void
@@ -1767,7 +1823,8 @@ CompileExpanded(
{
int wordIdx = 0;
DefineLineInformation;
int depth = TclGetStackDepth(envPtr);
StartExpanding(envPtr);
if (cmdObj) {
CompileCmdLiteral(interp, cmdObj, envPtr);
@@ -1813,6 +1870,7 @@ CompileExpanded(
*/
TclEmitInvoke(envPtr, INST_INVOKE_EXPANDED, wordIdx);
TclCheckStackDepth(depth+1, envPtr);
}
static int
@@ -1824,6 +1882,7 @@ CompileCmdCompileProc(
{
int unwind = 0, incrOffset = -1;
DefineLineInformation;
int depth = TclGetStackDepth(envPtr);
/*
* Emit of the INST_START_CMD instruction is controlled by the value of
@@ -1871,6 +1930,7 @@ CompileCmdCompileProc(
TclStoreInt4AtPtr(envPtr->codeNext - startPtr, startPtr + 1);
}
}
TclCheckStackDepth(depth+1, envPtr);
return TCL_OK;
}
@@ -1913,7 +1973,8 @@ CompileCommandTokens(
int *clNext = envPtr->clNext;
int cmdIdx = envPtr->numCommands;
int startCodeOffset = envPtr->codeNext - envPtr->codeStart;
int depth = TclGetStackDepth(envPtr);
assert (parsePtr->numWords > 0);
/* Pre-Compile */
@@ -2004,6 +2065,7 @@ CompileCommandTokens(
eclPtr->loc[wlineat].line = wlines;
eclPtr->loc[wlineat].next = NULL;
TclCheckStackDepth(depth, envPtr);
return cmdIdx;
}
@@ -2023,6 +2085,7 @@ TclCompileScript(
* Initial value of -1 indicates this routine
* has not yet generated any bytecode. */
const char *p = script; /* Where we are in our compile. */
int depth = TclGetStackDepth(envPtr);
if (envPtr->iPtr == NULL) {
Tcl_Panic("TclCompileScript() called on uninitialized CompileEnv");
@@ -2134,6 +2197,7 @@ TclCompileScript(
envPtr->codeNext--;
envPtr->currStackDepth++;
}
TclCheckStackDepth(depth+1, envPtr);
}
/*
@@ -2244,6 +2308,7 @@ TclCompileTokens(
#define NUM_STATIC_POS 20
int isLiteral, maxNumCL, numCL;
int *clPosition = NULL;
int depth = TclGetStackDepth(envPtr);
/*
* For the handling of continuation lines in literals we first check if
@@ -2397,11 +2462,11 @@ TclCompileTokens(
*/
while (numObjsToConcat > 255) {
TclEmitInstInt1(INST_CONCAT1, 255, envPtr);
TclEmitInstInt1(INST_STR_CONCAT1, 255, envPtr);
numObjsToConcat -= 254; /* concat pushes 1 obj, the result */
}
if (numObjsToConcat > 1) {
TclEmitInstInt1(INST_CONCAT1, numObjsToConcat, envPtr);
TclEmitInstInt1(INST_STR_CONCAT1, numObjsToConcat, envPtr);
}
/*
@@ -2421,6 +2486,7 @@ TclCompileTokens(
if (maxNumCL) {
ckfree(clPosition);
}
TclCheckStackDepth(depth+1, envPtr);
}
/*
@@ -2532,11 +2598,11 @@ TclCompileExprWords(
}
concatItems = 2*numWords - 1;
while (concatItems > 255) {
TclEmitInstInt1(INST_CONCAT1, 255, envPtr);
TclEmitInstInt1(INST_STR_CONCAT1, 255, envPtr);
concatItems -= 254;
}
if (concatItems > 1) {
TclEmitInstInt1(INST_CONCAT1, concatItems, envPtr);
TclEmitInstInt1(INST_STR_CONCAT1, concatItems, envPtr);
}
TclEmitOpcode(INST_EXPR_STK, envPtr);
}
@@ -3936,7 +4002,8 @@ TclEmitInvoke(
ExceptionAux *auxBreakPtr, *auxContinuePtr;
int arg1, arg2, wordCount = 0, expandCount = 0;
int loopRange = 0, breakRange = 0, continueRange = 0;
int cleanup, depth = TclGetStackDepth(envPtr);
/*
* Parse the arguments.
*/
@@ -3944,30 +4011,31 @@ TclEmitInvoke(
va_start(argList, opcode);
switch (opcode) {
case INST_INVOKE_STK1:
wordCount = arg1 = va_arg(argList, int);
wordCount = arg1 = cleanup = va_arg(argList, int);
arg2 = 0;
break;
case INST_INVOKE_STK4:
wordCount = arg1 = va_arg(argList, int);
wordCount = arg1 = cleanup = va_arg(argList, int);
arg2 = 0;
break;
case INST_INVOKE_REPLACE:
arg1 = va_arg(argList, int);
arg2 = va_arg(argList, int);
wordCount = arg1 + arg2 - 1;
cleanup = arg1 + 1;
break;
default:
Tcl_Panic("unexpected opcode");
case INST_EVAL_STK:
wordCount = 1;
wordCount = cleanup = 1;
arg1 = arg2 = 0;
break;
case INST_RETURN_STK:
wordCount = 2;
wordCount = cleanup = 2;
arg1 = arg2 = 0;
break;
case INST_INVOKE_EXPANDED:
wordCount = arg1 = va_arg(argList, int);
wordCount = arg1 = cleanup = va_arg(argList, int);
arg2 = 0;
expandCount = 1;
break;
@@ -4070,6 +4138,7 @@ TclEmitInvoke(
ExceptionRangeTarget(envPtr, loopRange, breakOffset);
TclCleanupStackForBreakContinue(envPtr, auxBreakPtr);
TclAddLoopBreakFixup(envPtr, auxBreakPtr);
TclAdjustStackDepth(1, envPtr);
envPtr->currStackDepth = savedStackDepth;
envPtr->expandCount = savedExpandCount;
@@ -4081,6 +4150,7 @@ TclEmitInvoke(
ExceptionRangeTarget(envPtr, loopRange, continueOffset);
TclCleanupStackForBreakContinue(envPtr, auxContinuePtr);
TclAddLoopContinueFixup(envPtr, auxContinuePtr);
TclAdjustStackDepth(1, envPtr);
envPtr->currStackDepth = savedStackDepth;
envPtr->expandCount = savedExpandCount;
@@ -4089,6 +4159,7 @@ TclEmitInvoke(
TclFinalizeLoopExceptionRange(envPtr, loopRange);
TclFixupForwardJumpToHere(envPtr, &nonTrapFixup, 127);
}
TclCheckStackDepth(depth+1-cleanup, envPtr);
}
/*
+41 -5
View File
@@ -512,7 +512,7 @@ typedef struct ByteCode {
#define INST_PUSH4 2
#define INST_POP 3
#define INST_DUP 4
#define INST_CONCAT1 5
#define INST_STR_CONCAT1 5
#define INST_INVOKE_STK1 6
#define INST_INVOKE_STK4 7
#define INST_EVAL_STK 8
@@ -769,14 +769,25 @@ typedef struct ByteCode {
#define INST_EXPAND_DROP 165
/* New foreach implementation */
#define INST_FOREACH_START 166
#define INST_FOREACH_STEP 167
#define INST_FOREACH_END 168
#define INST_LMAP_COLLECT 169
/* For compilation of [string trim] and related */
#define INST_STR_TRIM 170
#define INST_STR_TRIM_LEFT 171
#define INST_STR_TRIM_RIGHT 172
#define INST_CONCAT_STK 173
#define INST_STR_UPPER 174
#define INST_STR_LOWER 175
#define INST_STR_TITLE 176
#define INST_STR_REPLACE 177
/* The last opcode */
#define LAST_INST_OPCODE 169
#define LAST_INST_OPCODE 177
/*
* Table describing the Tcl bytecode instructions: their name (for displaying
@@ -1079,8 +1090,6 @@ MODULE_SCOPE void TclPushVarName(Tcl_Interp *interp,
Tcl_Token *varTokenPtr, CompileEnv *envPtr,
int flags, int *localIndexPtr,
int *isScalarPtr);
MODULE_SCOPE int TclRegisterLiteral(CompileEnv *envPtr,
char *bytes, int length, int flags);
MODULE_SCOPE void TclReleaseLiteral(Tcl_Interp *interp, Tcl_Obj *objPtr);
MODULE_SCOPE void TclInvalidateCmdLiteral(Tcl_Interp *interp,
const char *name, Namespace *nsPtr);
@@ -1171,6 +1180,21 @@ MODULE_SCOPE Tcl_Obj *TclNewInstNameObj(unsigned char inst);
(envPtr)->currStackDepth += (delta); \
} while (0)
#define TclGetStackDepth(envPtr) \
((envPtr)->currStackDepth)
#define TclSetStackDepth(depth, envPtr) \
(envPtr)->currStackDepth = (depth)
#define TclCheckStackDepth(depth, envPtr) \
do { \
int dd = (depth); \
if (dd != (envPtr)->currStackDepth) { \
Tcl_Panic("bad stack depth computations: is %i, should be %i", \
(envPtr)->currStackDepth, dd); \
} \
} while (0)
/*
* Macro used to update the stack requirements. It is called by the macros
* TclEmitOpCode, TclEmitInst1 and TclEmitInst4.
@@ -1310,6 +1334,18 @@ MODULE_SCOPE Tcl_Obj *TclNewInstNameObj(unsigned char inst);
} \
} while (0)
/*
* If the expr compiler finished with TRY_CONVERT, macro to remove it when the
* job is done by the following instruction.
*/
#define TclClearNumConversion(envPtr) \
do { \
if (*(envPtr->codeNext - 1) == INST_TRY_CVT_TO_NUMERIC) { \
envPtr->codeNext--; \
} \
} while (0)
/*
* Macros to update a (signed or unsigned) integer starting at a pointer. The
* two variants depend on the number of bytes. The ANSI C "prototypes" for
+292 -1
View File
@@ -2563,7 +2563,7 @@ TEBCresume(
NEXT_INST_F(5, 0, 0);
}
case INST_CONCAT1: {
case INST_STR_CONCAT1: {
int appendLen = 0;
char *bytes, *p;
Tcl_Obj **currPtr;
@@ -2712,6 +2712,17 @@ TEBCresume(
NEXT_INST_V(2, opnd, 1);
}
case INST_CONCAT_STK:
/*
* Pop the opnd (objc) top stack elements, run through Tcl_ConcatObj,
* and then decrement their ref counts.
*/
opnd = TclGetUInt4AtPtr(pc+1);
objResultPtr = Tcl_ConcatObj(opnd, &OBJ_AT_DEPTH(opnd-1));
TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr);
NEXT_INST_V(5, opnd, 1);
case INST_EXPAND_START:
/*
* Push an element to the auxObjList. This records the current
@@ -4991,6 +5002,55 @@ TEBCresume(
TRACE(("%.20s => %d\n", O2S(valuePtr), length));
NEXT_INST_F(1, 1, 1);
case INST_STR_UPPER:
valuePtr = OBJ_AT_TOS;
TRACE(("\"%.25s\" => ", O2S(valuePtr)));
if (Tcl_IsShared(valuePtr)) {
s1 = TclGetStringFromObj(valuePtr, &length);
TclNewStringObj(objResultPtr, s1, length);
length = Tcl_UtfToUpper(TclGetString(objResultPtr));
Tcl_SetObjLength(objResultPtr, length);
TRACE_APPEND(("\"%.25s\"\n", O2S(objResultPtr)));
NEXT_INST_F(1, 1, 1);
} else {
length = Tcl_UtfToUpper(TclGetString(valuePtr));
Tcl_SetObjLength(valuePtr, length);
TRACE_APPEND(("\"%.25s\"\n", O2S(valuePtr)));
NEXT_INST_F(1, 0, 0);
}
case INST_STR_LOWER:
valuePtr = OBJ_AT_TOS;
TRACE(("\"%.25s\" => ", O2S(valuePtr)));
if (Tcl_IsShared(valuePtr)) {
s1 = TclGetStringFromObj(valuePtr, &length);
TclNewStringObj(objResultPtr, s1, length);
length = Tcl_UtfToLower(TclGetString(objResultPtr));
Tcl_SetObjLength(objResultPtr, length);
TRACE_APPEND(("\"%.25s\"\n", O2S(objResultPtr)));
NEXT_INST_F(1, 1, 1);
} else {
length = Tcl_UtfToLower(TclGetString(valuePtr));
Tcl_SetObjLength(valuePtr, length);
TRACE_APPEND(("\"%.25s\"\n", O2S(valuePtr)));
NEXT_INST_F(1, 0, 0);
}
case INST_STR_TITLE:
valuePtr = OBJ_AT_TOS;
TRACE(("\"%.25s\" => ", O2S(valuePtr)));
if (Tcl_IsShared(valuePtr)) {
s1 = TclGetStringFromObj(valuePtr, &length);
TclNewStringObj(objResultPtr, s1, length);
length = Tcl_UtfToTitle(TclGetString(objResultPtr));
Tcl_SetObjLength(objResultPtr, length);
TRACE_APPEND(("\"%.25s\"\n", O2S(objResultPtr)));
NEXT_INST_F(1, 1, 1);
} else {
length = Tcl_UtfToTitle(TclGetString(valuePtr));
Tcl_SetObjLength(valuePtr, length);
TRACE_APPEND(("\"%.25s\"\n", O2S(valuePtr)));
NEXT_INST_F(1, 0, 0);
}
case INST_STR_INDEX:
value2Ptr = OBJ_AT_TOS;
valuePtr = OBJ_UNDER_TOS;
@@ -5097,6 +5157,178 @@ TEBCresume(
int length3;
Tcl_Obj *value3Ptr;
case INST_STR_REPLACE:
value3Ptr = POP_OBJECT();
valuePtr = OBJ_AT_DEPTH(2);
length = Tcl_GetCharLength(valuePtr) - 1;
TRACE(("\"%.20s\" %s %s \"%.20s\" => ", O2S(valuePtr),
O2S(OBJ_UNDER_TOS), O2S(OBJ_AT_TOS), O2S(value3Ptr)));
if (TclGetIntForIndexM(interp, OBJ_UNDER_TOS, length,
&fromIdx) != TCL_OK
|| TclGetIntForIndexM(interp, OBJ_AT_TOS, length,
&toIdx) != TCL_OK) {
TclDecrRefCount(value3Ptr);
goto gotError;
}
TclDecrRefCount(OBJ_AT_TOS);
(void) POP_OBJECT();
TclDecrRefCount(OBJ_AT_TOS);
(void) POP_OBJECT();
if (fromIdx < 0) {
fromIdx = 0;
}
if (fromIdx > toIdx || fromIdx > length) {
TRACE_APPEND(("%.30s\n", O2S(valuePtr)));
TclDecrRefCount(value3Ptr);
NEXT_INST_F(1, 0, 0);
}
if (toIdx > length) {
toIdx = length;
}
if (fromIdx == 0 && toIdx == length) {
TclDecrRefCount(OBJ_AT_TOS);
OBJ_AT_TOS = value3Ptr;
TRACE_APPEND(("%.30s\n", O2S(value3Ptr)));
NEXT_INST_F(1, 0, 0);
}
length3 = Tcl_GetCharLength(value3Ptr);
/*
* Remove substring. In-place.
*/
if (length3 == 0 && !Tcl_IsShared(valuePtr) && toIdx == length) {
TclDecrRefCount(value3Ptr);
Tcl_SetObjLength(valuePtr, fromIdx);
TRACE_APPEND(("%.30s\n", O2S(valuePtr)));
NEXT_INST_F(1, 0, 0);
}
/*
* See if we can splice in place. This happens when the number of
* characters being replaced is the same as the number of characters
* in the string to be inserted.
*/
if (length3 - 1 == toIdx - fromIdx) {
unsigned char *bytes1, *bytes2;
if (Tcl_IsShared(valuePtr)) {
objResultPtr = Tcl_DuplicateObj(valuePtr);
if (TclIsPureByteArray(objResultPtr)
&& TclIsPureByteArray(value3Ptr)) {
bytes1 = Tcl_GetByteArrayFromObj(objResultPtr, NULL);
bytes2 = Tcl_GetByteArrayFromObj(value3Ptr, NULL);
memcpy(bytes1 + fromIdx, bytes2, length3);
} else {
ustring1 = Tcl_GetUnicodeFromObj(objResultPtr, NULL);
ustring2 = Tcl_GetUnicodeFromObj(value3Ptr, NULL);
memcpy(ustring1 + fromIdx, ustring2,
length3 * sizeof(Tcl_UniChar));
/*
* Magic! Flush the info in the string internal rep that
* refers to the about-to-be-invalidated UTF-8 rep. This
* sets the 'allocated' field of the String structure to 0
* to indicate that a new buffer needs to be allocated.
* This is safe; we know we've got a tclStringTypePtr set
* at this point (post Tcl_GetUnicodeFromObj).
*/
((int *) objResultPtr->internalRep.otherValuePtr)[1] = 0;
}
Tcl_InvalidateStringRep(objResultPtr);
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 1, 1);
} else {
if (TclIsPureByteArray(valuePtr)
&& TclIsPureByteArray(value3Ptr)) {
bytes1 = Tcl_GetByteArrayFromObj(valuePtr, NULL);
bytes2 = Tcl_GetByteArrayFromObj(value3Ptr, NULL);
memcpy(bytes1 + fromIdx, bytes2, length3);
} else {
ustring1 = Tcl_GetUnicodeFromObj(valuePtr, NULL);
ustring2 = Tcl_GetUnicodeFromObj(value3Ptr, NULL);
memcpy(ustring1 + fromIdx, ustring2,
length3 * sizeof(Tcl_UniChar));
/*
* Magic! Flush the info in the string internal rep that
* refers to the about-to-be-invalidated UTF-8 rep. This
* sets the 'allocated' field of the String structure to 0
* to indicate that a new buffer needs to be allocated.
* This is safe; we know we've got a tclStringTypePtr set
* at this point (post Tcl_GetUnicodeFromObj).
*/
((int *) objResultPtr->internalRep.otherValuePtr)[1] = 0;
}
Tcl_InvalidateStringRep(valuePtr);
TRACE_APPEND(("%.30s\n", O2S(valuePtr)));
NEXT_INST_F(1, 0, 0);
}
}
/*
* Get the unicode representation; this is where we guarantee to lose
* bytearrays.
*/
ustring1 = Tcl_GetUnicodeFromObj(valuePtr, &length);
length--;
/*
* Remove substring using copying.
*/
if (length3 == 0) {
if (fromIdx > 0) {
objResultPtr = Tcl_NewUnicodeObj(ustring1, fromIdx);
if (toIdx < length) {
Tcl_AppendUnicodeToObj(objResultPtr, ustring1 + toIdx + 1,
length - toIdx);
}
} else {
objResultPtr = Tcl_NewUnicodeObj(ustring1 + toIdx + 1,
length - toIdx);
}
TclDecrRefCount(value3Ptr);
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 1, 1);
}
/*
* Splice string pieces by full copying.
*/
if (fromIdx > 0) {
objResultPtr = Tcl_NewUnicodeObj(ustring1, fromIdx);
Tcl_AppendObjToObj(objResultPtr, value3Ptr);
if (toIdx < length) {
Tcl_AppendUnicodeToObj(objResultPtr, ustring1 + toIdx + 1,
length - toIdx);
}
} else if (Tcl_IsShared(value3Ptr)) {
objResultPtr = Tcl_DuplicateObj(value3Ptr);
if (toIdx < length) {
Tcl_AppendUnicodeToObj(objResultPtr, ustring1 + toIdx + 1,
length - toIdx);
}
} else {
objResultPtr = value3Ptr;
if (toIdx < length) {
Tcl_AppendUnicodeToObj(objResultPtr, ustring1 + toIdx + 1,
length - toIdx);
}
}
TclDecrRefCount(value3Ptr);
TRACE_APPEND(("%.30s\n", O2S(objResultPtr)));
NEXT_INST_F(1, 1, 1);
case INST_STR_MAP:
valuePtr = OBJ_AT_TOS; /* "Main" string. */
value3Ptr = OBJ_UNDER_TOS; /* "Target" string. */
@@ -5256,6 +5488,65 @@ TEBCresume(
objResultPtr = TCONST(match);
NEXT_INST_F(0, 2, 1);
{
const char *string1, *string2;
int trim1, trim2;
case INST_STR_TRIM:
valuePtr = OBJ_UNDER_TOS; /* String */
value2Ptr = OBJ_AT_TOS; /* TrimSet */
string2 = TclGetStringFromObj(value2Ptr, &length2);
string1 = TclGetStringFromObj(valuePtr, &length);
trim1 = TclTrimLeft(string1, length, string2, length2);
if (trim1 < length) {
trim2 = TclTrimRight(string1, length, string2, length2);
} else {
trim2 = 0;
}
if (trim1 == 0 && trim2 == 0) {
TRACE_WITH_OBJ(("\"%.30s\" \"%.30s\" => ",
O2S(valuePtr), O2S(value2Ptr)), valuePtr);
NEXT_INST_F(1, 1, 0);
} else {
objResultPtr = Tcl_NewStringObj(string1+trim1, length-trim1-trim2);
TRACE_WITH_OBJ(("\"%.30s\" \"%.30s\" => ",
O2S(valuePtr), O2S(value2Ptr)), objResultPtr);
NEXT_INST_F(1, 2, 1);
}
case INST_STR_TRIM_LEFT:
valuePtr = OBJ_UNDER_TOS; /* String */
value2Ptr = OBJ_AT_TOS; /* TrimSet */
string2 = TclGetStringFromObj(value2Ptr, &length2);
string1 = TclGetStringFromObj(valuePtr, &length);
trim1 = TclTrimLeft(string1, length, string2, length2);
if (trim1 == 0) {
TRACE_WITH_OBJ(("\"%.30s\" \"%.30s\" => ",
O2S(valuePtr), O2S(value2Ptr)), valuePtr);
NEXT_INST_F(1, 1, 0);
} else {
objResultPtr = Tcl_NewStringObj(string1+trim1, length-trim1);
TRACE_WITH_OBJ(("\"%.30s\" \"%.30s\" => ",
O2S(valuePtr), O2S(value2Ptr)), objResultPtr);
NEXT_INST_F(1, 2, 1);
}
case INST_STR_TRIM_RIGHT:
valuePtr = OBJ_UNDER_TOS; /* String */
value2Ptr = OBJ_AT_TOS; /* TrimSet */
string2 = TclGetStringFromObj(value2Ptr, &length2);
string1 = TclGetStringFromObj(valuePtr, &length);
trim2 = TclTrimRight(string1, length, string2, length2);
if (trim2 == 0) {
TRACE_WITH_OBJ(("\"%.30s\" \"%.30s\" => ",
O2S(valuePtr), O2S(value2Ptr)), valuePtr);
NEXT_INST_F(1, 1, 0);
} else {
objResultPtr = Tcl_NewStringObj(string1, length-trim2);
TRACE_WITH_OBJ(("\"%.30s\" \"%.30s\" => ",
O2S(valuePtr), O2S(value2Ptr)), objResultPtr);
NEXT_INST_F(1, 2, 1);
}
}
case INST_REGEXP:
cflags = TclGetInt1AtPtr(pc+1); /* RE compile flages like NOCASE */
valuePtr = OBJ_AT_TOS; /* String */
+6
View File
@@ -1006,6 +1006,12 @@ declare 249 {
declare 250 {
void TclSetSlaveCancelFlags(Tcl_Interp *interp, int flags, int force)
}
# Allow extensions for optimization
declare 251 {
int TclRegisterLiteral(void *envPtr,
char *bytes, int length, int flags)
}
##############################################################################
+27
View File
@@ -3442,6 +3442,9 @@ MODULE_SCOPE int TclCompileBreakCmd(Tcl_Interp *interp,
MODULE_SCOPE int TclCompileCatchCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileConcatCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileContinueCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
@@ -3541,6 +3544,9 @@ MODULE_SCOPE int TclCompileLassignCmd(Tcl_Interp *interp,
MODULE_SCOPE int TclCompileLindexCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileLinsertCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileListCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
@@ -3622,6 +3628,27 @@ MODULE_SCOPE int TclCompileStringMatchCmd(Tcl_Interp *interp,
MODULE_SCOPE int TclCompileStringRangeCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileStringReplaceCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileStringToLowerCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileStringToTitleCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileStringToUpperCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileStringTrimCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileStringTrimLCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileStringTrimRCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
MODULE_SCOPE int TclCompileSubstCmd(Tcl_Interp *interp,
Tcl_Parse *parsePtr, Command *cmdPtr,
struct CompileEnv *envPtr);
+6
View File
@@ -614,6 +614,9 @@ EXTERN char * TclDoubleDigits(double dv, int ndigits, int flags,
/* 250 */
EXTERN void TclSetSlaveCancelFlags(Tcl_Interp *interp, int flags,
int force);
/* 251 */
EXTERN int TclRegisterLiteral(void *envPtr, char *bytes,
int length, int flags);
typedef struct TclIntStubs {
int magic;
@@ -870,6 +873,7 @@ typedef struct TclIntStubs {
int (*tclCopyChannel) (Tcl_Interp *interp, Tcl_Channel inChan, Tcl_Channel outChan, Tcl_WideInt toRead, Tcl_Obj *cmdPtr); /* 248 */
char * (*tclDoubleDigits) (double dv, int ndigits, int flags, int *decpt, int *signum, char **endPtr); /* 249 */
void (*tclSetSlaveCancelFlags) (Tcl_Interp *interp, int flags, int force); /* 250 */
int (*tclRegisterLiteral) (void *envPtr, char *bytes, int length, int flags); /* 251 */
} TclIntStubs;
extern const TclIntStubs *tclIntStubsPtr;
@@ -1299,6 +1303,8 @@ extern const TclIntStubs *tclIntStubsPtr;
(tclIntStubsPtr->tclDoubleDigits) /* 249 */
#define TclSetSlaveCancelFlags \
(tclIntStubsPtr->tclSetSlaveCancelFlags) /* 250 */
#define TclRegisterLiteral \
(tclIntStubsPtr->tclRegisterLiteral) /* 251 */
#endif /* defined(USE_TCL_STUBS) */
+2 -1
View File
@@ -358,7 +358,7 @@ TclFetchLiteral(
int
TclRegisterLiteral(
CompileEnv *envPtr, /* Points to the CompileEnv in whose object
void *ePtr, /* Points to the CompileEnv in whose object
* array an object is found or created. */
register char *bytes, /* Points to string for which to find or
* create an object in CompileEnv's object
@@ -372,6 +372,7 @@ TclRegisterLiteral(
* the literal should not be shared accross
* namespaces. */
{
CompileEnv *envPtr = ePtr;
Interp *iPtr = envPtr->iPtr;
LiteralTable *localTablePtr = &envPtr->localLitTable;
LiteralEntry *globalPtr, *localPtr;
+3 -3
View File
@@ -191,7 +191,7 @@ TrimUnreachable(
* ConvertZeroEffectToNOP --
*
* Replace PUSH/POP sequences (when non-hazardous) with NOPs. Also
* replace PUSH empty/CONCAT and TRY_CVT_NUMERIC (when followed by an
* replace PUSH empty/STR_CONCAT and TRY_CVT_NUMERIC (when followed by an
* operation that guarantees the check for arithmeticity) and eliminate
* LNOT when we can invert the following JUMP condition.
*
@@ -227,7 +227,7 @@ ConvertZeroEffectToNOP(
case INST_PUSH1:
if (nextInst == INST_POP) {
blank = size + InstLength(nextInst);
} else if (nextInst == INST_CONCAT1
} else if (nextInst == INST_STR_CONCAT1
&& TclGetUInt1AtPtr(currentInstPtr + size + 1) == 2) {
Tcl_Obj *litPtr = TclFetchLiteral(envPtr,
TclGetUInt1AtPtr(currentInstPtr + 1));
@@ -242,7 +242,7 @@ ConvertZeroEffectToNOP(
case INST_PUSH4:
if (nextInst == INST_POP) {
blank = size + 1;
} else if (nextInst == INST_CONCAT1
} else if (nextInst == INST_STR_CONCAT1
&& TclGetUInt1AtPtr(currentInstPtr + size + 1) == 2) {
Tcl_Obj *litPtr = TclFetchLiteral(envPtr,
TclGetUInt4AtPtr(currentInstPtr + 1));
Regular → Executable
View File
+1
View File
@@ -551,6 +551,7 @@ static const TclIntStubs tclIntStubs = {
TclCopyChannel, /* 248 */
TclDoubleDigits, /* 249 */
TclSetSlaveCancelFlags, /* 250 */
TclRegisterLiteral, /* 251 */
};
static const TclIntPlatStubs tclIntPlatStubs = {
-58
View File
@@ -1,58 +0,0 @@
/*
* tclStubLibTbl.c --
*
* Stub object that will be statically linked into extensions that want
* to access Tcl.
*
* Copyright (c) 1998-1999 by Scriptics Corporation.
* Copyright (c) 1998 Paul Duffin.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tclInt.h"
/*
*----------------------------------------------------------------------
*
* TclInitStubTable --
*
* Initialize the stub table, using the structure pointed at
* by the "version" argument.
*
* Results:
* Outputs the value of the "version" argument.
*
* Side effects:
* Sets the stub table pointers.
*
*----------------------------------------------------------------------
*/
MODULE_SCOPE const char *
TclInitStubTable(
const char *version) /* points to the version field of a
TclStubInfoType structure variable. */
{
tclStubsPtr = ((const TclStubInfoType *) version)->stubs;
if (tclStubsPtr->hooks) {
tclPlatStubsPtr = tclStubsPtr->hooks->tclPlatStubs;
tclIntStubsPtr = tclStubsPtr->hooks->tclIntStubs;
tclIntPlatStubsPtr = tclStubsPtr->hooks->tclIntPlatStubs;
} else {
tclPlatStubsPtr = NULL;
tclIntStubsPtr = NULL;
tclIntPlatStubsPtr = NULL;
}
return version;
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File

Some files were not shown because too many files have changed in this diff Show More