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

[osh] Implement SparseArray ${sp[@]...} #2218

Merged
merged 7 commits into from
Jan 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 37 additions & 7 deletions osh/word_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ def _ValueToPartValue(val, quoted, part_loc):
val = cast(value.BashArray, UP_val)
return part_value.Array(bash_impl.BashArray_GetValues(val))

elif case(value_e.SparseArray):
val = cast(value.SparseArray, UP_val)
return part_value.Array(bash_impl.SparseArray_GetValues(val))

elif case(value_e.BashAssoc):
val = cast(value.BashAssoc, UP_val)
# bash behavior: splice values!
Expand Down Expand Up @@ -685,10 +689,14 @@ def _ApplyTestOp(
else:
is_falsey = False

elif case(value_e.BashArray, value_e.BashAssoc):
elif case(value_e.BashArray, value_e.SparseArray,
value_e.BashAssoc):
if val.tag() == value_e.BashArray:
val = cast(value.BashArray, UP_val)
strs = bash_impl.BashArray_GetValues(val)
elif val.tag() == value_e.SparseArray:
val = cast(value.SparseArray, UP_val)
strs = bash_impl.SparseArray_GetValues(val)
elif val.tag() == value_e.BashAssoc:
val = cast(value.BashAssoc, UP_val)
strs = bash_impl.BashAssoc_GetValues(val)
Expand Down Expand Up @@ -961,11 +969,15 @@ def _ApplyUnarySuffixOp(self, val, op):
#log('%r %r -> %r', val.s, arg_val.s, s)
new_val = value.Str(s) # type: value_t

elif case(value_e.BashArray, value_e.BashAssoc):
elif case(value_e.BashArray, value_e.SparseArray,
value_e.BashAssoc):
# get values
if val.tag() == value_e.BashArray:
val = cast(value.BashArray, UP_val)
values = bash_impl.BashArray_GetValues(val)
elif val.tag() == value_e.SparseArray:
val = cast(value.SparseArray, UP_val)
values = bash_impl.SparseArray_GetValues(val)
elif val.tag() == value_e.BashAssoc:
val = cast(value.BashAssoc, UP_val)
values = bash_impl.BashAssoc_GetValues(val)
Expand Down Expand Up @@ -1024,10 +1036,14 @@ def _PatSub(self, val, op):
s = replacer.Replace(str_val.s, op)
val = value.Str(s)

elif case2(value_e.BashArray, value_e.BashAssoc):
elif case2(value_e.BashArray, value_e.SparseArray,
value_e.BashAssoc):
if val.tag() == value_e.BashArray:
array_val = cast(value.BashArray, val)
values = bash_impl.BashArray_GetValues(array_val)
elif val.tag() == value_e.SparseArray:
sparse_val = cast(value.SparseArray, val)
values = bash_impl.SparseArray_GetValues(sparse_val)
elif val.tag() == value_e.BashAssoc:
assoc_val = cast(value.BashAssoc, val)
values = bash_impl.BashAssoc_GetValues(assoc_val)
Expand Down Expand Up @@ -1092,13 +1108,17 @@ def _Nullary(self, val, op, var_name, vsub_token, vsub_state):
# readline gets rid of these, so we should too.
p = prompt.replace('\x01', '').replace('\x02', '')
result = value.Str(p)
elif case(value_e.BashArray, value_e.BashAssoc):
elif case(value_e.BashArray, value_e.SparseArray,
value_e.BashAssoc):
if val.tag() == value_e.BashArray:
val = cast(value.BashArray, UP_val)
values = [
s for s in bash_impl.BashArray_GetValues(val)
if s is not None
]
elif val.tag() == value_e.SparseArray:
val = cast(value.SparseArray, UP_val)
values = bash_impl.SparseArray_GetValues(val)
elif val.tag() == value_e.BashAssoc:
val = cast(value.BashAssoc, UP_val)
values = bash_impl.BashAssoc_GetValues(val)
Expand Down Expand Up @@ -1135,10 +1155,17 @@ def _Nullary(self, val, op, var_name, vsub_token, vsub_state):
# oddly, 'echo ${x@Q}' is equivalent to 'echo "${x@Q}"' in
# bash
quoted2 = True
elif case(value_e.BashArray, value_e.BashAssoc):
elif case(value_e.BashArray, value_e.SparseArray,
value_e.BashAssoc):
if val.tag() == value_e.BashArray:
val = cast(value.BashArray, UP_val)
values = [s for s in bash_impl.BashArray_GetValues(val) if s is not None]
values = [
s for s in bash_impl.BashArray_GetValues(val)
if s is not None
]
elif val.tag() == value_e.SparseArray:
val = cast(value.SparseArray, UP_val)
values = bash_impl.SparseArray_GetValues(val)
elif val.tag() == value_e.BashAssoc:
val = cast(value.BashAssoc, UP_val)
values = bash_impl.BashAssoc_GetValues(val)
Expand All @@ -1160,7 +1187,7 @@ def _Nullary(self, val, op, var_name, vsub_token, vsub_state):
# spec/ble-idioms.test.sh.
chars = [] # type: List[str]
with tagswitch(vsub_state.h_value) as case:
if case(value_e.BashArray):
if case(value_e.BashArray, value_e.SparseArray):
chars.append('a')
elif case(value_e.BashAssoc):
chars.append('A')
Expand All @@ -1182,6 +1209,9 @@ def _Nullary(self, val, op, var_name, vsub_token, vsub_state):
elif case(value_e.BashArray):
val = cast(value.BashArray, UP_val)
count = bash_impl.BashArray_Count(val)
elif case(value_e.SparseArray):
val = cast(value.SparseArray, UP_val)
count = bash_impl.SparseArray_Count(val)
elif case(value_e.BashAssoc):
val = cast(value.BashAssoc, UP_val)
count = bash_impl.BashAssoc_Count(val)
Expand Down
147 changes: 147 additions & 0 deletions spec/ble-idioms.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,153 @@ echo "[${a[@]: -4}][${a[*]: -4}]"
## END


#### SparseArray: ${a[@]}

case $SH in zsh|mksh|ash) exit ;; esac

