New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
:= doesn't work as expected #157
Comments
Confirmed on all versions of ksh93 down to s+ 1993-12-28 through ksh2020. Anther one that is going to be challenging to track down... Thanks for the report. |
Let's try:
Why should we expect for integer b to expand to its value and not to the string "b"? The status of "a" after |
Agreed, we should not expect the variable b to have its value of 42 expanded as the b in However, I did some testing and it appears that the variable expansion of $ ksh -c 'typeset -i a; typeset -p a; echo ${a:=42}; typeset -p a'
typeset -i a
0
typeset -i a
$ ksh -c 'typeset -F a; typeset -p a; echo ${a:=42}; typeset -p a'
typeset -F a
0
typeset -F a
$ ksh -c 'typeset -E a; typeset -p a; echo ${a:=42}; typeset -p a'
typeset -E a
0
typeset -E a
$ ksh -c 'typeset -X a; typeset -p a; echo ${a:=42}; typeset -p a'
typeset -X 32 a
0
typeset -X 32 a When the variable is text, it works as expected which @saper has shown above. $ ksh -c 'typeset a=; typeset -p a; echo ${a:=42}; typeset -p a'
a=''
42
a=42 |
I do not agree, because in the reproducer, that variable has been declared an integer with Compare with mksh, which does this right:
|
I think we should more careful here... I don't think that declaring a variable with p. 136 of The New Kornshell explains "Arithmetic Expressions" lists situations where the arithmetic expression can be used (such as ((...)), let etc. etc.) but there is no mention of parameter expansion here. p.137 says "If a variable in an arithmetic expression has the integer attribute (see attributes on page 178), then ksh uses the value of the variable". Then we have p.157 which is I think is the most important page in the book and it says:
So definitely "parameter expansion" is done before any arithmetic expansion. And in this context, p. 158 "Arithmetic expansion" explains that
Therefore I don't think the following applies:
Arithmetic expansion can be done only with $((...)) during the command processing stage according to page 158. I think the problem is that |
@saper Totally irrelevant. The rule that applies here is that Besides it wouldn't make any sense if |
|
KornShell book, "Attributes" chapter, section "-i or -ibase Integer", p. 178: "Whenever you assign a value to a variable, the value is evaluated as an arithmetic integer expression." The manual page (sh.1), section Parameter Expansion: "If any of the floating point attributes,
We did; the integer attribute tells ksh to automatically evaluate every value as an arithmetic expression. Arithmetic expressions are C-style and do not need |
Huh.. not judging whether it's good or bad, but IMHO that's counter intuitive and makes reading code harder, because one needs to know the type of the assignee in order to understand how the value is evaluated... Also, it behaves very unlike posix for a syntax which is well defined in posix - and depends on the type of the var which might have been set elsewhere at the code... |
@avih Actually, POSIX leaves room for such extensions.
|
This is going off topic, but I was referring only to what I quoted, not the The FWIW, this behavior, e.g. |
Right. There's no need to disable this in POSIX mode because There is one shell with a POSIX mode that tries to disable almost everything not specified by POSIX: yash. All the other shells with a POSIX mode (bash, mksh, zsh, and now ksh 93u+m) make the minimum adaptations necessary to avoid violating the standard so they are compatible with pure POSIX scripts, but they do not disable extensions. |
@McDutchie - you are right. That means that whenever radziecki> typeset -i a; a="2+2"
radziecki> echo $a
4 Now I begin to think that problem is somewhere else: radziecki> set -o nounset
radziecki> typeset -i a
radziecki> echo "${a}"
ksh93: a: parameter not set
radziecki> echo "${a?please set a}"
0
radziecki> echo "${a:?please give a value}"
0
radziecki> echo "${b:?please give b value}"
ksh93: b: please give b value
radziecki> echo "${b?please set b}"
ksh93: b: please set b
radziecki> echo "${b+xx}"
radziecki> echo "${a+xx}"
Looks like sometimes (? modifier, :? modifier, := modifier) |
I agree. The POSIX shell is fundamentally a typeless language in which variables are simple strings. ksh tacked types on top of it, which inevitably causes some unintuitive behaviour. However, it's been this way ever since there has been |
Good testing there. I agree this may give a clue to the cause of the bug. It will be a while before I can get to hunting this one down properly. In the meantime, if anyone else feels so called, please go right ahead. |
The root cause is that this check in Lines 1405 to 1408 in f8f2c4b
This only checks if the pointer is non-null, which is true if this diff --git a/src/cmd/ksh93/sh/macro.c b/src/cmd/ksh93/sh/macro.c
index 545d09a5..c750a6f2 100644
--- a/src/cmd/ksh93/sh/macro.c
+++ b/src/cmd/ksh93/sh/macro.c
@@ -1405,7 +1405,7 @@ retry1:
/*
* Check if the parameter is set or unset.
*/
- if(np && (type==M_TREE || !c || !ap))
+ if(np && !nv_isnull(np) && (type==M_TREE || !c || !ap))
{
/* The parameter is set. */
char *savptr; With this diff, the reproducer works as expected:
However, several regressions show up when running
So, the hunt continues. |
The functions.sh and variables.sh regressions reminded me of commit 9529441. Sure enough, those two are solved by moving the The other two regressions are solved by only checking for a non-null value if the expansion is of a regular With the diff below, it now all works for me. diff --git a/src/cmd/ksh93/sh/macro.c b/src/cmd/ksh93/sh/macro.c
index 545d09a5..3f7f6949 100644
--- a/src/cmd/ksh93/sh/macro.c
+++ b/src/cmd/ksh93/sh/macro.c
@@ -1405,9 +1405,13 @@ retry1:
/*
* Check if the parameter is set or unset.
*/
- if(np && (type==M_TREE || !c || !ap))
+#if SHOPT_OPTIMIZE
+ if(np && type==M_BRACE && mp->shp->argaddr)
+ nv_optimize(np); /* needed before calling nv_isnull() */
+#endif /* SHOPT_OPTIMIZE */
+ if(np && (type==M_BRACE ? !nv_isnull(np) : (type==M_TREE || !c || !ap)))
{
- /* The parameter is set. */
+ /* Either the parameter is set, or it's a special type of expansion where 'unset' doesn't apply. */
char *savptr;
c = *((unsigned char*)stkptr(stkp,offset-1));
savptr = stkfreeze(stkp,0);
@@ -1443,13 +1447,7 @@ retry1:
if(ap)
v = nv_arrayisset(np,ap)?(char*)"x":0;
else
- {
-#if SHOPT_OPTIMIZE
- if(mp->shp->argaddr)
- nv_optimize(np); /* avoid BUG_ISSETLOOP */
-#endif /* SHOPT_OPTIMIZE */
v = nv_isnull(np)?0:(char*)"x";
- }
}
else
v = nv_getval(np); |
@McDutchie Can't find a flaw, thanks for the fix |
This works fine on mksh, and partly on bash.
The text was updated successfully, but these errors were encountered: