Skip to content
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

Port illumos' shell linter improvements #353

Merged
merged 9 commits into from
Nov 30, 2021
Merged

Conversation

JohnoKing
Copy link

This pull request ports over two improvements to the shell linter from illumos (original patch written by Andy Fiddaman). Links to the relevant bug reports and the original patch:
https://www.illumos.org/issues/13601
https://www.illumos.org/issues/13631
illumos/illumos-gate@c7b656f

The first improvement is to the lint warning for arithmetic operators in [[ ... ]]. The ksh linter now suggests the correct equivalent operator to use in ((...)). Example:

# Original warning
$ ksh -nc '[[ 30 -gt 25 ]]'
ksh: warning: line 1: -gt within [[ ... ]] obsolete, use ((...))

# New warning
$ arch/*/bin/ksh -nc '[[ 30 -gt 25 ]]'
arch/linux.i386-64/bin/ksh: warning: line 1: [[ ... -gt ... ]] obsolete, use ((... > ...))

The second improvement pertains to variable expansion in arithmetic expressions. The ksh linter now suggests referencing variable names directly:

# Old warning
$ ksh -nc 'integer foo=40; (($foo < 50 ))'
ksh: warning: line 1: variable expansion makes arithmetic evaluation less efficient

# New warning
$ arch/*/bin/ksh -nc 'integer foo=40; (($foo < 50 ))'
arch/linux.i386-64/bin/ksh: warning: line 1: in '(($foo < 50))', using '$' is unnecessary, incurs a penalty and can introduce rounding errors

src/cmd/ksh93/{data/lexstates,sh/lex,sh/parse}.c:
- Port the improved shell lint warnings from illumos to ksh93u+m.
- The original checks for arithmetic operators involved a bunch of if statements with inefficient calls to strcmp. These were replaced with a more efficient switch statement that avoids strcmp.

This commit ports over two improvements to the shell linter from illumos
(original patch written by Andy Fiddaman). Links to the relevant bug
reports and the original patch:
https://www.illumos.org/issues/13601
https://www.illumos.org/issues/13631
illumos/illumos-gate@c7b656f

The first improvement is to the lint warning for arithmetic operators in
[[ ... ]]. The ksh linter now suggests the correct equivalent operator
to use in ((...)). Example:
  $ ksh -nc '[[ 30 -gt 25 ]]'
  # Original warning
  warning: line 1: -gt within [[ ... ]] obsolete, use ((...))
  # New warning
  warning: line 1: [[ ... -gt ... ]] obsolete, use ((... > ...))

The second improvement pertains to variable expansion in arithmetic
expressions. The ksh linter now suggests referencing variable names
directly:
  $ ksh -nc 'integer foo=40; (($foo < 50 ))'
  # Old warning
  warning: line 1: variable expansion makes arithmetic evaluation less efficient
  # New warning
  warning: line 1: in '(($foo < 50))', using '$' is unnecessary, incurs a penalty and can introduce rounding errors

src/cmd/ksh93/{data/lexstates,sh/lex,sh/parse}.c:
- Port the improved shell lint warnings from illumos to ksh93u+m.
- The original checks for arithmetic operators involved a bunch of if
  statements with inefficient calls to strcmp(3). These were replaced
  with a more efficient switch statement that avoids strcmp.
@hyenias
Copy link

hyenias commented Nov 28, 2021

Here is a further optimization if you wish. When I examined src/cmd/ksh93/include/test.h, all the six TESTs aligned up in a row thus an array can be employed avoiding all the branching just need to substract 36 (octal 040+4=36) to adjust to position 0.

#define TEST_ARITH 040 /* arithmetic operators */
#define TEST_ANDOR 0200 /* logical operators: -a, -o */
#define TEST_STRCMP 0100 /* literal string comparison; turn off bit for pattern matching */
#define TEST_NE (TEST_ARITH|9)
#define TEST_EQ (TEST_ARITH|4)
#define TEST_GE (TEST_ARITH|5)
#define TEST_GT (TEST_ARITH|6)
#define TEST_LE (TEST_ARITH|7)
#define TEST_LT (TEST_ARITH|8)

