Skip to content

Commit

Permalink
lexer: allow extglob wildcards as function names
Browse files Browse the repository at this point in the history
the lexer assumes an extglob token if any of the wildcards expressions
(such as `@`, and `+`) are succeeded by a left parenthesis but that
proves to be an issue if the wildcard is used as a function name.

example input:
```
$ cat in.sh
@() {
  echo "$@";
}
```

`bash` and `gosh` comparison:
```
$ bash ./in.sh
hello
$ ./gosh in.sh
in.sh:5:1: "}" can only be used to close a block
```

given `in.sh`, gosh reports about a syntax error - this is because
a closing bracket is found while the lexer isn't assuming a function
block

fix the issue by assuming a function if one of the conditions below is
true:
* if the expression is found at the beginning of the statement or if its
  preceded by a "function"
* if `(` is immediately succeeded by a `)` - although this is a valid
  bash syntax, we'll operate on the likelihood that it is a function

fixes mvdan#739
  • Loading branch information
riacataquian committed Dec 8, 2021
1 parent f965c62 commit 0ee56cf
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 2 deletions.
10 changes: 10 additions & 0 deletions interp/interp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3117,6 +3117,16 @@ hello, world
hello, world
`,
},
{
// globbing wildcard as function name
`@() { echo "$@"; }; @ lala; function +() { echo "$@"; }; + foo`,
"lala\nfoo\n",
},
{
// globbing wildcard as function name but with space after the name
`+ () { echo "$@"; }; + foo; @ () { echo "$@"; }; @ lala; ? () { echo "$@"; }; ? bar`,
"foo\nlala\nbar\n",
},
}

var runTestsWindows = []runTest{
Expand Down
24 changes: 22 additions & 2 deletions syntax/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ skipSpace:
p.advanceLitNone(r)
}
case '?', '*', '+', '@', '!':
if p.peekByte('(') {
if p.isExprGlob() {
switch r {
case '?':
p.tok = globQuest
Expand Down Expand Up @@ -346,6 +346,26 @@ skipSpace:
}
}

// isExprGlob determines whether the expression is an extglob wildcard literal
func (p *Parser) isExprGlob() bool {
leftParen := p.peekByte('(')
if !leftParen {
return false
}
// it must not be a globbing if its at the beginning of a statement or
// if its preceded by "function"
if p.pos.Col() == 1 || p.val == "function" {
return false
}
// its must not be a globbing if left parens is succeeded by a right parens
// NOTE: empty pattern list is a valid globbing syntax, eg @()
// but we'll operate on the "likelihood" that it is a function
if len(p.bs) > p.bsp+p.w {
return p.bs[p.bsp+p.w] != ')'
}
return true
}

func (p *Parser) peekByte(b byte) bool {
if p.bsp == len(p.bs) {
p.fill()
Expand Down Expand Up @@ -882,7 +902,7 @@ loop:
tok = _Lit
break loop
case '?', '*', '+', '@', '!':
if p.peekByte('(') {
if p.isExprGlob() {
tok = _Lit
break loop
}
Expand Down

0 comments on commit 0ee56cf

Please sign in to comment.