mirror of
https://github.com/go-task/task.git
synced 2026-07-02 17:08:45 +00:00
Update dependencies
This commit is contained in:
19
vendor/github.com/mvdan/sh/interp/builtin.go
generated
vendored
19
vendor/github.com/mvdan/sh/interp/builtin.go
generated
vendored
@@ -19,7 +19,7 @@ func isBuiltin(name string) bool {
|
||||
"echo", "printf", "break", "continue", "pwd", "cd",
|
||||
"wait", "builtin", "trap", "type", "source", "command",
|
||||
"pushd", "popd", "umask", "alias", "unalias", "fg", "bg",
|
||||
"getopts", "eval":
|
||||
"getopts", "eval", "test", "[":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -207,6 +207,23 @@ func (r *Runner) builtinCode(pos syntax.Pos, name string, args []string) int {
|
||||
r2.File = file
|
||||
r2.Run()
|
||||
return r2.exit
|
||||
case "[":
|
||||
if len(args) == 0 || args[len(args)-1] != "]" {
|
||||
r.runErr(pos, "[: missing matching ]")
|
||||
break
|
||||
}
|
||||
args = args[:len(args)-1]
|
||||
fallthrough
|
||||
case "test":
|
||||
p := testParser{
|
||||
rem: args,
|
||||
err: func(format string, a ...interface{}) {
|
||||
r.runErr(pos, format, a...)
|
||||
},
|
||||
}
|
||||
p.next()
|
||||
expr := p.classicTest("[", false)
|
||||
return oneIf(r.bashTest(expr) == "")
|
||||
case "trap", "source", "command", "pushd", "popd",
|
||||
"umask", "alias", "unalias", "fg", "bg", "getopts":
|
||||
r.runErr(pos, "unhandled builtin: %s", name)
|
||||
|
||||
21
vendor/github.com/mvdan/sh/interp/interp.go
generated
vendored
21
vendor/github.com/mvdan/sh/interp/interp.go
generated
vendored
@@ -563,6 +563,7 @@ func (r *Runner) loopStmtsBroken(stmts []*syntax.Stmt) bool {
|
||||
func (r *Runner) wordParts(wps []syntax.WordPart, quoted bool) []string {
|
||||
var parts []string
|
||||
var curBuf bytes.Buffer
|
||||
allowEmpty := false
|
||||
flush := func() {
|
||||
if curBuf.Len() == 0 {
|
||||
return
|
||||
@@ -590,17 +591,18 @@ func (r *Runner) wordParts(wps []syntax.WordPart, quoted bool) []string {
|
||||
}
|
||||
curBuf.WriteString(s)
|
||||
case *syntax.SglQuoted:
|
||||
allowEmpty = true
|
||||
curBuf.WriteString(x.Value)
|
||||
case *syntax.DblQuoted:
|
||||
// TODO: @ between double quotes but not alone
|
||||
allowEmpty = true
|
||||
if len(x.Parts) == 1 {
|
||||
pe, ok := x.Parts[0].(*syntax.ParamExp)
|
||||
if ok && pe.Param.Value == "@" {
|
||||
for i, arg := range r.args {
|
||||
pe, _ := x.Parts[0].(*syntax.ParamExp)
|
||||
if elems := r.quotedElems(pe); elems != nil {
|
||||
for i, elem := range elems {
|
||||
if i > 0 {
|
||||
flush()
|
||||
}
|
||||
curBuf.WriteString(arg)
|
||||
curBuf.WriteString(elem)
|
||||
}
|
||||
continue
|
||||
}
|
||||
@@ -617,10 +619,10 @@ func (r *Runner) wordParts(wps []syntax.WordPart, quoted bool) []string {
|
||||
}
|
||||
case *syntax.CmdSubst:
|
||||
r2 := *r
|
||||
var outBuf bytes.Buffer
|
||||
r2.Stdout = &outBuf
|
||||
var buf bytes.Buffer
|
||||
r2.Stdout = &buf
|
||||
r2.stmts(x.Stmts)
|
||||
val := strings.TrimRight(outBuf.String(), "\n")
|
||||
val := strings.TrimRight(buf.String(), "\n")
|
||||
if quoted {
|
||||
curBuf.WriteString(val)
|
||||
} else {
|
||||
@@ -633,6 +635,9 @@ func (r *Runner) wordParts(wps []syntax.WordPart, quoted bool) []string {
|
||||
}
|
||||
}
|
||||
flush()
|
||||
if allowEmpty && len(parts) == 0 {
|
||||
parts = append(parts, "")
|
||||
}
|
||||
return parts
|
||||
}
|
||||
|
||||
|
||||
23
vendor/github.com/mvdan/sh/interp/param.go
generated
vendored
23
vendor/github.com/mvdan/sh/interp/param.go
generated
vendored
@@ -12,6 +12,29 @@ import (
|
||||
"github.com/mvdan/sh/syntax"
|
||||
)
|
||||
|
||||
func (r *Runner) quotedElems(pe *syntax.ParamExp) []string {
|
||||
if pe == nil {
|
||||
return nil
|
||||
}
|
||||
if pe.Param.Value == "@" {
|
||||
return r.args
|
||||
}
|
||||
w, _ := pe.Index.(*syntax.Word)
|
||||
if w == nil || len(w.Parts) != 1 {
|
||||
return nil
|
||||
}
|
||||
l, _ := w.Parts[0].(*syntax.Lit)
|
||||
if l == nil || l.Value != "@" {
|
||||
return nil
|
||||
}
|
||||
val, _ := r.lookupVar(pe.Param.Value)
|
||||
switch x := val.(type) {
|
||||
case []string:
|
||||
return x
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Runner) paramExp(pe *syntax.ParamExp) string {
|
||||
name := pe.Param.Value
|
||||
var val varValue
|
||||
|
||||
182
vendor/github.com/mvdan/sh/interp/test_classic.go
generated
vendored
Normal file
182
vendor/github.com/mvdan/sh/interp/test_classic.go
generated
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
// Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc>
|
||||
// See LICENSE for licensing information
|
||||
|
||||
package interp
|
||||
|
||||
import (
|
||||
"github.com/mvdan/sh/syntax"
|
||||
)
|
||||
|
||||
const illegalTok = 0
|
||||
|
||||
type testParser struct {
|
||||
eof bool
|
||||
val string
|
||||
rem []string
|
||||
|
||||
err func(format string, a ...interface{})
|
||||
}
|
||||
|
||||
func (p *testParser) next() {
|
||||
if p.eof || len(p.rem) == 0 {
|
||||
p.eof = true
|
||||
return
|
||||
}
|
||||
p.val = p.rem[0]
|
||||
p.rem = p.rem[1:]
|
||||
}
|
||||
|
||||
func (p *testParser) followWord(fval string) *syntax.Word {
|
||||
if p.eof {
|
||||
p.err("%s must be followed by a word", fval)
|
||||
}
|
||||
w := &syntax.Word{Parts: []syntax.WordPart{
|
||||
&syntax.Lit{Value: p.val},
|
||||
}}
|
||||
p.next()
|
||||
return w
|
||||
}
|
||||
|
||||
func (p *testParser) classicTest(fval string, pastAndOr bool) syntax.TestExpr {
|
||||
var left syntax.TestExpr
|
||||
if pastAndOr {
|
||||
left = p.testExprBase(fval)
|
||||
} else {
|
||||
left = p.classicTest(fval, true)
|
||||
}
|
||||
if left == nil || p.eof {
|
||||
return left
|
||||
}
|
||||
opStr := p.val
|
||||
op := testBinaryOp(p.val)
|
||||
if op == illegalTok {
|
||||
p.err("not a valid test operator: %s", p.val)
|
||||
}
|
||||
b := &syntax.BinaryTest{
|
||||
Op: op,
|
||||
X: left,
|
||||
}
|
||||
p.next()
|
||||
switch b.Op {
|
||||
case syntax.AndTest, syntax.OrTest:
|
||||
if b.Y = p.classicTest(opStr, false); b.Y == nil {
|
||||
p.err("%s must be followed by an expression", opStr)
|
||||
}
|
||||
default:
|
||||
b.Y = p.followWord(opStr)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (p *testParser) testExprBase(fval string) syntax.TestExpr {
|
||||
if p.eof {
|
||||
return nil
|
||||
}
|
||||
op := testUnaryOp(p.val)
|
||||
switch op {
|
||||
case syntax.TsNot:
|
||||
u := &syntax.UnaryTest{Op: op}
|
||||
p.next()
|
||||
u.X = p.classicTest(op.String(), false)
|
||||
return u
|
||||
case illegalTok:
|
||||
return p.followWord(fval)
|
||||
default:
|
||||
u := &syntax.UnaryTest{Op: op}
|
||||
p.next()
|
||||
u.X = p.followWord(op.String())
|
||||
return u
|
||||
}
|
||||
}
|
||||
|
||||
// testUnaryOp is an exact copy of syntax's.
|
||||
func testUnaryOp(val string) syntax.UnTestOperator {
|
||||
switch val {
|
||||
case "!":
|
||||
return syntax.TsNot
|
||||
case "-e", "-a":
|
||||
return syntax.TsExists
|
||||
case "-f":
|
||||
return syntax.TsRegFile
|
||||
case "-d":
|
||||
return syntax.TsDirect
|
||||
case "-c":
|
||||
return syntax.TsCharSp
|
||||
case "-b":
|
||||
return syntax.TsBlckSp
|
||||
case "-p":
|
||||
return syntax.TsNmPipe
|
||||
case "-S":
|
||||
return syntax.TsSocket
|
||||
case "-L", "-h":
|
||||
return syntax.TsSmbLink
|
||||
case "-k":
|
||||
return syntax.TsSticky
|
||||
case "-g":
|
||||
return syntax.TsGIDSet
|
||||
case "-u":
|
||||
return syntax.TsUIDSet
|
||||
case "-G":
|
||||
return syntax.TsGrpOwn
|
||||
case "-O":
|
||||
return syntax.TsUsrOwn
|
||||
case "-N":
|
||||
return syntax.TsModif
|
||||
case "-r":
|
||||
return syntax.TsRead
|
||||
case "-w":
|
||||
return syntax.TsWrite
|
||||
case "-x":
|
||||
return syntax.TsExec
|
||||
case "-s":
|
||||
return syntax.TsNoEmpty
|
||||
case "-t":
|
||||
return syntax.TsFdTerm
|
||||
case "-z":
|
||||
return syntax.TsEmpStr
|
||||
case "-n":
|
||||
return syntax.TsNempStr
|
||||
case "-o":
|
||||
return syntax.TsOptSet
|
||||
case "-v":
|
||||
return syntax.TsVarSet
|
||||
case "-R":
|
||||
return syntax.TsRefVar
|
||||
default:
|
||||
return illegalTok
|
||||
}
|
||||
}
|
||||
|
||||
// testBinaryOp is like syntax's, but with -a and -o, and without =~.
|
||||
func testBinaryOp(val string) syntax.BinTestOperator {
|
||||
switch val {
|
||||
case "-a":
|
||||
return syntax.AndTest
|
||||
case "-o":
|
||||
return syntax.OrTest
|
||||
case "==", "=":
|
||||
return syntax.TsMatch
|
||||
case "!=":
|
||||
return syntax.TsNoMatch
|
||||
case "-nt":
|
||||
return syntax.TsNewer
|
||||
case "-ot":
|
||||
return syntax.TsOlder
|
||||
case "-ef":
|
||||
return syntax.TsDevIno
|
||||
case "-eq":
|
||||
return syntax.TsEql
|
||||
case "-ne":
|
||||
return syntax.TsNeq
|
||||
case "-le":
|
||||
return syntax.TsLeq
|
||||
case "-ge":
|
||||
return syntax.TsGeq
|
||||
case "-lt":
|
||||
return syntax.TsLss
|
||||
case "-gt":
|
||||
return syntax.TsGtr
|
||||
default:
|
||||
return illegalTok
|
||||
}
|
||||
}
|
||||
101
vendor/github.com/mvdan/sh/syntax/lexer.go
generated
vendored
101
vendor/github.com/mvdan/sh/syntax/lexer.go
generated
vendored
@@ -28,6 +28,15 @@ func paramOps(r rune) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// these start a parameter expansion name
|
||||
func paramNameOp(r rune) bool {
|
||||
switch r {
|
||||
case '}', ':', '+', '=', '%', '[', ']', '/', '^', ',', '@':
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// tokenize these inside arithmetic expansions
|
||||
func arithmOps(r rune) bool {
|
||||
switch r {
|
||||
@@ -86,14 +95,6 @@ retry:
|
||||
return p.r
|
||||
}
|
||||
|
||||
func (p *Parser) unrune(r rune, tok token) {
|
||||
if p.r != utf8.RuneSelf {
|
||||
p.npos -= utf8.RuneLen(p.r)
|
||||
p.r = r
|
||||
p.tok = tok
|
||||
}
|
||||
}
|
||||
|
||||
// fill reads more bytes from the input src into readBuf. Any bytes that
|
||||
// had not yet been used at the end of the buffer are slid into the
|
||||
// beginning of the buffer.
|
||||
@@ -528,7 +529,7 @@ func (p *Parser) paramToken(r rune) token {
|
||||
p.rune()
|
||||
return leftBrack
|
||||
case '/':
|
||||
if p.rune() == '/' {
|
||||
if p.rune() == '/' && p.quote != paramExpRepl {
|
||||
p.rune()
|
||||
return dblSlash
|
||||
}
|
||||
@@ -961,90 +962,90 @@ loop:
|
||||
p.tok, p.val = _LitWord, p.endLit()
|
||||
}
|
||||
|
||||
func testUnaryOp(val string) token {
|
||||
func testUnaryOp(val string) UnTestOperator {
|
||||
switch val {
|
||||
case "!":
|
||||
return exclMark
|
||||
return TsNot
|
||||
case "-e", "-a":
|
||||
return tsExists
|
||||
return TsExists
|
||||
case "-f":
|
||||
return tsRegFile
|
||||
return TsRegFile
|
||||
case "-d":
|
||||
return tsDirect
|
||||
return TsDirect
|
||||
case "-c":
|
||||
return tsCharSp
|
||||
return TsCharSp
|
||||
case "-b":
|
||||
return tsBlckSp
|
||||
return TsBlckSp
|
||||
case "-p":
|
||||
return tsNmPipe
|
||||
return TsNmPipe
|
||||
case "-S":
|
||||
return tsSocket
|
||||
return TsSocket
|
||||
case "-L", "-h":
|
||||
return tsSmbLink
|
||||
return TsSmbLink
|
||||
case "-k":
|
||||
return tsSticky
|
||||
return TsSticky
|
||||
case "-g":
|
||||
return tsGIDSet
|
||||
return TsGIDSet
|
||||
case "-u":
|
||||
return tsUIDSet
|
||||
return TsUIDSet
|
||||
case "-G":
|
||||
return tsGrpOwn
|
||||
return TsGrpOwn
|
||||
case "-O":
|
||||
return tsUsrOwn
|
||||
return TsUsrOwn
|
||||
case "-N":
|
||||
return tsModif
|
||||
return TsModif
|
||||
case "-r":
|
||||
return tsRead
|
||||
return TsRead
|
||||
case "-w":
|
||||
return tsWrite
|
||||
return TsWrite
|
||||
case "-x":
|
||||
return tsExec
|
||||
return TsExec
|
||||
case "-s":
|
||||
return tsNoEmpty
|
||||
return TsNoEmpty
|
||||
case "-t":
|
||||
return tsFdTerm
|
||||
return TsFdTerm
|
||||
case "-z":
|
||||
return tsEmpStr
|
||||
return TsEmpStr
|
||||
case "-n":
|
||||
return tsNempStr
|
||||
return TsNempStr
|
||||
case "-o":
|
||||
return tsOptSet
|
||||
return TsOptSet
|
||||
case "-v":
|
||||
return tsVarSet
|
||||
return TsVarSet
|
||||
case "-R":
|
||||
return tsRefVar
|
||||
return TsRefVar
|
||||
default:
|
||||
return illegalTok
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func testBinaryOp(val string) token {
|
||||
func testBinaryOp(val string) BinTestOperator {
|
||||
switch val {
|
||||
case "==", "=":
|
||||
return equal
|
||||
return TsMatch
|
||||
case "!=":
|
||||
return nequal
|
||||
return TsNoMatch
|
||||
case "=~":
|
||||
return tsReMatch
|
||||
return TsReMatch
|
||||
case "-nt":
|
||||
return tsNewer
|
||||
return TsNewer
|
||||
case "-ot":
|
||||
return tsOlder
|
||||
return TsOlder
|
||||
case "-ef":
|
||||
return tsDevIno
|
||||
return TsDevIno
|
||||
case "-eq":
|
||||
return tsEql
|
||||
return TsEql
|
||||
case "-ne":
|
||||
return tsNeq
|
||||
return TsNeq
|
||||
case "-le":
|
||||
return tsLeq
|
||||
return TsLeq
|
||||
case "-ge":
|
||||
return tsGeq
|
||||
return TsGeq
|
||||
case "-lt":
|
||||
return tsLss
|
||||
return TsLss
|
||||
case "-gt":
|
||||
return tsGtr
|
||||
return TsGtr
|
||||
default:
|
||||
return illegalTok
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
87
vendor/github.com/mvdan/sh/syntax/nodes.go
generated
vendored
87
vendor/github.com/mvdan/sh/syntax/nodes.go
generated
vendored
@@ -111,17 +111,16 @@ func (c *Comment) End() Pos { return c.Hash + Pos(len(c.Text)) }
|
||||
// Stmt represents a statement, otherwise known as a compound command.
|
||||
// It is compromised of a command and other components that may come
|
||||
// before or after it.
|
||||
//
|
||||
// The Coprocess field is particular to MirBSDKorn.
|
||||
type Stmt struct {
|
||||
Cmd Command
|
||||
Position Pos
|
||||
Semicolon Pos
|
||||
Negated bool
|
||||
Background bool
|
||||
Coprocess bool
|
||||
Assigns []*Assign
|
||||
Redirs []*Redirect
|
||||
Negated bool // ! stmt
|
||||
Background bool // stmt &
|
||||
Coprocess bool // mksh's |&
|
||||
|
||||
Assigns []*Assign // a=x b=y stmt
|
||||
Redirs []*Redirect // stmt >a <b
|
||||
}
|
||||
|
||||
func (s *Stmt) Pos() Pos { return s.Position }
|
||||
@@ -174,13 +173,13 @@ func (*CoprocClause) commandNode() {}
|
||||
|
||||
// Assign represents an assignment to a variable.
|
||||
type Assign struct {
|
||||
Append bool
|
||||
Naked bool
|
||||
Append bool // +=
|
||||
Naked bool // without '='
|
||||
Name *Lit
|
||||
Index ArithmExpr
|
||||
Key *DblQuoted
|
||||
Value *Word
|
||||
Array *ArrayExpr
|
||||
Index ArithmExpr // [i]
|
||||
Key *DblQuoted // ["k"]
|
||||
Value *Word // =val
|
||||
Array *ArrayExpr // =(arr)
|
||||
}
|
||||
|
||||
func (a *Assign) Pos() Pos { return a.Name.Pos() }
|
||||
@@ -193,8 +192,7 @@ func (a *Assign) End() Pos {
|
||||
}
|
||||
if a.Index != nil {
|
||||
return a.Index.End() + 2
|
||||
}
|
||||
if a.Key != nil {
|
||||
} else if a.Key != nil {
|
||||
return a.Key.End() + 2
|
||||
}
|
||||
if a.Naked {
|
||||
@@ -205,10 +203,11 @@ func (a *Assign) End() Pos {
|
||||
|
||||
// Redirect represents an input/output redirection.
|
||||
type Redirect struct {
|
||||
OpPos Pos
|
||||
Op RedirOperator
|
||||
N *Lit
|
||||
Word, Hdoc *Word
|
||||
OpPos Pos
|
||||
Op RedirOperator
|
||||
N *Lit // N>
|
||||
Word *Word // >word
|
||||
Hdoc *Word // here-document body
|
||||
}
|
||||
|
||||
func (r *Redirect) Pos() Pos {
|
||||
@@ -330,10 +329,10 @@ func (b *BinaryCmd) End() Pos { return b.Y.End() }
|
||||
|
||||
// FuncDecl represents the declaration of a function.
|
||||
type FuncDecl struct {
|
||||
Position Pos
|
||||
BashStyle bool
|
||||
Name *Lit
|
||||
Body *Stmt
|
||||
Position Pos
|
||||
RsrvWord bool // non-posix "function " style
|
||||
Name *Lit
|
||||
Body *Stmt
|
||||
}
|
||||
|
||||
func (f *FuncDecl) Pos() Pos { return f.Position }
|
||||
@@ -379,7 +378,7 @@ func (l *Lit) End() Pos { return l.ValueEnd }
|
||||
// SglQuoted represents a string within single quotes.
|
||||
type SglQuoted struct {
|
||||
Position Pos
|
||||
Dollar bool
|
||||
Dollar bool // $''
|
||||
Value string
|
||||
}
|
||||
|
||||
@@ -395,7 +394,7 @@ func (q *SglQuoted) End() Pos {
|
||||
// DblQuoted represents a list of nodes within double quotes.
|
||||
type DblQuoted struct {
|
||||
Position Pos
|
||||
Dollar bool
|
||||
Dollar bool // $""
|
||||
Parts []WordPart
|
||||
}
|
||||
|
||||
@@ -415,10 +414,8 @@ type CmdSubst struct {
|
||||
Left, Right Pos
|
||||
Stmts []*Stmt
|
||||
|
||||
// MirBSDTempFile is true for mksh's ${ foo;}
|
||||
MirBSDTempFile bool
|
||||
// MirBSDReplyvar is true for mksh's ${|foo;}
|
||||
MirBSDReplyVar bool
|
||||
TempFile bool // mksh's ${ foo;}
|
||||
ReplyVar bool // mksh's ${|foo;}
|
||||
}
|
||||
|
||||
func (c *CmdSubst) Pos() Pos { return c.Left }
|
||||
@@ -427,16 +424,16 @@ func (c *CmdSubst) End() Pos { return c.Right + 1 }
|
||||
// ParamExp represents a parameter expansion.
|
||||
type ParamExp struct {
|
||||
Dollar, Rbrace Pos
|
||||
Short bool
|
||||
Indirect bool
|
||||
Length bool
|
||||
Width bool
|
||||
Short bool // $a instead of ${a}
|
||||
Indirect bool // ${!a}
|
||||
Length bool // ${#a}
|
||||
Width bool // ${%a}
|
||||
Param *Lit
|
||||
Index ArithmExpr
|
||||
Key *DblQuoted
|
||||
Slice *Slice
|
||||
Repl *Replace
|
||||
Exp *Expansion
|
||||
Index ArithmExpr // ${a[i]}
|
||||
Key *DblQuoted // ${a["k"]}
|
||||
Slice *Slice // ${a:x:y}
|
||||
Repl *Replace // ${a/x/y}
|
||||
Exp *Expansion // ${a:-b}, ${a#b}, etc
|
||||
}
|
||||
|
||||
func (p *ParamExp) Pos() Pos { return p.Dollar }
|
||||
@@ -446,8 +443,7 @@ func (p *ParamExp) End() Pos {
|
||||
}
|
||||
if p.Index != nil {
|
||||
return p.Index.End() + 1
|
||||
}
|
||||
if p.Key != nil {
|
||||
} else if p.Key != nil {
|
||||
return p.Key.End() + 1
|
||||
}
|
||||
return p.Param.End()
|
||||
@@ -480,8 +476,8 @@ type Expansion struct {
|
||||
// ArithmExp represents an arithmetic expansion.
|
||||
type ArithmExp struct {
|
||||
Left, Right Pos
|
||||
Bracket bool
|
||||
Unsigned bool
|
||||
Bracket bool // deprecated $[expr] form
|
||||
Unsigned bool // mksh's $((# expr))
|
||||
X ArithmExpr
|
||||
}
|
||||
|
||||
@@ -498,7 +494,7 @@ func (a *ArithmExp) End() Pos {
|
||||
// This node will never appear when in PosixConformant mode.
|
||||
type ArithmCmd struct {
|
||||
Left, Right Pos
|
||||
Unsigned bool
|
||||
Unsigned bool // mksh's ((# expr))
|
||||
X ArithmExpr
|
||||
}
|
||||
|
||||
@@ -651,7 +647,7 @@ func (p *ParenTest) End() Pos { return p.Rparen + 1 }
|
||||
// This node will never appear when in PosixConformant mode.
|
||||
type DeclClause struct {
|
||||
Position Pos
|
||||
Variant string
|
||||
Variant string // "declare", "local", etc
|
||||
Opts []*Word
|
||||
Assigns []*Assign
|
||||
}
|
||||
@@ -684,8 +680,7 @@ type ArrayElem struct {
|
||||
func (a *ArrayElem) Pos() Pos {
|
||||
if a.Index != nil {
|
||||
return a.Index.Pos()
|
||||
}
|
||||
if a.Key != nil {
|
||||
} else if a.Key != nil {
|
||||
return a.Key.Pos()
|
||||
}
|
||||
return a.Value.Pos()
|
||||
|
||||
178
vendor/github.com/mvdan/sh/syntax/parser.go
generated
vendored
178
vendor/github.com/mvdan/sh/syntax/parser.go
generated
vendored
@@ -118,7 +118,7 @@ func (p *Parser) getPos() Pos { return Pos(p.offs + p.npos) }
|
||||
|
||||
func (p *Parser) lit(pos Pos, val string) *Lit {
|
||||
if len(p.litBatch) == 0 {
|
||||
p.litBatch = make([]Lit, 64)
|
||||
p.litBatch = make([]Lit, 128)
|
||||
}
|
||||
l := &p.litBatch[0]
|
||||
p.litBatch = p.litBatch[1:]
|
||||
@@ -130,7 +130,7 @@ func (p *Parser) lit(pos Pos, val string) *Lit {
|
||||
|
||||
func (p *Parser) word(parts []WordPart) *Word {
|
||||
if len(p.wordBatch) == 0 {
|
||||
p.wordBatch = make([]Word, 32)
|
||||
p.wordBatch = make([]Word, 64)
|
||||
}
|
||||
w := &p.wordBatch[0]
|
||||
p.wordBatch = p.wordBatch[1:]
|
||||
@@ -150,7 +150,7 @@ func (p *Parser) wps(wp WordPart) []WordPart {
|
||||
|
||||
func (p *Parser) stmt(pos Pos) *Stmt {
|
||||
if len(p.stmtBatch) == 0 {
|
||||
p.stmtBatch = make([]Stmt, 16)
|
||||
p.stmtBatch = make([]Stmt, 64)
|
||||
}
|
||||
s := &p.stmtBatch[0]
|
||||
p.stmtBatch = p.stmtBatch[1:]
|
||||
@@ -160,7 +160,7 @@ func (p *Parser) stmt(pos Pos) *Stmt {
|
||||
|
||||
func (p *Parser) stList() []*Stmt {
|
||||
if len(p.stListBatch) == 0 {
|
||||
p.stListBatch = make([]*Stmt, 128)
|
||||
p.stListBatch = make([]*Stmt, 256)
|
||||
}
|
||||
stmts := p.stListBatch[:0:4]
|
||||
p.stListBatch = p.stListBatch[4:]
|
||||
@@ -184,7 +184,7 @@ func (p *Parser) call(w *Word) *CallExpr {
|
||||
return ce
|
||||
}
|
||||
|
||||
type quoteState uint
|
||||
type quoteState uint32
|
||||
|
||||
const (
|
||||
noState quoteState = 1 << iota
|
||||
@@ -557,9 +557,9 @@ func (p *Parser) wordPart() WordPart {
|
||||
p.curErr(`"${ stmts;}" is a mksh feature`)
|
||||
}
|
||||
cs := &CmdSubst{
|
||||
Left: p.pos,
|
||||
MirBSDTempFile: p.r != '|',
|
||||
MirBSDReplyVar: p.r == '|',
|
||||
Left: p.pos,
|
||||
TempFile: p.r != '|',
|
||||
ReplyVar: p.r == '|',
|
||||
}
|
||||
old := p.preNested(subCmd)
|
||||
p.rune() // don't tokenize '|'
|
||||
@@ -792,6 +792,9 @@ func (p *Parser) arithmExpr(ftok token, fpos Pos, level int, compact, tern bool)
|
||||
case _Lit, _LitWord:
|
||||
p.curErr("not a valid arithmetic operator: %s", p.val)
|
||||
return nil
|
||||
case leftBrack:
|
||||
p.curErr("[ must follow a name")
|
||||
return nil
|
||||
case rightParen, _EOF:
|
||||
default:
|
||||
if p.quote == arithmExpr {
|
||||
@@ -845,7 +848,7 @@ func isArithName(left ArithmExpr) bool {
|
||||
}
|
||||
switch x := w.Parts[0].(type) {
|
||||
case *Lit:
|
||||
return validIdent(x.Value)
|
||||
return ValidName(x.Value)
|
||||
case *ParamExp:
|
||||
return x.nakedIndex()
|
||||
default:
|
||||
@@ -905,10 +908,6 @@ func (p *Parser) arithmExprBase(compact bool) ArithmExpr {
|
||||
p.postNested(old)
|
||||
p.matched(left, leftBrack, rightBrack)
|
||||
x = p.word(p.wps(pe))
|
||||
case dollar:
|
||||
x = p.word(p.wps(p.shortParamExp()))
|
||||
case dollBrace:
|
||||
x = p.word(p.wps(p.paramExp()))
|
||||
case bckQuote:
|
||||
if p.quote == arithmExprLet {
|
||||
return nil
|
||||
@@ -964,15 +963,18 @@ func (p *Parser) paramExp() *ParamExp {
|
||||
pe := &ParamExp{Dollar: p.pos}
|
||||
old := p.quote
|
||||
p.quote = paramExpName
|
||||
p.next()
|
||||
if p.r == '#' {
|
||||
p.tok = hash
|
||||
p.pos = p.getPos()
|
||||
p.rune()
|
||||
} else {
|
||||
p.next()
|
||||
}
|
||||
switch p.tok {
|
||||
case at:
|
||||
p.tok, p.val = _LitWord, "@"
|
||||
case dblHash:
|
||||
p.unrune('#', hash)
|
||||
fallthrough
|
||||
case hash:
|
||||
if p.r != '}' {
|
||||
if paramNameOp(p.r) {
|
||||
pe.Length = true
|
||||
p.next()
|
||||
}
|
||||
@@ -980,12 +982,12 @@ func (p *Parser) paramExp() *ParamExp {
|
||||
if p.lang != LangMirBSDKorn {
|
||||
p.posErr(pe.Pos(), `"${%%foo}" is a mksh feature`)
|
||||
}
|
||||
if p.r != '}' {
|
||||
if paramNameOp(p.r) {
|
||||
pe.Width = true
|
||||
p.next()
|
||||
}
|
||||
case exclMark:
|
||||
if p.r != '}' {
|
||||
if paramNameOp(p.r) {
|
||||
pe.Indirect = true
|
||||
p.next()
|
||||
}
|
||||
@@ -1006,9 +1008,7 @@ func (p *Parser) paramExp() *ParamExp {
|
||||
p.curErr("%s cannot be followed by a word", op)
|
||||
}
|
||||
default:
|
||||
if !pe.Length {
|
||||
p.posErr(pe.Dollar, "parameter expansion requires a literal")
|
||||
}
|
||||
p.curErr("parameter expansion requires a literal")
|
||||
}
|
||||
if p.tok == rightBrace {
|
||||
pe.Rbrace = p.pos
|
||||
@@ -1050,14 +1050,9 @@ func (p *Parser) paramExp() *ParamExp {
|
||||
p.next()
|
||||
pe.Repl.Orig = p.getWord()
|
||||
p.quote = paramExpExp
|
||||
switch p.tok {
|
||||
case dblSlash:
|
||||
p.unrune('/', slash)
|
||||
p.next()
|
||||
case slash:
|
||||
p.next()
|
||||
if p.got(slash) {
|
||||
pe.Repl.With = p.getWord()
|
||||
}
|
||||
pe.Repl.With = p.getWord()
|
||||
case colon:
|
||||
if p.lang == LangPOSIX {
|
||||
p.curErr("slicing is a bash feature")
|
||||
@@ -1119,7 +1114,8 @@ func stopToken(tok token) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func validIdent(val string) bool {
|
||||
// ValidName returns whether val is a valid name as per the POSIX spec.
|
||||
func ValidName(val string) bool {
|
||||
for i, c := range val {
|
||||
switch {
|
||||
case 'a' <= c && c <= 'z':
|
||||
@@ -1138,7 +1134,7 @@ func (p *Parser) hasValidIdent() bool {
|
||||
if p.val[end-1] == '+' && p.lang != LangPOSIX {
|
||||
end--
|
||||
}
|
||||
if validIdent(p.val[:end]) {
|
||||
if ValidName(p.val[:end]) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -1387,57 +1383,51 @@ preLoop:
|
||||
case "esac":
|
||||
p.curErr(`%q can only be used to end a case`, p.val)
|
||||
case "[[":
|
||||
if p.lang == LangPOSIX {
|
||||
break
|
||||
if p.lang != LangPOSIX {
|
||||
s.Cmd = p.testClause()
|
||||
}
|
||||
s.Cmd = p.testClause()
|
||||
case "]]":
|
||||
if p.lang == LangPOSIX {
|
||||
break
|
||||
if p.lang != LangPOSIX {
|
||||
p.curErr(`%s can only be used to close a test`,
|
||||
p.val)
|
||||
}
|
||||
p.curErr(`%s can only be used to close a test`, p.val)
|
||||
case "let":
|
||||
if p.lang == LangPOSIX {
|
||||
break
|
||||
if p.lang != LangPOSIX {
|
||||
s.Cmd = p.letClause()
|
||||
}
|
||||
s.Cmd = p.letClause()
|
||||
case "function":
|
||||
if p.lang == LangPOSIX {
|
||||
break
|
||||
if p.lang != LangPOSIX {
|
||||
s.Cmd = p.bashFuncDecl()
|
||||
}
|
||||
s.Cmd = p.bashFuncDecl()
|
||||
case "declare":
|
||||
if p.lang != LangBash {
|
||||
break
|
||||
if p.lang == LangBash {
|
||||
s.Cmd = p.declClause()
|
||||
}
|
||||
s.Cmd = p.declClause()
|
||||
case "local", "export", "readonly", "typeset", "nameref":
|
||||
if p.lang == LangPOSIX {
|
||||
break
|
||||
if p.lang != LangPOSIX {
|
||||
s.Cmd = p.declClause()
|
||||
}
|
||||
s.Cmd = p.declClause()
|
||||
case "time":
|
||||
if p.lang == LangPOSIX {
|
||||
break
|
||||
if p.lang != LangPOSIX {
|
||||
s.Cmd = p.timeClause()
|
||||
}
|
||||
s.Cmd = p.timeClause()
|
||||
case "coproc":
|
||||
if p.lang != LangBash {
|
||||
break
|
||||
if p.lang == LangBash {
|
||||
s.Cmd = p.coprocClause()
|
||||
}
|
||||
s.Cmd = p.coprocClause()
|
||||
}
|
||||
if s.Cmd == nil {
|
||||
name := p.lit(p.pos, p.val)
|
||||
if p.next(); p.gotSameLine(leftParen) {
|
||||
p.follow(name.ValuePos, "foo(", rightParen)
|
||||
if p.lang == LangPOSIX && !validIdent(name.Value) {
|
||||
p.posErr(name.Pos(), "invalid func name")
|
||||
}
|
||||
s.Cmd = p.funcDecl(name, name.ValuePos)
|
||||
} else {
|
||||
s.Cmd = p.callExpr(s, p.word(p.wps(name)))
|
||||
if s.Cmd != nil {
|
||||
break
|
||||
}
|
||||
name := p.lit(p.pos, p.val)
|
||||
if p.next(); p.gotSameLine(leftParen) {
|
||||
p.follow(name.ValuePos, "foo(", rightParen)
|
||||
if p.lang == LangPOSIX && !ValidName(name.Value) {
|
||||
p.posErr(name.Pos(), "invalid func name")
|
||||
}
|
||||
s.Cmd = p.funcDecl(name, name.ValuePos)
|
||||
} else {
|
||||
s.Cmd = p.callExpr(s, p.word(p.wps(name)))
|
||||
}
|
||||
case bckQuote:
|
||||
if p.quote == subCmdBckquo {
|
||||
@@ -1576,25 +1566,16 @@ func (p *Parser) loop(forPos Pos) Loop {
|
||||
if p.tok == dblLeftParen {
|
||||
cl := &CStyleLoop{Lparen: p.pos}
|
||||
old := p.preNested(arithmExprCmd)
|
||||
if p.next(); p.tok == dblSemicolon {
|
||||
p.unrune(';', semicolon)
|
||||
}
|
||||
if p.tok != semicolon {
|
||||
cl.Init = p.arithmExpr(dblLeftParen, cl.Lparen, 0, false, false)
|
||||
}
|
||||
p.next()
|
||||
cl.Init = p.arithmExpr(dblLeftParen, cl.Lparen, 0, false, false)
|
||||
scPos := p.pos
|
||||
if p.tok == dblSemicolon {
|
||||
p.unrune(';', semicolon)
|
||||
}
|
||||
p.follow(p.pos, "expression", semicolon)
|
||||
if p.tok != semicolon {
|
||||
if !p.got(dblSemicolon) {
|
||||
p.follow(p.pos, "expr", semicolon)
|
||||
cl.Cond = p.arithmExpr(semicolon, scPos, 0, false, false)
|
||||
scPos = p.pos
|
||||
p.follow(p.pos, "expr", semicolon)
|
||||
}
|
||||
scPos = p.pos
|
||||
p.follow(p.pos, "expression", semicolon)
|
||||
if p.tok != semicolon {
|
||||
cl.Post = p.arithmExpr(semicolon, scPos, 0, false, false)
|
||||
}
|
||||
cl.Post = p.arithmExpr(semicolon, scPos, 0, false, false)
|
||||
cl.Rparen = p.arithmEnd(dblLeftParen, cl.Lparen, old)
|
||||
p.gotSameLine(semicolon)
|
||||
return cl
|
||||
@@ -1677,7 +1658,7 @@ func (p *Parser) testClause() *TestClause {
|
||||
if p.next(); p.tok == _EOF || p.gotRsrv("]]") {
|
||||
p.posErr(tc.Left, "test clause requires at least one expression")
|
||||
}
|
||||
tc.X = p.testExpr(illegalTok, tc.Left, 0)
|
||||
tc.X = p.testExpr(illegalTok, tc.Left, false)
|
||||
tc.Right = p.pos
|
||||
if !p.gotRsrv("]]") {
|
||||
p.matchingErr(tc.Left, "[[", "]]")
|
||||
@@ -1685,26 +1666,23 @@ func (p *Parser) testClause() *TestClause {
|
||||
return tc
|
||||
}
|
||||
|
||||
func (p *Parser) testExpr(ftok token, fpos Pos, level int) TestExpr {
|
||||
func (p *Parser) testExpr(ftok token, fpos Pos, pastAndOr bool) TestExpr {
|
||||
var left TestExpr
|
||||
if level > 1 {
|
||||
if pastAndOr {
|
||||
left = p.testExprBase(ftok, fpos)
|
||||
} else {
|
||||
left = p.testExpr(ftok, fpos, level+1)
|
||||
left = p.testExpr(ftok, fpos, true)
|
||||
}
|
||||
if left == nil {
|
||||
return left
|
||||
}
|
||||
var newLevel int
|
||||
switch p.tok {
|
||||
case andAnd, orOr:
|
||||
case _LitWord:
|
||||
if p.val == "]]" {
|
||||
return left
|
||||
}
|
||||
fallthrough
|
||||
case rdrIn, rdrOut:
|
||||
newLevel = 1
|
||||
case _EOF, rightParen:
|
||||
return left
|
||||
case _Lit:
|
||||
@@ -1712,11 +1690,8 @@ func (p *Parser) testExpr(ftok token, fpos Pos, level int) TestExpr {
|
||||
default:
|
||||
p.curErr("not a valid test operator: %v", p.tok)
|
||||
}
|
||||
if newLevel < level {
|
||||
return left
|
||||
}
|
||||
if p.tok == _LitWord {
|
||||
if p.tok = testBinaryOp(p.val); p.tok == illegalTok {
|
||||
if p.tok = token(testBinaryOp(p.val)); p.tok == illegalTok {
|
||||
p.curErr("not a valid test operator: %s", p.val)
|
||||
}
|
||||
}
|
||||
@@ -1728,7 +1703,7 @@ func (p *Parser) testExpr(ftok token, fpos Pos, level int) TestExpr {
|
||||
switch b.Op {
|
||||
case AndTest, OrTest:
|
||||
p.next()
|
||||
if b.Y = p.testExpr(token(b.Op), b.OpPos, newLevel); b.Y == nil {
|
||||
if b.Y = p.testExpr(token(b.Op), b.OpPos, false); b.Y == nil {
|
||||
p.followErrExp(b.OpPos, b.Op.String())
|
||||
}
|
||||
case TsReMatch:
|
||||
@@ -1754,11 +1729,10 @@ func (p *Parser) testExprBase(ftok token, fpos Pos) TestExpr {
|
||||
case _EOF:
|
||||
return nil
|
||||
case _LitWord:
|
||||
op := testUnaryOp(p.val)
|
||||
op := token(testUnaryOp(p.val))
|
||||
switch op {
|
||||
case illegalTok:
|
||||
case tsRefVar, tsModif:
|
||||
// TODO: check with man mksh
|
||||
case tsRefVar, tsModif: // not available in mksh
|
||||
if p.lang == LangBash {
|
||||
p.tok = op
|
||||
}
|
||||
@@ -1770,7 +1744,7 @@ func (p *Parser) testExprBase(ftok token, fpos Pos) TestExpr {
|
||||
case exclMark:
|
||||
u := &UnaryTest{OpPos: p.pos, Op: TsNot}
|
||||
p.next()
|
||||
u.X = p.testExpr(token(u.Op), u.OpPos, 0)
|
||||
u.X = p.testExpr(token(u.Op), u.OpPos, false)
|
||||
return u
|
||||
case tsExists, tsRegFile, tsDirect, tsCharSp, tsBlckSp, tsNmPipe,
|
||||
tsSocket, tsSmbLink, tsSticky, tsGIDSet, tsUIDSet, tsGrpOwn,
|
||||
@@ -1783,7 +1757,7 @@ func (p *Parser) testExprBase(ftok token, fpos Pos) TestExpr {
|
||||
case leftParen:
|
||||
pe := &ParenTest{Lparen: p.pos}
|
||||
p.next()
|
||||
if pe.X = p.testExpr(leftParen, pe.Lparen, 0); pe.X == nil {
|
||||
if pe.X = p.testExpr(leftParen, pe.Lparen, false); pe.X == nil {
|
||||
p.followErrExp(pe.Lparen, "(")
|
||||
}
|
||||
pe.Rparen = p.matched(pe.Lparen, leftParen, rightParen)
|
||||
@@ -1953,9 +1927,9 @@ func (p *Parser) callExpr(s *Stmt, w *Word) *CallExpr {
|
||||
|
||||
func (p *Parser) funcDecl(name *Lit, pos Pos) *FuncDecl {
|
||||
fd := &FuncDecl{
|
||||
Position: pos,
|
||||
BashStyle: pos != name.ValuePos,
|
||||
Name: name,
|
||||
Position: pos,
|
||||
RsrvWord: pos != name.ValuePos,
|
||||
Name: name,
|
||||
}
|
||||
if fd.Body, _ = p.getStmt(false, false); fd.Body == nil {
|
||||
p.followErr(fd.Pos(), "foo()", "a statement")
|
||||
|
||||
10
vendor/github.com/mvdan/sh/syntax/printer.go
generated
vendored
10
vendor/github.com/mvdan/sh/syntax/printer.go
generated
vendored
@@ -289,13 +289,13 @@ func (p *Printer) wordPart(wp WordPart) {
|
||||
case *CmdSubst:
|
||||
p.incLines(x.Pos())
|
||||
switch {
|
||||
case x.MirBSDTempFile:
|
||||
case x.TempFile:
|
||||
p.WriteString("${")
|
||||
p.wantSpace = true
|
||||
p.nestedStmts(x.Stmts, x.Right)
|
||||
p.wantSpace = false
|
||||
p.semiRsrv("}", x.Right, true)
|
||||
case x.MirBSDReplyVar:
|
||||
case x.ReplyVar:
|
||||
p.WriteString("${|")
|
||||
p.nestedStmts(x.Stmts, x.Right)
|
||||
p.wantSpace = false
|
||||
@@ -380,9 +380,7 @@ func (p *Printer) paramExp(pe *ParamExp) {
|
||||
case pe.Indirect:
|
||||
p.WriteByte('!')
|
||||
}
|
||||
if pe.Param != nil {
|
||||
p.WriteString(pe.Param.Value)
|
||||
}
|
||||
p.WriteString(pe.Param.Value)
|
||||
p.wroteIndex(pe.Index, pe.Key)
|
||||
if pe.Slice != nil {
|
||||
p.WriteByte(':')
|
||||
@@ -741,7 +739,7 @@ func (p *Printer) command(cmd Command, redirs []*Redirect) (startRedirs int) {
|
||||
}
|
||||
p.nestedBinary = false
|
||||
case *FuncDecl:
|
||||
if x.BashStyle {
|
||||
if x.RsrvWord {
|
||||
p.WriteString("function ")
|
||||
}
|
||||
p.WriteString(x.Name.Value)
|
||||
|
||||
243
vendor/github.com/mvdan/sh/syntax/simplify.go
generated
vendored
Normal file
243
vendor/github.com/mvdan/sh/syntax/simplify.go
generated
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
// Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc>
|
||||
// See LICENSE for licensing information
|
||||
|
||||
package syntax
|
||||
|
||||
import "bytes"
|
||||
|
||||
// Simplify simplifies a given program and returns whether any changes
|
||||
// were made.
|
||||
//
|
||||
// This function is EXPERIMENTAL; it may change or disappear at any
|
||||
// point until this notice is removed.
|
||||
func Simplify(f *File) bool {
|
||||
s := simplifier{}
|
||||
Walk(f, s.visit)
|
||||
return s.modified
|
||||
}
|
||||
|
||||
type simplifier struct {
|
||||
modified bool
|
||||
}
|
||||
|
||||
func (s *simplifier) visit(node Node) bool {
|
||||
switch x := node.(type) {
|
||||
case *Assign:
|
||||
if x.Index != nil {
|
||||
x.Index = s.removeParensArithm(x.Index)
|
||||
x.Index = s.inlineSimpleParams(x.Index)
|
||||
}
|
||||
case *ParamExp:
|
||||
if x.Index != nil {
|
||||
x.Index = s.removeParensArithm(x.Index)
|
||||
x.Index = s.inlineSimpleParams(x.Index)
|
||||
}
|
||||
if x.Slice == nil {
|
||||
break
|
||||
}
|
||||
if x.Slice.Offset != nil {
|
||||
x.Slice.Offset = s.removeParensArithm(x.Slice.Offset)
|
||||
x.Slice.Offset = s.inlineSimpleParams(x.Slice.Offset)
|
||||
}
|
||||
if x.Slice.Length != nil {
|
||||
x.Slice.Length = s.removeParensArithm(x.Slice.Length)
|
||||
x.Slice.Length = s.inlineSimpleParams(x.Slice.Length)
|
||||
}
|
||||
case *ArithmExp:
|
||||
x.X = s.removeParensArithm(x.X)
|
||||
x.X = s.inlineSimpleParams(x.X)
|
||||
case *ArithmCmd:
|
||||
x.X = s.removeParensArithm(x.X)
|
||||
x.X = s.inlineSimpleParams(x.X)
|
||||
case *ParenArithm:
|
||||
x.X = s.removeParensArithm(x.X)
|
||||
x.X = s.inlineSimpleParams(x.X)
|
||||
case *BinaryArithm:
|
||||
x.X = s.inlineSimpleParams(x.X)
|
||||
x.Y = s.inlineSimpleParams(x.Y)
|
||||
case *CmdSubst:
|
||||
x.Stmts = s.inlineSubshell(x.Stmts)
|
||||
case *Subshell:
|
||||
x.Stmts = s.inlineSubshell(x.Stmts)
|
||||
case *Word:
|
||||
x.Parts = s.simplifyWord(x.Parts)
|
||||
case *TestClause:
|
||||
x.X = s.removeParensTest(x.X)
|
||||
x.X = s.removeNegateTest(x.X)
|
||||
case *ParenTest:
|
||||
x.X = s.removeParensTest(x.X)
|
||||
x.X = s.removeNegateTest(x.X)
|
||||
case *BinaryTest:
|
||||
x.X = s.unquoteParams(x.X)
|
||||
x.X = s.removeNegateTest(x.X)
|
||||
switch x.Op {
|
||||
case TsMatch, TsNoMatch:
|
||||
// unquoting enables globbing
|
||||
default:
|
||||
x.Y = s.unquoteParams(x.Y)
|
||||
}
|
||||
x.Y = s.removeNegateTest(x.Y)
|
||||
case *UnaryTest:
|
||||
x.X = s.unquoteParams(x.X)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *simplifier) simplifyWord(wps []WordPart) []WordPart {
|
||||
parts:
|
||||
for i, wp := range wps {
|
||||
dq, _ := wp.(*DblQuoted)
|
||||
if dq == nil || len(dq.Parts) != 1 {
|
||||
break
|
||||
}
|
||||
lit, _ := dq.Parts[0].(*Lit)
|
||||
if lit == nil {
|
||||
break
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
escaped := false
|
||||
for _, r := range lit.Value {
|
||||
switch r {
|
||||
case '\\':
|
||||
escaped = !escaped
|
||||
if escaped {
|
||||
continue
|
||||
}
|
||||
case '\'':
|
||||
continue parts
|
||||
case '$', '"', '`':
|
||||
escaped = false
|
||||
default:
|
||||
if escaped {
|
||||
continue parts
|
||||
}
|
||||
escaped = false
|
||||
}
|
||||
buf.WriteRune(r)
|
||||
}
|
||||
newVal := buf.String()
|
||||
if newVal == lit.Value {
|
||||
break
|
||||
}
|
||||
s.modified = true
|
||||
wps[i] = &SglQuoted{
|
||||
Position: dq.Position,
|
||||
Dollar: dq.Dollar,
|
||||
Value: newVal,
|
||||
}
|
||||
}
|
||||
return wps
|
||||
}
|
||||
|
||||
func (s *simplifier) removeParensArithm(x ArithmExpr) ArithmExpr {
|
||||
for {
|
||||
par, _ := x.(*ParenArithm)
|
||||
if par == nil {
|
||||
return x
|
||||
}
|
||||
s.modified = true
|
||||
x = par.X
|
||||
}
|
||||
}
|
||||
|
||||
func (s *simplifier) inlineSimpleParams(x ArithmExpr) ArithmExpr {
|
||||
w, _ := x.(*Word)
|
||||
if w == nil || len(w.Parts) != 1 {
|
||||
return x
|
||||
}
|
||||
pe, _ := w.Parts[0].(*ParamExp)
|
||||
if pe == nil || !ValidName(pe.Param.Value) {
|
||||
return x
|
||||
}
|
||||
if pe.Indirect || pe.Length || pe.Width || pe.Key != nil ||
|
||||
pe.Slice != nil || pe.Repl != nil || pe.Exp != nil {
|
||||
return x
|
||||
}
|
||||
if pe.Index != nil {
|
||||
s.modified = true
|
||||
pe.Short = true
|
||||
return w
|
||||
}
|
||||
s.modified = true
|
||||
return &Word{Parts: []WordPart{pe.Param}}
|
||||
}
|
||||
|
||||
func (s *simplifier) inlineSubshell(stmts []*Stmt) []*Stmt {
|
||||
for len(stmts) == 1 {
|
||||
st := stmts[0]
|
||||
if st.Negated || st.Background || st.Coprocess ||
|
||||
len(st.Assigns) > 0 || len(st.Redirs) > 0 {
|
||||
break
|
||||
}
|
||||
sub, _ := st.Cmd.(*Subshell)
|
||||
if sub == nil {
|
||||
break
|
||||
}
|
||||
s.modified = true
|
||||
stmts = sub.Stmts
|
||||
}
|
||||
return stmts
|
||||
}
|
||||
|
||||
func (s *simplifier) unquoteParams(x TestExpr) TestExpr {
|
||||
w, _ := x.(*Word)
|
||||
if w == nil || len(w.Parts) != 1 {
|
||||
return x
|
||||
}
|
||||
dq, _ := w.Parts[0].(*DblQuoted)
|
||||
if dq == nil || len(dq.Parts) != 1 {
|
||||
return x
|
||||
}
|
||||
if _, ok := dq.Parts[0].(*ParamExp); !ok {
|
||||
return x
|
||||
}
|
||||
s.modified = true
|
||||
w.Parts = dq.Parts
|
||||
return w
|
||||
}
|
||||
|
||||
func (s *simplifier) removeParensTest(x TestExpr) TestExpr {
|
||||
for {
|
||||
par, _ := x.(*ParenTest)
|
||||
if par == nil {
|
||||
return x
|
||||
}
|
||||
s.modified = true
|
||||
x = par.X
|
||||
}
|
||||
}
|
||||
|
||||
func (s *simplifier) removeNegateTest(x TestExpr) TestExpr {
|
||||
u, _ := x.(*UnaryTest)
|
||||
if u == nil || u.Op != TsNot {
|
||||
return x
|
||||
}
|
||||
switch y := u.X.(type) {
|
||||
case *UnaryTest:
|
||||
switch y.Op {
|
||||
case TsEmpStr:
|
||||
y.Op = TsNempStr
|
||||
s.modified = true
|
||||
return y
|
||||
case TsNempStr:
|
||||
y.Op = TsEmpStr
|
||||
s.modified = true
|
||||
return y
|
||||
case TsNot:
|
||||
s.modified = true
|
||||
return y.X
|
||||
}
|
||||
case *BinaryTest:
|
||||
switch y.Op {
|
||||
case TsMatch:
|
||||
y.Op = TsNoMatch
|
||||
s.modified = true
|
||||
return y
|
||||
case TsNoMatch:
|
||||
y.Op = TsMatch
|
||||
s.modified = true
|
||||
return y
|
||||
}
|
||||
}
|
||||
return x
|
||||
}
|
||||
13
vendor/github.com/mvdan/sh/syntax/walk.go
generated
vendored
13
vendor/github.com/mvdan/sh/syntax/walk.go
generated
vendored
@@ -46,6 +46,11 @@ func Walk(node Node, f func(Node) bool) {
|
||||
if x.Value != nil {
|
||||
Walk(x.Value, f)
|
||||
}
|
||||
if x.Index != nil {
|
||||
Walk(x.Index, f)
|
||||
} else if x.Key != nil {
|
||||
Walk(x.Key, f)
|
||||
}
|
||||
if x.Array != nil {
|
||||
Walk(x.Array, f)
|
||||
}
|
||||
@@ -109,11 +114,11 @@ func Walk(node Node, f func(Node) bool) {
|
||||
case *CmdSubst:
|
||||
walkStmts(x.Stmts, f)
|
||||
case *ParamExp:
|
||||
if x.Param != nil {
|
||||
Walk(x.Param, f)
|
||||
}
|
||||
Walk(x.Param, f)
|
||||
if x.Index != nil {
|
||||
Walk(x.Index, f)
|
||||
} else if x.Key != nil {
|
||||
Walk(x.Key, f)
|
||||
}
|
||||
if x.Repl != nil {
|
||||
if x.Repl.Orig != nil {
|
||||
@@ -164,6 +169,8 @@ func Walk(node Node, f func(Node) bool) {
|
||||
case *ArrayElem:
|
||||
if x.Index != nil {
|
||||
Walk(x.Index, f)
|
||||
} else if x.Key != nil {
|
||||
Walk(x.Key, f)
|
||||
}
|
||||
Walk(x.Value, f)
|
||||
case *ExtGlob:
|
||||
|
||||
Reference in New Issue
Block a user