TEST_EQ		(TEST_ARITH|4) // pos0
TEST_GE		(TEST_ARITH|5) // pos1
TEST_GT		(TEST_ARITH|6) // pos2
TEST_LE		(TEST_ARITH|7) // pos3
TEST_LT		(TEST_ARITH|8) // pos4
TEST_NE		(TEST_ARITH|9) // pos5
diff --git a/NEWS b/NEWS
index 613058d..014bad5 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,11 @@ For full details, see the git log at: https://github.com/ksh93/ksh

 Any uppercase BUG_* names are modernish shell bug IDs.

+2021-11-28:
+
+- The shell linter's warnings for obsolete arithmetic operators in [[ ... ]]
+  and unnecessary variable expansion in ((...)) have been improved.
+
 2021-11-24:

 - The --posix mode was amended to stop the '.' command (but not 'source') from
diff --git a/src/cmd/ksh93/data/lexstates.c b/src/cmd/ksh93/data/lexstates.c
index 2465e26..bf490fe 100644
--- a/src/cmd/ksh93/data/lexstates.c
+++ b/src/cmd/ksh93/data/lexstates.c
@@ -430,13 +430,13 @@ const char e_lexsyntax2[]	= "syntax error: `%s' %s";
 const char e_lexsyntax3[]	= "syntax error at line %d: duplicate label %s";
 const char e_lexsyntax4[]	= "syntax error at line %d: invalid reference list";
 const char e_lexsyntax5[]	= "syntax error at line %d: `<<%s' here-document not contained within command substitution";
-const char e_lexwarnvar[]	= "line %d: variable expansion makes arithmetic evaluation less efficient";
+const char e_lexwarnvar[]	= "line %d: in '((%s))', using '$' is unnecessary, incurs a penalty and can introduce rounding errors";
 const char e_lexlabignore[]	= "line %d: label %s ignored";
 const char e_lexlabunknown[]	= "line %d: %s unknown label";
 const char e_lexobsolete1[]	= "line %d: `...` obsolete, use $(...)";
 const char e_lexobsolete2[]	= "line %d: -a obsolete, use -e";
 const char e_lexobsolete3[]	= "line %d: '=' obsolete, use '=='";
-const char e_lexobsolete4[]	= "line %d: %s within [[ ... ]] obsolete, use ((...))";
+const char e_lexobsolete4[]	= "line %d: [[ ... %s ... ]] obsolete, use ((... %s ...))";
 const char e_lexobsolete5[]	= "line %d: set %s obsolete";
 const char e_lexobsolete6[]	= "line %d: `{' instead of `in' is obsolete";
 const char e_lexusebrace[]	= "line %d: use braces to avoid ambiguities with $id[...]";
diff --git a/src/cmd/ksh93/include/version.h b/src/cmd/ksh93/include/version.h
index 6b18caf..2d48982 100644
--- a/src/cmd/ksh93/include/version.h
+++ b/src/cmd/ksh93/include/version.h
@@ -21,7 +21,7 @@

 #define SH_RELEASE_FORK	"93u+m"		/* only change if you develop a new ksh93 fork */
 #define SH_RELEASE_SVER	"1.1.0-alpha"	/* semantic version number: https://semver.org */
-#define SH_RELEASE_DATE	"2021-11-24"	/* must be in this format for $((.sh.version)) */
+#define SH_RELEASE_DATE	"2021-11-28"	/* must be in this format for $((.sh.version)) */
 #define SH_RELEASE_CPYR	"(c) 2020-2021 Contributors to ksh " SH_RELEASE_FORK

 /* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */
