Skip to content

Commit

Permalink
[ysh] In command.Simple, won't words after typed args (x) or [x]
Browse files Browse the repository at this point in the history
This is issue #1850.  I stumbled across this bug while testing out YSH
myself.

We still allow redirects at the end, like

    json write (x) >out.txt
  • Loading branch information
Andy Chu committed Apr 14, 2024
1 parent bd8b88c commit 3e6e896
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 45 deletions.
78 changes: 46 additions & 32 deletions osh/cmd_parse.py
Expand Up @@ -885,44 +885,58 @@ def _ScanSimpleCommand(self):

words.append(w)

elif self.c_id == Id.Op_LParen:
# 1. Check that there's a preceding space
prev_byte = self.lexer.ByteLookBack()
if prev_byte not in (SPACE_CH, TAB_CH):
if self.parse_opts.parse_at():
p_die('Space required before (',
loc.Word(self.cur_word))
else:
# inline func call like @sorted(x) is invalid in OSH, but the
# solution isn't a space
p_die(
'Unexpected left paren (might need a space before it)',
loc.Word(self.cur_word))

# 2. Check that it's not (). We disallow this because it's a no-op and
# there could be confusion with shell func defs.
# For some reason we need to call lexer.LookPastSpace, not
# w_parser.LookPastSpace. I think this is because we're at (, which is
# an operator token. All the other cases are like 'x=', which is PART
# of a word, and we don't know if it will end.
next_id = self.lexer.LookPastSpace(lex_mode_e.ShCommand)
if next_id == Id.Op_RParen:
p_die('Empty arg list not allowed',
loc.Word(self.cur_word))

typed_args = self.w_parser.ParseProcCallArgs(
grammar_nt.ysh_eager_arglist)

elif self.c_id == Id.Op_LBracket: # only when parse_bracket set
typed_args = self.w_parser.ParseProcCallArgs(
grammar_nt.ysh_lazy_arglist)

else:
break

self._SetNextBrack() # Allow bracket for SECOND word on
i += 1

# my-cmd (x) or my-cmd [x]
self._GetWord()
if self.c_id == Id.Op_LParen:
# 1. Check that there's a preceding space
prev_byte = self.lexer.ByteLookBack()
if prev_byte not in (SPACE_CH, TAB_CH):
if self.parse_opts.parse_at():
p_die('Space required before (',
loc.Word(self.cur_word))
else:
# inline func call like @sorted(x) is invalid in OSH, but the
# solution isn't a space
p_die(
'Unexpected left paren (might need a space before it)',
loc.Word(self.cur_word))

# 2. Check that it's not (). We disallow this because it's a no-op and
# there could be confusion with shell func defs.
# For some reason we need to call lexer.LookPastSpace, not
# w_parser.LookPastSpace. I think this is because we're at (, which is
# an operator token. All the other cases are like 'x=', which is PART
# of a word, and we don't know if it will end.
next_id = self.lexer.LookPastSpace(lex_mode_e.ShCommand)
if next_id == Id.Op_RParen:
p_die('Empty arg list not allowed',
loc.Word(self.cur_word))

typed_args = self.w_parser.ParseProcCallArgs(
grammar_nt.ysh_eager_arglist)

self._SetNext()

elif self.c_id == Id.Op_LBracket: # only when parse_bracket set
typed_args = self.w_parser.ParseProcCallArgs(
grammar_nt.ysh_lazy_arglist)

self._SetNext()

self._GetWord()

# Allow redirects after typed args, e.g.
# json write (x) > out.txt
if self.c_kind == Kind.Redir:
redirects.extend(self._ParseRedirectList())

# my-cmd { echo hi } my-cmd (x) { echo hi } ...
if (self.parse_opts.parse_brace() and self.c_id == Id.Lit_LBrace and
# Disabled for if/while condition, etc.
self.allow_block):
Expand Down
16 changes: 3 additions & 13 deletions test/ysh-parse-errors.sh
Expand Up @@ -272,11 +272,10 @@ test-ysh-expr-more() {

_ysh-parse-error 'echo @[split(x)]extra'

# Old syntax to remove
#_ysh-parse-error 'echo @split("a")'
# Old syntax that's now invalid
_ysh-parse-error 'echo @split("a")'
}


test-blocks() {
_ysh-parse-error '>out { echo hi }'
_ysh-parse-error 'a=1 b=2 { echo hi }'
Expand Down Expand Up @@ -1213,8 +1212,6 @@ test-bug-1850() {
_ysh-should-parse 'pp line (42); pp line (43)'
#_osh-should-parse 'pp line (42); pp line (43)'

return

# Extra word is bad
_ysh-parse-error 'pp line (42) extra'

Expand All @@ -1230,26 +1227,19 @@ test-bug-1850() {
_ysh-should-parse 'pp line (42);'
_ysh-should-parse 'pp line (42) { echo hi }'

return

# Original bug

# Accidental comma instead of ;
# Wow this is parsed horribly
# Why does this replace (42) with (43)
# Wow this is parsed horribly - (42) replaced (43)
_ysh-parse-error 'pp line (42), pp line (43)'
}

test-bug-1850-more() {
### Regression

return

# TODO: shouldn't allow extra words
_ysh-parse-error 'assert (42)extra'
_ysh-parse-error 'assert (42) extra'


_ysh-parse-error 'assert [42]extra'
_ysh-parse-error 'assert [42] extra'
}
Expand Down

0 comments on commit 3e6e896

Please sign in to comment.