Tcl Source Code

Check-in [0b8e874e2c]
Login

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: 0b8e874e2c252c22fd776919cb4f4b86de3a8d89
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
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tclCompCmds.c.

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;
    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.







|







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






















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
    }

    /*
     * Allocate local (unnamed, untraced) working variables.
     */

    gotPath = (parsePtr->numWords > 3);






















    varNameTmp = TclFindCompiledLocal(NULL, 0, 1, envPtr);



    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;

    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);
    }

    TclEmitOpcode(		INST_LOAD_STK,			envPtr);





    if (gotPath) {
	if (pathTmp <= 255) {
	    TclEmitInstInt1(	INST_LOAD_SCALAR1, pathTmp,	envPtr);
	} else {
	    TclEmitInstInt4(	INST_LOAD_SCALAR4, pathTmp,	envPtr);
	}
    } else {







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>












>
|
|
|
|
|
>















>
|
>
>
>
>
>







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
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372

1373



1374
1375
1376
1377
1378
1379
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
    ExceptionRangeEnds(envPtr, range);

    /*
     * Now fold the results back into the dictionary in the OK case.
     */

    TclEmitOpcode(		INST_END_CATCH,			envPtr);
    if (varNameTmp <= 255) {
	TclEmitInstInt1(	INST_LOAD_SCALAR1, varNameTmp,	envPtr);
    } else {
	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);
    }

    TclEmitOpcode(		INST_DICT_RECOMBINE,		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 <= 255) {
	TclEmitInstInt1(	INST_LOAD_SCALAR1, varNameTmp,	envPtr);
    } else {
	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);
    }

    TclEmitOpcode(		INST_DICT_RECOMBINE,		envPtr);



    TclEmitOpcode(		INST_RETURN_STK,		envPtr);

    /*
     * Prepare for the start of the next command.
     */

    if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) {







|

|
















>
|
>
>
>










|

|
















>
|
>
>
>







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
429
430
431
432




433
434
435
436
437
438
439
	 * 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 */
    {"dictRecombine",    1,    -3,        0,    {OPERAND_NONE}},
        /* Map variable contents back into a dictionary in a variable. Part of
         * [dict with].
	 * Stack:  ... dictVarName path keyList => ... */





    {NULL, 0, 0, 0, {OPERAND_NONE}}
};

/*
 * Prototypes for procedures defined later in this file:
 */







|



>
>
>
>







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
680

681
682
683
684
685
686
687
688
689
690
/* 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		139


/* The last opcode */
#define LAST_INST_OPCODE		139

/*
 * 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"







|
>


|







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





3186


3187
3188
3189
3190
3191
3192
3193
	pathv = NULL;
    }

    /*
     * Pack from local variables back into the dictionary.
     */






    result = TclDictWithFinish(interp, varName, pathc, pathv, keysPtr);



    /*
     * Tidy up and return the real result (unless we had an error).
     */

    TclDecrRefCount(varName);
    TclDecrRefCount(keysPtr);







>
>
>
>
>
|
>
>







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
3292







3293







3294

3295
3296

3297
3298
3299
3300
3301
3302
3303
3304
3305
3306

3307
3308
3309
3310
3311
3312
3313
 *	the dictionary in the named variable.
 *
 *----------------------------------------------------------------------
 */

int
TclDictWithFinish(
    Tcl_Interp *interp,







    Tcl_Obj *varName,







    int pathc,

    Tcl_Obj *const pathv[],
    Tcl_Obj *keysPtr)

{
    Tcl_Obj *dictPtr, *leafPtr, *valPtr;
    int i, allocdict, keyc;
    Tcl_Obj **keyv;

    /*
     * If the dictionary variable doesn't exist, drop everything silently.
     */

    dictPtr = Tcl_ObjGetVar2(interp, varName, NULL, 0);

    if (dictPtr == NULL) {
	return TCL_OK;
    }

    /*
     * Double-check that it is still a dictionary.
     */







|
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
|
>
|
|
>









|
>







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
3388
3389
3390
3391
3392
3393
3394
3395
3396
	InvalidateDictChain(leafPtr);
    }

    /*
     * Write back the outermost dictionary to the variable.
     */

    if (Tcl_ObjSetVar2(interp, varName, NULL, dictPtr,
	    TCL_LEAVE_ERR_MSG) == NULL) {
	if (allocdict) {
	    TclDecrRefCount(dictPtr);
	}
	return TCL_ERROR;
    }
    return TCL_OK;
}







|
|







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
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
	    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:

	varNamePtr = OBJ_AT_DEPTH(2);
	listPtr = OBJ_UNDER_TOS;

	keysPtr = OBJ_AT_TOS;
	if (TclListObjGetElements(interp, listPtr, &objc, &objv) != TCL_OK) {
	    TRACE_WITH_OBJ(("%.30s %.30s %.30s => ERROR: ",
		    O2S(varNamePtr), O2S(listPtr), O2S(keysPtr)),





		    Tcl_GetObjResult(interp));

	    goto gotError;
	}

	if (TclDictWithFinish(interp, varNamePtr, objc, objv,



		keysPtr) != TCL_OK) {





	    TRACE_WITH_OBJ(("%.30s %.30s %.30s => ERROR: ",






		    O2S(varNamePtr), O2S(listPtr), O2S(keysPtr)),

		    Tcl_GetObjResult(interp));
	    goto gotError;
	}





	TclDecrRefCount(keysPtr);
	POP_OBJECT();





	NEXT_INST_F(1, 2, 0);
    }

    /*
     *	   End of dictionary-related instructions.
     * -----------------------------------------------------------------
     */








|
>
|
|
>
|

|
|
>
>
>
>
>
|
>


>
|
>
>
>
|
>
>
>
>
>
|
>
>
>
>
>
>
|
>
|


>
>
>
>
>
|
|
>
>
>
>
>
|







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
3234
3235

3236
3237
3238
3239
3240
3241
3242
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,
			    Tcl_Obj *varName, 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[]);
			    







|
|
>







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[]);