diff --git a/src/cmd/ksh93/sh/lex.c b/src/cmd/ksh93/sh/lex.c
index c30c2d8..0fd25f1 100644
--- a/src/cmd/ksh93/sh/lex.c
+++ b/src/cmd/ksh93/sh/lex.c
@@ -1435,7 +1435,11 @@ breakloop:
 			if(lp->lex.testop2)
 			{
 				if(lp->lexd.warn && (c&TEST_ARITH))
-					errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete4,shp->inlineno,state);
+				{
+					/* test.h: octal 040+4=36, (TEST_EQ, TEST_GE, TEST_GT, TEST_LE, TEST_LT, TEST_NE) */
+					static const char *alt[] = { "==", ">=", ">", "<=", "<", "!=" };
+					errormsg(SH_DICT, ERROR_warn(0), e_lexobsolete4, shp->inlineno, state, alt[c-36]);
+				}
 				if(c&TEST_STRCMP)
 					lp->lex.incase = 1;
 				else if(c==TEST_REP)
diff --git a/src/cmd/ksh93/sh/parse.c b/src/cmd/ksh93/sh/parse.c
index 7f55ce5..74c5a75 100644
--- a/src/cmd/ksh93/sh/parse.c
+++ b/src/cmd/ksh93/sh/parse.c
@@ -304,7 +304,7 @@ static Shnode_t *getanode(Lex_t *lp, struct argnod *ap)
 	else
 	{
 		if(sh_isoption(SH_NOEXEC) && (ap->argflag&ARG_MAC) && paramsub(ap->argval))
-			errormsg(SH_DICT,ERROR_warn(0),e_lexwarnvar,lp->sh->inlineno);
+			errormsg(SH_DICT,ERROR_warn(0),e_lexwarnvar,lp->sh->inlineno,ap->argval);
 		t->ar.arcomp = 0;
 	}
 	return(t);

@JohnoKing JohnoKing changed the title Port illumos' improvements to the shell linter Port illumos' shell linter improvements Nov 28, 2021
@McDutchie
Copy link

McDutchie commented Nov 29, 2021

I prefer the illumos version @JohnoKing's version. Assuming literal numeric values from macros in headers such as test.h defeats the purpose of those macros. We should be able to change those values in the header and things should just keep working without having to hunt down assumptions in unrelated parts of the code. Plus, any performance gain is probably not even negligible, but rather nonexistent: optimising compilers translate the switch block into assembly code that does what you have done manually. So you've obfuscated the code for no gain at all.

@McDutchie
Copy link

Here's some relevant reading: From Switch Statement Down to Machine Code

This commit also adds some comments to improve readability.
@JohnoKing
Copy link
Author

Assuming literal numeric values from macros in headers such as test.h defeats the purpose of those macros. We should be able to change those values in the header and things should just keep working without having to hunt down assumptions in unrelated parts of the code.

Good point. I'll revert the patch to use a more readable switch statement.

Plus, any performance gain is probably not even negligible, but rather nonexistent: optimising compilers translate the switch block into assembly code that does what you have done manually. So you've obfuscated the code for no gain at all.

