Packages
Packages copied to clipboard
[ShellScript] arithmetic evaluation context has no comments in ZSH
- Sublime Version: 3.2.2, Build 3211
- OS Version: Arch Linux
% i=$(( # abc ))
# zsh: bad math expression: operator expected at `abc '
% i=$(( #def ))
# assuming $def in undefined, this silently fails and sets $i to zero.
It is not something unique to Zsh. Bash also has very similar rules regarding Arithmetic Evaluation context as demonstrated below.
$ i=$(( # abc ))
# bash: bad substitution: no closing `)' in $(( # abc ))
$ i=$(( #def ))
# bash: bad substitution: no closing `)' in $(( #def ))

Summary
Arithmetic Evaluation context is not subject to comments.
Description
Syntax highlighting engine treats # symbol inside an Arithmetic Evaluation context as the beginning of a comment. Which is incorrect, because # in that context could be one of several operators but not a comment.
According to zsh documentation at http://zsh.sourceforge.net/Doc/Release/Arithmetic-Evaluation.html#Arithmetic-Evaluation:
An expression of the form ‘##x’ where x is any character sequence such as ‘a’, ‘^A’, or ‘\M-\C-x’ gives the value of this character and an expression of the form ‘#name’ gives the value of the first character of the contents of the parameter name.
Real-world line which causes trouble: https://github.com/ohmyzsh/ohmyzsh/blob/7a76afd61e5daab6fb33f955930efa7f4cf16021/lib/functions.zsh#L184

And there are also special variables syntax involving #. Not everything is great with them too.
echo $#
echo ${#}
echo ${word}
echo $#word

First three lines from example all have different scopes (and consequently colors) for #/word variables:
| variable | scope |
|---|---|
$# |
source.shell.bash meta.function-call.arguments.shell meta.group.expansion.parameter.shell variable.language.shell |
${#} |
source.shell.bash meta.function-call.arguments.shell meta.group.expansion.parameter.shell keyword.operator.arithmetic.shell |
${word} |
source.shell.bash meta.function-call.arguments.shell meta.group.expansion.parameter.shell variable.other.readwrite.shell |
The last one "thinks" its a function call spanning the entire $#word expression:
- source.shell.bash meta.function-call.arguments.shell.
Zsh documentation on Parameters states the following:
# <S>The number of positional parameters in decimal. Note that some confusion may occur with the syntax $#param which substitutes the length of param. Use ${#} to resolve ambiguities. In particular, the sequence ‘$#-...’ in an arithmetic expression is interpreted as the length of the parameter -, q.v.

The Bash on master doesn't highlight comments within arithmetics atm. I guess that's an oversight caused by removing comments from prototype context. As the error message clearly states the ) is missing, I guess Bash detects # as comment within arithmetics.
With regards to $# and friends, the only reference I can find is at https://www.gnu.org/software/bash/manual/bash.html#Special-Parameters. A single # within ${#} expansions seems to be synonym for $#, indeed. We may fix that.
${#foo} returns the length of the content of foo. As such, # is defined as "strlen"-operator, yes. That's not too bad, I think.
$#foo has no special meaning in Bash. Perl knows about that returning the length of foo's content. $# are scoped punctuation.definition.variable for simplicity reasons, but # would be a length operator, too, in that context.
From the perspective of bash, the only fix needed is scoping ${#} as variable.language somehow.
The other issues should not go into Bash.sublime-syntax.
With inheritance being available it should be possible to create a ZSH syntax which handles such differences, though. It could extend Bash. I guess that's what issue #2638 is about.