Documentation ¶
Overview ¶
Package syntax implements parsing and formatting of shell programs. It supports both POSIX Shell and Bash.
Example ¶
package main import ( "os" "strings" "mvdan.cc/sh/syntax" ) func main() { r := strings.NewReader("{ foo; bar; }") f, err := syntax.NewParser().Parse(r, "") if err != nil { return } syntax.NewPrinter().Print(os.Stdout, f) }
Output: { foo bar }
Index ¶
- Constants
- func BinaryNextLine(p *Printer)
- func DebugPrint(w io.Writer, node Node) error
- func HasPattern(pattern string) bool
- func Indent(spaces uint) func(*Printer)
- func KeepComments(p *Parser)
- func KeepPadding(p *Printer)
- func Minify(p *Printer)
- func QuotePattern(pattern string) string
- func Simplify(n Node) bool
- func SpaceRedirects(p *Printer)
- func StopAt(word string) func(*Parser)
- func SwitchCaseIndent(p *Printer)
- func TranslatePattern(pattern string, greedy bool) (string, error)
- func ValidName(val string) bool
- func Variant(l LangVariant) func(*Parser)
- func Walk(node Node, f func(Node) bool)
- type ArithmCmd
- type ArithmExp
- type ArithmExpr
- type ArrayElem
- type ArrayExpr
- type Assign
- type BinAritOperator
- type BinCmdOperator
- type BinTestOperator
- type BinaryArithm
- type BinaryCmd
- type BinaryTest
- type Block
- type CStyleLoop
- type CallExpr
- type CaseClause
- type CaseItem
- type CaseOperator
- type CmdSubst
- type Command
- type Comment
- type CoprocClause
- type DblQuoted
- type DeclClause
- type Expansion
- type ExtGlob
- type File
- type ForClause
- type FuncDecl
- type GlobOperator
- type IfClause
- type LangError
- type LangVariant
- type LetClause
- type Lit
- type Loop
- type Node
- type ParExpOperator
- type ParNamesOperator
- type ParamExp
- type ParenArithm
- type ParenTest
- type ParseError
- type Parser
- func (p *Parser) Document(r io.Reader) (*Word, error)
- func (p *Parser) Incomplete() bool
- func (p *Parser) Interactive(r io.Reader, fn func([]*Stmt) bool) error
- func (p *Parser) Parse(r io.Reader, name string) (*File, error)
- func (p *Parser) Stmts(r io.Reader, fn func(*Stmt) bool) error
- func (p *Parser) Words(r io.Reader, fn func(*Word) bool) error
- type Pos
- type Printer
- type ProcOperator
- type ProcSubst
- type RedirOperator
- type Redirect
- type Replace
- type SglQuoted
- type Slice
- type Stmt
- type StmtList
- type Subshell
- type TestClause
- type TestExpr
- type TimeClause
- type UnAritOperator
- type UnTestOperator
- type UnaryArithm
- type UnaryTest
- type WhileClause
- type Word
- func ExpandBraces(word *Word) []*Worddeprecated
- type WordIter
- type WordPart
Examples ¶
Constants ¶
const ( RdrOut = RedirOperator(rdrOut) + iota AppOut RdrIn RdrInOut DplIn DplOut ClbOut Hdoc DashHdoc WordHdoc RdrAll AppAll )
const ( CmdIn = ProcOperator(cmdIn) + iota CmdOut )
const ( GlobQuest = GlobOperator(globQuest) + iota GlobStar GlobPlus GlobAt GlobExcl )
const ( AndStmt = BinCmdOperator(andAnd) + iota OrStmt Pipe PipeAll )
const ( Break = CaseOperator(dblSemicolon) + iota Fallthrough Resume ResumeKorn )
const ( NamesPrefix = ParNamesOperator(star) NamesPrefixWords = ParNamesOperator(at) )
const ( SubstPlus = ParExpOperator(plus) + iota SubstColPlus SubstMinus SubstColMinus SubstQuest SubstColQuest SubstAssgn SubstColAssgn RemSmallSuffix RemLargeSuffix RemSmallPrefix RemLargePrefix UpperFirst UpperAll LowerFirst LowerAll OtherParamOps )
const ( Not = UnAritOperator(exclMark) + iota Inc Dec Plus = UnAritOperator(plus) Minus = UnAritOperator(minus) )
const ( Add = BinAritOperator(plus) Sub = BinAritOperator(minus) Mul = BinAritOperator(star) Quo = BinAritOperator(slash) Rem = BinAritOperator(perc) Pow = BinAritOperator(power) Eql = BinAritOperator(equal) Gtr = BinAritOperator(rdrOut) Lss = BinAritOperator(rdrIn) Neq = BinAritOperator(nequal) Leq = BinAritOperator(lequal) Geq = BinAritOperator(gequal) And = BinAritOperator(and) Or = BinAritOperator(or) Xor = BinAritOperator(caret) Shr = BinAritOperator(appOut) Shl = BinAritOperator(hdoc) AndArit = BinAritOperator(andAnd) OrArit = BinAritOperator(orOr) Comma = BinAritOperator(comma) Quest = BinAritOperator(quest) Colon = BinAritOperator(colon) Assgn = BinAritOperator(assgn) AddAssgn = BinAritOperator(addAssgn) SubAssgn = BinAritOperator(subAssgn) MulAssgn = BinAritOperator(mulAssgn) QuoAssgn = BinAritOperator(quoAssgn) RemAssgn = BinAritOperator(remAssgn) AndAssgn = BinAritOperator(andAssgn) OrAssgn = BinAritOperator(orAssgn) XorAssgn = BinAritOperator(xorAssgn) ShlAssgn = BinAritOperator(shlAssgn) ShrAssgn = BinAritOperator(shrAssgn) )
const ( TsExists = UnTestOperator(tsExists) + iota TsRegFile TsDirect TsCharSp TsBlckSp TsNmPipe TsSocket TsSmbLink TsSticky TsGIDSet TsUIDSet TsGrpOwn TsUsrOwn TsModif TsRead TsWrite TsExec TsNoEmpty TsFdTerm TsEmpStr TsNempStr TsOptSet TsVarSet TsRefVar TsNot = UnTestOperator(exclMark) )
const ( TsReMatch = BinTestOperator(tsReMatch) + iota TsNewer TsOlder TsDevIno TsEql TsNeq TsLeq TsGeq TsLss TsGtr AndTest = BinTestOperator(andAnd) OrTest = BinTestOperator(orOr) TsMatch = BinTestOperator(equal) TsNoMatch = BinTestOperator(nequal) TsBefore = BinTestOperator(rdrIn) TsAfter = BinTestOperator(rdrOut) )
Variables ¶
This section is empty.
Functions ¶
func BinaryNextLine ¶
func BinaryNextLine(p *Printer)
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 DebugPrint ¶
DebugPrint prints the provided syntax tree, spanning multiple lines and with indentation. Can be useful to investigate the content of a syntax tree.
Example ¶
package main import ( "os" "strings" "mvdan.cc/sh/syntax" ) func main() { in := strings.NewReader(`echo 'foo'`) f, err := syntax.NewParser().Parse(in, "") if err != nil { return } syntax.DebugPrint(os.Stdout, f) }
Output: *syntax.File { . Name: "" . StmtList: syntax.StmtList { . . Stmts: []*syntax.Stmt (len = 1) { . . . 0: *syntax.Stmt { . . . . Comments: []syntax.Comment (len = 0) {} . . . . Cmd: *syntax.CallExpr { . . . . . Assigns: []*syntax.Assign (len = 0) {} . . . . . Args: []*syntax.Word (len = 2) { . . . . . . 0: *syntax.Word { . . . . . . . Parts: []syntax.WordPart (len = 1) { . . . . . . . . 0: *syntax.Lit { . . . . . . . . . ValuePos: 1:1 . . . . . . . . . ValueEnd: 1:5 . . . . . . . . . Value: "echo" . . . . . . . . } . . . . . . . } . . . . . . } . . . . . . 1: *syntax.Word { . . . . . . . Parts: []syntax.WordPart (len = 1) { . . . . . . . . 0: *syntax.SglQuoted { . . . . . . . . . Left: 1:6 . . . . . . . . . Right: 1:10 . . . . . . . . . Dollar: false . . . . . . . . . Value: "foo" . . . . . . . . } . . . . . . . } . . . . . . } . . . . . } . . . . } . . . . Position: 1:1 . . . . Semicolon: 0:0 . . . . Negated: false . . . . Background: false . . . . Coprocess: false . . . . Redirs: []*syntax.Redirect (len = 0) {} . . . } . . } . . Last: []syntax.Comment (len = 0) {} . } }
func HasPattern ¶
HasPattern returns whether a string contains any unescaped wildcard characters: '*', '?', or '['. When the function returns false, the given pattern can only match at most one string.
For example, HasPattern(`foo\*bar`) returns false, but HasPattern(`foo*bar`) returns true.
This can be useful to avoid extra work, like TranslatePattern. Note that this function cannot be used to avoid QuotePattern, as backslashes are quoted by that function but ignored here.
func Indent ¶
Indent sets the number of spaces used for indentation. If set to 0, tabs will be used instead.
func KeepComments ¶
func KeepComments(p *Parser)
KeepComments makes the parser parse comments and attach them to nodes, as opposed to discarding them.
func KeepPadding ¶
func KeepPadding(p *Printer)
KeepPadding will keep most nodes and tokens in the same column that they were in the original source. This allows the user to decide how to align and pad their code with spaces.
Note that this feature is best-effort and will only keep the alignment stable, so it may need some human help the first time it is run.
func Minify ¶
func Minify(p *Printer)
Minify will print programs in a way to save the most bytes possible. For example, indentation and comments are skipped, and extra whitespace is avoided when possible.
func QuotePattern ¶
QuotePattern returns a string that quotes all special characters in the given wildcard pattern. The returned string is a pattern that matches the literal string.
For example, QuotePattern(`foo*bar?`) returns `foo\*bar\?`.
Example ¶
package main import ( "fmt" "regexp" "mvdan.cc/sh/syntax" ) func main() { wildcard := "foo?bar*" fmt.Println(wildcard) quoted := syntax.QuotePattern(wildcard) fmt.Println(quoted) expr, err := syntax.TranslatePattern(quoted, true) if err != nil { return } rx := regexp.MustCompile(expr) fmt.Println(rx.MatchString("foo bar baz")) fmt.Println(rx.MatchString("foo?bar*")) }
Output: foo?bar* foo\?bar\* false true
func Simplify ¶
Simplify simplifies a given program and returns whether any changes were made.
The changes currently applied are:
Remove clearly useless parentheses $(( (expr) )) Remove dollars from vars in exprs (($var)) Remove duplicate subshells $( (stmts) ) Remove redundant quotes [[ "$var" == str ]] Merge negations with unary operators [[ ! -n $var ]] Use single quotes to shorten literals "\$foo"
func SpaceRedirects ¶
func SpaceRedirects(p *Printer)
SpaceRedirects will put a space after most redirection operators. The exceptions are '>&', '<&', '>(', and '<('.
func StopAt ¶
StopAt configures the lexer to stop at an arbitrary word, treating it as if it were the end of the input. It can contain any characters except whitespace, and cannot be over four bytes in size.
This can be useful to embed shell code within another language, as one can use a special word to mark the delimiters between the two.
As a word, it will only apply when following whitespace or a separating token. For example, StopAt("$$") will act on the inputs "foo $$" and "foo;$$", but not on "foo '$$'".
The match is done by prefix, so the example above will also act on "foo $$bar".
func SwitchCaseIndent ¶
func SwitchCaseIndent(p *Printer)
SwitchCaseIndent will make switch cases be indented. As such, switch case bodies will be two levels deeper than the switch itself.
func TranslatePattern ¶
TranslatePattern turns a shell wildcard pattern into a regular expression that can be used with regexp.Compile. It will return an error if the input pattern was incorrect. Otherwise, the returned expression can be passed to regexp.MustCompile.
For example, TranslatePattern(`foo*bar?`, true) returns `foo.*bar.`.
Note that this function (and QuotePattern) should not be directly used with file paths if Windows is supported, as the path separator on that platform is the same character as the escaping character for shell patterns.
Example ¶
package main import ( "fmt" "regexp" "mvdan.cc/sh/syntax" ) func main() { wildcard := "foo?bar*" fmt.Println(wildcard) expr, err := syntax.TranslatePattern(wildcard, true) if err != nil { return } fmt.Println(expr) rx := regexp.MustCompile(expr) fmt.Println(rx.MatchString("foo bar baz")) fmt.Println(rx.MatchString("foobarbaz")) }
Output: foo?bar* foo.bar.* true false
func Variant ¶
func Variant(l LangVariant) func(*Parser)
Variant changes the shell language variant that the parser will accept.
func Walk ¶
Walk traverses a syntax tree in depth-first order: It starts by calling f(node); node must not be nil. If f returns true, Walk invokes f recursively for each of the non-nil children of node, followed by f(nil).
Example ¶
package main import ( "os" "strings" "mvdan.cc/sh/syntax" ) func main() { in := strings.NewReader(`echo $foo "and $bar"`) f, err := syntax.NewParser().Parse(in, "") if err != nil { return } syntax.Walk(f, func(node syntax.Node) bool { switch x := node.(type) { case *syntax.ParamExp: x.Param.Value = strings.ToUpper(x.Param.Value) } return true }) syntax.NewPrinter().Print(os.Stdout, f) }
Output: echo $FOO "and $BAR"
Types ¶
type ArithmCmd ¶
type ArithmCmd struct {
Left, Right Pos
Unsigned bool // mksh's ((# expr))
X ArithmExpr
}
ArithmCmd represents an arithmetic command.
This node will only appear in LangBash and LangMirBSDKorn.
type ArithmExp ¶
type ArithmExp struct {
Left, Right Pos
Bracket bool // deprecated $[expr] form
Unsigned bool // mksh's $((# expr))
X ArithmExpr
}
ArithmExp represents an arithmetic expansion.
type ArithmExpr ¶
type ArithmExpr interface { Node // contains filtered or unexported methods }
ArithmExpr represents all nodes that form arithmetic expressions.
These are *BinaryArithm, *UnaryArithm, *ParenArithm, and *Word.
type ArrayElem ¶
type ArrayElem struct { Index ArithmExpr Value *Word Comments []Comment }
ArrayElem represents a Bash array element.
Index can be nil; for example, declare -a x=(value). Value can be nil; for example, declare -A x=([index]=). Finally, neither can be nil; for example, declare -A x=([index]=value)
type ArrayExpr ¶
ArrayExpr represents a Bash array expression.
This node will only appear with LangBash.
type Assign ¶
type Assign struct { Append bool // += Naked bool // without '=' Name *Lit Index ArithmExpr // [i], ["k"] Value *Word // =val Array *ArrayExpr // =(arr) }
Assign represents an assignment to a variable.
Here and elsewhere, Index can mean either an index expression into an indexed array, or a string key into an associative array.
If Index is non-nil, the value will be a word and not an array as nested arrays are not allowed.
If Naked is true and Name is nil, the assignment is part of a DeclClause and the assignment expression (in the Value field) will be evaluated at run-time.
type BinAritOperator ¶
type BinAritOperator token
func (BinAritOperator) String ¶
func (o BinAritOperator) String() string
type BinCmdOperator ¶
type BinCmdOperator token
func (BinCmdOperator) String ¶
func (o BinCmdOperator) String() string
type BinTestOperator ¶
type BinTestOperator token
func (BinTestOperator) String ¶
func (o BinTestOperator) String() string
type BinaryArithm ¶
type BinaryArithm struct { OpPos Pos Op BinAritOperator X, Y ArithmExpr }
BinaryArithm represents a binary arithmetic expression.
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 only be Colon in that scenario.
func (*BinaryArithm) End ¶
func (b *BinaryArithm) End() Pos
func (*BinaryArithm) Pos ¶
func (b *BinaryArithm) Pos() Pos
type BinaryCmd ¶
type BinaryCmd struct { OpPos Pos Op BinCmdOperator X, Y *Stmt }
BinaryCmd represents a binary expression between two statements.
type BinaryTest ¶
type BinaryTest struct { OpPos Pos Op BinTestOperator X, Y TestExpr }
BinaryTest represents a binary test expression.
func (*BinaryTest) End ¶
func (b *BinaryTest) End() Pos
func (*BinaryTest) Pos ¶
func (b *BinaryTest) Pos() Pos
type CStyleLoop ¶
type CStyleLoop struct {
Lparen, Rparen Pos
Init, Cond, Post ArithmExpr
}
CStyleLoop represents the behaviour of a for clause similar to the C language.
This node will only appear with LangBash.
func (*CStyleLoop) End ¶
func (c *CStyleLoop) End() Pos
func (*CStyleLoop) Pos ¶
func (c *CStyleLoop) Pos() Pos
type CallExpr ¶
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 are variables that cannot be arrays and which only apply to the call.
type CaseClause ¶
CaseClause represents a case (switch) clause.
func (*CaseClause) End ¶
func (c *CaseClause) End() Pos
func (*CaseClause) Pos ¶
func (c *CaseClause) Pos() Pos
type CaseItem ¶
type CaseItem struct { Op CaseOperator OpPos Pos // unset if it was finished by "esac" Comments []Comment Patterns []*Word StmtList }
CaseItem represents a pattern list (case) within a CaseClause.
type CaseOperator ¶
type CaseOperator token
func (CaseOperator) String ¶
func (o CaseOperator) String() string
type CmdSubst ¶
type CmdSubst struct {
Left, Right Pos
StmtList
TempFile bool // mksh's ${ foo;}
ReplyVar bool // mksh's ${|foo;}
}
CmdSubst represents a command substitution.
type Command ¶
type Command interface { Node // contains filtered or unexported methods }
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, *TestClause, *DeclClause, *LetClause, *TimeClause, and *CoprocClause.
Example ¶
package main import ( "fmt" "os" "strings" "mvdan.cc/sh/syntax" ) func main() { r := strings.NewReader("echo foo; if x; then y; fi; foo | bar") f, err := syntax.NewParser().Parse(r, "") if err != nil { return } printer := syntax.NewPrinter() for i, stmt := range f.Stmts { fmt.Printf("Cmd %d: %-20T - ", i, stmt.Cmd) printer.Print(os.Stdout, stmt.Cmd) fmt.Println() } }
Output: Cmd 0: *syntax.CallExpr - echo foo Cmd 1: *syntax.IfClause - if x; then y; fi Cmd 2: *syntax.BinaryCmd - foo | bar
type CoprocClause ¶
CoprocClause represents a Bash coproc clause.
This node will only appear with LangBash.
func (*CoprocClause) End ¶
func (c *CoprocClause) End() Pos
func (*CoprocClause) Pos ¶
func (c *CoprocClause) Pos() Pos
type DeclClause ¶
type DeclClause struct { // Variant is one of "declare", "local", "export", "readonly", // "typeset", or "nameref". Variant *Lit Opts []*Word Assigns []*Assign }
DeclClause represents a Bash declare clause.
This node will only appear with LangBash.
func (*DeclClause) End ¶
func (d *DeclClause) End() Pos
func (*DeclClause) Pos ¶
func (d *DeclClause) Pos() Pos
type Expansion ¶
type Expansion struct { Op ParExpOperator Word *Word }
Expansion represents string manipulation in a ParamExp other than those covered by Replace.
type ExtGlob ¶
type ExtGlob struct { OpPos Pos Op GlobOperator Pattern *Lit }
ExtGlob represents a Bash extended globbing expression. Note that these are parsed independently of whether shopt has been called or not.
This node will only appear in LangBash and LangMirBSDKorn.
type FuncDecl ¶
type FuncDecl struct { Position Pos RsrvWord bool // non-posix "function f()" style Name *Lit Body *Stmt }
FuncDecl represents the declaration of a function.
type GlobOperator ¶
type GlobOperator token
func (GlobOperator) String ¶
func (o GlobOperator) String() string
type IfClause ¶
type IfClause struct { Elif bool // whether this IfClause begins with "elif" IfPos Pos // position of the starting "if" or "elif" token ThenPos Pos ElsePos Pos // position of a following "else" or "elif", if any FiPos Pos // position of "fi", empty if Elif == true Cond StmtList Then StmtList Else StmtList ElseComments []Comment // comments on the "else" FiComments []Comment // comments on the "fi" }
IfClause represents an if statement.
func (*IfClause) FollowedByElif ¶
FollowedByElif reports whether this IfClause is followed by an "elif" IfClause in its Else branch. This is true if Else.Stmts has exactly one statement with an IfClause whose Elif field is true.
type LangError ¶
type LangError struct { Filename string Pos Feature string Langs []LangVariant }
LangError is returned when the parser encounters code that is only valid in other shell language variants. The error includes what feature is not present in the current language variant, and what languages support it.
type LangVariant ¶
type LangVariant int
const ( LangBash LangVariant = iota LangPOSIX LangMirBSDKorn )
func (LangVariant) String ¶
func (l LangVariant) String() string
type LetClause ¶
type LetClause struct { Let Pos Exprs []ArithmExpr }
LetClause represents a Bash let clause.
This node will only appear in LangBash and LangMirBSDKorn.
type Lit ¶
Lit represents a string literal.
Note that a parsed string literal may not appear as-is in the original source code, as it is possible to split literals by escaping newlines. The splitting is lost, but the end position is not.
type Loop ¶
type Loop interface { Node // contains filtered or unexported methods }
Loop holds either *WordIter or *CStyleLoop.
type Node ¶
type Node interface { // Pos returns the position of the first character of the node. Comments // are ignored, except if the node is a *File. Pos() Pos // End returns the position of the character immediately after the node. // If the character is a newline, the line number won't cross into the // next line. Comments are ignored, except if the node is a *File. End() Pos }
Node represents a syntax tree node.
type ParExpOperator ¶
type ParExpOperator token
func (ParExpOperator) String ¶
func (o ParExpOperator) String() string
type ParNamesOperator ¶
type ParNamesOperator token
func (ParNamesOperator) String ¶
func (o ParNamesOperator) String() string
type ParamExp ¶
type ParamExp struct {
Dollar, Rbrace Pos
Short bool // $a instead of ${a}
Excl bool // ${!a}
Length bool // ${#a}
Width bool // ${%a}
Param *Lit
Index ArithmExpr // ${a[i]}, ${a["k"]}
Slice *Slice // ${a:x:y}
Repl *Replace // ${a/x/y}
Names ParNamesOperator // ${!prefix*} or ${!prefix@}
Exp *Expansion // ${a:-b}, ${a#b}, etc
}
ParamExp represents a parameter expansion.
type ParenArithm ¶
type ParenArithm struct {
Lparen, Rparen Pos
X ArithmExpr
}
ParenArithm represents an arithmetic expression within parentheses.
func (*ParenArithm) End ¶
func (p *ParenArithm) End() Pos
func (*ParenArithm) Pos ¶
func (p *ParenArithm) Pos() Pos
type ParseError ¶
ParseError represents an error found when parsing a source file, from which the parser cannot recover.
func (ParseError) Error ¶
func (e ParseError) Error() string
type Parser ¶
type Parser struct {
// contains filtered or unexported fields
}
Parser holds the internal state of the parsing mechanism of a program.
func NewParser ¶
NewParser allocates a new Parser and applies any number of options.
Example (Options) ¶
package main import ( "fmt" "os" "strings" "mvdan.cc/sh/syntax" ) func main() { src := "for ((i = 0; i < 5; i++)); do echo $i >f; done" // LangBash is the default r := strings.NewReader(src) f, err := syntax.NewParser().Parse(r, "") fmt.Println(err) // Parser errors with LangPOSIX r = strings.NewReader(src) _, err = syntax.NewParser(syntax.Variant(syntax.LangPOSIX)).Parse(r, "") fmt.Println(err) syntax.NewPrinter().Print(os.Stdout, f) syntax.NewPrinter(syntax.SpaceRedirects).Print(os.Stdout, f) }
Output: <nil> 1:5: c-style fors are a bash feature for ((i = 0; i < 5; i++)); do echo $i >f; done for ((i = 0; i < 5; i++)); do echo $i > f; done
func (*Parser) Document ¶
Document parses a single here-document word. That is, it parses the input as if they were lines following a <<EOF redirection.
In practice, this is the same as parsing the input as if it were within double quotes, but without having to escape all double quote characters. Similarly, the here-document word parsed here cannot be ended by any delimiter other than reaching the end of the input.
func (*Parser) Incomplete ¶
func (*Parser) Interactive ¶
Interactive implements what is necessary to parse statements in an interactive shell. The parser will call the given function under two circumstances outlined below.
If a line containing any number of statements is parsed, the function will be called with said statements.
If a line ending in an incomplete statement is parsed, the function will be called with any fully parsed statents, and Parser.Incomplete will return true.
One can imagine a simple interactive shell implementation as follows:
fmt.Fprintf(os.Stdout, "$ ") parser.Interactive(os.Stdin, func(stmts []*syntax.Stmt) bool { if parser.Incomplete() { fmt.Fprintf(os.Stdout, "> ") return true } run(stmts) fmt.Fprintf(os.Stdout, "$ ") return true }
If the callback function returns false, parsing is stopped and the function is not called again.
func (*Parser) Parse ¶
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. 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 (*Parser) Stmts ¶
Stmts reads and parses statements one at a time, calling a function each time one is parsed. If the function returns false, parsing is stopped and the function is not called again.
func (*Parser) Words ¶
Words reads and parses words one at a time, calling a function each time one is parsed. If the function returns false, parsing is stopped and the function is not called again.
Newlines are skipped, meaning that multi-line input will work fine. If the parser encounters a token that isn't a word, such as a semicolon, an error will be returned.
Note that the lexer doesn't currently tokenize spaces, so it may need to read a non-space byte such as a newline or a letter before finishing the parsing of a word. This will be fixed in the future.
type Pos ¶
type Pos struct {
// contains filtered or unexported fields
}
Pos is a position within a shell source file.
func (Pos) After ¶
After reports whether the position p is after p2. It is a more expressive version of p.Offset() > p2.Offset().
func (Pos) IsValid ¶ added in v0.6.0
IsValid reports whether the position is valid. All positions in nodes returned by Parse are valid.
type Printer ¶
type Printer struct {
// contains filtered or unexported fields
}
Printer holds the internal state of the printing mechanism of a program.
func NewPrinter ¶
NewPrinter allocates a new Printer and applies any number of options.
type ProcOperator ¶
type ProcOperator token
func (ProcOperator) String ¶
func (o ProcOperator) String() string
type ProcSubst ¶
type ProcSubst struct {
OpPos, Rparen Pos
Op ProcOperator
StmtList
}
ProcSubst represents a Bash process substitution.
This node will only appear with LangBash.
type RedirOperator ¶
type RedirOperator token
func (RedirOperator) String ¶
func (o RedirOperator) String() string
type Redirect ¶
type Redirect struct { OpPos Pos Op RedirOperator N *Lit // fd>, or {varname}> in Bash Word *Word // >word Hdoc *Word // here-document body }
Redirect represents an input/output redirection.
type Slice ¶
type Slice struct {
Offset, Length ArithmExpr
}
Slice represents a character slicing expression inside a ParamExp.
This node will only appear in LangBash and LangMirBSDKorn.
type Stmt ¶
type Stmt struct { Comments []Comment Cmd Command Position Pos Semicolon Pos // position of ';', '&', or '|&', if any Negated bool // ! stmt Background bool // stmt & Coprocess bool // mksh's |& Redirs []*Redirect // stmt >a <b }
Stmt represents a statement, also known as a "complete command". It is compromised of a command and other components that may come before or after it.
type StmtList ¶
StmtList is a list of statements with any number of trailing comments. Both lists can be empty.
type Subshell ¶
Subshell represents a series of commands that should be executed in a nested shell environment.
type TestClause ¶
TestClause represents a Bash extended test clause.
This node will only appear in LangBash and LangMirBSDKorn.
func (*TestClause) End ¶
func (t *TestClause) End() Pos
func (*TestClause) Pos ¶
func (t *TestClause) Pos() Pos
type TestExpr ¶
type TestExpr interface { Node // contains filtered or unexported methods }
TestExpr represents all nodes that form test expressions.
These are *BinaryTest, *UnaryTest, *ParenTest, and *Word.
type TimeClause ¶
TimeClause represents a Bash time clause. PosixFormat corresponds to the -p flag.
This node will only appear in LangBash and LangMirBSDKorn.
func (*TimeClause) End ¶
func (c *TimeClause) End() Pos
func (*TimeClause) Pos ¶
func (c *TimeClause) Pos() Pos
type UnAritOperator ¶
type UnAritOperator token
func (UnAritOperator) String ¶
func (o UnAritOperator) String() string
type UnTestOperator ¶
type UnTestOperator token
func (UnTestOperator) String ¶
func (o UnTestOperator) String() string
type UnaryArithm ¶
type UnaryArithm struct { OpPos Pos Op UnAritOperator Post bool X ArithmExpr }
UnaryArithm represents an unary arithmetic expression. The unary opearator may come before or after the sub-expression.
If Op is Inc or Dec, X will be a word with a single *Lit whose value is a valid name.
func (*UnaryArithm) End ¶
func (u *UnaryArithm) End() Pos
func (*UnaryArithm) Pos ¶
func (u *UnaryArithm) Pos() Pos
type UnaryTest ¶
type UnaryTest struct { OpPos Pos Op UnTestOperator X TestExpr }
UnaryTest represents a unary test expression. The unary opearator may come before or after the sub-expression.
type WhileClause ¶
WhileClause represents a while or an until clause.
func (*WhileClause) End ¶
func (w *WhileClause) End() Pos
func (*WhileClause) Pos ¶
func (w *WhileClause) Pos() Pos
type Word ¶
type Word struct {
Parts []WordPart
}
Word represents a shell word, containing one or more word parts contiguous to each other. The word is delimeted by word boundaries, such as spaces, newlines, semicolons, or parentheses.
Example ¶
package main import ( "fmt" "os" "strings" "mvdan.cc/sh/syntax" ) func main() { r := strings.NewReader("echo foo${bar}'baz'") f, err := syntax.NewParser().Parse(r, "") if err != nil { return } printer := syntax.NewPrinter() args := f.Stmts[0].Cmd.(*syntax.CallExpr).Args for i, word := range args { fmt.Printf("Word number %d:\n", i) for _, part := range word.Parts { fmt.Printf("%-20T - ", part) printer.Print(os.Stdout, part) fmt.Println() } fmt.Println() } }
Output: Word number 0: *syntax.Lit - echo Word number 1: *syntax.Lit - foo *syntax.ParamExp - ${bar} *syntax.SglQuoted - 'baz'
func ExpandBraces
deprecated
func (*Word) Lit ¶
Lit returns the word as a literal value, if the word consists of *syntax.Lit nodes only. An empty string is returned otherwise. Words with multiple literals, which can appear in some edge cases, are handled properly.
For example, the word "foo" will return "foo", but the word "foo${bar}" will return "".