Skip to content

Commit

Permalink
[osh-language] Start getting rid of int_coerce for assoc array keys.
Browse files Browse the repository at this point in the history
Instead we will use EvalWordToString, and disallow arbitrary
expressions.

Related to #207.

- Also add comments about assoc array literals
- All spec tests pass.  Tightened up spec for (( array1 == array 2 )).
  • Loading branch information
Andy Chu committed Jul 14, 2019
1 parent df97cc3 commit 81fabfd
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 20 deletions.
30 changes: 24 additions & 6 deletions osh/expr_eval.py
Expand Up @@ -103,6 +103,7 @@ def _StringToInteger(s, span_id=const.NO_INTEGER):
#
# Calls EvalLhs()
# a[$key]=$val # osh/cmd_exec.py:814 (command_e.Assignment)
# Calls _EvalLhsArith()
# (( a[key] = val )) # osh/expr_eval.py:326 (_EvalLhsArith)
#
# Calls EvalLhsAndLookup():
Expand Down Expand Up @@ -369,16 +370,33 @@ def _Store(self, lval, new_int):
val = value.Str(str(new_int))
self.mem.SetVar(lval, val, (), scope_e.Dynamic)

def EvalToIndex(self, node):
# TODO:
# - For StrArray, Check that you got an integer (not None, etc.)
# - For AssocArray, do something else? Get rid of int_coerce?
pass
def EvalWordToString(self, node):
"""
Args:
node: arith_expr_t
Returns:
str
Raises:
util.FatalRuntimeError if the expression isn't a string
Or if it contains a bare variable like a[x]
These are allowed because they're unambiguous, unlike a[x]
a[$x] a["$x"] a["x"] a['x']
"""
if node.tag != arith_expr_e.ArithWord: # $(( $x )) $(( ${x}${y} )), etc.
# TODO: location info for orginal
e_die("Associative array keys must be strings: $x 'x' \"$x\" etc.")

val = self.word_ev.EvalWordToString(node.w)
return val.s

def Eval(self, node, int_coerce=True):
"""
Args:
node: osh_ast.arith_expr
node: arith_expr_t
Returns:
None for Undef (e.g. empty cell) TODO: Don't return 0!
Expand Down
2 changes: 1 addition & 1 deletion osh/word_eval.py
Expand Up @@ -662,7 +662,7 @@ def _EvalBracedVarSub(self, part, part_vals, quoted):
val = value.Str(s)

elif val.tag == value_e.AssocArray:
key = self.arith_ev.Eval(anode, int_coerce=False)
key = self.arith_ev.EvalWordToString(anode)
s = val.d.get(key)

if s is None:
Expand Down
17 changes: 17 additions & 0 deletions osh/word_parse.py
Expand Up @@ -963,6 +963,23 @@ def ReadForExpression(self):

def _ReadArrayLiteralPart(self):
# type: () -> word_part__ArrayLiteralPart
"""
a=(1 2 3)
TODO: See osh/cmd_parse.py:164 for Id.Lit_ArrayLhsOpen, for a[x++]=1
We want:
A=(['x']=1 ["x"]=2 [$x$y]=3)
Maybe allow this as a literal string? Because I think I've seen it before?
Or maybe force people to patch to learn the rule.
A=([x]=4)
Starts with Lit_Other '[', and then it has Lit_ArrayLhsClose
Maybe enforce that ALL have keys or NONE of have keys.
"""
self._Next(lex_mode_e.ShCommand) # advance past (
self._Peek()
if self.cur_token.id != Id.Op_LParen:
Expand Down
7 changes: 4 additions & 3 deletions spec/assoc.test.sh
Expand Up @@ -244,11 +244,12 @@ assoc[i]=string
assoc[i+1]=string+1
## END

#### Array stored in associative array gets converted to string
#### Array stored in associative array gets converted to string (without strict-array)

array=('1 2' 3)
declare -A d
d[a]="${array[@]}"
argv.py "${d[a]}"
d['key']="${array[@]}"
argv.py "${d['key']}"
## stdout: ['1 2 3']

#### Indexed array as key of associative array coerces to string (without shopt -s strict-array)
Expand Down
14 changes: 5 additions & 9 deletions spec/dbracket.test.sh
Expand Up @@ -208,7 +208,7 @@ true
false
## END

#### (( array1 == array2 ))
#### (( array1 == array2 )) doesn't work
a=('1 3' 5)
b=('1 3' 5)
c=('1' '3 5')
Expand All @@ -224,18 +224,14 @@ echo status=$?
(( a == d ))
echo status=$?

## STDOUT:
status=0
status=1
status=1
## END
## N-I bash STDOUT:
## stdout-json: ""
## status: 1
## BUG bash STDOUT:
status=1
status=1
status=1
## END
## N-I mksh stdout-json: ""
## N-I mksh status: 1
## BUG bash status: 0

#### Quotes don't matter in comparison
[[ '3' = 3 ]] && echo true
Expand Down
2 changes: 1 addition & 1 deletion test/spec.sh
Expand Up @@ -593,7 +593,7 @@ dbracket() {
}

dparen() {
sh-spec spec/dparen.test.sh --osh-failures-allowed 5 \
sh-spec spec/dparen.test.sh --osh-failures-allowed 4 \
$BASH $MKSH $ZSH $OSH_LIST "$@"
}

Expand Down

0 comments on commit 81fabfd

Please sign in to comment.