1
0
mirror of https://github.com/go-task/task.git synced 2025-01-26 05:27:15 +02:00

Update github.com/mvdan/sh

This commit is contained in:
Andrey Nering 2017-05-27 11:17:49 -03:00
parent 460297e43a
commit c40148a52e
12 changed files with 788 additions and 442 deletions

View File

@ -11,8 +11,8 @@ import (
func (r *Runner) arithm(expr syntax.ArithmExpr) int {
switch x := expr.(type) {
case *syntax.Lit:
str := x.Value
case *syntax.Word:
str := r.loneWord(x)
// recursively fetch vars
for {
val := r.getVar(str)
@ -23,14 +23,12 @@ func (r *Runner) arithm(expr syntax.ArithmExpr) int {
}
// default to 0
return atoi(str)
case *syntax.ParamExp:
return atoi(r.paramExp(x))
case *syntax.ParenArithm:
return r.arithm(x.X)
case *syntax.UnaryArithm:
switch x.Op {
case syntax.Inc, syntax.Dec:
name := x.X.(*syntax.Lit).Value
name := x.X.(*syntax.Word).Parts[0].(*syntax.Lit).Value
old := atoi(r.getVar(name))
val := old
if x.Op == syntax.Inc {
@ -83,7 +81,7 @@ func atoi(s string) int {
}
func (r *Runner) assgnArit(b *syntax.BinaryArithm) int {
name := b.X.(*syntax.Lit).Value
name := b.X.(*syntax.Word).Parts[0].(*syntax.Lit).Value
val := atoi(r.getVar(name))
arg := r.arithm(b.Y)
switch b.Op {

View File

@ -98,10 +98,12 @@ func (r *Runner) varInd(v varValue, e syntax.ArithmExpr) string {
}
case []string:
// TODO: @ between double quotes
if lit, ok := e.(*syntax.Lit); ok {
switch lit.Value {
case "@", "*":
return strings.Join(x, " ")
if w, ok := e.(*syntax.Word); ok {
if lit, ok := w.Parts[0].(*syntax.Lit); ok {
switch lit.Value {
case "@", "*":
return strings.Join(x, " ")
}
}
}
i := r.arithm(e)
@ -231,6 +233,9 @@ func (r *Runner) fields(words []*syntax.Word) []string {
}
func (r *Runner) loneWord(word *syntax.Word) string {
if word == nil {
return ""
}
return strings.Join(r.wordParts(word.Parts, false), "")
}
@ -263,13 +268,37 @@ func (r *Runner) stmt(st *syntax.Stmt) {
}
func (r *Runner) assignValue(as *syntax.Assign) varValue {
prev, _ := r.lookupVar(as.Name.Value)
if as.Value != nil {
return r.loneWord(as.Value)
s := r.loneWord(as.Value)
if !as.Append || prev == nil {
return s
}
switch x := prev.(type) {
case string:
return x + s
case []string:
if len(x) == 0 {
return []string{s}
}
x[0] += s
return x
}
return s
}
if as.Array != nil {
strs := make([]string, len(as.Array.List))
for i, w := range as.Array.List {
strs[i] = r.loneWord(w)
strs := make([]string, len(as.Array.Elems))
for i, elem := range as.Array.Elems {
strs[i] = r.loneWord(elem.Value)
}
if !as.Append || prev == nil {
return strs
}
switch x := prev.(type) {
case string:
return append([]string{x}, strs...)
case []string:
return append(x, strs...)
}
return strs
}
@ -279,16 +308,15 @@ func (r *Runner) assignValue(as *syntax.Assign) varValue {
func (r *Runner) stmtSync(st *syntax.Stmt) {
oldVars := r.cmdVars
for _, as := range st.Assigns {
name := as.Name.Value
val := r.assignValue(as)
if st.Cmd == nil {
r.setVar(name, val)
r.setVar(as.Name.Value, val)
continue
}
if r.cmdVars == nil {
r.cmdVars = make(map[string]varValue, len(st.Assigns))
}
r.cmdVars[name] = val
r.cmdVars[as.Name.Value] = val
}
oldIn, oldOut, oldErr := r.Stdin, r.Stdout, r.Stderr
for _, rd := range st.Redirs {
@ -392,7 +420,7 @@ func (r *Runner) cmd(cm syntax.Command) {
switch y := x.Loop.(type) {
case *syntax.WordIter:
name := y.Name.Value
for _, field := range r.fields(y.List) {
for _, field := range r.fields(y.Items) {
r.setVar(name, field)
if r.loopStmtsBroken(x.DoStmts) {
break
@ -423,11 +451,11 @@ func (r *Runner) cmd(cm syntax.Command) {
}
case *syntax.CaseClause:
str := r.loneWord(x.Word)
for _, pl := range x.List {
for _, word := range pl.Patterns {
for _, ci := range x.Items {
for _, word := range ci.Patterns {
pat := r.loneWord(word)
if match(pat, str) {
r.stmts(pl.Stmts)
r.stmts(ci.Stmts)
return
}
}
@ -436,6 +464,13 @@ func (r *Runner) cmd(cm syntax.Command) {
if r.bashTest(x.X) == "" && r.exit == 0 {
r.exit = 1
}
case *syntax.DeclClause:
if len(x.Opts) > 0 {
r.runErr(cm.Pos(), "unhandled declare opts")
}
for _, as := range x.Assigns {
r.setVar(as.Name.Value, r.assignValue(as))
}
default:
r.runErr(cm.Pos(), "unhandled command node: %T", x)
}

View File

@ -146,7 +146,9 @@ func (r *Runner) unTest(op syntax.UnTestOperator, x string) bool {
case syntax.TsNempStr:
return x != ""
//case syntax.TsOptSet:
//case syntax.TsVarSet:
case syntax.TsVarSet:
_, e := r.lookupVar(x)
return e
//case syntax.TsRefVar:
case syntax.TsNot:
return x == ""

View File

@ -18,10 +18,10 @@ for foo in a b c; do
done
case $foo in
a) A ;;
b)
B
;;
a) A ;;
b)
B
;;
esac
foo | bar

View File

@ -32,7 +32,7 @@ func paramOps(r rune) bool {
func arithmOps(r rune) bool {
switch r {
case '+', '-', '!', '*', '/', '%', '(', ')', '^', '<', '>', ':', '=',
',', '?', '|', '&', ']':
',', '?', '|', '&', '[', ']', '#':
return true
}
return false
@ -86,10 +86,11 @@ retry:
return p.r
}
func (p *Parser) unrune(r rune) {
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
}
}
@ -240,6 +241,13 @@ skipSpace:
p.litBs = nil
}
p.next()
case '[':
if p.quote == arrayElems {
p.tok = leftBrack
p.rune()
} else {
p.advanceLitNone(r)
}
case '?', '*', '+', '@', '!':
if p.peekByte('(') {
switch r {
@ -306,7 +314,7 @@ func (p *Parser) regToken(r rune) token {
p.rune()
return andAnd
case '>':
if !p.bash() {
if p.lang == LangPOSIX {
break
}
if p.rune() == '>' {
@ -322,23 +330,23 @@ func (p *Parser) regToken(r rune) token {
p.rune()
return orOr
case '&':
if !p.bash() {
if p.lang == LangPOSIX {
break
}
p.rune()
return pipeAll
return orAnd
}
return or
case '$':
switch p.rune() {
case '\'':
if !p.bash() {
if p.lang == LangPOSIX {
break
}
p.rune()
return dollSglQuote
case '"':
if !p.bash() {
if p.lang == LangPOSIX {
break
}
p.rune()
@ -347,7 +355,7 @@ func (p *Parser) regToken(r rune) token {
p.rune()
return dollBrace
case '[':
if !p.bash() {
if p.lang != LangBash {
break
}
p.rune()
@ -361,7 +369,7 @@ func (p *Parser) regToken(r rune) token {
}
return dollar
case '(':
if p.rune() == '(' && p.bash() {
if p.rune() == '(' && p.lang != LangPOSIX {
p.rune()
return dblLeftParen
}
@ -372,17 +380,23 @@ func (p *Parser) regToken(r rune) token {
case ';':
switch p.rune() {
case ';':
if p.rune() == '&' && p.bash() {
if p.rune() == '&' && p.lang == LangBash {
p.rune()
return dblSemiFall
return dblSemiAnd
}
return dblSemicolon
case '&':
if !p.bash() {
if p.lang == LangPOSIX {
break
}
p.rune()
return semiFall
return semiAnd
case '|':
if p.lang != LangMirBSDKorn {
break
}
p.rune()
return semiOr
}
return semicolon
case '<':
@ -391,7 +405,7 @@ func (p *Parser) regToken(r rune) token {
if r = p.rune(); r == '-' {
p.rune()
return dashHdoc
} else if r == '<' && p.bash() {
} else if r == '<' && p.lang != LangPOSIX {
p.rune()
return wordHdoc
}
@ -403,7 +417,7 @@ func (p *Parser) regToken(r rune) token {
p.rune()
return dplIn
case '(':
if !p.bash() {
if p.lang != LangBash {
break
}
p.rune()
@ -422,7 +436,7 @@ func (p *Parser) regToken(r rune) token {
p.rune()
return clbOut
case '(':
if !p.bash() {
if p.lang != LangBash {
break
}
p.rune()
@ -446,7 +460,7 @@ func (p *Parser) dqToken(r rune) token {
p.rune()
return dollBrace
case '[':
if !p.bash() {
if p.lang != LangBash {
break
}
p.rune()
@ -651,6 +665,9 @@ func (p *Parser) arithmToken(r rune) token {
return xorAssgn
}
return caret
case '[':
p.rune()
return leftBrack
case ']':
p.rune()
return rightBrack
@ -660,9 +677,12 @@ func (p *Parser) arithmToken(r rune) token {
case '?':
p.rune()
return quest
default: // ':'
case ':':
p.rune()
return colon
default: // '#'
p.rune()
return hash
}
}
@ -756,7 +776,7 @@ loop:
if p.quote&allParamReg != 0 {
break loop
}
if r == '[' && p.bash() && p.quote&allArithmExpr != 0 {
if r == '[' && p.lang != LangPOSIX && p.quote&allArithmExpr != 0 {
break loop
}
case '+':
@ -829,7 +849,7 @@ loop:
case '=':
p.asPos = len(p.litBs) - 1
case '[':
if p.bash() && len(p.litBs) > 1 && p.litBs[0] != '[' {
if p.lang != LangPOSIX && len(p.litBs) > 1 && p.litBs[0] != '[' {
tok = _Lit
break loop
}
@ -864,19 +884,25 @@ func (p *Parser) advanceLitHdoc(r rune) {
}
}
lStart := len(p.litBs) - 1
loop:
for ; r != utf8.RuneSelf; r = p.rune() {
for ; ; r = p.rune() {
switch r {
case '`', '$':
break loop
p.val = p.endLit()
return
case '\\': // escaped byte follows
p.rune()
case '\n':
if bytes.Equal(p.litBs[lStart:len(p.litBs)-1], p.hdocStop) {
case '\n', utf8.RuneSelf:
if bytes.HasPrefix(p.litBs[lStart:], p.hdocStop) {
p.val = p.endLit()[:lStart]
if p.val == "" {
p.tok = illegalTok
}
p.hdocStop = nil
return
}
if r == utf8.RuneSelf {
return
}
if p.quote == hdocBodyTabs {
for p.peekByte('\t') {
p.rune()
@ -885,22 +911,15 @@ loop:
lStart = len(p.litBs)
}
}
if bytes.Equal(p.litBs[lStart:], p.hdocStop) {
p.val = p.endLit()[:lStart]
p.hdocStop = nil
} else {
p.val = p.endLit()
}
}
func (p *Parser) hdocLitWord() *Word {
r := p.r
p.newLit(r)
pos, val := p.getPos(), ""
for {
pos := p.getPos()
for ; ; r = p.rune() {
if r == utf8.RuneSelf {
val = p.endLit()
break
return nil
}
if p.quote == hdocBodyTabs {
for r == '\t' {
@ -911,18 +930,15 @@ func (p *Parser) hdocLitWord() *Word {
for r != utf8.RuneSelf && r != '\n' {
r = p.rune()
}
lEnd := len(p.litBs)
if r != utf8.RuneSelf {
lEnd--
if bytes.HasPrefix(p.litBs[lStart:], p.hdocStop) {
p.hdocStop = nil
val := p.endLit()[:lStart]
if val == "" {
return nil
}
return p.word(p.wps(p.lit(pos, val)))
}
if bytes.Equal(p.litBs[lStart:lEnd], p.hdocStop) {
val = p.endLit()[:lStart]
break
}
r = p.rune()
}
l := p.lit(pos, val)
return p.word(p.wps(l))
}
func (p *Parser) advanceLitRe(r rune) {

View File

@ -111,12 +111,15 @@ 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
}
@ -147,7 +150,7 @@ func (s *Stmt) End() Pos {
//
// These are *CallExpr, *IfClause, *WhileClause, *ForClause,
// *CaseClause, *Block, *Subshell, *BinaryCmd, *FuncDecl, *ArithmCmd,
// *TestClause, *DeclClause, *LetClause, and *CoprocClause.
// *TestClause, *DeclClause, *LetClause, *TimeClause, and *CoprocClause.
type Command interface {
Node
commandNode()
@ -166,24 +169,21 @@ func (*ArithmCmd) commandNode() {}
func (*TestClause) commandNode() {}
func (*DeclClause) commandNode() {}
func (*LetClause) commandNode() {}
func (*TimeClause) commandNode() {}
func (*CoprocClause) commandNode() {}
// Assign represents an assignment to a variable.
type Assign struct {
Append bool
Naked bool
Name *Lit
Index ArithmExpr
Key *DblQuoted
Value *Word
Array *ArrayExpr
}
func (a *Assign) Pos() Pos {
if a.Name != nil {
return a.Name.Pos()
}
return a.Value.Pos()
}
func (a *Assign) Pos() Pos { return a.Name.Pos() }
func (a *Assign) End() Pos {
if a.Value != nil {
return a.Value.End()
@ -194,6 +194,12 @@ func (a *Assign) End() Pos {
if a.Index != nil {
return a.Index.End() + 2
}
if a.Key != nil {
return a.Key.End() + 2
}
if a.Naked {
return a.Name.End()
}
return a.Name.End() + 1
}
@ -293,12 +299,12 @@ func (*CStyleLoop) loopNode() {}
// WordIter represents the iteration of a variable over a series of
// words in a for clause.
type WordIter struct {
Name *Lit
List []*Word
Name *Lit
Items []*Word
}
func (w *WordIter) Pos() Pos { return w.Name.Pos() }
func (w *WordIter) End() Pos { return posMax(w.Name.End(), wordLastEnd(w.List)) }
func (w *WordIter) End() Pos { return posMax(w.Name.End(), wordLastEnd(w.Items)) }
// CStyleLoop represents the behaviour of a for clause similar to the C
// language.
@ -408,6 +414,11 @@ func (q *DblQuoted) End() Pos {
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
}
func (c *CmdSubst) Pos() Pos { return c.Left }
@ -419,8 +430,10 @@ type ParamExp struct {
Short bool
Indirect bool
Length bool
Width bool
Param *Lit
Index ArithmExpr
Key *DblQuoted
Slice *Slice
Repl *Replace
Exp *Expansion
@ -431,10 +444,18 @@ func (p *ParamExp) End() Pos {
if !p.Short {
return p.Rbrace + 1
}
if p.Index != nil {
return p.Index.End() + 1
}
if p.Key != nil {
return p.Key.End() + 1
}
return p.Param.End()
}
func (p *ParamExp) nakedIndex() bool { return p.Short && p.Index != nil }
func (p *ParamExp) nakedIndex() bool {
return p.Short && (p.Index != nil || p.Key != nil)
}
// Slice represents character slicing inside a ParamExp.
//
@ -460,6 +481,7 @@ type Expansion struct {
type ArithmExp struct {
Left, Right Pos
Bracket bool
Unsigned bool
X ArithmExpr
}
@ -476,6 +498,7 @@ func (a *ArithmExp) End() Pos {
// This node will never appear when in PosixConformant mode.
type ArithmCmd struct {
Left, Right Pos
Unsigned bool
X ArithmExpr
}
@ -484,8 +507,7 @@ func (a *ArithmCmd) End() Pos { return a.Right + 2 }
// ArithmExpr represents all nodes that form arithmetic expressions.
//
// These are *BinaryArithm, *UnaryArithm, *ParenArithm, *Lit, and
// *ParamExp.
// These are *BinaryArithm, *UnaryArithm, *ParenArithm, and *Word.
type ArithmExpr interface {
Node
arithmExprNode()
@ -494,14 +516,13 @@ type ArithmExpr interface {
func (*BinaryArithm) arithmExprNode() {}
func (*UnaryArithm) arithmExprNode() {}
func (*ParenArithm) arithmExprNode() {}
func (*Lit) arithmExprNode() {}
func (*ParamExp) arithmExprNode() {}
func (*Word) arithmExprNode() {}
// BinaryArithm represents a binary expression between two arithmetic
// expression.
//
// If Op is any assign operator, X will be a *Lit whose value is a valid
// name.
// If Op is any assign operator, X will be a word with a single *Lit
// whose value is a valid name.
//
// Ternary operators like "a ? b : c" are fit into this structure. Thus,
// if Op == Quest, Y will be a *BinaryArithm with Op == Colon. Op can
@ -518,7 +539,8 @@ func (b *BinaryArithm) End() Pos { return b.Y.End() }
// UnaryArithm represents an unary expression over a node, either before
// or after it.
//
// If Op is Inc or Dec, X will be a *Lit whose value is a valid name.
// If Op is Inc or Dec, X will be a word with a single *Lit whose value
// is a valid name.
type UnaryArithm struct {
OpPos Pos
Op UnAritOperator
@ -554,14 +576,14 @@ func (p *ParenArithm) End() Pos { return p.Rparen + 1 }
type CaseClause struct {
Case, Esac Pos
Word *Word
List []*PatternList
Items []*CaseItem
}
func (c *CaseClause) Pos() Pos { return c.Case }
func (c *CaseClause) End() Pos { return c.Esac + 4 }
// PatternList represents a pattern list (case) within a CaseClause.
type PatternList struct {
// CaseItem represents a pattern list (case) within a CaseClause.
type CaseItem struct {
Op CaseOperator
OpPos Pos
Patterns []*Word
@ -647,12 +669,29 @@ func (d *DeclClause) End() Pos {
// This node will never appear when in PosixConformant mode.
type ArrayExpr struct {
Lparen, Rparen Pos
List []*Word
Elems []*ArrayElem
}
func (a *ArrayExpr) Pos() Pos { return a.Lparen }
func (a *ArrayExpr) End() Pos { return a.Rparen + 1 }
type ArrayElem struct {
Index ArithmExpr
Key *DblQuoted
Value *Word
}
func (a *ArrayElem) Pos() Pos {
if a.Index != nil {
return a.Index.Pos()
}
if a.Key != nil {
return a.Key.Pos()
}
return a.Value.Pos()
}
func (a *ArrayElem) End() Pos { return a.Value.End() }
// ExtGlob represents a Bash extended globbing expression. Note that
// these are parsed independently of whether shopt has been called or
// not.
@ -679,6 +718,22 @@ type ProcSubst struct {
func (s *ProcSubst) Pos() Pos { return s.OpPos }
func (s *ProcSubst) End() Pos { return s.Rparen + 1 }
// TimeClause represents a Bash time clause.
//
// This node will never appear when in PosixConformant mode.
type TimeClause struct {
Time Pos
Stmt *Stmt
}
func (c *TimeClause) Pos() Pos { return c.Time }
func (c *TimeClause) End() Pos {
if c.Stmt == nil {
return c.Time + 4
}
return c.Stmt.End()
}
// CoprocClause represents a Bash coproc clause.
//
// This node will never appear when in PosixConformant mode.

File diff suppressed because it is too large Load Diff

View File

@ -34,18 +34,14 @@ func (p *Printer) Print(w io.Writer, f *File) error {
p.stmts(f.Stmts)
p.commentsUpTo(0)
p.newline(0)
if flusher, ok := p.bufWriter.(interface {
Flush() error
}); ok {
return flusher.Flush()
}
return nil
return p.bufWriter.Flush()
}
type bufWriter interface {
WriteByte(byte) error
WriteString(string) (int, error)
Reset(io.Writer)
Flush() error
}
type Printer struct {
@ -190,8 +186,10 @@ func (p *Printer) newline(pos Pos) {
hdocs := p.pendingHdocs
p.pendingHdocs = p.pendingHdocs[:0]
for _, r := range hdocs {
p.word(r.Hdoc)
p.incLines(r.Hdoc.End())
if r.Hdoc != nil {
p.word(r.Hdoc)
p.incLines(r.Hdoc.End())
}
p.unquotedWord(r.Word)
p.WriteByte('\n')
p.incLine()
@ -233,13 +231,13 @@ func (p *Printer) semiRsrv(s string, pos Pos, fallback bool) {
p.level--
if p.wantNewline || pos > p.nline {
p.newlines(pos)
} else if fallback {
if !p.wroteSemi {
} else {
if fallback && !p.wroteSemi {
p.WriteByte(';')
}
p.WriteByte(' ')
} else if p.wantSpace {
p.WriteByte(' ')
if p.wantSpace {
p.WriteByte(' ')
}
}
p.WriteString(s)
p.wantSpace = true
@ -287,27 +285,34 @@ func (p *Printer) wordPart(wp WordPart) {
p.WriteByte('\'')
p.incLines(x.End())
case *DblQuoted:
if x.Dollar {
p.WriteByte('$')
}
p.WriteByte('"')
for i, n := range x.Parts {
p.wordPart(n)
if i == len(x.Parts)-1 {
p.incLines(n.End())
}
}
p.WriteByte('"')
p.dblQuoted(x)
case *CmdSubst:
p.incLines(x.Pos())
p.WriteString("$(")
p.wantSpace = len(x.Stmts) > 0 && startsWithLparen(x.Stmts[0])
p.nestedStmts(x.Stmts, x.Right)
p.sepTok(")", x.Right)
switch {
case x.MirBSDTempFile:
p.WriteString("${")
p.wantSpace = true
p.nestedStmts(x.Stmts, x.Right)
p.wantSpace = false
p.semiRsrv("}", x.Right, true)
case x.MirBSDReplyVar:
p.WriteString("${|")
p.nestedStmts(x.Stmts, x.Right)
p.wantSpace = false
p.semiRsrv("}", x.Right, true)
default:
p.WriteString("$(")
p.wantSpace = len(x.Stmts) > 0 && startsWithLparen(x.Stmts[0])
p.nestedStmts(x.Stmts, x.Right)
p.sepTok(")", x.Right)
}
case *ParamExp:
p.paramExp(x)
case *ArithmExp:
p.WriteString("$((")
if x.Unsigned {
p.WriteString("# ")
}
p.arithmExpr(x.X, false, false)
p.WriteString("))")
case *ExtGlob:
@ -326,12 +331,38 @@ func (p *Printer) wordPart(wp WordPart) {
}
}
func (p *Printer) dblQuoted(dq *DblQuoted) {
if dq.Dollar {
p.WriteByte('$')
}
p.WriteByte('"')
for i, n := range dq.Parts {
p.wordPart(n)
if i == len(dq.Parts)-1 {
p.incLines(n.End())
}
}
p.WriteByte('"')
}
func (p *Printer) wroteIndex(index ArithmExpr, key *DblQuoted) bool {
if index == nil && key == nil {
return false
}
p.WriteByte('[')
if index != nil {
p.arithmExpr(index, false, false)
} else {
p.dblQuoted(key)
}
p.WriteByte(']')
return true
}
func (p *Printer) paramExp(pe *ParamExp) {
if pe.nakedIndex() { // arr[i]
if pe.nakedIndex() { // arr[x]
p.WriteString(pe.Param.Value)
p.WriteByte('[')
p.arithmExpr(pe.Index, false, false)
p.WriteByte(']')
p.wroteIndex(pe.Index, pe.Key)
return
}
if pe.Short { // $var
@ -344,17 +375,15 @@ func (p *Printer) paramExp(pe *ParamExp) {
switch {
case pe.Length:
p.WriteByte('#')
case pe.Width:
p.WriteByte('%')
case pe.Indirect:
p.WriteByte('!')
}
if pe.Param != nil {
p.WriteString(pe.Param.Value)
}
if pe.Index != nil {
p.WriteByte('[')
p.arithmExpr(pe.Index, false, false)
p.WriteByte(']')
}
p.wroteIndex(pe.Index, pe.Key)
if pe.Slice != nil {
p.WriteByte(':')
p.arithmExpr(pe.Slice.Offset, true, true)
@ -367,12 +396,18 @@ func (p *Printer) paramExp(pe *ParamExp) {
p.WriteByte('/')
}
p.WriteByte('/')
p.word(pe.Repl.Orig)
if pe.Repl.Orig != nil {
p.word(pe.Repl.Orig)
}
p.WriteByte('/')
p.word(pe.Repl.With)
if pe.Repl.With != nil {
p.word(pe.Repl.With)
}
} else if pe.Exp != nil {
p.WriteString(pe.Exp.Op.String())
p.word(pe.Exp.Word)
if pe.Exp.Word != nil {
p.word(pe.Exp.Word)
}
}
p.WriteByte('}')
}
@ -381,9 +416,9 @@ func (p *Printer) loop(loop Loop) {
switch x := loop.(type) {
case *WordIter:
p.WriteString(x.Name.Value)
if len(x.List) > 0 {
if len(x.Items) > 0 {
p.spacedString(" in")
p.wordJoin(x.List, true)
p.wordJoin(x.Items)
}
case *CStyleLoop:
p.WriteString("((")
@ -401,10 +436,8 @@ func (p *Printer) loop(loop Loop) {
func (p *Printer) arithmExpr(expr ArithmExpr, compact, spacePlusMinus bool) {
switch x := expr.(type) {
case *Lit:
p.WriteString(x.Value)
case *ParamExp:
p.paramExp(x)
case *Word:
p.word(x)
case *BinaryArithm:
if compact {
p.arithmExpr(x.X, compact, spacePlusMinus)
@ -491,17 +524,12 @@ func (p *Printer) unquotedWord(w *Word) {
}
}
func (p *Printer) wordJoin(ws []*Word, backslash bool) {
func (p *Printer) wordJoin(ws []*Word) {
anyNewline := false
for _, w := range ws {
if pos := w.Pos(); pos > p.nline {
p.commentsUpTo(pos)
if backslash {
p.bslashNewl()
} else {
p.WriteByte('\n')
p.incLine()
}
p.bslashNewl()
if !anyNewline {
p.incLevel()
anyNewline = true
@ -518,11 +546,37 @@ func (p *Printer) wordJoin(ws []*Word, backslash bool) {
}
}
func (p *Printer) elemJoin(elems []*ArrayElem) {
anyNewline := false
for _, el := range elems {
if pos := el.Pos(); pos > p.nline {
p.commentsUpTo(pos)
p.WriteByte('\n')
p.incLine()
if !anyNewline {
p.incLevel()
anyNewline = true
}
p.indent()
} else if p.wantSpace {
p.WriteByte(' ')
p.wantSpace = false
}
if p.wroteIndex(el.Index, el.Key) {
p.WriteByte('=')
}
p.word(el.Value)
}
if anyNewline {
p.decLevel()
}
}
func (p *Printer) stmt(s *Stmt) {
if s.Negated {
p.spacedString("!")
}
p.assigns(s.Assigns)
p.assigns(s.Assigns, true)
var startRedirs int
if s.Cmd != nil {
startRedirs = p.command(s.Cmd, s.Redirs)
@ -545,21 +599,25 @@ func (p *Printer) stmt(s *Stmt) {
p.WriteString(r.N.Value)
}
p.WriteString(r.Op.String())
p.wantSpace = true
p.word(r.Word)
if r.Op == Hdoc || r.Op == DashHdoc {
p.pendingHdocs = append(p.pendingHdocs, r)
}
}
p.wroteSemi = false
if s.Semicolon.IsValid() && s.Semicolon > p.nline {
switch {
case s.Semicolon.IsValid() && s.Semicolon > p.nline:
p.incLevel()
p.bslashNewl()
p.indent()
p.decLevel()
p.WriteByte(';')
p.wroteSemi = true
} else if s.Background {
case s.Background:
p.WriteString(" &")
case s.Coprocess:
p.WriteString(" |&")
}
if anyNewline {
p.decLevel()
@ -574,10 +632,10 @@ func (p *Printer) command(cmd Command, redirs []*Redirect) (startRedirs int) {
switch x := cmd.(type) {
case *CallExpr:
if len(x.Args) <= 1 {
p.wordJoin(x.Args, true)
p.wordJoin(x.Args)
return 0
}
p.wordJoin(x.Args[:1], true)
p.wordJoin(x.Args[:1])
for _, r := range redirs {
if r.Pos() > x.Args[1].Pos() || r.Op == Hdoc || r.Op == DashHdoc {
break
@ -589,10 +647,11 @@ func (p *Printer) command(cmd Command, redirs []*Redirect) (startRedirs int) {
p.WriteString(r.N.Value)
}
p.WriteString(r.Op.String())
p.wantSpace = true
p.word(r.Word)
startRedirs++
}
p.wordJoin(x.Args[1:], true)
p.wordJoin(x.Args[1:])
case *Block:
p.WriteByte('{')
p.wantSpace = true
@ -639,13 +698,18 @@ func (p *Printer) command(cmd Command, redirs []*Redirect) (startRedirs int) {
p.semiRsrv("done", x.Done, true)
case *BinaryCmd:
p.stmt(x.X)
if x.Y.Pos() < p.nline {
// leave p.nestedBinary untouched
p.spacedString(x.Op.String())
p.stmt(x.Y)
break
}
indent := !p.nestedBinary
if indent {
p.incLevel()
}
_, p.nestedBinary = x.Y.Cmd.(*BinaryCmd)
if p.binNextLine {
if len(p.pendingHdocs) == 0 && x.Y.Pos() > p.nline {
if len(p.pendingHdocs) == 0 {
p.bslashNewl()
p.indent()
}
@ -662,16 +726,15 @@ func (p *Printer) command(cmd Command, redirs []*Redirect) (startRedirs int) {
} else {
p.wantSpace = true
p.spacedString(x.Op.String())
if x.Y.Pos() > p.nline {
if x.OpPos > p.nline {
p.incLines(x.OpPos)
}
p.commentsUpTo(x.Y.Pos())
p.newline(0)
p.indent()
if x.OpPos > p.nline {
p.incLines(x.OpPos)
}
p.commentsUpTo(x.Y.Pos())
p.newline(0)
p.indent()
}
p.incLines(x.Y.Pos())
_, p.nestedBinary = x.Y.Cmd.(*BinaryCmd)
p.stmt(x.Y)
if indent {
p.decLevel()
@ -689,10 +752,9 @@ func (p *Printer) command(cmd Command, redirs []*Redirect) (startRedirs int) {
p.WriteString("case ")
p.word(x.Word)
p.WriteString(" in")
p.incLevel()
for _, pl := range x.List {
p.commentsAndSeparate(pl.Patterns[0].Pos())
for i, w := range pl.Patterns {
for _, ci := range x.Items {
p.commentsAndSeparate(ci.Patterns[0].Pos())
for i, w := range ci.Patterns {
if i > 0 {
p.spacedString("|")
}
@ -703,24 +765,26 @@ func (p *Printer) command(cmd Command, redirs []*Redirect) (startRedirs int) {
}
p.WriteByte(')')
p.wantSpace = true
sep := len(pl.Stmts) > 1 || (len(pl.Stmts) > 0 && pl.Stmts[0].Pos() > p.nline)
p.nestedStmts(pl.Stmts, 0)
sep := len(ci.Stmts) > 1 || (len(ci.Stmts) > 0 && ci.Stmts[0].Pos() > p.nline)
p.nestedStmts(ci.Stmts, 0)
p.level++
if sep {
p.commentsUpTo(pl.OpPos)
p.newlines(pl.OpPos)
p.commentsUpTo(ci.OpPos)
p.newlines(ci.OpPos)
}
p.spacedString(pl.Op.String())
p.incLines(pl.OpPos)
p.spacedString(ci.Op.String())
p.incLines(ci.OpPos)
p.level--
if sep || pl.OpPos == x.Esac {
if sep || ci.OpPos == x.Esac {
p.wantNewline = true
}
}
p.decLevel()
p.semiRsrv("esac", x.Esac, len(x.List) == 0)
p.semiRsrv("esac", x.Esac, len(x.Items) == 0)
case *ArithmCmd:
p.WriteString("((")
if x.Unsigned {
p.WriteString("# ")
}
p.arithmExpr(x.X, false, false)
p.WriteString("))")
case *TestClause:
@ -728,16 +792,17 @@ func (p *Printer) command(cmd Command, redirs []*Redirect) (startRedirs int) {
p.testExpr(x.X)
p.spacedString("]]")
case *DeclClause:
name := x.Variant
if name == "" {
name = "declare"
}
p.spacedString(name)
p.spacedString(x.Variant)
for _, w := range x.Opts {
p.WriteByte(' ')
p.word(w)
}
p.assigns(x.Assigns)
p.assigns(x.Assigns, false)
case *TimeClause:
p.spacedString("time")
if x.Stmt != nil {
p.stmt(x.Stmt)
}
case *CoprocClause:
p.spacedString("coproc")
if x.Name != nil {
@ -878,6 +943,7 @@ func (c *byteCounter) WriteString(s string) (int, error) {
return 0, nil
}
func (c *byteCounter) Reset(io.Writer) { *c = 0 }
func (c *byteCounter) Flush() error { return nil }
// stmtCols reports the length that s will take when formatted in a
// single line. If it will span multiple lines, stmtCols will return -1.
@ -902,7 +968,7 @@ func (p *Printer) nestedStmts(stmts []*Stmt, closing Pos) {
p.decLevel()
}
func (p *Printer) assigns(assigns []*Assign) {
func (p *Printer) assigns(assigns []*Assign, alwaysEqual bool) {
anyNewline := false
for _, a := range assigns {
if a.Pos() > p.nline {
@ -917,22 +983,20 @@ func (p *Printer) assigns(assigns []*Assign) {
}
if a.Name != nil {
p.WriteString(a.Name.Value)
if a.Index != nil {
p.WriteByte('[')
p.arithmExpr(a.Index, false, false)
p.WriteByte(']')
}
p.wroteIndex(a.Index, a.Key)
if a.Append {
p.WriteByte('+')
}
p.WriteByte('=')
if alwaysEqual || a.Value != nil || a.Array != nil {
p.WriteByte('=')
}
}
if a.Value != nil {
p.word(a.Value)
} else if a.Array != nil {
p.wantSpace = false
p.WriteByte('(')
p.wordJoin(a.Array.List, false)
p.elemJoin(a.Array.Elems)
p.sepTok(")", a.Array.Rparen)
}
p.wantSpace = true

View File

@ -1,12 +1,12 @@
// Code generated by "stringer -type token"; DO NOT EDIT
// Code generated by "stringer -type token -linecoms"; DO NOT EDIT.
package syntax
import "fmt"
const _token_name = "illegalTokEOFLitLitWordLitRedir'\"`&&&||||&$$'$\"${$[$($(([(((}])));;;;&;;&!++--***==!=<=>=+=-=*=/=%=&=|=^=<<=>>=>>><<><&>&>|<<<<-<<<&>&>><(>(+:+-:-?:?=:=%%%###^^^,,,@///:-e-f-d-c-b-p-S-L-k-g-u-G-O-N-r-w-x-s-t-z-n-o-v-R=~-nt-ot-ef-eq-ne-le-ge-lt-gt?(*(+(@(!("
const _token_name = "illegalTokEOFLitLitWordLitRedir'\"`&&&||||&$$'$\"${$[$($(([(((}])));;;;&;;&;|!++--***==!=<=>=+=-=*=/=%=&=|=^=<<=>>=>>><<><&>&>|<<<<-<<<&>&>><(>(+:+-:-?:?=:=%%%###^^^,,,@///:-e-f-d-c-b-p-S-L-k-g-u-G-O-N-r-w-x-s-t-z-n-o-v-R=~-nt-ot-ef-eq-ne-le-ge-lt-gt?(*(+(@(!("
var _token_index = [...]uint16{0, 10, 13, 16, 23, 31, 32, 33, 34, 35, 37, 39, 40, 42, 43, 45, 47, 49, 51, 53, 56, 57, 58, 60, 61, 62, 63, 65, 66, 68, 70, 73, 74, 76, 78, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 108, 111, 112, 114, 115, 117, 119, 121, 123, 125, 128, 131, 133, 136, 138, 140, 141, 143, 144, 146, 147, 149, 150, 152, 153, 155, 156, 158, 159, 161, 162, 164, 165, 166, 168, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 222, 225, 228, 231, 234, 237, 240, 243, 246, 248, 250, 252, 254, 256}
var _token_index = [...]uint16{0, 10, 13, 16, 23, 31, 32, 33, 34, 35, 37, 39, 40, 42, 43, 45, 47, 49, 51, 53, 56, 57, 58, 60, 61, 62, 63, 65, 66, 68, 70, 73, 75, 76, 78, 80, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 110, 113, 114, 116, 117, 119, 121, 123, 125, 127, 130, 133, 135, 138, 140, 142, 143, 145, 146, 148, 149, 151, 152, 154, 155, 157, 158, 160, 161, 163, 164, 166, 167, 168, 170, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 224, 227, 230, 233, 236, 239, 242, 245, 248, 250, 252, 254, 256, 258}
func (i token) String() string {
if i >= token(len(_token_index)-1) {

View File

@ -8,25 +8,26 @@ type token uint32
// Modified version of golang.org/x/tools/cmd/stringer that gets the
// string value from the inline comment of each constant, if there is
// one. Also removes leading '_'.
//go:generate stringer -type token
//go:generate stringer -type token -linecoms
// The list of all possible tokens.
const (
illegalTok token = iota
_EOF
_Lit
_LitWord
_LitRedir
_EOF // EOF
_Lit // Lit
_LitWord // LitWord
_LitRedir // LitRedir
sglQuote // '
dblQuote // "
bckQuote // `
and // &
andAnd // &&
orOr // ||
or // |
pipeAll // |&
and // &
andAnd // &&
orOr // ||
or // |
orAnd // |&
dollar // $
dollSglQuote // $'
@ -46,8 +47,9 @@ const (
semicolon // ;
dblSemicolon // ;;
semiFall // ;&
dblSemiFall // ;;&
semiAnd // ;&
dblSemiAnd // ;;&
semiOr // ;|
exclMark // !
addAdd // ++
@ -196,9 +198,10 @@ const (
type CaseOperator token
const (
DblSemicolon = CaseOperator(dblSemicolon) + iota
SemiFall
DblSemiFall
Break = CaseOperator(dblSemicolon) + iota
Fallthrough
Resume
ResumeKorn
)
type ParExpOperator token

View File

@ -79,7 +79,7 @@ func Walk(node Node, f func(Node) bool) {
walkStmts(x.DoStmts, f)
case *WordIter:
Walk(x.Name, f)
walkWords(x.List, f)
walkWords(x.Items, f)
case *CStyleLoop:
if x.Init != nil {
Walk(x.Init, f)
@ -116,20 +116,20 @@ func Walk(node Node, f func(Node) bool) {
Walk(x.Index, f)
}
if x.Repl != nil {
Walk(x.Repl.Orig, f)
Walk(x.Repl.With, f)
if x.Repl.Orig != nil {
Walk(x.Repl.Orig, f)
}
if x.Repl.With != nil {
Walk(x.Repl.With, f)
}
}
if x.Exp != nil {
if x.Exp != nil && x.Exp.Word != nil {
Walk(x.Exp.Word, f)
}
case *ArithmExp:
if x.X != nil {
Walk(x.X, f)
}
Walk(x.X, f)
case *ArithmCmd:
if x.X != nil {
Walk(x.X, f)
}
Walk(x.X, f)
case *BinaryArithm:
Walk(x.X, f)
Walk(x.Y, f)
@ -146,9 +146,9 @@ func Walk(node Node, f func(Node) bool) {
Walk(x.X, f)
case *CaseClause:
Walk(x.Word, f)
for _, pl := range x.List {
walkWords(pl.Patterns, f)
walkStmts(pl.Stmts, f)
for _, ci := range x.Items {
walkWords(ci.Patterns, f)
walkStmts(ci.Stmts, f)
}
case *TestClause:
Walk(x.X, f)
@ -158,11 +158,22 @@ func Walk(node Node, f func(Node) bool) {
Walk(a, f)
}
case *ArrayExpr:
walkWords(x.List, f)
for _, el := range x.Elems {
Walk(el, f)
}
case *ArrayElem:
if x.Index != nil {
Walk(x.Index, f)
}
Walk(x.Value, f)
case *ExtGlob:
Walk(x.Pattern, f)
case *ProcSubst:
walkStmts(x.Stmts, f)
case *TimeClause:
if x.Stmt != nil {
Walk(x.Stmt, f)
}
case *CoprocClause:
if x.Name != nil {
Walk(x.Name, f)

12
vendor/vendor.json vendored
View File

@ -51,16 +51,16 @@
"revisionTime": "2017-01-24T11:57:57Z"
},
{
"checksumSHA1": "ohm6oyTSFu/xZk5HtTUG7RIONO4=",
"checksumSHA1": "dZOPdDhOrEZfccmKxqRLsbCwm6g=",
"path": "github.com/mvdan/sh/interp",
"revision": "380eaf2df0412887a2240f5b15e76ac810ca2e71",
"revisionTime": "2017-05-17T16:44:15Z"
"revision": "27fa62d749f4f87716626413e5960586c91e36f9",
"revisionTime": "2017-05-26T14:37:19Z"
},
{
"checksumSHA1": "2OcfNJuStj/eAcEPW5yRdU02DCc=",
"checksumSHA1": "vGslbhw/1KheACSg3CayaaKY6DA=",
"path": "github.com/mvdan/sh/syntax",
"revision": "380eaf2df0412887a2240f5b15e76ac810ca2e71",
"revisionTime": "2017-05-17T16:44:15Z"
"revision": "27fa62d749f4f87716626413e5960586c91e36f9",
"revisionTime": "2017-05-26T14:37:19Z"
},
{
"checksumSHA1": "HUXE+Nrcau8FSaVEvPYHMvDjxOE=",