Skip to content

Commit

Permalink
[extglob] Fix quoting and parsing issues in extglob.
Browse files Browse the repository at this point in the history
All spec tests pass now!

- shell scripts to audit the usage of extglob.
  • Loading branch information
Andy Chu committed Oct 5, 2018
1 parent 6e3fe06 commit 889fd29
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 9 deletions.
2 changes: 1 addition & 1 deletion core/expr_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,7 @@ def Eval(self, node):
if arg_type == bool_arg_type_e.Str:

if op_id in (Id.BoolBinary_GlobEqual, Id.BoolBinary_GlobDEqual):
#log('Comparing %s and %s', s2, s1)
#log('Matching %s against pattern %s', s1, s2)

# TODO: Respect extended glob? * and ! and ? are quoted improperly.
# But @ and + are OK.
Expand Down
2 changes: 2 additions & 0 deletions core/runtime.asdl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ module runtime
-- A static word_part from osh.asdl is evaluated to a dynamic part_value.
part_value =
-- Substitutions and unquoted literals get split/elided/globbed.
-- TODO: invert and rename to 'quoted', because quoted means escaping
-- in other contexts!
StringPartValue(string s, bool do_split_glob)
-- "$@" or "${a[@]}" -- never split or globbed since double quoted.
| ArrayPartValue(string* strs)
Expand Down
23 changes: 19 additions & 4 deletions core/word_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -800,12 +800,15 @@ def _EvalWordPart(self, part, part_vals, quoted=False):
part_vals.append(v)

elif part.tag == word_part_e.ExtGlobPart:
part_vals.append(runtime.StringPartValue(part.op.val, False))
# do_split_glob should be renamed 'unquoted'? or inverted and renamed
# 'quoted'?
part_vals.append(runtime.StringPartValue(part.op.val, True))
for i, w in enumerate(part.arms):
if i != 0:
part_vals.append(runtime.StringPartValue('|', False)) # separator
self._EvalWordToParts(w, True, part_vals) # eval like quoted
part_vals.append(runtime.StringPartValue(')', False)) # closing )
part_vals.append(runtime.StringPartValue('|', True)) # separator
# This flattens the tree!
self._EvalWordToParts(w, False, part_vals) # eval like not quoted?
part_vals.append(runtime.StringPartValue(')', True)) # closing )

else:
raise AssertionError(part.__class__.__name__)
Expand All @@ -827,6 +830,16 @@ def _EvalWordToParts(self, word, quoted, part_vals):
else:
raise AssertionError(word.__class__.__name__)

# Do we need this?
def EvalWordToPattern(self, word):
"""
Given a word, returns pattern.ERE if has an ExtGlobPart, or pattern.Fnmatch
otherwise.
NOTE: Have ot handle nested extglob like: [[ foo == ${empty:-@(foo|bar) ]]
"""
pass

def EvalWordToString(self, word, do_fnmatch=False, do_ere=False):
"""
Args:
Expand All @@ -841,6 +854,8 @@ def EvalWordToString(self, word, do_fnmatch=False, do_ere=False):
$pat) echo 'matches glob pattern' ;;
"$pat") echo 'equal to glob string' ;; # must be glob escaped
esac
TODO: Raise AssertionError if it has ExtGlobPart.
"""
if word.tag == word_e.EmptyWord:
return runtime.Str('')
Expand Down
2 changes: 1 addition & 1 deletion osh/lex.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ def IsKeyword(name):
#
# Example: echo @(<> <>|&&|'foo'|$bar)
LEXER_DEF[lex_mode_e.EXTGLOB] = \
_BACKSLASH + _LEFT_SUBS + _VARS + _EXTGLOB_BEGIN + [
_BACKSLASH + _LEFT_SUBS + _LEFT_UNQUOTED + _VARS + _EXTGLOB_BEGIN + [
R(r'[^\\$`"\'|)@*+!?\0]+', Id.Lit_Chars),
C('|', Id.Op_Pipe),
C(')', Id.Op_RParen), # maybe be translated to Id.ExtGlob_RParen
Expand Down
9 changes: 9 additions & 0 deletions scripts/complete.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ readonly BASH_COMP=../bash-completion/bash_completion

readonly GIT_COMP=testdata/completion/git

grep-extglob() {
grep -E --color '[@?!+*]\(' "$@"
}

audit() {
local file=${1:-$GIT_COMP}

Expand All @@ -32,6 +36,9 @@ audit() {
# Search for array usage
grep -E --color ']=' $file
grep -E --color ']+=' $file

# extended glob
grep-extglob $file
}

audit-git() {
Expand All @@ -52,6 +59,8 @@ audit-bashcomp() {
# Some of these are not cash variables.
grep -E -o 'COMP_[A-Z]+' $path | hist

grep-extglob ../bash-completion/completions/*

#find /usr/share/bash-completion/ -type f | xargs grep -E --color ']\+?='
}

Expand Down
2 changes: 1 addition & 1 deletion spec/extglob-match.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ FALSE
TRUE
TRUE
## END
## OK mksh STDOUT:
## OK osh/mksh STDOUT:
TRUE
TRUE
TRUE
Expand Down
3 changes: 1 addition & 2 deletions test/spec.sh
Original file line number Diff line number Diff line change
Expand Up @@ -570,8 +570,7 @@ extended-glob() {

# This does string matching.
extglob-match() {
sh-spec spec/extglob-match.test.sh --osh-failures-allowed 9 \
$BASH $MKSH $OSH_LIST "$@"
sh-spec spec/extglob-match.test.sh $BASH $MKSH $OSH_LIST "$@"
}

# ${!var} syntax -- oil should replace this with associative arrays.
Expand Down

0 comments on commit 889fd29

Please sign in to comment.