The performance gain probably is negligible, but any performance gain to be had isn't from using a switch block (I'm well aware that has no notable impact on the assembly code). Rather, any minor gains comes from avoiding string comparison. The illumos patch is very readable, but I think a switch statement that uses the TEST_* macros is also very readable and avoids the unnecessary cost of using strcmp (I'll add some comments though to improve readability).

@McDutchie
Copy link

Right, that was actually your version I prefer, sorry about that. I hadn't actually looked at the illumos version. Even though compilers do inline and optimize strcmp(3) calls too, using the TEST_* macros is still better for the sake of having a single source of truth for these operators.

@McDutchie
Copy link

warning: line 1: in '(($foo < 50))', using '$' is unnecessary, incurs a penalty and can introduce rounding errors

I've two comments about that warning:

  1. What does "incurs a penalty" mean? If it means using $ is slower, it should say it's slower.
  2. Can it actually introduce rounding errors? It makes sense in theory but I've been trying to reproduce a rounding error without success. Any ideas on how to reproduce that? (Also ping @citrus-it)

@McDutchie
Copy link

Here's the script I used to try to produce a rounding error. The minimum value representable in ksh arithmetic is 0.00000000000000001. Add a zero and it rounds to zero. So you'd think adding that value repeatedly should eventually result in a rounding error, but the decimal fraction keeps corresponding to the number of iterations.

check()
{
	print -n "i==$i x==$x"
	tr=$i
	while [[ $tr == *0 ]]; do tr=${tr%0}; done
	[[ $x == *"$tr" ]] || print -n " <=== ROUNDING ERROR"
	print
		
}
LC_NUMERIC=C
#typeset -F17 x y
x="1.00000000000000000"
y="0.00000000000000001"
integer i=0
(
	trap 'check' USR1
	while ((++i)); do
		x=$(( $x + $y ))
		#(( x += y ))
	done
) &
trap 'kill %1' EXIT
while sleep 1; do
	kill -s USR1 %1
done

A fragment of output on my system:

i==4586737 x==1.00000000004586737
i==4844408 x==1.00000000004844408
i==5105807 x==1.00000000005105807
i==5362246 x==1.00000000005362246
i==5617906 x==1.00000000005617906
i==5875580 x==1.00000000005875579 <=== ROUNDING ERROR
i==6134937 x==1.00000000006134937
i==6387959 x==1.00000000006387959
i==6642825 x==1.00000000006642825
i==6897117 x==1.00000000006897117

Very occasionally a rounding error occurs. But it does not propagate. Each iteration's value depends on the previous one being correct, so it must be an output problem only.

What's more, if we replace the x=$(( $x + $y )) with a pure arithmetic expression (( x += y )), then the exact same phenomenon occurs. It makes no difference at all.

Now, if we declare typeset -F17 x y at the beginning, then rounding errors definitely occur with the dollar sign variant:

i==113052 x==1.00000000000000000 <=== ROUNDING ERROR
i==224975 x==1.00000000000000000 <=== ROUNDING ERROR
i==336516 x==1.00000000000000000 <=== ROUNDING ERROR
i==448383 x==1.00000000000000000 <=== ROUNDING ERROR
i==555898 x==1.00000000000000000 <=== ROUNDING ERROR

But again, it makes no difference whether you use the dreaded dollar sign or not; the results are identical, except the values increase a great deal faster with the float declaration (supporting the performance argument).

i==1703078 x==1.00000000000000000 <=== ROUNDING ERROR
i==3392112 x==1.00000000000000000 <=== ROUNDING ERROR
i==5060350 x==1.00000000000000000 <=== ROUNDING ERROR
i==6736878 x==1.00000000000000000 <=== ROUNDING ERROR
i==8423613 x==1.00000000000000000 <=== ROUNDING ERROR

So, I want to see some actual evidence that this warning is correct before committing it.

@citrus-it
Copy link

warning: line 1: in '(($foo < 50))', using '$' is unnecessary, incurs a penalty and can introduce rounding errors

I've two comments about that warning:

  1. What does "incurs a penalty" mean? If it means using $ is slower, it should say it's slower.
  2. Can it actually introduce rounding errors? It makes sense in theory but I've been trying to reproduce a rounding error without success. Any ideas on how to reproduce that? (Also ping @citrus-it)

The wording there was based on the OpenSolaris shell guide (which I think was originally written by Roland Mainz) - there's a copy at http://www.fiddaman.net/shell/#avoid_unnecessary_string_number_conversions

@hyenias
Copy link

hyenias commented Nov 29, 2021

I can provide evidence along with other detail.

@hyenias
Copy link

hyenias commented Nov 30, 2021

I will try to provide some evidence to help understand what is going on when working with ksh floats and how that relates to ((...))s. I cannot explain it all and I am sure I will skip over something but the following I believe should help people understand that generally avoiding a $ variable expansion from within an arithmetic expression, ((...)), results in less work with more precise results as most people only want to round as the last step if at all.

using '$' is unnecessary, incurs a penalty and can introduce rounding errors

The $ var_name causes ksh to perform variable expansion and insert that rounding result using the $var_name's applied or defaulted precision into the arithmetic expression as a literal. Default precision for a -F is 10 decimal places. On my x86_64 and aarch64 systems -F is a C 64bit double. `-lF' on my Intel x86_64 machines are 80bit long doubles whereas on my arrach64 systems they use 128-bit long doubles. ksh uses long doubles as default and for literals. One has to define and use other datatypes expressly which I will show later on.

using '$' is unnecessary

I do not agree 100% with this part as the coder may want to round a numeric value to a certain precision.

incurs a penalty and can introduce rounding errors

Let me provide some insights:

For a typeset -F float number (aka C double), one should be not exceed a decimal point precision of 15. Depending on the floating point representation of the number, the remaining bits may not provide back a quality 16th, 17th, or 18th decimal value. As you approach the lower limit of a 64bit double float, your mileage is going to vary to an ever increasing extent as there is simply not enough bits left to interpret to a near decimal.

In ksh, if you want to dump out the full decimal representation of a float numeric then issue $((var_name)).

# On x86_64
$ unset x; typeset -F10 x=2./3; typeset -p x; printf '%s\n' _.123456789012345678901234567890123 $x $((x))
typeset -F x=0.6666666667
_.123456789012345678901234567890123
0.6666666667
0.66666666666666663
$ unset x; typeset -lF10 x=2./3; typeset -p x; printf '%s\n' _.123456789012345678901234567890123 $x $((x))
typeset -l -F x=0.6666666667
_.123456789012345678901234567890123
0.6666666667
0.666666666666666667
$
# On arrach64
typeset -F x=0.6666666667
_.123456789012345678901234567890123
0.6666666667
0.666666666666666629659232512494782
$ unset x; typeset -lF10 x=2./3; typeset -p x; printf '%s\n' _.123456789012345678901234567890123 $x $((x))
typeset -l -F x=0.6666666667
_.123456789012345678901234567890123
0.6666666667
0.666666666666666666666666666666667

If your precision level exceeds maximum allowable safe digits for the platform then ksh will output all the digits it can up to that limit and then tack on zeroes for the rest.

$ unset x; typeset -F20 x=2./3; typeset -p x; printf '%s\n' _.12345678901234567890 $x $((x))
typeset -F 20 x=0.66666666666666700000
_.12345678901234567890
0.66666666666666700000
0.66666666666666663

Now, let's see what happens with ksh when we try to add .1 and .2 together, see reference:

{
typeset -F x=.1 y=.2 z=x+y # doubles (64bit)
typeset -lF r=x+y          # long double (80bit) receiving the result of two doubles
#                            .1 and .2 are literal long doubles within ((...))
printf '                       digit scale: %s\n' _.123456789012345678901234567890123
printf '                 value of double x: %s\n' $((x))
printf '                 value of double y: %s\n' $((y))
printf '         long double result of x+y: %s\n' $((x+y))
printf '                 value of double z: %s\n' $((z))
printf '            value of long double r: %s\n' $((r))
printf 'long double result of long doubles: %s\n' $((.1+.2))
}

Output from x86_64:

                       digit scale: _.123456789012345678901234567890123
                 value of double x: 0.100000000000000006
                 value of double y: 0.200000000000000011
         long double result of x+y: 0.300000000000000017
                 value of double z: 0.300000000000000044
            value of long double r: 0.300000000000000017
long double result of long doubles: 0.3

Output from arrach64:

                       digit scale: _.123456789012345678901234567890123
                 value of double x: 0.100000000000000005551115123125783
                 value of double y: 0.200000000000000011102230246251565
         long double result of x+y: 0.300000000000000016653345369377348
                 value of double z: 0.300000000000000044408920985006262
            value of long double r: 0.300000000000000016653345369377348
long double result of long doubles: 0.3

Swinging back to the impact of the $var_name expansion. More work is performed to round numeric variable x to its precision and then reintroduce its value back into the arithmetic expression thus incurring rounding and conversation errors. By using the variable name without expansion, ksh will operate on a defined numeric's stored raw value.

$ unset x; typeset -F3 x=2./3; typeset -p x; printf '%s\n' $((x)) $(($x))
typeset -F 3 x=0.667
0.66666666666666663
0.667

Now, for the generalization of the error message applying to text variables. Since variable a is text and not defined as a numeric, ksh is going to have to do a conversion no matter what to a long double on my platforms. Still, ksh is going to have to do less work as it does not have to insert the text value via the $ expansion then pull it back out and operate on it.

$ unset a; a=2./3; typeset -p a; printf '%s\n' $((a)) $(($a))
a=2./3
0.666666666666666667
0.666666666666666667

That does it for me on this. Hopefully this helps. I could be wrong but I have tried.

@McDutchie
Copy link

Thanks @hyenias, I really appreciate that, I learned a few things.

@McDutchie McDutchie merged commit b0282f2 into ksh93:master Nov 30, 2021
@JohnoKing JohnoKing deleted the arith-lint branch November 30, 2021 20:54
McDutchie pushed a commit that referenced this pull request Dec 5, 2021
This commit ports over two improvements to the shell linter from
illumos (original patch written by Andy Fiddaman). Links to the
relevant bug reports and the original patch:
https://www.illumos.org/issues/13601
https://www.illumos.org/issues/13631
illumos/illumos-gate@c7b656f

The first improvement is to the lint warning for arithmetic
operators in [[ ... ]]. The ksh linter now suggests the correct
equivalent operator to use in ((...)). Example:
  $ ksh -nc '[[ 30 -gt 25 ]]'
  # Original warning
  warning: line 1: -gt within [[ ... ]] obsolete, use ((...))
  # New warning
  warning: line 1: [[ ... -gt ... ]] obsolete, use ((... > ...))

The second improvement pertains to variable expansion in arithmetic
expressions. The ksh linter now suggests referencing variable names
directly:
  $ ksh -nc 'integer foo=40; (($foo < 50 ))'
  # Old warning
  warning: line 1: variable expansion makes arithmetic evaluation less efficient
  # New warning
  warning: line 1: in '(($foo < 50))', using '$' is slower and can introduce rounding errors

src/cmd/ksh93/{data/lexstates,sh/lex,sh/parse}.c:
- Port the improved shell lint warnings from illumos to ksh93u+m.
- The original checks for arithmetic operators involved a bunch of
  if statements with inefficient calls to strcmp(3). These were
  replaced with a more efficient switch statement that avoids
  strcmp.
JohnoKing added a commit to JohnoKing/ksh that referenced this pull request Dec 12, 2021
This commit adds onto <ksh93#353> by porting
over two additional improvements to the shell linter:

1) The changes in the aforementioned pull request were merged into
   illumos-gate with an additional change.[*] The illumos revision of
   the patch improved the warning for (( $foo = $? )) to specify '$foo'
   causes the warning.[**] Example:
      $ ksh -n -c '(( $? != $bar ))'
      ksh: warning: line 1: in '(( $? != $bar ))', using '$' as in '$bar' is slower and can introduce rounding errors
   While I was porting the illumos patch I did notice one problem. The
   string it uses from paramsub() skips over the initial '{' in
   '${var}', resulting in the warning printing '$var}' instead:
      $ ksh -n -c '(( ${.sh.pid} != $$ ))'
      ...  in '(( ${.sh.pid} != $$ ))', using '$' as in '$.sh.pid}' is slower  ...
   This was fixed by including the missing '{' in the string returned by
   paramsub for ${var} variables.

