diff options
author | Steve Bennett <steveb@workware.net.au> | 2020-12-19 09:31:40 +1000 |
---|---|---|
committer | Steve Bennett <steveb@workware.net.au> | 2020-12-26 18:08:29 +1000 |
commit | ea1b12824f360ca2f3b4838e1d88605b9b1c1a6d (patch) | |
tree | da9cc972a7fedcfe45eaa068636345013c785d12 | |
parent | a905122e48ae2f5208b037d8bfc08631b753cb63 (diff) | |
download | jimtcl-ea1b12824f360ca2f3b4838e1d88605b9b1c1a6d.zip jimtcl-ea1b12824f360ca2f3b4838e1d88605b9b1c1a6d.tar.gz jimtcl-ea1b12824f360ca2f3b4838e1d88605b9b1c1a6d.tar.bz2 |
core: support integer expressions in various commands
For convenience, many commands now accept integer expressions
rather than only simple integers.
These are:
loop, range, incr, string repeat, lrepeat, pack, unpack, rand
This simplifies many cases where previously expr {} or $() was required.
e.g.
foreach i [range 4+1 2*$b] { ... }
string repeat 2**$n a
Signed-off-by: Steve Bennett <steveb@workware.net.au>
-rw-r--r-- | jim-pack.c | 10 | ||||
-rw-r--r-- | jim.c | 54 | ||||
-rw-r--r-- | jim.h | 2 | ||||
-rw-r--r-- | jim_tcl.txt | 8 | ||||
-rw-r--r-- | tests/binary.test | 26 | ||||
-rw-r--r-- | tests/coverage.test | 4 | ||||
-rw-r--r-- | tests/dict2.test | 4 | ||||
-rw-r--r-- | tests/jim.test | 32 | ||||
-rw-r--r-- | tests/pack.test | 8 |
9 files changed, 88 insertions, 60 deletions
@@ -290,14 +290,14 @@ static int Jim_UnpackCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return JIM_ERR; } - if (Jim_GetWide(interp, argv[3], &pos) != JIM_OK) { + if (Jim_GetWideExpr(interp, argv[3], &pos) != JIM_OK) { return JIM_ERR; } if (pos < 0 || (option == OPT_STR && pos % 8)) { Jim_SetResultFormatted(interp, "bad bitoffset: %#s", argv[3]); return JIM_ERR; } - if (Jim_GetWide(interp, argv[4], &width) != JIM_OK) { + if (Jim_GetWideExpr(interp, argv[4], &width) != JIM_OK) { return JIM_ERR; } if (width < 0 || (option == OPT_STR && width % 8) || (option != OPT_STR && width > sizeof(jim_wide) * 8) || @@ -387,14 +387,14 @@ static int Jim_PackCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return JIM_ERR; } if ((option == OPT_LE || option == OPT_BE) && - Jim_GetWide(interp, argv[2], &value) != JIM_OK) { + Jim_GetWideExpr(interp, argv[2], &value) != JIM_OK) { return JIM_ERR; } if ((option == OPT_FLOATLE || option == OPT_FLOATBE) && Jim_GetDouble(interp, argv[2], &fvalue) != JIM_OK) { return JIM_ERR; } - if (Jim_GetWide(interp, argv[4], &width) != JIM_OK) { + if (Jim_GetWideExpr(interp, argv[4], &width) != JIM_OK) { return JIM_ERR; } if (width <= 0 || (option == OPT_STR && width % 8) || (option != OPT_STR && width > sizeof(jim_wide) * 8) || @@ -403,7 +403,7 @@ static int Jim_PackCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return JIM_ERR; } if (argc == 6) { - if (Jim_GetWide(interp, argv[5], &pos) != JIM_OK) { + if (Jim_GetWideExpr(interp, argv[5], &pos) != JIM_OK) { return JIM_ERR; } if (pos < 0 || (option == OPT_STR && pos % 8)) { @@ -6063,6 +6063,27 @@ int Jim_GetWide(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr) return JIM_OK; } +int Jim_GetWideExpr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr) +{ + int ret = JIM_OK; + if (objPtr->typePtr == &intObjType) { + *widePtr = JimWideValue(objPtr); + } + else { + ret = Jim_EvalExpression(interp, objPtr); + if (ret == JIM_OK) { + ret = Jim_GetWide(interp, Jim_GetResult(interp), widePtr); + } + else { + /* XXX By doing this we throw away any more detailed message, + * but typical integer expressions won't be very complex + */ + Jim_SetResultFormatted(interp, "expected integer expression but got \"%#s\"", objPtr); + } + } + return ret; +} + /* Get a wide but does not set an error if the format is bad. */ static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr) { @@ -10415,7 +10436,7 @@ static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg return JIM_ERR; } if (argc == 3) { - if (Jim_GetWide(interp, argv[2], &increment) != JIM_OK) + if (Jim_GetWideExpr(interp, argv[2], &increment) != JIM_OK) return JIM_ERR; } intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED); @@ -12049,7 +12070,7 @@ static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv /* Get the stop condition (must be a variable or integer) */ if (expr->expr->right->type == JIM_TT_EXPR_INT) { - if (Jim_GetWide(interp, expr->expr->right->objPtr, &stop) == JIM_ERR) { + if (Jim_GetWideExpr(interp, expr->expr->right->objPtr, &stop) == JIM_ERR) { goto evalstart; } } @@ -12161,14 +12182,14 @@ static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg return JIM_ERR; } - if (Jim_GetWide(interp, argv[2], &i) != JIM_OK || - Jim_GetWide(interp, argv[3], &limit) != JIM_OK || - (argc == 6 && Jim_GetWide(interp, argv[4], &incr) != JIM_OK)) { + if (Jim_GetWideExpr(interp, argv[2], &i) != JIM_OK || + Jim_GetWideExpr(interp, argv[3], &limit) != JIM_OK || + (argc == 6 && Jim_GetWideExpr(interp, argv[4], &incr) != JIM_OK)) { return JIM_ERR; } bodyObjPtr = (argc == 5) ? argv[4] : argv[5]; - retval = Jim_SetVariable(interp, argv[1], argv[2]); + retval = Jim_SetVariable(interp, argv[1], Jim_NewIntObj(interp, i)); while (((i < limit && incr > 0) || (i > limit && incr < 0)) && retval == JIM_OK) { retval = Jim_EvalObj(interp, bodyObjPtr); @@ -13978,7 +13999,7 @@ badcompareargs: Jim_WrongNumArgs(interp, 2, argv, "string count"); return JIM_ERR; } - if (Jim_GetWide(interp, argv[3], &count) != JIM_OK) { + if (Jim_GetWideExpr(interp, argv[3], &count) != JIM_OK) { return JIM_ERR; } objPtr = Jim_NewStringObj(interp, "", 0); @@ -15413,13 +15434,14 @@ static int Jim_LrangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a static int Jim_LrepeatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; - long count; + jim_wide count; - if (argc < 2 || Jim_GetLong(interp, argv[1], &count) != JIM_OK || count < 0) { + if (argc < 2 || Jim_GetWideExpr(interp, argv[1], &count) != JIM_OK || count < 0) { Jim_WrongNumArgs(interp, 1, argv, "count ?value ...?"); return JIM_ERR; } if (count == 0 || argc == 2) { + Jim_SetEmptyResult(interp); return JIM_OK; } @@ -15578,14 +15600,14 @@ static int Jim_RangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar return JIM_ERR; } if (argc == 2) { - if (Jim_GetWide(interp, argv[1], &end) != JIM_OK) + if (Jim_GetWideExpr(interp, argv[1], &end) != JIM_OK) return JIM_ERR; } else { - if (Jim_GetWide(interp, argv[1], &start) != JIM_OK || - Jim_GetWide(interp, argv[2], &end) != JIM_OK) + if (Jim_GetWideExpr(interp, argv[1], &start) != JIM_OK || + Jim_GetWideExpr(interp, argv[2], &end) != JIM_OK) return JIM_ERR; - if (argc == 4 && Jim_GetWide(interp, argv[3], &step) != JIM_OK) + if (argc == 4 && Jim_GetWideExpr(interp, argv[3], &step) != JIM_OK) return JIM_ERR; } if ((len = JimRangeLen(start, end, step)) == -1) { @@ -15612,11 +15634,11 @@ static int Jim_RandCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg if (argc == 1) { max = JIM_WIDE_MAX; } else if (argc == 2) { - if (Jim_GetWide(interp, argv[1], &max) != JIM_OK) + if (Jim_GetWideExpr(interp, argv[1], &max) != JIM_OK) return JIM_ERR; } else if (argc == 3) { - if (Jim_GetWide(interp, argv[1], &min) != JIM_OK || - Jim_GetWide(interp, argv[2], &max) != JIM_OK) + if (Jim_GetWideExpr(interp, argv[1], &min) != JIM_OK || + Jim_GetWideExpr(interp, argv[2], &max) != JIM_OK) return JIM_ERR; } len = max-min; @@ -849,6 +849,8 @@ JIM_EXPORT int Jim_GetBoolean(Jim_Interp *interp, Jim_Obj *objPtr, /* integer object */ JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr, jim_wide *widePtr); +JIM_EXPORT int Jim_GetWideExpr(Jim_Interp *interp, Jim_Obj *objPtr, + jim_wide *widePtr); JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr, long *longPtr); #define Jim_NewWideObj Jim_NewIntObj diff --git a/jim_tcl.txt b/jim_tcl.txt index 328aaab..b76f9ab 100644 --- a/jim_tcl.txt +++ b/jim_tcl.txt @@ -56,6 +56,8 @@ Changes since 0.80 ~~~~~~~~~~~~~~~~~~ 1. TIP 582, comments allowed in expressions 2. Indexes may contain any number of +n, -n +3. Many commands now accept integer expressions rather than simple integers: + `loop`, `range`, `incr`, `string repeat`, `lrepeat`, `pack`, `unpack`, `rand` Changes between 0.79 and 0.80 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2771,7 +2773,7 @@ Increment the value stored in the variable whose name is +'varName'+. The value of the variable must be integral. If +'increment'+ is supplied then its value (which must be an -integer) is added to the value of variable +'varName'+; otherwise +integer expression) is added to the value of variable +'varName'+; otherwise 1 is added to +'varName'+. The new value is stored as a decimal string in variable +'varName'+ @@ -3070,6 +3072,8 @@ If +'incr'+ is not specified, 1 is used. Note that setting the loop variable inside the loop does not affect the loop count. +Integer parameters may be any integer expression. + lindex ~~~~~~ +*lindex* 'list ?index ...?'+ @@ -3594,6 +3598,8 @@ and ranging up to but not including +'end'+ in steps of +'step'+ defaults to 1). 7 5 ---- +Integer parameters may be any integer expression. + read ~~~~ +*read* ?*-nonewline*? 'fileId'+ diff --git a/tests/binary.test b/tests/binary.test index 8eb93f9..5c6ca72 100644 --- a/tests/binary.test +++ b/tests/binary.test @@ -251,7 +251,7 @@ test binary-8.9 {Tcl_BinaryObjCmd: format} -returnCodes error -body { test binary-8.10 {Tcl_BinaryObjCmd: format} -returnCodes error -body { set a {0x50 0x51} binary format c $a -} -result "expected integer but got \"0x50 0x51\"" +} -match glob -result "expected integer *but got \"0x50 0x51\"" test binary-8.11 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} binary format c1 $a @@ -262,7 +262,7 @@ test binary-9.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { } -result {not enough arguments for all format specifiers} test binary-9.2 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format s blat -} -result {expected integer but got "blat"} +} -match glob -result {expected integer *but got "blat"} test binary-9.3 {Tcl_BinaryObjCmd: format} { binary format s0 0x50 } {} @@ -290,7 +290,7 @@ test binary-9.10 {Tcl_BinaryObjCmd: format} -returnCodes error -body { test binary-9.11 {Tcl_BinaryObjCmd: format} -returnCodes error -body { set a {0x50 0x51} binary format s $a -} -result "expected integer but got \"0x50 0x51\"" +} -match glob -result "expected integer *but got \"0x50 0x51\"" test binary-9.12 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} binary format s1 $a @@ -301,7 +301,7 @@ test binary-10.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { } -result {not enough arguments for all format specifiers} test binary-10.2 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format S blat -} -result {expected integer but got "blat"} +} -match glob -result {expected integer *but got "blat"} test binary-10.3 {Tcl_BinaryObjCmd: format} { binary format S0 0x50 } {} @@ -329,7 +329,7 @@ test binary-10.10 {Tcl_BinaryObjCmd: format} -returnCodes error -body { test binary-10.11 {Tcl_BinaryObjCmd: format} -returnCodes error -body { set a {0x50 0x51} binary format S $a -} -result "expected integer but got \"0x50 0x51\"" +} -match glob -result "expected integer *but got \"0x50 0x51\"" test binary-10.12 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} binary format S1 $a @@ -340,7 +340,7 @@ test binary-11.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { } -result {not enough arguments for all format specifiers} test binary-11.2 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format i blat -} -result {expected integer but got "blat"} +} -match glob -result {expected integer *but got "blat"} test binary-11.3 {Tcl_BinaryObjCmd: format} { binary format i0 0x50 } {} @@ -371,7 +371,7 @@ test binary-11.11 {Tcl_BinaryObjCmd: format} -returnCodes error -body { test binary-11.12 {Tcl_BinaryObjCmd: format} -returnCodes error -body { set a {0x50 0x51} binary format i $a -} -result "expected integer but got \"0x50 0x51\"" +} -match glob -result "expected integer *but got \"0x50 0x51\"" test binary-11.13 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} binary format i1 $a @@ -382,7 +382,7 @@ test binary-12.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { } -result {not enough arguments for all format specifiers} test binary-12.2 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format I blat -} -result {expected integer but got "blat"} +} -match glob -result {expected integer *but got "blat"} test binary-12.3 {Tcl_BinaryObjCmd: format} { binary format I0 0x50 } {} @@ -413,7 +413,7 @@ test binary-12.11 {Tcl_BinaryObjCmd: format} -returnCodes error -body { test binary-12.12 {Tcl_BinaryObjCmd: format} -returnCodes error -body { set a {0x50 0x51} binary format I $a -} -result "expected integer but got \"0x50 0x51\"" +} -match glob -result "expected integer *but got \"0x50 0x51\"" test binary-12.13 {Tcl_BinaryObjCmd: format} { set a {0x50 0x51} binary format I1 $a @@ -1664,7 +1664,7 @@ test binary-48.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { } -result {not enough arguments for all format specifiers} test binary-48.2 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format t blat -} -result {expected integer but got "blat"} +} -match glob -result {expected integer *but got "blat"} test binary-48.3 {Tcl_BinaryObjCmd: format} { binary format S0 0x50 } {} @@ -1710,7 +1710,7 @@ test binary-48.16 {Tcl_BinaryObjCmd: format} -returnCodes error -body { test binary-48.17 {Tcl_BinaryObjCmd: format} -returnCodes error -body { set a {0x50 0x51} binary format t $a -} -result "expected integer but got \"0x50 0x51\"" +} -match glob -result "expected integer *but got \"0x50 0x51\"" test binary-48.18 {Tcl_BinaryObjCmd: format} bigEndian { set a {0x50 0x51} binary format t1 $a @@ -1726,7 +1726,7 @@ test binary-49.1 {Tcl_BinaryObjCmd: format} -returnCodes error -body { } -result {not enough arguments for all format specifiers} test binary-49.2 {Tcl_BinaryObjCmd: format} -returnCodes error -body { binary format n blat -} -result {expected integer but got "blat"} +} -match glob -result {expected integer *but got "blat"} test binary-49.3 {Tcl_BinaryObjCmd: format} { binary format n0 0x50 } {} @@ -1757,7 +1757,7 @@ test binary-49.11 {Tcl_BinaryObjCmd: format} -returnCodes error -body { test binary-49.12 {Tcl_BinaryObjCmd: format} -returnCodes error -body { set a {0x50 0x51} binary format n $a -} -result "expected integer but got \"0x50 0x51\"" +} -match glob -result "expected integer *but got \"0x50 0x51\"" test binary-49.13 {Tcl_BinaryObjCmd: format} littleEndian { set a {0x50 0x51} binary format n1 $a diff --git a/tests/coverage.test b/tests/coverage.test index faa1f02..a405c43 100644 --- a/tests/coverage.test +++ b/tests/coverage.test @@ -182,11 +182,11 @@ test rand-1 {rand} -constraints rand -body { test rand-2 {rand} -constraints rand -body { rand foo -} -returnCodes error -result {expected integer but got "foo"} +} -returnCodes error -match glob -result {expected integer *but got "foo"} test rand-3 {rand} -constraints rand -body { rand 2 bar -} -returnCodes error -result {expected integer but got "bar"} +} -returnCodes error -match glob -result {expected integer *but got "bar"} test rand-4 {rand} rand { string is integer [rand] diff --git a/tests/dict2.test b/tests/dict2.test index 493cf91..2a36dc1 100644 --- a/tests/dict2.test +++ b/tests/dict2.test @@ -316,14 +316,14 @@ test dict-11.9 {dict incr command} -returnCodes error -body { dict-sort $dictv } -cleanup { unset dictv -} -result {expected integer but got "dummy"} +} -match glob -result {expected integer *but got "dummy"} test dict-11.10 {dict incr command} -returnCodes error -body { set dictv {a 1} dict incr dictv a dummy dict-sort $dictv } -cleanup { unset dictv -} -result {expected integer but got "dummy"} +} -match glob -result {expected integer *but got "dummy"} test dict-11.11 {dict incr command} -setup { unset -nocomplain dictv } -body { diff --git a/tests/jim.test b/tests/jim.test index ba76879..79cbd8d 100644 --- a/tests/jim.test +++ b/tests/jim.test @@ -1269,11 +1269,10 @@ test incr-1.23 {TclCompileIncrCmd: increment given, formatted int != int} { set i 25 incr i 000012345 ;# a decimal literal } 12370 -test incr-1.24 {TclCompileIncrCmd: increment given, formatted int != int} { +test incr-1.24 {TclCompileIncrCmd: increment given, formatted int != int} -body { set i 25 - catch {incr i 1a} msg - set msg -} {expected integer but got "1a"} + incr i 1a +} -returnCodes error -match glob -result {expected integer *but got "1a"} test incr-1.25 {TclCompileIncrCmd: too many arguments} { set i 10 @@ -1282,10 +1281,10 @@ test incr-1.25 {TclCompileIncrCmd: too many arguments} { } {wrong # args: should be "incr varName ?increment?"} -test incr-1.29 {TclCompileIncrCmd: runtime error, bad variable value} { +test incr-1.29 {TclCompileIncrCmd: runtime error, bad variable value} -body { set x " - " - list [catch {incr x 1} msg] $msg -} {1 {expected integer but got " - "}} + incr x 1 +} -returnCodes error -match glob -result {expected integer *but got " - "} test incr-1.30 {TclCompileIncrCmd: array var, braced (no subs)} { catch {unset array} @@ -1488,12 +1487,11 @@ test incr-2.23 {incr command (not compiled): increment given, formatted int != i set i 25 $z i 000012345 ;# an octal literal } 12370 -test incr-2.24 {incr command (not compiled): increment given, formatted int != int} { +test incr-2.24 {incr command (not compiled): increment given, formatted int != int} -body { set z incr set i 25 - catch {$z i 1a} msg - set msg -} {expected integer but got "1a"} + $z i 1a +} -returnCodes error -match glob -result {expected integer *but got "1a"} test incr-2.25 {incr command (not compiled): too many arguments} { set z incr @@ -1502,11 +1500,11 @@ test incr-2.25 {incr command (not compiled): too many arguments} { set msg } {wrong # args: should be "incr varName ?increment?"} -test incr-2.29 {incr command (not compiled): runtime error, bad variable value} { +test incr-2.29 {incr command (not compiled): runtime error, bad variable value} -body { set z incr set x " - " - list [catch {$z x 1} msg] $msg -} {1 {expected integer but got " - "}} + $z x 1 +} -returnCodes error -match glob -result {expected integer *but got " - "} ################################################################################ # LLENGTH @@ -3433,15 +3431,15 @@ test range-6.1 {range} -body { test range-6.2 {range} -body { range foo -} -returnCodes error -result {expected integer but got "foo"} +} -returnCodes error -match glob -result {expected integer *but got "foo"} test range-6.3 {range} -body { range 2 bar -} -returnCodes error -result {expected integer but got "bar"} +} -returnCodes error -match glob -result {expected integer *but got "bar"} test range-6.4 {range} -body { range 2 4 foo -} -returnCodes error -result {expected integer but got "foo"} +} -returnCodes error -match glob -result {expected integer *but got "foo"} test range-6.5 {range} -body { range 10 0 diff --git a/tests/pack.test b/tests/pack.test index d059087..0746e44 100644 --- a/tests/pack.test +++ b/tests/pack.test @@ -12,7 +12,7 @@ test pack-1.2 {pack invalid type} -body { test pack-1.3 {pack bad width} -body { pack a 1 -intbe badint -} -returnCodes error -result {expected integer but got "badint"} +} -returnCodes error -match glob -result {expected integer *but got "badint"} test pack-1.4 {pack bad width} -body { pack a 1 -intbe -5 @@ -20,7 +20,7 @@ test pack-1.4 {pack bad width} -body { test pack-1.5 {pack bad offset} -body { pack a 1 -intbe 5 badint -} -returnCodes error -result {expected integer but got "badint"} +} -returnCodes error -match glob -result {expected integer *but got "badint"} test pack-1.6 {pack bad offset} -body { pack a 1 -intbe 5 -6 @@ -78,7 +78,7 @@ test unpack-1.2 {unpack invalid type} -body { test unpack-1.3 {unpack bad width} -body { unpack abc -intle 0 badint -} -returnCodes error -result {expected integer but got "badint"} +} -returnCodes error -match glob -result {expected integer *but got "badint"} test unpack-1.4 {unpack bad width} -body { unpack abc -intle 0 -5 @@ -86,7 +86,7 @@ test unpack-1.4 {unpack bad width} -body { test unpack-1.5 {unpack bad offset} -body { unpack abc -intle badint 8 -} -returnCodes error -result {expected integer but got "badint"} +} -returnCodes error -match glob -result {expected integer *but got "badint"} test unpack-1.6 {unpack bad offset} -body { unpack abc -intle -6 8 |