From c450611fa62e31564086453d6921a47bd7fb9044 Mon Sep 17 00:00:00 2001 From: dkf Date: Wed, 24 Oct 2012 09:50:09 +0000 Subject: Added compilation of [dict unset]; the bytecode needed already existed anyway. --- ChangeLog | 7 +++++- generic/tclCompCmds.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++ generic/tclDictObj.c | 2 +- generic/tclInt.h | 3 +++ tests/dict.test | 49 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 120 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 22f24b8..4964249 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-10-24 Donal K. Fellows + + * generic/tclCompCmds.c (TclCompileDictUnsetCmd): Added compilation of + the [dict unset] command (for scalar var in LVT only). + 2012-10-23 Jan Nijtmans * generic/tclInt.h: Add "flags" parameter from Tcl_LoadFile to @@ -10,7 +15,7 @@ * generic/tclBasic.c (TclNRCoroutineObjCmd): insure that numlevels are properly set, fix bug discovered by dkf and reported at - http://code.activestate.com/lists/tcl-core/12213/ + http://code.activestate.com/lists/tcl-core/12213/ 2012-10-16 Donal K. Fellows diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 61f7988..fc60016 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -787,6 +787,67 @@ TclCompileDictGetCmd( } int +TclCompileDictUnsetCmd( + Tcl_Interp *interp, /* Used for looking up stuff. */ + 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. */ +{ + Tcl_Token *tokenPtr; + DefineLineInformation; /* TIP #280 */ + int i, dictVarIndex, nameChars; + const char *name; + + /* + * There must be at least one argument after the variable name for us to + * compile to bytecode. + */ + + if (parsePtr->numWords < 3) { + return TCL_ERROR; + } + + /* + * The dictionary variable must be a local scalar that is knowable at + * compile time; anything else exceeds the complexity of the opcode. So + * discover what the index is. + */ + + tokenPtr = TokenAfter(parsePtr->tokenPtr); + if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { + return TCL_ERROR; + } + name = tokenPtr[1].start; + nameChars = tokenPtr[1].size; + if (!TclIsLocalScalar(name, nameChars)) { + return TCL_ERROR; + } + dictVarIndex = TclFindCompiledLocal(name, nameChars, 1, envPtr); + if (dictVarIndex < 0) { + return TCL_ERROR; + } + + /* + * Remaining words (the key path) can be handled normally. + */ + + for (i=2 ; inumWords ; i++) { + tokenPtr = TokenAfter(tokenPtr); + CompileWord(envPtr, tokenPtr, interp, i); + } + + /* + * Now emit the instruction to do the dict manipulation. + */ + + TclEmitInstInt4( INST_DICT_UNSET, parsePtr->numWords-2, envPtr); + TclEmitInt4( dictVarIndex, envPtr); + return TCL_OK; +} + +int TclCompileDictForCmd( Tcl_Interp *interp, /* Used for looking up stuff. */ Tcl_Parse *parsePtr, /* Points to a parse structure for the command diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c index d1087b2..ea9411c 100644 --- a/generic/tclDictObj.c +++ b/generic/tclDictObj.c @@ -104,7 +104,7 @@ static const EnsembleImplMap implementationMap[] = { {"replace", DictReplaceCmd, NULL, NULL, NULL, 0 }, {"set", DictSetCmd, TclCompileDictSetCmd, NULL, NULL, 0 }, {"size", DictSizeCmd, NULL, NULL, NULL, 0 }, - {"unset", DictUnsetCmd, NULL, NULL, NULL, 0 }, + {"unset", DictUnsetCmd, TclCompileDictUnsetCmd, NULL, NULL, 0 }, {"update", DictUpdateCmd, TclCompileDictUpdateCmd, NULL, NULL, 0 }, {"values", DictValuesCmd, NULL, NULL, NULL, 0 }, {"with", DictWithCmd, TclCompileDictWithCmd, NULL, NULL, 0 }, diff --git a/generic/tclInt.h b/generic/tclInt.h index 860755a..ea712b8 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -3519,6 +3519,9 @@ MODULE_SCOPE int TclCompileDictLappendCmd(Tcl_Interp *interp, MODULE_SCOPE int TclCompileDictSetCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileDictUnsetCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileDictUpdateCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); diff --git a/tests/dict.test b/tests/dict.test index aa22c00..72f239e 100644 --- a/tests/dict.test +++ b/tests/dict.test @@ -781,6 +781,55 @@ test dict-16.9 {dict unset command: write failure} -setup { } -returnCodes error -cleanup { unset dictVar } -result {can't set "dictVar": variable is array} +# Now test with an LVT present (i.e., the bytecoded version). +test dict-16.10 {dict unset command} -body { + apply {{} { + set dictVar {a b c d} + dict unset dictVar a + }} +} -result {c d} +test dict-16.11 {dict unset command} -body { + apply {{} { + set dictVar {a b c d} + dict unset dictVar c + }} +} -result {a b} +test dict-16.12 {dict unset command} -body { + apply {{} { + set dictVar {a b} + dict unset dictVar c + }} +} -result {a b} +test dict-16.13 {dict unset command} -body { + apply {{} { + set dictVar {a {b c d e}} + dict unset dictVar a b + }} +} -result {a {d e}} +test dict-16.14 {dict unset command} -returnCodes error -body { + apply {{} { + set dictVar a + dict unset dictVar a + }} +} -result {missing value to go with key} +test dict-16.15 {dict unset command} -returnCodes error -body { + apply {{} { + set dictVar {a b} + dict unset dictVar c d + }} +} -result {key "c" not known in dictionary} +test dict-16.16 {dict unset command} -body { + apply {{} {list [info exists dictVar] [dict unset dictVar a] [info exists dictVar]}} +} -result {0 {} 1} +test dict-16.17 {dict unset command} -returnCodes error -body { + apply {{} {dict unset dictVar}} +} -result {wrong # args: should be "dict unset varName key ?key ...?"} +test dict-16.18 {dict unset command: write failure} -body { + apply {{} { + set dictVar(block) {} + dict unset dictVar a + }} +} -returnCodes error -result {can't set "dictVar": variable is array} test dict-17.1 {dict filter command: key} -body { set dictVar {a1 a a2 b b1 c b2 d foo bar bar foo} -- cgit v0.12