2) In ksh93v-, parsing x=$((expr)) with the shell linter will cause ksh
   to warn the user x=$((expr)) is slower than ((x=expr)). This
   improvement has been backported with a modified warning:
      # Result from this commit
      $ ksh -n -c 'x=$((1 + 2))'
      ksh: warning: line 1: x=$((1 + 2)) is slower than ((x=1 + 2))
      # Result from ksh93v-
      $ ksh93v -n -c 'x=$((1 + 2))'
      ksh93v: warning: line 1: ((x=1 + 2)) is more efficient than x=$((1 + 2))
   Minor note: the ksh93v- patch had an invalid use of memcmp; this
   version of the patch uses strncmp instead.

References:
illumos/illumos-gate@be548e8
https://code.illumos.org/c/illumos-gate/+/1834/comment/65722363_22fdf8e7/
McDutchie pushed a commit that referenced this pull request Dec 12, 2021
This commit adds onto <#353> by porting
over two additional improvements to the shell linter:

1) The changes in the aforementioned pull request were merged into
   illumos-gate with an additional change.[*] The illumos revision of
   the patch improved the warning for (( $foo = $? )) to specify '$foo'
   causes the warning.[**] Example:
      $ ksh -n -c '(( $? != $bar ))'
      ksh: warning: line 1: in '(( $? != $bar ))', using '$' as in '$bar' is slower and can introduce rounding errors
   While I was porting the illumos patch I did notice one problem. The
   string it uses from paramsub() skips over the initial '{' in
   '${var}', resulting in the warning printing '$var}' instead:
      $ ksh -n -c '(( ${.sh.pid} != $$ ))'
      ...  in '(( ${.sh.pid} != $$ ))', using '$' as in '$.sh.pid}' is slower  ...
   This was fixed by including the missing '{' in the string returned by
   paramsub for ${var} variables.

