Skip to content

Commit

Permalink
[osh-language] Decay arrays to strings for indirect expansion
Browse files Browse the repository at this point in the history
- For string ref '*' which is like $*
- For string ref 'a[*]' which is like ${a[*]}

Preparing to address issue #964
  • Loading branch information
Andy C committed Jul 13, 2021
1 parent ed5a5ee commit a70d6c1
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 14 deletions.
30 changes: 20 additions & 10 deletions osh/word_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -612,9 +612,9 @@ def _ApplyTestOp(self,
else:
raise NotImplementedError(tok.id)

def _EvalIndirectArrayExpansion(self, name, index):
def _EvalIndirectArrayExpansion(self, name, index, box):
# type: (str, str) -> Optional[value_t]
"""Expands ${!ref} when $ref has the form `name[index]`.
"""Expands ${!ref} when $ref has the form 'name[index]'.
Args:
name, index: arbitrary strings
Expand All @@ -636,9 +636,13 @@ def _EvalIndirectArrayExpansion(self, name, index):

elif case(value_e.MaybeStrArray):
val = cast(value__MaybeStrArray, UP_val)
if index in ('@', '*'):
# TODO: maybe_decay_array
if index == '@':
return value.MaybeStrArray(val.strs)

elif index == '*':
box[0] = True # maybe_decay_array
return value.MaybeStrArray(val.strs)

try:
index_num = int(index)
except ValueError:
Expand Down Expand Up @@ -734,8 +738,8 @@ def _Keys(self, val, token):
else:
raise AssertionError()

def _IndirectExpansion(self, val, token):
# type: (value_t, Token) -> value_t
def _IndirectExpansion(self, val, token, box):
# type: (value_t, Token, List[bool]) -> value_t
"""Handles indirect expansion ${!var} and ${!a[0]}."""
UP_val = val
with tagswitch(val) as case:
Expand All @@ -754,8 +758,11 @@ def _IndirectExpansion(self, val, token):
except ValueError:
pass

if val.s in ('@', '*'):
# TODO: maybe_decay_array
if val.s == '@':
return value.MaybeStrArray(self.mem.GetArgv())

elif val.s == '*':
box[0] = True # maybe_decay_array
return value.MaybeStrArray(self.mem.GetArgv())

if 1:
Expand All @@ -765,7 +772,7 @@ def _IndirectExpansion(self, val, token):
if i >= 0 and val.s[-1] == ']':
name = val.s[:i]
index = val.s[i+1:-1]
result = self._EvalIndirectArrayExpansion(name, index)
result = self._EvalIndirectArrayExpansion(name, index, box)
if result is not None:
return result

Expand Down Expand Up @@ -1266,7 +1273,10 @@ def _EvalBracedVarSub(self, part, part_vals, quoted):
else:
# Process ${!ref}. SURPRISE: ${!a[0]} is an indirect expansion unlike
# ${!a[@]} !
val = self._IndirectExpansion(val, part.token)
box = [False]
val = self._IndirectExpansion(val, part.token, box)
if box[0]:
maybe_decay_array = True

if not suffix_is_test: # undef -> '' AFTER indirection
val = self._EmptyStrOrError(val, part.token)
Expand Down
6 changes: 3 additions & 3 deletions spec/var-ref.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ ref1=one
ref2=two
## END

#### var ref with 1 and @ and *
#### var ref: 1, @, *
set -- x y
ref=1; argv.py "${!ref}"
ref=@; argv.py "${!ref}"
Expand Down Expand Up @@ -247,8 +247,8 @@ f() {
f a[0]
b=(x y)
f b[0]
f b[@]
f "b[*]"
f 'b[@]'
f 'b[*]'
# Also associative arrays.
## STDOUT:
['']
Expand Down
2 changes: 1 addition & 1 deletion test/spec.sh
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,7 @@ nocasematch-match() {
# ${!var} syntax -- oil should replace this with associative arrays.
# mksh has completely different behavior for this syntax. Not worth testing.
var-ref() {
sh-spec spec/var-ref.test.sh --osh-failures-allowed 4 \
sh-spec spec/var-ref.test.sh --osh-failures-allowed 2 \
$BASH $OSH_LIST "$@"
}

Expand Down

0 comments on commit a70d6c1

Please sign in to comment.