diff --git a/syntax/filetests_test.go b/syntax/filetests_test.go index af70891f6..2da6759ea 100644 --- a/syntax/filetests_test.go +++ b/syntax/filetests_test.go @@ -2608,7 +2608,7 @@ var fileTests = []testCase{ }, { Strs: []string{`${!foo*} ${!bar@}`}, - bsmk: call( + bash: call( word(&ParamExp{ Excl: true, Param: lit("foo"), diff --git a/syntax/parser.go b/syntax/parser.go index a795e44c3..05db88852 100644 --- a/syntax/parser.go +++ b/syntax/parser.go @@ -1264,9 +1264,6 @@ func (p *Parser) paramExp() *ParamExp { } case exclMark: if paramNameOp(p.r) { - if p.lang == LangPOSIX { - p.langErr(p.pos, "${!foo}", LangBash, LangMirBSDKorn) - } pe.Excl = true p.next() } @@ -1298,6 +1295,9 @@ func (p *Parser) paramExp() *ParamExp { case _Lit, _LitWord: p.curErr("%s cannot be followed by a word", op) case rightBrace: + if pe.Excl && p.lang == LangPOSIX { + p.posErr(pe.Pos(), `"${!foo}" is a bash/mksh feature`) + } pe.Rbrace = p.pos p.quote = old p.next() @@ -1368,6 +1368,9 @@ func (p *Parser) paramExp() *ParamExp { case p.tok == star && !pe.Excl: p.curErr("not a valid parameter expansion operator: %v", p.tok) case pe.Excl && p.r == '}': + if !p.lang.isBash() { + p.posErr(pe.Pos(), `"${!foo`+p.tok.String()+`}" is a bash feature`) + } pe.Names = ParNamesOperator(p.tok) p.next() default: diff --git a/syntax/parser_test.go b/syntax/parser_test.go index bd70092aa..51ae38469 100644 --- a/syntax/parser_test.go +++ b/syntax/parser_test.go @@ -1928,7 +1928,21 @@ var shellTests = []errorCase{ }, { in: "echo ${!foo}", - posix: `1:8: ${!foo} is a bash/mksh feature`, + posix: `1:6: "${!foo}" is a bash/mksh feature`, + }, + { + in: "echo ${!foo*}", + posix: `1:6: "${!foo*}" is a bash feature`, + mksh: `1:6: "${!foo*}" is a bash feature`, + }, + { + in: "echo ${!foo@}", + posix: `1:12: this expansion operator is a bash/mksh feature`, + mksh: `1:6: "${!foo@}" is a bash feature`, + }, + { + in: "echo ${!foo[@]}", + posix: `1:12: arrays are a bash/mksh feature`, }, { in: "echo ${foo[1]}",