2) In ksh93v-, parsing x=$((expr)) with the shell linter will cause ksh
   to warn the user x=$((expr)) is slower than ((x=expr)). This
   improvement has been backported with a modified warning:
      # Result from this commit
      $ ksh -n -c 'x=$((1 + 2))'
      ksh: warning: line 1: x=$((1 + 2)) is slower than ((x=1 + 2))
      # Result from ksh93v-
      $ ksh93v -n -c 'x=$((1 + 2))'
      ksh93v: warning: line 1: ((x=1 + 2)) is more efficient than x=$((1 + 2))
   Minor note: the ksh93v- patch had an invalid use of memcmp; this
   version of the patch uses strncmp instead.

References:
illumos/illumos-gate@be548e8
https://code.illumos.org/c/illumos-gate/+/1834/comment/65722363_22fdf8e7/
McDutchie pushed a commit that referenced this pull request Dec 13, 2021
This commit adds onto <#353> by porting
over two additional improvements to the shell linter:

1) The changes in the aforementioned pull request were merged into
   illumos-gate with an additional change.[*] The illumos revision of
   the patch improved the warning for (( $foo = $? )) to specify '$foo'
   causes the warning.[**] Example:
      $ ksh -n -c '(( $? != $bar ))'
      ksh: warning: line 1: in '(( $? != $bar ))', using '$' as in '$bar' is slower and can introduce rounding errors
   While I was porting the illumos patch I did notice one problem. The
   string it uses from paramsub() skips over the initial '{' in
   '${var}', resulting in the warning printing '$var}' instead:
      $ ksh -n -c '(( ${.sh.pid} != $$ ))'
      ...  in '(( ${.sh.pid} != $$ ))', using '$' as in '$.sh.pid}' is slower  ...
   This was fixed by including the missing '{' in the string returned by
   paramsub for ${var} variables.

2) In ksh93v-, parsing x=$((expr)) with the shell linter will cause ksh
   to warn the user x=$((expr)) is slower than ((x=expr)). This
   improvement has been backported with a modified warning:
      # Result from this commit
      $ ksh -n -c 'x=$((1 + 2))'
      ksh: warning: line 1: x=$((1 + 2)) is slower than ((x=1 + 2))
      # Result from ksh93v-
      $ ksh93v -n -c 'x=$((1 + 2))'
      ksh93v: warning: line 1: ((x=1 + 2)) is more efficient than x=$((1 + 2))
   Minor note: the ksh93v- patch had an invalid use of memcmp; this
   version of the patch uses strncmp instead.

References:
illumos/illumos-gate@be548e8
https://code.illumos.org/c/illumos-gate/+/1834/comment/65722363_22fdf8e7/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants