Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Added support for having the dict var itself referenced by LVT index. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | dkf-dict-with-compiled |
Files: | files | file ages | folders |
SHA1: |
0b8e874e2c252c22fd776919cb4f4b86 |
User & Date: | dkf 2011-10-03 10:45:35 |
Context
2011-10-04
| ||
08:44 | merge trunk check-in: 7d5b912b37 user: dkf tags: dkf-dict-with-compiled | |
2011-10-03
| ||
10:45 | Added support for having the dict var itself referenced by LVT index. check-in: 0b8e874e2c user: dkf tags: dkf-dict-with-compiled | |
07:51 | Add assembler support for the new INST that I think has a stable interface. check-in: 13d6ce4ce6 user: dkf tags: dkf-dict-with-compiled | |
Changes
Changes to generic/tclCompCmds.c.
︙ | ︙ | |||
1241 1242 1243 1244 1245 1246 1247 | 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 */ | | | 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 | 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 */ int i, range, varNameTmp, pathTmp, keysTmp, gotPath, dictVar = -1; Tcl_Token *dictVarTokenPtr, *tokenPtr; int savedStackDepth = envPtr->currStackDepth; JumpFixup jumpFixup; /* * There must be at least one argument after the command and we must be in * a procedure so we can have local temporaries. |
︙ | ︙ | |||
1277 1278 1279 1280 1281 1282 1283 | } /* * Allocate local (unnamed, untraced) working variables. */ gotPath = (parsePtr->numWords > 3); | > > > > > > > > > > > > > > > > > > > > > > | > > > > | | | | | > > | > > > > > | 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 | } /* * Allocate local (unnamed, untraced) working variables. */ gotPath = (parsePtr->numWords > 3); if (dictVarTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { const char *ptr = dictVarTokenPtr[1].start; const char *end = ptr + dictVarTokenPtr[1].size; int notArray = 1; /* * A conservative check for if we're working with an array since we * have a reasonable fallback if things are tricky. */ for (; ptr<end ; ptr++) { if (*ptr == '(' || *ptr == ')') { notArray = 0; break; } } if (notArray) { dictVar = TclFindCompiledLocal(dictVarTokenPtr[1].start, dictVarTokenPtr[1].size, 1, envPtr); } } if (dictVar == -1) { varNameTmp = TclFindCompiledLocal(NULL, 0, 1, envPtr); } else { varNameTmp = -1; } if (gotPath) { pathTmp = TclFindCompiledLocal(NULL, 0, 1, envPtr); } else { pathTmp = -1; } keysTmp = TclFindCompiledLocal(NULL, 0, 1, envPtr); /* * Issue instructions. First, the part to expand the dictionary. */ tokenPtr = dictVarTokenPtr; if (varNameTmp > -1) { CompileWord(envPtr, tokenPtr, interp, 0); if (varNameTmp <= 255) { TclEmitInstInt1( INST_STORE_SCALAR1, varNameTmp, envPtr); } else { TclEmitInstInt4( INST_STORE_SCALAR4, varNameTmp, envPtr); } } tokenPtr = TokenAfter(tokenPtr); if (gotPath) { for (i=2 ; i<parsePtr->numWords-1 ; i++) { CompileWord(envPtr, tokenPtr, interp, i-1); tokenPtr = TokenAfter(tokenPtr); } TclEmitInstInt4( INST_LIST, parsePtr->numWords-3,envPtr); if (pathTmp <= 255) { TclEmitInstInt1( INST_STORE_SCALAR1, pathTmp, envPtr); } else { TclEmitInstInt4( INST_STORE_SCALAR4, pathTmp, envPtr); } TclEmitOpcode( INST_POP, envPtr); } if (dictVar == -1) { TclEmitOpcode( INST_LOAD_STK, envPtr); } else if (dictVar <= 255) { TclEmitInstInt1( INST_LOAD_SCALAR1, dictVar, envPtr); } else { TclEmitInstInt4( INST_LOAD_SCALAR4, dictVar, envPtr); } if (gotPath) { if (pathTmp <= 255) { TclEmitInstInt1( INST_LOAD_SCALAR1, pathTmp, envPtr); } else { TclEmitInstInt4( INST_LOAD_SCALAR4, pathTmp, envPtr); } } else { |
︙ | ︙ | |||
1347 1348 1349 1350 1351 1352 1353 | ExceptionRangeEnds(envPtr, range); /* * Now fold the results back into the dictionary in the OK case. */ TclEmitOpcode( INST_END_CATCH, envPtr); | | | > | > > > | | > | > > > | 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 | ExceptionRangeEnds(envPtr, range); /* * Now fold the results back into the dictionary in the OK case. */ TclEmitOpcode( INST_END_CATCH, envPtr); if (varNameTmp > -1 && varNameTmp <= 255) { TclEmitInstInt1( INST_LOAD_SCALAR1, varNameTmp, envPtr); } else if (varNameTmp > -1) { TclEmitInstInt4( INST_LOAD_SCALAR4, varNameTmp, envPtr); } if (gotPath) { if (pathTmp <= 255) { TclEmitInstInt1( INST_LOAD_SCALAR1, pathTmp, envPtr); } else { TclEmitInstInt4( INST_LOAD_SCALAR4, pathTmp, envPtr); } } else { PushLiteral(envPtr, "", 0); } if (keysTmp <= 255) { TclEmitInstInt1( INST_LOAD_SCALAR1, keysTmp, envPtr); } else { TclEmitInstInt4( INST_LOAD_SCALAR4, keysTmp, envPtr); } if (dictVar == -1) { TclEmitOpcode( INST_DICT_RECOMBINE_STK, envPtr); } else { TclEmitInstInt4( INST_DICT_RECOMBINE_IMM, dictVar, envPtr); } TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup); /* * Now fold the results back into the dictionary in the exception case. */ ExceptionRangeTarget(envPtr, range, catchOffset); TclEmitOpcode( INST_PUSH_RETURN_OPTIONS, envPtr); TclEmitOpcode( INST_PUSH_RESULT, envPtr); TclEmitOpcode( INST_END_CATCH, envPtr); if (varNameTmp > -1 && varNameTmp <= 255) { TclEmitInstInt1( INST_LOAD_SCALAR1, varNameTmp, envPtr); } else if (varNameTmp > -1) { TclEmitInstInt4( INST_LOAD_SCALAR4, varNameTmp, envPtr); } if (parsePtr->numWords > 3) { if (pathTmp <= 255) { TclEmitInstInt1( INST_LOAD_SCALAR1, pathTmp, envPtr); } else { TclEmitInstInt4( INST_LOAD_SCALAR4, pathTmp, envPtr); } } else { PushLiteral(envPtr, "", 0); } if (keysTmp <= 255) { TclEmitInstInt1( INST_LOAD_SCALAR1, keysTmp, envPtr); } else { TclEmitInstInt4( INST_LOAD_SCALAR4, keysTmp, envPtr); } if (dictVar == -1) { TclEmitOpcode( INST_DICT_RECOMBINE_STK, envPtr); } else { TclEmitInstInt4( INST_DICT_RECOMBINE_IMM, dictVar, envPtr); } TclEmitOpcode( INST_RETURN_STK, envPtr); /* * Prepare for the start of the next command. */ if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) { |
︙ | ︙ |
Changes to generic/tclCompile.c.
︙ | ︙ | |||
422 423 424 425 426 427 428 | * stktop; op1 is 1 for errors on problems, 0 otherwise */ {"dictExpand", 1, -1, 0, {OPERAND_NONE}}, /* Probe into a dict and extract it (or a subdict of it) into * variables with matched names. Produces list of keys bound as * result. Part of [dict with]. * Stack: ... dict path => ... keyList */ | | > > > > | 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 | * stktop; op1 is 1 for errors on problems, 0 otherwise */ {"dictExpand", 1, -1, 0, {OPERAND_NONE}}, /* Probe into a dict and extract it (or a subdict of it) into * variables with matched names. Produces list of keys bound as * result. Part of [dict with]. * Stack: ... dict path => ... keyList */ {"dictRecombineStk", 1, -3, 0, {OPERAND_NONE}}, /* Map variable contents back into a dictionary in a variable. Part of * [dict with]. * Stack: ... dictVarName path keyList => ... */ {"dictRecombineImm", 1, -2, 1, {OPERAND_LVT4}}, /* Map variable contents back into a dictionary in the local variable * indicated by the LVT index. Part of [dict with]. * Stack: ... path keyList => ... */ {NULL, 0, 0, 0, {OPERAND_NONE}} }; /* * Prototypes for procedures defined later in this file: */ |
︙ | ︙ |
Changes to generic/tclCompile.h.
︙ | ︙ | |||
673 674 675 676 677 678 679 | /* For [unset] compilation */ #define INST_UNSET_SCALAR 134 #define INST_UNSET_ARRAY 135 #define INST_UNSET_ARRAY_STK 136 #define INST_UNSET_STK 137 #define INST_DICT_EXPAND 138 | | > | | 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 | /* For [unset] compilation */ #define INST_UNSET_SCALAR 134 #define INST_UNSET_ARRAY 135 #define INST_UNSET_ARRAY_STK 136 #define INST_UNSET_STK 137 #define INST_DICT_EXPAND 138 #define INST_DICT_RECOMBINE_STK 139 #define INST_DICT_RECOMBINE_IMM 140 /* The last opcode */ #define LAST_INST_OPCODE 140 /* * Table describing the Tcl bytecode instructions: their name (for displaying * code), total number of code bytes required (including operand bytes), and a * description of the type of each operand. These operand types include signed * and unsigned integers of length one and four bytes. The unsigned integers * are used for indexes or for, e.g., the count of objects to push in a "push" |
︙ | ︙ |
Changes to generic/tclDictObj.c.
︙ | ︙ | |||
3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 | { Tcl_Obj **pathv; int pathc; Tcl_InterpState state; Tcl_Obj *varName = data[0]; Tcl_Obj *keysPtr = data[1]; Tcl_Obj *pathPtr = data[2]; if (result == TCL_ERROR) { Tcl_AddErrorInfo(interp, "\n (body of \"dict with\")"); } /* * Save the result state; TDWF doesn't guarantee to not modify that on | > | 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 | { Tcl_Obj **pathv; int pathc; Tcl_InterpState state; Tcl_Obj *varName = data[0]; Tcl_Obj *keysPtr = data[1]; Tcl_Obj *pathPtr = data[2]; Var *varPtr, *arrayPtr; if (result == TCL_ERROR) { Tcl_AddErrorInfo(interp, "\n (body of \"dict with\")"); } /* * Save the result state; TDWF doesn't guarantee to not modify that on |
︙ | ︙ | |||
3179 3180 3181 3182 3183 3184 3185 | pathv = NULL; } /* * Pack from local variables back into the dictionary. */ | > > > > > | > > | 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 | pathv = NULL; } /* * Pack from local variables back into the dictionary. */ varPtr = TclObjLookupVarEx(interp, varName, NULL, TCL_LEAVE_ERR_MSG, "set", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr); if (varPtr == NULL) { result = TCL_ERROR; } else { result = TclDictWithFinish(interp, varPtr, arrayPtr, varName, NULL, -1, pathc, pathv, keysPtr); } /* * Tidy up and return the real result (unless we had an error). */ TclDecrRefCount(varName); TclDecrRefCount(keysPtr); |
︙ | ︙ | |||
3285 3286 3287 3288 3289 3290 3291 | * the dictionary in the named variable. * *---------------------------------------------------------------------- */ int TclDictWithFinish( | | > > > > > > > | > > > > > > > | > | | > | > | 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 | * the dictionary in the named variable. * *---------------------------------------------------------------------- */ int TclDictWithFinish( Tcl_Interp *interp, /* Command interpreter in which variable * exists. Used for state management, traces * and error reporting. */ Var *varPtr, /* Reference to the variable holding the * dictionary. */ Var *arrayPtr, /* Reference to the array containing the * variable, or NULL if the variable is a * scalar. */ Tcl_Obj *part1Ptr, /* Name of an array (if part2 is non-NULL) or * the name of a variable. NULL if the 'index' * parameter is >= 0 */ Tcl_Obj *part2Ptr, /* If non-NULL, gives the name of an element * in the array part1. */ int index, /* Index into the local variable table of the * variable, or -1. Only used when part1Ptr is * NULL. */ int pathc, /* The number of elements in the path into the * dictionary. */ Tcl_Obj *const pathv[], /* The elements of the path to the subdict. */ Tcl_Obj *keysPtr) /* List of keys to be synchronized. This is * the result value from TclDictWithInit. */ { Tcl_Obj *dictPtr, *leafPtr, *valPtr; int i, allocdict, keyc; Tcl_Obj **keyv; /* * If the dictionary variable doesn't exist, drop everything silently. */ dictPtr = TclPtrGetVar(interp, varPtr, arrayPtr, part1Ptr, part2Ptr, TCL_LEAVE_ERR_MSG, index); if (dictPtr == NULL) { return TCL_OK; } /* * Double-check that it is still a dictionary. */ |
︙ | ︙ | |||
3381 3382 3383 3384 3385 3386 3387 | InvalidateDictChain(leafPtr); } /* * Write back the outermost dictionary to the variable. */ | | | | 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 | InvalidateDictChain(leafPtr); } /* * Write back the outermost dictionary to the variable. */ if (TclPtrSetVar(interp, varPtr, arrayPtr, part1Ptr, part2Ptr, dictPtr, TCL_LEAVE_ERR_MSG, index) == NULL) { if (allocdict) { TclDecrRefCount(dictPtr); } return TCL_ERROR; } return TCL_OK; } |
︙ | ︙ |
Changes to generic/tclExecute.c.
︙ | ︙ | |||
6118 6119 6120 6121 6122 6123 6124 | TRACE_WITH_OBJ(("%.30s %.30s => ERROR: ", O2S(dictPtr), O2S(listPtr)), Tcl_GetObjResult(interp)); goto gotError; } TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); NEXT_INST_F(1, 2, 1); | | > | | > | | | > > > > > | > > | > > > | > > > > > | > > > > > > | > | > > > > > | | > > > > > | | 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 | TRACE_WITH_OBJ(("%.30s %.30s => ERROR: ", O2S(dictPtr), O2S(listPtr)), Tcl_GetObjResult(interp)); goto gotError; } TRACE_APPEND(("%.30s\n", O2S(objResultPtr))); NEXT_INST_F(1, 2, 1); case INST_DICT_RECOMBINE_STK: keysPtr = POP_OBJECT(); varNamePtr = OBJ_UNDER_TOS; listPtr = OBJ_AT_TOS; TRACE(("\"%.30s\" \"%.30s\" \"%.30s\" => ", O2S(varNamePtr), O2S(valuePtr), O2S(keysPtr))); if (TclListObjGetElements(interp, listPtr, &objc, &objv) != TCL_OK) { TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); TclDecrRefCount(keysPtr); goto gotError; } varPtr = TclObjLookupVarEx(interp, varNamePtr, NULL, TCL_LEAVE_ERR_MSG, "set", 1, 1, &arrayPtr); if (varPtr == NULL) { TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); TclDecrRefCount(keysPtr); goto gotError; } DECACHE_STACK_INFO(); result = TclDictWithFinish(interp, varPtr,arrayPtr,varNamePtr,NULL,-1, objc, objv, keysPtr); CACHE_STACK_INFO(); TclDecrRefCount(keysPtr); if (result != TCL_OK) { TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); goto gotError; } TRACE_APPEND(("OK\n")); NEXT_INST_F(1, 2, 0); case INST_DICT_RECOMBINE_IMM: opnd = TclGetUInt4AtPtr(pc+1); listPtr = OBJ_UNDER_TOS; keysPtr = OBJ_AT_TOS; varPtr = LOCAL(opnd); TRACE(("%u <- \"%.30s\" \"%.30s\" => ", opnd, O2S(valuePtr), O2S(keysPtr))); if (TclListObjGetElements(interp, listPtr, &objc, &objv) != TCL_OK) { TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); goto gotError; } while (TclIsVarLink(varPtr)) { varPtr = varPtr->value.linkPtr; } DECACHE_STACK_INFO(); result = TclDictWithFinish(interp, varPtr, NULL, NULL, NULL, opnd, objc, objv, keysPtr); CACHE_STACK_INFO(); if (result != TCL_OK) { TRACE_APPEND(("ERROR: %.30s\n", O2S(Tcl_GetObjResult(interp)))); goto gotError; } TRACE_APPEND(("OK\n")); NEXT_INST_F(5, 2, 0); } /* * End of dictionary-related instructions. * ----------------------------------------------------------------- */ |
︙ | ︙ |
Changes to generic/tclInt.h.
︙ | ︙ | |||
3227 3228 3229 3230 3231 3232 3233 | MODULE_SCOPE Tcl_TimerToken TclCreateAbsoluteTimerHandler( Tcl_Time *timePtr, Tcl_TimerProc *proc, ClientData clientData); MODULE_SCOPE int TclDefaultBgErrorHandlerObjCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE Tcl_Command TclInitDictCmd(Tcl_Interp *interp); | | | > | 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 | MODULE_SCOPE Tcl_TimerToken TclCreateAbsoluteTimerHandler( Tcl_Time *timePtr, Tcl_TimerProc *proc, ClientData clientData); MODULE_SCOPE int TclDefaultBgErrorHandlerObjCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE Tcl_Command TclInitDictCmd(Tcl_Interp *interp); MODULE_SCOPE int TclDictWithFinish(Tcl_Interp *interp, Var *varPtr, Var *arrayPtr, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, int index, int pathc, Tcl_Obj *const pathv[], Tcl_Obj *keysPtr); MODULE_SCOPE Tcl_Obj * TclDictWithInit(Tcl_Interp *interp, Tcl_Obj *dictPtr, int pathc, Tcl_Obj *const pathv[]); MODULE_SCOPE int Tcl_DisassembleObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); |
︙ | ︙ |