a=(v{0..9})
unset -v 'a[2]' 'a[3]' 'a[4]' 'a[7]'
case ${SH##*/} in osh) eval 'var a = _a2sp(a)' ;; esac

argv.py "${a[@]}"
argv.py "abc${a[@]}xyz"

## STDOUT:
['v0', 'v1', 'v5', 'v6', 'v8', 'v9']
['abcv0', 'v1', 'v5', 'v6', 'v8', 'v9xyz']
## END

## N-I zsh/mksh/ash STDOUT:
## END


#### SparseArray: ${a[@]#...}

case $SH in zsh|mksh|ash) exit ;; esac

a=(v{0..9})
unset -v 'a[2]' 'a[3]' 'a[4]' 'a[7]'
case ${SH##*/} in osh) eval 'var a = _a2sp(a)' ;; esac

argv.py "${a[@]#v}"
argv.py "abc${a[@]#v}xyz"
argv.py "${a[@]%[0-5]}"
argv.py "abc${a[@]%[0-5]}xyz"
argv.py "${a[@]#v?}"

## STDOUT:
['0', '1', '5', '6', '8', '9']
['abc0', '1', '5', '6', '8', '9xyz']
['v', 'v', 'v', 'v6', 'v8', 'v9']
['abcv', 'v', 'v', 'v6', 'v8', 'v9xyz']
['', '', '', '', '', '']
## END

## N-I zsh/mksh/ash STDOUT:
## END


#### SparseArray: ${a[@]/pat/rep}

case $SH in zsh|mksh|ash) exit ;; esac

a=(v{0..9})
unset -v 'a[2]' 'a[3]' 'a[4]' 'a[7]'
case ${SH##*/} in osh) eval 'var a = _a2sp(a)' ;; esac

argv.py "${a[@]/?}"
argv.py "${a[@]//?}"
argv.py "${a[@]/#?}"
argv.py "${a[@]/%?}"

argv.py "${a[@]/v/x}"
argv.py "${a[@]//v/x}"
argv.py "${a[@]/[0-5]/D}"
argv.py "${a[@]//[!0-5]/_}"

## STDOUT:
['0', '1', '5', '6', '8', '9']
['', '', '', '', '', '']
['0', '1', '5', '6', '8', '9']
['v', 'v', 'v', 'v', 'v', 'v']
['x0', 'x1', 'x5', 'x6', 'x8', 'x9']
['x0', 'x1', 'x5', 'x6', 'x8', 'x9']
['vD', 'vD', 'vD', 'v6', 'v8', 'v9']
['_0', '_1', '_5', '__', '__', '__']
## END

## N-I zsh/mksh/ash STDOUT:
## END


#### SparseArray: ${a[@]@P}, ${a[@]@Q}, and ${a[@]@a}
case $SH in zsh|mksh|ash) exit ;; esac

a=(v{0..9})
unset -v 'a[2]' 'a[3]' 'a[4]' 'a[7]'
case ${SH##*/} in osh) eval 'var a = _a2sp(a)' ;; esac

argv.py "${a[@]@P}"
argv.py "${a[*]@P}"
argv.py "${a[@]@Q}"
argv.py "${a[*]@Q}"
argv.py "${a[@]@a}"
argv.py "${a[*]@a}"

## STDOUT:
['v0', 'v1', 'v5', 'v6', 'v8', 'v9']
['v0 v1 v5 v6 v8 v9']
['v0', 'v1', 'v5', 'v6', 'v8', 'v9']
['v0 v1 v5 v6 v8 v9']
['a', 'a', 'a', 'a', 'a', 'a']
['a a a a a a']
## END

## OK bash STDOUT:
['v0', 'v1', 'v5', 'v6', 'v8', 'v9']
['v0 v1 v5 v6 v8 v9']
["'v0'", "'v1'", "'v5'", "'v6'", "'v8'", "'v9'"]
["'v0' 'v1' 'v5' 'v6' 'v8' 'v9'"]
['a', 'a', 'a', 'a', 'a', 'a']
['a a a a a a']
## END

## N-I zsh/mksh/ash STDOUT:
## END


#### SparseArray: ${a[@]-unset}, ${a[@]:-empty}, etc.
case $SH in zsh|mksh|ash) exit ;; esac

a1=()
a2=("")
a3=("" "")

case $SH in
bash) ;;
*) eval "var a1 = _a2sp(a1); var a2 = _a2sp(a2); var a3 = _a2sp(a3)" ;;
esac

echo "a1 unset: [${a1[@]-unset}]"
echo "a1 empty: [${a1[@]:-empty}]"
echo "a2 unset: [${a2[@]-unset}]"
echo "a2 empty: [${a2[@]:-empty}]"
echo "a3 unset: [${a3[@]-unset}]"
echo "a3 empty: [${a3[@]:-empty}]"

## STDOUT:
a1 unset: [unset]
a1 empty: [empty]
a2 unset: []
a2 empty: [empty]
a3 unset: [ ]
a3 empty: [ ]
## END

## N-I zsh/mksh/ash STDOUT:
## END


#### SparseArray: compgen -F _set_COMPREPLY
case $SH in zsh|mksh|ash) exit ;; esac

Expand Down