mirror of
https://github.com/go-task/task.git
synced 2026-06-16 04:11:40 +00:00
update deps
This commit is contained in:
25
vendor/github.com/mvdan/sh/interp/builtin.go
generated
vendored
25
vendor/github.com/mvdan/sh/interp/builtin.go
generated
vendored
@@ -75,16 +75,15 @@ func (r *Runner) builtinCode(pos syntax.Pos, name string, args []string) int {
|
||||
r.delVar(arg)
|
||||
}
|
||||
case "echo":
|
||||
newline := true
|
||||
newline, expand := true, false
|
||||
echoOpts:
|
||||
for len(args) > 0 {
|
||||
switch args[0] {
|
||||
case "-n":
|
||||
newline = false
|
||||
case "-e", "-E":
|
||||
// TODO: what should be our default?
|
||||
// exactly what is the difference in
|
||||
// what we write?
|
||||
case "-e":
|
||||
expand = true
|
||||
case "-E": // default
|
||||
default:
|
||||
break echoOpts
|
||||
}
|
||||
@@ -94,6 +93,9 @@ func (r *Runner) builtinCode(pos syntax.Pos, name string, args []string) int {
|
||||
if i > 0 {
|
||||
r.outf(" ")
|
||||
}
|
||||
if expand {
|
||||
arg = r.expand(arg, true)
|
||||
}
|
||||
r.outf("%s", arg)
|
||||
}
|
||||
if newline {
|
||||
@@ -104,11 +106,7 @@ func (r *Runner) builtinCode(pos syntax.Pos, name string, args []string) int {
|
||||
r.errf("usage: printf format [arguments]\n")
|
||||
return 2
|
||||
}
|
||||
var a []interface{}
|
||||
for _, arg := range args[1:] {
|
||||
a = append(a, arg)
|
||||
}
|
||||
r.outf(args[0], a...)
|
||||
r.outf("%s", r.expand(args[0], false, args[1:]...))
|
||||
case "break":
|
||||
if !r.inLoop {
|
||||
r.errf("break is only useful in a loop")
|
||||
@@ -159,7 +157,8 @@ func (r *Runner) builtinCode(pos syntax.Pos, name string, args []string) int {
|
||||
return 2
|
||||
}
|
||||
dir = r.relPath(dir)
|
||||
if _, err := os.Stat(dir); err != nil {
|
||||
info, err := os.Stat(dir)
|
||||
if err != nil || !info.IsDir() {
|
||||
return 1
|
||||
}
|
||||
r.Dir = dir
|
||||
@@ -207,7 +206,7 @@ func (r *Runner) builtinCode(pos syntax.Pos, name string, args []string) int {
|
||||
return 1
|
||||
}
|
||||
r2 := *r
|
||||
r2.File = file
|
||||
r2.Node = file
|
||||
r2.Run()
|
||||
return r2.exit
|
||||
case "source", ".":
|
||||
@@ -228,7 +227,7 @@ func (r *Runner) builtinCode(pos syntax.Pos, name string, args []string) int {
|
||||
}
|
||||
r2 := *r
|
||||
r2.Params = args[1:]
|
||||
r2.File = file
|
||||
r2.Node = file
|
||||
r2.Run()
|
||||
return r2.exit
|
||||
case "[":
|
||||
|
||||
3
vendor/github.com/mvdan/sh/interp/doc.go
generated
vendored
3
vendor/github.com/mvdan/sh/interp/doc.go
generated
vendored
@@ -2,7 +2,8 @@
|
||||
// See LICENSE for licensing information
|
||||
|
||||
// Package interp implements an interpreter that executes shell
|
||||
// programs. It aims to support POSIX.
|
||||
// programs. It aims to support POSIX, but its support is not complete
|
||||
// yet. It also supports some Bash features.
|
||||
//
|
||||
// This package is a work in progress and EXPERIMENTAL; its API is not
|
||||
// subject to the 1.x backwards compatibility guarantee.
|
||||
|
||||
115
vendor/github.com/mvdan/sh/interp/interp.go
generated
vendored
115
vendor/github.com/mvdan/sh/interp/interp.go
generated
vendored
@@ -29,8 +29,7 @@ import (
|
||||
// concurrent use, consider a workaround like hiding writes behind a
|
||||
// mutex.
|
||||
type Runner struct {
|
||||
// TODO: syntax.Node instead of *syntax.File?
|
||||
File *syntax.File
|
||||
Node syntax.Node
|
||||
|
||||
// Env specifies the environment of the interpreter.
|
||||
// If Env is nil, Run uses the current process's environment.
|
||||
@@ -243,7 +242,16 @@ func (r *Runner) Run() error {
|
||||
}
|
||||
r.Dir = dir
|
||||
}
|
||||
r.stmts(r.File.StmtList)
|
||||
switch x := r.Node.(type) {
|
||||
case *syntax.File:
|
||||
r.stmts(x.StmtList)
|
||||
case *syntax.Stmt:
|
||||
r.stmt(x)
|
||||
case syntax.Command:
|
||||
r.cmd(x)
|
||||
default:
|
||||
return fmt.Errorf("Node can only be File, Stmt, or Command: %T", x)
|
||||
}
|
||||
r.lastExit()
|
||||
if r.err == ExitCode(0) {
|
||||
r.err = nil
|
||||
@@ -259,6 +267,56 @@ func (r *Runner) errf(format string, a ...interface{}) {
|
||||
fmt.Fprintf(r.Stderr, format, a...)
|
||||
}
|
||||
|
||||
func (r *Runner) expand(format string, onlyChars bool, args ...string) string {
|
||||
var buf bytes.Buffer
|
||||
esc, fmt := false, false
|
||||
for _, c := range format {
|
||||
if esc {
|
||||
esc = false
|
||||
switch c {
|
||||
case 'n':
|
||||
buf.WriteRune('\n')
|
||||
case 'r':
|
||||
buf.WriteRune('\r')
|
||||
case 't':
|
||||
buf.WriteRune('\t')
|
||||
case '\\':
|
||||
buf.WriteRune('\\')
|
||||
default:
|
||||
buf.WriteRune('\\')
|
||||
buf.WriteRune(c)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if fmt {
|
||||
fmt = false
|
||||
arg := ""
|
||||
if len(args) > 0 {
|
||||
arg, args = args[0], args[1:]
|
||||
}
|
||||
switch c {
|
||||
case 's':
|
||||
buf.WriteString(arg)
|
||||
case 'd':
|
||||
// round-trip to convert invalid to 0
|
||||
n, _ := strconv.Atoi(arg)
|
||||
buf.WriteString(strconv.Itoa(n))
|
||||
default:
|
||||
r.runErr(syntax.Pos{}, "unhandled format char: %c", c)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if c == '\\' {
|
||||
esc = true
|
||||
} else if !onlyChars && c == '%' {
|
||||
fmt = true
|
||||
} else {
|
||||
buf.WriteRune(c)
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func fieldJoin(parts []fieldPart) string {
|
||||
var buf bytes.Buffer
|
||||
for _, part := range parts {
|
||||
@@ -394,18 +452,6 @@ func (r *Runner) assignValue(as *syntax.Assign) varValue {
|
||||
}
|
||||
|
||||
func (r *Runner) stmtSync(st *syntax.Stmt) {
|
||||
oldVars := r.cmdVars
|
||||
for _, as := range st.Assigns {
|
||||
val := r.assignValue(as)
|
||||
if st.Cmd == nil {
|
||||
r.setVar(as.Name.Value, val)
|
||||
continue
|
||||
}
|
||||
if r.cmdVars == nil {
|
||||
r.cmdVars = make(map[string]varValue, len(st.Assigns))
|
||||
}
|
||||
r.cmdVars[as.Name.Value] = val
|
||||
}
|
||||
oldIn, oldOut, oldErr := r.Stdin, r.Stdout, r.Stderr
|
||||
for _, rd := range st.Redirs {
|
||||
cls, err := r.redir(rd)
|
||||
@@ -425,7 +471,6 @@ func (r *Runner) stmtSync(st *syntax.Stmt) {
|
||||
if st.Negated {
|
||||
r.exit = oneIf(r.exit == 0)
|
||||
}
|
||||
r.cmdVars = oldVars
|
||||
r.Stdin, r.Stdout, r.Stderr = oldIn, oldOut, oldErr
|
||||
}
|
||||
|
||||
@@ -448,8 +493,22 @@ func (r *Runner) cmd(cm syntax.Command) {
|
||||
r2.stmts(x.StmtList)
|
||||
r.exit = r2.exit
|
||||
case *syntax.CallExpr:
|
||||
if len(x.Args) == 0 {
|
||||
for _, as := range x.Assigns {
|
||||
r.setVar(as.Name.Value, r.assignValue(as))
|
||||
}
|
||||
break
|
||||
}
|
||||
oldVars := r.cmdVars
|
||||
if r.cmdVars == nil {
|
||||
r.cmdVars = make(map[string]varValue, len(x.Assigns))
|
||||
}
|
||||
for _, as := range x.Assigns {
|
||||
r.cmdVars[as.Name.Value] = r.assignValue(as)
|
||||
}
|
||||
fields := r.fields(x.Args)
|
||||
r.call(x.Args[0].Pos(), fields[0], fields[1:])
|
||||
r.cmdVars = oldVars
|
||||
case *syntax.BinaryCmd:
|
||||
switch x.Op {
|
||||
case syntax.AndStmt:
|
||||
@@ -612,10 +671,17 @@ func (r *Runner) redir(rd *syntax.Redirect) (io.Closer, error) {
|
||||
case syntax.RdrOut, syntax.RdrAll:
|
||||
mode = os.O_RDWR | os.O_CREATE | os.O_TRUNC
|
||||
}
|
||||
f, err := os.OpenFile(r.relPath(arg), mode, 0644)
|
||||
if err != nil {
|
||||
// TODO: print to stderr?
|
||||
return nil, err
|
||||
var f io.ReadWriteCloser
|
||||
switch arg {
|
||||
case "/dev/null":
|
||||
f = devNull{}
|
||||
default:
|
||||
var err error
|
||||
f, err = os.OpenFile(r.relPath(arg), mode, 0644)
|
||||
if err != nil {
|
||||
// TODO: print to stderr?
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
switch rd.Op {
|
||||
case syntax.RdrIn:
|
||||
@@ -685,10 +751,11 @@ func (r *Runner) wordFields(wps []syntax.WordPart, quoted bool) [][]fieldPart {
|
||||
curField = append(curField, fieldPart{val: s})
|
||||
case *syntax.SglQuoted:
|
||||
allowEmpty = true
|
||||
curField = append(curField, fieldPart{
|
||||
quoted: true,
|
||||
val: x.Value,
|
||||
})
|
||||
fp := fieldPart{quoted: true, val: x.Value}
|
||||
if x.Dollar {
|
||||
fp.val = r.expand(fp.val, true)
|
||||
}
|
||||
curField = append(curField, fp)
|
||||
case *syntax.DblQuoted:
|
||||
allowEmpty = true
|
||||
if len(x.Parts) == 1 {
|
||||
|
||||
31
vendor/github.com/mvdan/sh/syntax/lexer.go
generated
vendored
31
vendor/github.com/mvdan/sh/syntax/lexer.go
generated
vendored
@@ -56,22 +56,23 @@ func wordBreak(r rune) bool {
|
||||
}
|
||||
|
||||
func (p *Parser) rune() rune {
|
||||
if p.r == '\n' {
|
||||
// p.r instead of b so that newline
|
||||
// character positions don't have col 0.
|
||||
p.npos.line++
|
||||
p.npos.col = 1
|
||||
} else {
|
||||
p.npos.col += p.w
|
||||
}
|
||||
retry:
|
||||
if p.bsp < len(p.bs) {
|
||||
if b := p.bs[p.bsp]; b < utf8.RuneSelf {
|
||||
p.bsp++
|
||||
if p.r == '\n' {
|
||||
// p.r instead of b so that newline
|
||||
// character positions don't have col 0.
|
||||
p.npos.line++
|
||||
p.npos.col = 0
|
||||
}
|
||||
p.npos.col++
|
||||
if p.litBs != nil {
|
||||
p.litBs = append(p.litBs, b)
|
||||
}
|
||||
r := rune(b)
|
||||
p.r = r
|
||||
p.r, p.w = r, 1
|
||||
return r
|
||||
}
|
||||
if p.bsp+utf8.UTFMax >= len(p.bs) {
|
||||
@@ -85,10 +86,10 @@ retry:
|
||||
p.litBs = append(p.litBs, p.bs[p.bsp:p.bsp+w]...)
|
||||
}
|
||||
p.bsp += w
|
||||
p.npos.col += uint16(w)
|
||||
if p.r == utf8.RuneError && w == 1 {
|
||||
p.posErr(p.npos, "invalid UTF-8 encoding")
|
||||
}
|
||||
p.w = uint16(w)
|
||||
} else {
|
||||
if p.r == utf8.RuneSelf {
|
||||
} else if p.fill(); p.bs == nil {
|
||||
@@ -134,9 +135,7 @@ func (p *Parser) fill() {
|
||||
|
||||
func (p *Parser) nextKeepSpaces() {
|
||||
r := p.r
|
||||
if p.pos = p.getPos(); r > utf8.RuneSelf {
|
||||
p.pos = posAddCol(p.pos, -1) // TODO
|
||||
}
|
||||
p.pos = p.getPos()
|
||||
switch p.quote {
|
||||
case paramExpRepl:
|
||||
switch r {
|
||||
@@ -225,9 +224,7 @@ skipSpace:
|
||||
break skipSpace
|
||||
}
|
||||
}
|
||||
if p.pos = p.getPos(); r > utf8.RuneSelf {
|
||||
p.pos = posAddCol(p.pos, -1) // TODO
|
||||
}
|
||||
p.pos = p.getPos()
|
||||
switch {
|
||||
case p.quote&allRegTokens != 0:
|
||||
switch r {
|
||||
@@ -810,7 +807,7 @@ loop:
|
||||
}
|
||||
|
||||
func (p *Parser) advanceLitNone(r rune) {
|
||||
p.asPos = 0
|
||||
p.eqlOffs = 0
|
||||
tok := _LitWord
|
||||
loop:
|
||||
for p.newLit(r); r != utf8.RuneSelf; r = p.rune() {
|
||||
@@ -854,7 +851,7 @@ loop:
|
||||
break loop
|
||||
}
|
||||
case '=':
|
||||
p.asPos = len(p.litBs) - 1
|
||||
p.eqlOffs = len(p.litBs) - 1
|
||||
case '[':
|
||||
if p.lang != LangPOSIX && len(p.litBs) > 1 && p.litBs[0] != '[' {
|
||||
tok = _Lit
|
||||
|
||||
63
vendor/github.com/mvdan/sh/syntax/nodes.go
generated
vendored
63
vendor/github.com/mvdan/sh/syntax/nodes.go
generated
vendored
@@ -40,6 +40,16 @@ func (s StmtList) pos() Pos {
|
||||
return Pos{}
|
||||
}
|
||||
|
||||
func (s StmtList) end() Pos {
|
||||
if len(s.Last) > 0 {
|
||||
return s.Last[len(s.Last)-1].End()
|
||||
}
|
||||
if len(s.Stmts) > 0 {
|
||||
return s.Stmts[len(s.Stmts)-1].End()
|
||||
}
|
||||
return Pos{}
|
||||
}
|
||||
|
||||
func (s StmtList) empty() bool {
|
||||
return len(s.Stmts) == 0 && len(s.Last) == 0
|
||||
}
|
||||
@@ -52,20 +62,14 @@ type Pos struct {
|
||||
|
||||
// Offset returns the byte offset of the position in the original
|
||||
// source file. Byte offsets start at 0.
|
||||
func (p Pos) Offset() uint {
|
||||
return uint(p.offs)
|
||||
}
|
||||
func (p Pos) Offset() uint { return uint(p.offs) }
|
||||
|
||||
// Line returns the line number of the position, starting at 1.
|
||||
func (p Pos) Line() uint {
|
||||
return uint(p.line)
|
||||
}
|
||||
func (p Pos) Line() uint { return uint(p.line) }
|
||||
|
||||
// Col returns the column number of the position, starting at 0. It
|
||||
// Col returns the column number of the position, starting at 1. It
|
||||
// counts in bytes.
|
||||
func (p Pos) Col() uint {
|
||||
return uint(p.col)
|
||||
}
|
||||
func (p Pos) Col() uint { return uint(p.col) }
|
||||
|
||||
func (p Pos) String() string {
|
||||
return fmt.Sprintf("%d:%d", p.Line(), p.Col())
|
||||
@@ -113,9 +117,8 @@ type Comment struct {
|
||||
func (c *Comment) Pos() Pos { return c.Hash }
|
||||
func (c *Comment) End() Pos { return posAddCol(c.Hash, 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.
|
||||
// Stmt represents a statement. It is compromised of a command and other
|
||||
// components that may come before or after it.
|
||||
type Stmt struct {
|
||||
Comments []Comment
|
||||
Cmd Command
|
||||
@@ -125,8 +128,7 @@ type Stmt struct {
|
||||
Background bool // stmt &
|
||||
Coprocess bool // mksh's |&
|
||||
|
||||
Assigns []*Assign // a=x b=y stmt
|
||||
Redirs []*Redirect // stmt >a <b
|
||||
Redirs []*Redirect // stmt >a <b
|
||||
}
|
||||
|
||||
func (s *Stmt) Pos() Pos { return s.Position }
|
||||
@@ -141,17 +143,14 @@ func (s *Stmt) End() Pos {
|
||||
if s.Cmd != nil {
|
||||
end = s.Cmd.End()
|
||||
}
|
||||
if len(s.Assigns) > 0 {
|
||||
end = posMax(end, s.Assigns[len(s.Assigns)-1].End())
|
||||
}
|
||||
if len(s.Redirs) > 0 {
|
||||
end = posMax(end, s.Redirs[len(s.Redirs)-1].End())
|
||||
}
|
||||
return end
|
||||
}
|
||||
|
||||
// Command represents all nodes that are simple commands, which are
|
||||
// directly placed in a Stmt.
|
||||
// Command represents all nodes that are simple or compound commands,
|
||||
// including function declarations.
|
||||
//
|
||||
// These are *CallExpr, *IfClause, *WhileClause, *ForClause,
|
||||
// *CaseClause, *Block, *Subshell, *BinaryCmd, *FuncDecl, *ArithmCmd,
|
||||
@@ -237,13 +236,29 @@ func (r *Redirect) Pos() Pos {
|
||||
}
|
||||
func (r *Redirect) End() Pos { return r.Word.End() }
|
||||
|
||||
// CallExpr represents a command execution or function call.
|
||||
// CallExpr represents a command execution or function call, otherwise
|
||||
// known as a simple command.
|
||||
//
|
||||
// If Args is empty, Assigns apply to the shell environment. Otherwise,
|
||||
// they only apply to the call.
|
||||
type CallExpr struct {
|
||||
Args []*Word
|
||||
Assigns []*Assign // a=x b=y args
|
||||
Args []*Word
|
||||
}
|
||||
|
||||
func (c *CallExpr) Pos() Pos { return c.Args[0].Pos() }
|
||||
func (c *CallExpr) End() Pos { return c.Args[len(c.Args)-1].End() }
|
||||
func (c *CallExpr) Pos() Pos {
|
||||
if len(c.Assigns) > 0 {
|
||||
return c.Assigns[0].Pos()
|
||||
}
|
||||
return c.Args[0].Pos()
|
||||
}
|
||||
|
||||
func (c *CallExpr) End() Pos {
|
||||
if len(c.Args) == 0 {
|
||||
return c.Assigns[len(c.Assigns)-1].End()
|
||||
}
|
||||
return c.Args[len(c.Args)-1].End()
|
||||
}
|
||||
|
||||
// Subshell represents a series of commands that should be executed in a
|
||||
// nested shell environment.
|
||||
|
||||
130
vendor/github.com/mvdan/sh/syntax/parser.go
generated
vendored
130
vendor/github.com/mvdan/sh/syntax/parser.go
generated
vendored
@@ -11,6 +11,8 @@ import (
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// KeepComments makes the parser parse comments and attach them to
|
||||
// nodes, as opposed to discarding them.
|
||||
func KeepComments(p *Parser) { p.keepComments = true }
|
||||
|
||||
type LangVariant int
|
||||
@@ -21,10 +23,13 @@ const (
|
||||
LangMirBSDKorn
|
||||
)
|
||||
|
||||
// Variant changes the shell language variant that the parser will
|
||||
// accept.
|
||||
func Variant(l LangVariant) func(*Parser) {
|
||||
return func(p *Parser) { p.lang = l }
|
||||
}
|
||||
|
||||
// NewParser allocates a new Parser and applies any number of options.
|
||||
func NewParser(options ...func(*Parser)) *Parser {
|
||||
p := &Parser{helperBuf: new(bytes.Buffer)}
|
||||
for _, opt := range options {
|
||||
@@ -35,11 +40,14 @@ func NewParser(options ...func(*Parser)) *Parser {
|
||||
|
||||
// Parse reads and parses a shell program with an optional name. It
|
||||
// returns the parsed program if no issues were encountered. Otherwise,
|
||||
// an error is returned.
|
||||
func (p *Parser) Parse(src io.Reader, name string) (*File, error) {
|
||||
// an error is returned. Reads from r are buffered.
|
||||
//
|
||||
// Parse can be called more than once, but not concurrently. That is, a
|
||||
// Parser can be reused once it is done working.
|
||||
func (p *Parser) Parse(r io.Reader, name string) (*File, error) {
|
||||
p.reset()
|
||||
p.f = &File{Name: name}
|
||||
p.src = src
|
||||
p.src = r
|
||||
p.rune()
|
||||
p.next()
|
||||
p.f.StmtList = p.stmts()
|
||||
@@ -51,11 +59,14 @@ func (p *Parser) Parse(src io.Reader, name string) (*File, error) {
|
||||
return p.f, p.err
|
||||
}
|
||||
|
||||
// Parser holds the internal state of the parsing mechanism of a
|
||||
// program.
|
||||
type Parser struct {
|
||||
src io.Reader
|
||||
bs []byte // current chunk of read bytes
|
||||
bsp int // pos within chunk for the next rune
|
||||
r rune
|
||||
bsp int // pos within chunk for the rune after r
|
||||
r rune // next rune
|
||||
w uint16 // width of r
|
||||
|
||||
f *File
|
||||
|
||||
@@ -70,10 +81,10 @@ type Parser struct {
|
||||
|
||||
offs int
|
||||
pos Pos // position of tok
|
||||
npos Pos // next position
|
||||
npos Pos // next position (of r)
|
||||
|
||||
quote quoteState // current lexer state
|
||||
asPos int // position of '=' in a literal
|
||||
quote quoteState // current lexer state
|
||||
eqlOffs int // position of '=' in val (a literal)
|
||||
|
||||
keepComments bool
|
||||
lang LangVariant
|
||||
@@ -105,17 +116,20 @@ type Parser struct {
|
||||
const bufSize = 1 << 10
|
||||
|
||||
func (p *Parser) reset() {
|
||||
p.tok, p.val = illegalTok, ""
|
||||
p.eqlOffs = 0
|
||||
p.bs, p.bsp = nil, 0
|
||||
p.offs = 0
|
||||
p.npos = Pos{line: 1}
|
||||
p.r, p.err, p.readErr = 0, nil, nil
|
||||
p.npos = Pos{line: 1, col: 1}
|
||||
p.r, p.w = 0, 0
|
||||
p.err, p.readErr = nil, nil
|
||||
p.quote, p.forbidNested = noState, false
|
||||
p.heredocs, p.buriedHdocs = p.heredocs[:0], 0
|
||||
p.accComs, p.curComs = nil, &p.accComs
|
||||
}
|
||||
|
||||
func (p *Parser) getPos() Pos {
|
||||
p.npos.offs = uint32(p.offs + p.bsp - 1)
|
||||
p.npos.offs = uint32(p.offs + p.bsp - int(p.w))
|
||||
return p.npos
|
||||
}
|
||||
|
||||
@@ -1145,7 +1159,7 @@ func ValidName(val string) bool {
|
||||
}
|
||||
|
||||
func (p *Parser) hasValidIdent() bool {
|
||||
if end := p.asPos; end > 0 {
|
||||
if end := p.eqlOffs; end > 0 {
|
||||
if p.val[end-1] == '+' && p.lang != LangPOSIX {
|
||||
end--
|
||||
}
|
||||
@@ -1158,9 +1172,9 @@ func (p *Parser) hasValidIdent() bool {
|
||||
|
||||
func (p *Parser) getAssign(needEqual bool) *Assign {
|
||||
as := &Assign{}
|
||||
if p.asPos > 0 { // foo=bar
|
||||
nameEnd := p.asPos
|
||||
if p.lang != LangPOSIX && p.val[p.asPos-1] == '+' {
|
||||
if p.eqlOffs > 0 { // foo=bar
|
||||
nameEnd := p.eqlOffs
|
||||
if p.lang != LangPOSIX && p.val[p.eqlOffs-1] == '+' {
|
||||
// a+=b
|
||||
as.Append = true
|
||||
nameEnd--
|
||||
@@ -1168,9 +1182,9 @@ func (p *Parser) getAssign(needEqual bool) *Assign {
|
||||
as.Name = p.lit(p.pos, p.val[:nameEnd])
|
||||
// since we're not using the entire p.val
|
||||
as.Name.ValueEnd = posAddCol(as.Name.ValuePos, nameEnd)
|
||||
left := p.lit(posAddCol(p.pos, 1), p.val[p.asPos+1:])
|
||||
left := p.lit(posAddCol(p.pos, 1), p.val[p.eqlOffs+1:])
|
||||
if left.Value != "" {
|
||||
left.ValuePos = posAddCol(left.ValuePos, p.asPos)
|
||||
left.ValuePos = posAddCol(left.ValuePos, p.eqlOffs)
|
||||
as.Value = p.word(p.wps(left))
|
||||
}
|
||||
p.next()
|
||||
@@ -1371,25 +1385,6 @@ func (p *Parser) getStmt(readEnd, binCmd bool) (s *Stmt, gotEnd bool) {
|
||||
}
|
||||
|
||||
func (p *Parser) gotStmtPipe(s *Stmt) *Stmt {
|
||||
preLoop:
|
||||
for {
|
||||
switch p.tok {
|
||||
case _Lit, _LitWord:
|
||||
if !p.hasValidIdent() {
|
||||
break preLoop
|
||||
}
|
||||
s.Assigns = append(s.Assigns, p.getAssign(true))
|
||||
case rdrOut, appOut, rdrIn, dplIn, dplOut, clbOut, rdrInOut,
|
||||
hdoc, dashHdoc, wordHdoc, rdrAll, appAll, _LitRedir:
|
||||
p.doRedirect(s)
|
||||
default:
|
||||
break preLoop
|
||||
}
|
||||
switch {
|
||||
case p.newLine, p.tok == _EOF, p.tok == semicolon:
|
||||
return s
|
||||
}
|
||||
}
|
||||
switch p.tok {
|
||||
case _LitWord:
|
||||
switch p.val {
|
||||
@@ -1458,6 +1453,10 @@ preLoop:
|
||||
if s.Cmd != nil {
|
||||
break
|
||||
}
|
||||
if p.hasValidIdent() {
|
||||
s.Cmd = p.callExpr(s, nil, true)
|
||||
break
|
||||
}
|
||||
name := p.lit(p.pos, p.val)
|
||||
if p.next(); p.gotSameLine(leftParen) {
|
||||
p.follow(name.ValuePos, "foo(", rightParen)
|
||||
@@ -1466,8 +1465,16 @@ preLoop:
|
||||
}
|
||||
s.Cmd = p.funcDecl(name, name.ValuePos)
|
||||
} else {
|
||||
s.Cmd = p.callExpr(s, p.word(p.wps(name)))
|
||||
s.Cmd = p.callExpr(s, p.word(p.wps(name)), false)
|
||||
}
|
||||
case rdrOut, appOut, rdrIn, dplIn, dplOut, clbOut, rdrInOut,
|
||||
hdoc, dashHdoc, wordHdoc, rdrAll, appAll, _LitRedir:
|
||||
p.doRedirect(s)
|
||||
switch {
|
||||
case p.newLine, p.tok == _EOF, p.tok == semicolon:
|
||||
return s
|
||||
}
|
||||
s.Cmd = p.callExpr(s, nil, false)
|
||||
case bckQuote:
|
||||
if p.quote == subCmdBckquo {
|
||||
return s
|
||||
@@ -1476,17 +1483,21 @@ preLoop:
|
||||
case _Lit, dollBrace, dollDblParen, dollParen, dollar, cmdIn, cmdOut,
|
||||
sglQuote, dollSglQuote, dblQuote, dollDblQuote, dollBrack,
|
||||
globQuest, globStar, globPlus, globAt, globExcl:
|
||||
if p.tok == _Lit && p.hasValidIdent() {
|
||||
s.Cmd = p.callExpr(s, nil, true)
|
||||
break
|
||||
}
|
||||
w := p.word(p.wordParts())
|
||||
if p.gotSameLine(leftParen) && p.err == nil {
|
||||
p.posErr(w.Pos(), "invalid func name")
|
||||
}
|
||||
s.Cmd = p.callExpr(s, w)
|
||||
s.Cmd = p.callExpr(s, w, false)
|
||||
case leftParen:
|
||||
s.Cmd = p.subshell()
|
||||
case dblLeftParen:
|
||||
s.Cmd = p.arithmExpCmd()
|
||||
default:
|
||||
if len(s.Redirs) == 0 && len(s.Assigns) == 0 {
|
||||
if len(s.Redirs) == 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -1829,7 +1840,9 @@ 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, false)
|
||||
if u.X = p.testExpr(token(u.Op), u.OpPos, false); u.X == nil {
|
||||
p.followErrExp(u.OpPos, u.Op.String())
|
||||
}
|
||||
return u
|
||||
case tsExists, tsRegFile, tsDirect, tsCharSp, tsBlckSp, tsNmPipe,
|
||||
tsSocket, tsSmbLink, tsSticky, tsGIDSet, tsUIDSet, tsGrpOwn,
|
||||
@@ -1837,7 +1850,7 @@ func (p *Parser) testExprBase(ftok token, fpos Pos) TestExpr {
|
||||
tsFdTerm, tsEmpStr, tsNempStr, tsOptSet, tsVarSet, tsRefVar:
|
||||
u := &UnaryTest{OpPos: p.pos, Op: UnTestOperator(p.tok)}
|
||||
p.next()
|
||||
u.X = p.followWordTok(ftok, fpos)
|
||||
u.X = p.followWordTok(token(u.Op), u.OpPos)
|
||||
return u
|
||||
case leftParen:
|
||||
pe := &ParenTest{Lparen: p.pos}
|
||||
@@ -1866,6 +1879,8 @@ func (p *Parser) declClause() *DeclClause {
|
||||
for !p.newLine && !stopToken(p.tok) && !p.peekRedir() {
|
||||
if (p.tok == _Lit || p.tok == _LitWord) && p.hasValidIdent() {
|
||||
ds.Assigns = append(ds.Assigns, p.getAssign(false))
|
||||
} else if p.eqlOffs > 0 {
|
||||
p.curErr("invalid var name")
|
||||
} else if p.tok == _LitWord {
|
||||
ds.Assigns = append(ds.Assigns, &Assign{
|
||||
Naked: true,
|
||||
@@ -1975,24 +1990,41 @@ func (p *Parser) bashFuncDecl() *FuncDecl {
|
||||
return p.funcDecl(name, fpos)
|
||||
}
|
||||
|
||||
func (p *Parser) callExpr(s *Stmt, w *Word) *CallExpr {
|
||||
func (p *Parser) callExpr(s *Stmt, w *Word, assign bool) Command {
|
||||
ce := p.call(w)
|
||||
if w == nil {
|
||||
ce.Args = ce.Args[:0]
|
||||
}
|
||||
if assign {
|
||||
ce.Assigns = append(ce.Assigns, p.getAssign(true))
|
||||
}
|
||||
loop:
|
||||
for !p.newLine {
|
||||
switch p.tok {
|
||||
case _EOF, semicolon, and, or, andAnd, orOr, orAnd,
|
||||
dblSemicolon, semiAnd, dblSemiAnd, semiOr:
|
||||
return ce
|
||||
break loop
|
||||
case _LitWord:
|
||||
if len(ce.Args) == 0 && p.hasValidIdent() {
|
||||
ce.Assigns = append(ce.Assigns, p.getAssign(true))
|
||||
break
|
||||
}
|
||||
ce.Args = append(ce.Args, p.word(
|
||||
p.wps(p.lit(p.pos, p.val)),
|
||||
))
|
||||
p.next()
|
||||
case _Lit:
|
||||
if len(ce.Args) == 0 && p.hasValidIdent() {
|
||||
ce.Assigns = append(ce.Assigns, p.getAssign(true))
|
||||
break
|
||||
}
|
||||
ce.Args = append(ce.Args, p.word(p.wordParts()))
|
||||
case bckQuote:
|
||||
if p.quote == subCmdBckquo {
|
||||
return ce
|
||||
break loop
|
||||
}
|
||||
fallthrough
|
||||
case _Lit, dollBrace, dollDblParen, dollParen, dollar, cmdIn, cmdOut,
|
||||
case dollBrace, dollDblParen, dollParen, dollar, cmdIn, cmdOut,
|
||||
sglQuote, dollSglQuote, dblQuote, dollDblQuote, dollBrack,
|
||||
globQuest, globStar, globPlus, globAt, globExcl:
|
||||
ce.Args = append(ce.Args, p.word(p.wordParts()))
|
||||
@@ -2003,13 +2035,19 @@ func (p *Parser) callExpr(s *Stmt, w *Word) *CallExpr {
|
||||
p.curErr("%s can only be used to open an arithmetic cmd", p.tok)
|
||||
case rightParen:
|
||||
if p.quote == subCmd {
|
||||
return ce
|
||||
break loop
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
p.curErr("a command can only contain words and redirects")
|
||||
}
|
||||
}
|
||||
if len(ce.Assigns) == 0 && len(ce.Args) == 0 {
|
||||
return nil
|
||||
}
|
||||
if len(ce.Args) == 0 {
|
||||
ce.Args = nil
|
||||
}
|
||||
return ce
|
||||
}
|
||||
|
||||
|
||||
40
vendor/github.com/mvdan/sh/syntax/printer.go
generated
vendored
40
vendor/github.com/mvdan/sh/syntax/printer.go
generated
vendored
@@ -7,14 +7,21 @@ import (
|
||||
"bufio"
|
||||
"io"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
func Indent(spaces int) func(*Printer) {
|
||||
// Indent sets the number of spaces used for indentation. If set to 0,
|
||||
// tabs will be used instead.
|
||||
func Indent(spaces uint) func(*Printer) {
|
||||
return func(p *Printer) { p.indentSpaces = spaces }
|
||||
}
|
||||
|
||||
// BinaryNextLine will make binary operators appear on the next line
|
||||
// when a binary command, such as a pipe, spans multiple lines. A
|
||||
// backslash will be used.
|
||||
func BinaryNextLine(p *Printer) { p.binNextLine = true }
|
||||
|
||||
// NewPrinter allocates a new Printer and applies any number of options.
|
||||
func NewPrinter(options ...func(*Printer)) *Printer {
|
||||
p := &Printer{
|
||||
bufWriter: bufio.NewWriter(nil),
|
||||
@@ -26,7 +33,8 @@ func NewPrinter(options ...func(*Printer)) *Printer {
|
||||
return p
|
||||
}
|
||||
|
||||
// Print "pretty-prints" the given AST file to the given writer.
|
||||
// Print "pretty-prints" the given AST file to the given writer. Writes
|
||||
// to w are buffered.
|
||||
func (p *Printer) Print(w io.Writer, f *File) error {
|
||||
p.reset()
|
||||
p.bufWriter.Reset(w)
|
||||
@@ -42,25 +50,27 @@ type bufWriter interface {
|
||||
Flush() error
|
||||
}
|
||||
|
||||
// Printer holds the internal state of the printing mechanism of a
|
||||
// program.
|
||||
type Printer struct {
|
||||
bufWriter
|
||||
|
||||
indentSpaces int
|
||||
indentSpaces uint
|
||||
binNextLine bool
|
||||
|
||||
wantSpace bool
|
||||
wantNewline bool
|
||||
wroteSemi bool
|
||||
|
||||
commentPadding int
|
||||
commentPadding uint
|
||||
|
||||
// line is the current line number
|
||||
line uint
|
||||
|
||||
// lastLevel is the last level of indentation that was used.
|
||||
lastLevel int
|
||||
lastLevel uint
|
||||
// level is the current level of indentation.
|
||||
level int
|
||||
level uint
|
||||
// levelIncs records which indentation level increments actually
|
||||
// took place, to revert them once their section ends.
|
||||
levelIncs []bool
|
||||
@@ -85,8 +95,8 @@ func (p *Printer) reset() {
|
||||
p.pendingHdocs = p.pendingHdocs[:0]
|
||||
}
|
||||
|
||||
func (p *Printer) spaces(n int) {
|
||||
for i := 0; i < n; i++ {
|
||||
func (p *Printer) spaces(n uint) {
|
||||
for i := uint(0); i < n; i++ {
|
||||
p.WriteByte(' ')
|
||||
}
|
||||
}
|
||||
@@ -148,10 +158,10 @@ func (p *Printer) indent() {
|
||||
switch {
|
||||
case p.level == 0:
|
||||
case p.indentSpaces == 0:
|
||||
for i := 0; i < p.level; i++ {
|
||||
for i := uint(0); i < p.level; i++ {
|
||||
p.WriteByte('\t')
|
||||
}
|
||||
case p.indentSpaces > 0:
|
||||
default:
|
||||
p.spaces(p.indentSpaces * p.level)
|
||||
}
|
||||
}
|
||||
@@ -219,7 +229,7 @@ func (p *Printer) comment(c Comment) {
|
||||
}
|
||||
p.line = c.Hash.Line()
|
||||
p.WriteByte('#')
|
||||
p.WriteString(c.Text)
|
||||
p.WriteString(strings.TrimRightFunc(c.Text, unicode.IsSpace))
|
||||
}
|
||||
|
||||
func (p *Printer) comments(cs []Comment) {
|
||||
@@ -529,7 +539,6 @@ func (p *Printer) stmt(s *Stmt) {
|
||||
if s.Negated {
|
||||
p.spacedString("!")
|
||||
}
|
||||
p.assigns(s.Assigns, true)
|
||||
var startRedirs int
|
||||
if s.Cmd != nil {
|
||||
startRedirs = p.command(s.Cmd, s.Redirs)
|
||||
@@ -573,6 +582,7 @@ func (p *Printer) command(cmd Command, redirs []*Redirect) (startRedirs int) {
|
||||
}
|
||||
switch x := cmd.(type) {
|
||||
case *CallExpr:
|
||||
p.assigns(x.Assigns, true)
|
||||
if len(x.Args) <= 1 {
|
||||
p.wordJoin(x.Args)
|
||||
return 0
|
||||
@@ -704,6 +714,10 @@ func (p *Printer) command(cmd Command, redirs []*Redirect) (startRedirs int) {
|
||||
p.WriteByte(')')
|
||||
p.wantSpace = true
|
||||
sep := len(ci.Stmts) > 1 || ci.StmtList.pos().Line() > p.line
|
||||
if ci.OpPos != x.Esac && !ci.StmtList.empty() &&
|
||||
ci.OpPos.Line() > ci.StmtList.end().Line() {
|
||||
sep = true
|
||||
}
|
||||
sl := ci.StmtList
|
||||
p.nestedStmts(sl, Pos{})
|
||||
p.level++
|
||||
@@ -868,7 +882,7 @@ func (p *Printer) stmts(sl StmtList) {
|
||||
}
|
||||
if inlineIndent > 0 {
|
||||
if l := p.stmtCols(s); l > 0 {
|
||||
p.commentPadding = inlineIndent - l
|
||||
p.commentPadding = uint(inlineIndent - l)
|
||||
}
|
||||
lastIndentedLine = p.line
|
||||
}
|
||||
|
||||
2
vendor/github.com/mvdan/sh/syntax/simplify.go
generated
vendored
2
vendor/github.com/mvdan/sh/syntax/simplify.go
generated
vendored
@@ -167,7 +167,7 @@ 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 {
|
||||
len(st.Redirs) > 0 {
|
||||
break
|
||||
}
|
||||
sub, _ := st.Cmd.(*Subshell)
|
||||
|
||||
6
vendor/github.com/mvdan/sh/syntax/walk.go
generated
vendored
6
vendor/github.com/mvdan/sh/syntax/walk.go
generated
vendored
@@ -33,9 +33,6 @@ func Walk(node Node, f func(Node) bool) {
|
||||
if x.Cmd != nil {
|
||||
Walk(x.Cmd, f)
|
||||
}
|
||||
for _, a := range x.Assigns {
|
||||
Walk(a, f)
|
||||
}
|
||||
for _, r := range x.Redirs {
|
||||
Walk(r, f)
|
||||
}
|
||||
@@ -61,6 +58,9 @@ func Walk(node Node, f func(Node) bool) {
|
||||
Walk(x.Hdoc, f)
|
||||
}
|
||||
case *CallExpr:
|
||||
for _, a := range x.Assigns {
|
||||
Walk(a, f)
|
||||
}
|
||||
walkWords(x.Args, f)
|
||||
case *Subshell:
|
||||
walkStmts(x.StmtList, f)
|
||||
|
||||
Reference in New Issue
Block a user