summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2024-06-12 00:17:18 (GMT)
committersebres <sebres@users.sourceforge.net>2024-06-12 00:17:18 (GMT)
commit9cca6cadd9fb96e7e52c48a1e9885bb9ca3c417d (patch)
treee26e5a806e56720bc90c686a70462be9c8229b0f
parent88a04f641970ef62f7e81a88ccddd914e16c38a0 (diff)
parent57f3d0d139f13955e69bbc6833d6ad01b9983396 (diff)
downloadtcl-9cca6cadd9fb96e7e52c48a1e9885bb9ca3c417d.zip
tcl-9cca6cadd9fb96e7e52c48a1e9885bb9ca3c417d.tar.gz
tcl-9cca6cadd9fb96e7e52c48a1e9885bb9ca3c417d.tar.bz2
merge 8.7 (fix for [f05f5ef759c1f7f9])
-rw-r--r--generic/tclCmdIL.c136
-rw-r--r--tests/lseq.test26
2 files changed, 89 insertions, 73 deletions
diff --git a/generic/tclCmdIL.c b/generic/tclCmdIL.c
index 83320cd..ad8eb94 100644
--- a/generic/tclCmdIL.c
+++ b/generic/tclCmdIL.c
@@ -105,12 +105,8 @@ static const char *const seq_operations[] = {
typedef enum Sequence_Operators {
LSEQ_DOTS, LSEQ_TO, LSEQ_COUNT, LSEQ_BY
} SequenceOperators;
-static const char *const seq_step_keywords[] = {"by", NULL};
-typedef enum Step_Operators {
- STEP_BY = 4
-} SequenceByMode;
typedef enum Sequence_Decoded {
- NoneArg, NumericArg, RangeKeywordArg, ByKeywordArg
+ NoneArg, NumericArg, RangeKeywordArg
} SequenceDecoded;
/*
@@ -4027,7 +4023,7 @@ Tcl_LsearchObjCmd(
* 3 - value is a by keyword
*
* The decoded value will be assigned to the appropriate
- * pointer, if supplied.
+ * pointer, numValuePtr reference count is incremented.
*/
static SequenceDecoded
@@ -4037,71 +4033,45 @@ SequenceIdentifyArgument(
Tcl_Obj **numValuePtr, /* Return numeric value */
int *keywordIndexPtr) /* Return keyword enum */
{
- int status;
+ int result;
SequenceOperators opmode;
- SequenceByMode bymode;
- void *clientData;
+ void *internalPtr;
- status = Tcl_GetNumberFromObj(NULL, argPtr, &clientData, keywordIndexPtr);
- if (status == TCL_OK) {
- if (numValuePtr) {
- *numValuePtr = argPtr;
- }
+ result = Tcl_GetNumberFromObj(NULL, argPtr, &internalPtr, keywordIndexPtr);
+ if (result == TCL_OK) {
+ *numValuePtr = argPtr;
+ Tcl_IncrRefCount(argPtr);
return NumericArg;
+ }
+
+ result = Tcl_GetIndexFromObj(NULL, argPtr, seq_operations,
+ "range operation", 0, &opmode);
+ if (result == TCL_OK) {
+ *keywordIndexPtr = opmode;
+ return RangeKeywordArg;
} else {
/* Check for an index expression */
- long value;
- double dvalue;
+ SequenceDecoded ret = NoneArg;
Tcl_Obj *exprValueObj;
int keyword;
Tcl_InterpState savedstate;
- savedstate = Tcl_SaveInterpState(interp, status);
- if (Tcl_ExprLongObj(interp, argPtr, &value) != TCL_OK) {
- status = Tcl_RestoreInterpState(interp, savedstate);
- exprValueObj = argPtr;
- } else {
- // Determine if expression is double or int
- if (Tcl_ExprDoubleObj(interp, argPtr, &dvalue) != TCL_OK) {
- keyword = TCL_NUMBER_INT;
- exprValueObj = argPtr;
- } else {
- if (floor(dvalue) == dvalue) {
- TclNewIntObj(exprValueObj, value);
- keyword = TCL_NUMBER_INT;
- } else {
- TclNewDoubleObj(exprValueObj, dvalue);
- keyword = TCL_NUMBER_DOUBLE;
- }
- }
- status = Tcl_RestoreInterpState(interp, savedstate);
- if (numValuePtr) {
- *numValuePtr = exprValueObj;
- }
- if (keywordIndexPtr) {
- *keywordIndexPtr = keyword ;// type of expression result
- }
- return NumericArg;
- }
- }
-
- status = Tcl_GetIndexFromObj(NULL, argPtr, seq_operations,
- "range operation", 0, &opmode);
- if (status == TCL_OK) {
- if (keywordIndexPtr) {
- *keywordIndexPtr = opmode;
+ savedstate = Tcl_SaveInterpState(interp, result);
+ if (Tcl_ExprObj(interp, argPtr, &exprValueObj) != TCL_OK) {
+ goto done;
}
- return RangeKeywordArg;
- }
-
- status = Tcl_GetIndexFromObj(NULL, argPtr, seq_step_keywords,
- "step keyword", 0, &bymode);
- if (status == TCL_OK) {
- if (keywordIndexPtr) {
- *keywordIndexPtr = bymode;
+ /* Determine if result of expression is double or int */
+ if (Tcl_GetNumberFromObj(NULL, exprValueObj, &internalPtr,
+ &keyword) != TCL_OK
+ ) {
+ goto done;
}
- return ByKeywordArg;
+ *numValuePtr = exprValueObj; /* incremented in Tcl_ExprObj */
+ *keywordIndexPtr = keyword; /* type of expression result */
+ ret = NumericArg;
+ done:
+ (void)Tcl_RestoreInterpState(interp, savedstate);
+ return ret;
}
- return NoneArg;
}
/*
@@ -4157,9 +4127,9 @@ Tcl_LseqObjCmd(
SequenceOperators opmode;
SequenceDecoded decoded;
int i, arg_key = 0, value_i = 0;
- // Default constants
- Tcl_Obj *zero = Tcl_NewIntObj(0);
- Tcl_Obj *one = Tcl_NewIntObj(1);
+ /* Default constants */
+ #define zero ((Interp *)interp)->execEnvPtr->constants[0];
+ #define one ((Interp *)interp)->execEnvPtr->constants[1];
/*
* Create a decoding key by looping through the arguments and identify
@@ -4187,7 +4157,6 @@ Tcl_LseqObjCmd(
case NumericArg:
arg_key += NumericArg;
numValues[value_i] = numberObj;
- Tcl_IncrRefCount(numValues[value_i]);
values[value_i] = keyword; // This is the TCL_NUMBER_* value
useDoubles = useDoubles ? useDoubles : keyword == TCL_NUMBER_DOUBLE;
value_i++;
@@ -4199,12 +4168,6 @@ Tcl_LseqObjCmd(
value_i++;
break;
- case ByKeywordArg:
- arg_key += ByKeywordArg;
- values[value_i] = keyword;
- value_i++;
- break;
-
default:
arg_key += 9; // Error state
value_i++;
@@ -4379,6 +4342,27 @@ Tcl_LseqObjCmd(
break;
}
+ /* Count needs to be integer, so try to convert if possible */
+ if (elementCount && TclHasInternalRep(elementCount, &tclDoubleType)) {
+ double d;
+ (void)Tcl_GetDoubleFromObj(NULL, elementCount, &d);
+ if (floor(d) == d) {
+ if ((d >= (double)WIDE_MAX) || (d <= (double)WIDE_MIN)) {
+ mp_int big;
+
+ if (Tcl_InitBignumFromDouble(NULL, d, &big) == TCL_OK) {
+ elementCount = Tcl_NewBignumObj(&big);
+ keyword = TCL_NUMBER_INT;
+ }
+ /* Infinity, don't convert, let fail later */
+ } else {
+ elementCount = Tcl_NewWideIntObj((Tcl_WideInt)d);
+ keyword = TCL_NUMBER_INT;
+ }
+ }
+ }
+
+
/*
* Success! Now lets create the series object.
*/
@@ -4393,13 +4377,19 @@ Tcl_LseqObjCmd(
// Free number arguments.
while (--value_i>=0) {
if (numValues[value_i]) {
+ if (elementCount == numValues[value_i]) {
+ elementCount = NULL;
+ }
Tcl_DecrRefCount(numValues[value_i]);
}
}
+ if (elementCount) {
+ Tcl_DecrRefCount(elementCount);
+ }
- // Free constants
- Tcl_DecrRefCount(zero);
- Tcl_DecrRefCount(one);
+ /* Undef constants */
+ #undef zero
+ #undef one
return status;
}
diff --git a/tests/lseq.test b/tests/lseq.test
index feb0a29..569af95 100644
--- a/tests/lseq.test
+++ b/tests/lseq.test
@@ -140,6 +140,19 @@ test lseq-1.22 {n n by -n} {
lseq 84 66 by -3
} {84 81 78 75 72 69 66}
+test lseq-1.23 {consistence, accept double count representable as integer (but use double in series)} {
+ list [lseq 0.0 2.0] [lseq 3.0] [lseq 0 count 3.0] \
+ [lseq 0.0 count 3.0] [lseq 0 count 3.0 by 1.0]
+} [lrepeat 5 {0.0 1.0 2.0}]
+test lseq-1.24 {consistence, use double (even if representable as integer) in all variants, if contains a double somewhere} {
+ list [lseq 0.0 2] [lseq 0 2.0] [lseq 0.0 count 3] \
+ [lseq 0 count 3 by 1.0] [lseq 0 .. 2.0] [lseq 0 to 2 by 1.0]
+} [lrepeat 6 {0.0 1.0 2.0}]
+test lseq-1.25 {consistence, use double (even if representable as integer) in all variants, if contains a double somewhere} {
+ list [lseq double(0) 2] [lseq 0 double(2)] [lseq double(0) count 3] \
+ [lseq 0 count 3 by double(1)] [lseq 0 .. double(2)] [lseq 0 to 2 by double(1)]
+} [lrepeat 6 {0.0 1.0 2.0}]
+
#
# Short-hand use cases
#
@@ -221,6 +234,19 @@ test lseq-2.18 {signs} {
} {{-10 -8 -6 -4 -2} {} {} {10 6 2} {-10 -7 -4 -1} {10 5}}
+test lseq-2.19 {expressions as indices} {
+ list [lseq {1+1}] \
+ [lseq {1+1} {2+2}] \
+ [lseq {1+1} count {2+2}] \
+ [lseq {1+1} {5+5} {2+2}] \
+ [lseq {1+1} count {2+2} by {2+2}]
+} {{0 1} {2 3 4} {2 3 4 5} {2 6 10} {2 6 10 14}}
+
+test lseq-2.20 {expressions as indices, no duplicative eval of expr} {
+ set i 1
+ list [lseq {[incr i]}] $i [lseq {0 + [incr i]}] $i [lseq {0.0 + [incr i]}] $i
+} {{0 1} 2 {0 1 2} 3 {0.0 1.0 2.0 3.0} 4}
+
test lseq-3.1 {experiement} -body {
set ans {}
foreach factor [lseq 2.0 10.0] {