update vendor

Signed-off-by: Roland.Ma <rolandma@yunify.com>
This commit is contained in:
Roland.Ma
2021-08-11 07:10:14 +00:00
parent a18f72b565
commit ea8f47c73a
2901 changed files with 269317 additions and 43103 deletions

129
vendor/go.starlark.net/syntax/grammar.txt generated vendored Normal file
View File

@@ -0,0 +1,129 @@
Grammar of Starlark
==================
File = {Statement | newline} eof .
Statement = DefStmt | IfStmt | ForStmt | WhileStmt | SimpleStmt .
DefStmt = 'def' identifier '(' [Parameters [',']] ')' ':' Suite .
Parameters = Parameter {',' Parameter}.
Parameter = identifier | identifier '=' Test | '*' | '*' identifier | '**' identifier .
IfStmt = 'if' Test ':' Suite {'elif' Test ':' Suite} ['else' ':' Suite] .
ForStmt = 'for' LoopVariables 'in' Expression ':' Suite .
WhileStmt = 'while' Test ':' Suite .
Suite = [newline indent {Statement} outdent] | SimpleStmt .
SimpleStmt = SmallStmt {';' SmallStmt} [';'] '\n' .
# NOTE: '\n' optional at EOF
SmallStmt = ReturnStmt
| BreakStmt | ContinueStmt | PassStmt
| AssignStmt
| ExprStmt
| LoadStmt
.
ReturnStmt = 'return' [Expression] .
BreakStmt = 'break' .
ContinueStmt = 'continue' .
PassStmt = 'pass' .
AssignStmt = Expression ('=' | '+=' | '-=' | '*=' | '/=' | '//=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=') Expression .
ExprStmt = Expression .
LoadStmt = 'load' '(' string {',' [identifier '='] string} [','] ')' .
Test = LambdaExpr
| IfExpr
| PrimaryExpr
| UnaryExpr
| BinaryExpr
.
LambdaExpr = 'lambda' [Parameters] ':' Test .
IfExpr = Test 'if' Test 'else' Test .
PrimaryExpr = Operand
| PrimaryExpr DotSuffix
| PrimaryExpr CallSuffix
| PrimaryExpr SliceSuffix
.
Operand = identifier
| int | float | string
| ListExpr | ListComp
| DictExpr | DictComp
| '(' [Expression [',']] ')'
| ('-' | '+') PrimaryExpr
.
DotSuffix = '.' identifier .
CallSuffix = '(' [Arguments [',']] ')' .
SliceSuffix = '[' [Expression] [':' Test [':' Test]] ']' .
Arguments = Argument {',' Argument} .
Argument = Test | identifier '=' Test | '*' Test | '**' Test .
ListExpr = '[' [Expression [',']] ']' .
ListComp = '[' Test {CompClause} ']'.
DictExpr = '{' [Entries [',']] '}' .
DictComp = '{' Entry {CompClause} '}' .
Entries = Entry {',' Entry} .
Entry = Test ':' Test .
CompClause = 'for' LoopVariables 'in' Test | 'if' Test .
UnaryExpr = 'not' Test .
BinaryExpr = Test {Binop Test} .
Binop = 'or'
| 'and'
| '==' | '!=' | '<' | '>' | '<=' | '>=' | 'in' | 'not' 'in'
| '|'
| '^'
| '&'
| '-' | '+'
| '*' | '%' | '/' | '//'
.
Expression = Test {',' Test} .
# NOTE: trailing comma permitted only when within [...] or (...).
LoopVariables = PrimaryExpr {',' PrimaryExpr} .
# Notation (similar to Go spec):
- lowercase and 'quoted' items are lexical tokens.
- Capitalized names denote grammar productions.
- (...) implies grouping
- x | y means either x or y.
- [x] means x is optional
- {x} means x is repeated zero or more times
- The end of each declaration is marked with a period.
# Tokens
- spaces: newline, eof, indent, outdent.
- identifier.
- literals: string, int, float.
- plus all quoted tokens such as '+=', 'return'.
# Notes:
- Ambiguity is resolved using operator precedence.
- The grammar does not enforce the legal order of params and args,
nor that the first compclause must be a 'for'.
TODO:
- explain how the lexer generates indent, outdent, and newline tokens.
- why is unary NOT separated from unary - and +?
- the grammar is (mostly) in LL(1) style so, for example,
dot expressions are formed suffixes, not complete expressions,
which makes the spec harder to read. Reorganize into non-LL(1) form?

1029
vendor/go.starlark.net/syntax/parse.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

269
vendor/go.starlark.net/syntax/quote.go generated vendored Normal file
View File

@@ -0,0 +1,269 @@
// Copyright 2017 The Bazel Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package syntax
// Starlark quoted string utilities.
import (
"fmt"
"strconv"
"strings"
)
// unesc maps single-letter chars following \ to their actual values.
var unesc = [256]byte{
'a': '\a',
'b': '\b',
'f': '\f',
'n': '\n',
'r': '\r',
't': '\t',
'v': '\v',
'\\': '\\',
'\'': '\'',
'"': '"',
}
// esc maps escape-worthy bytes to the char that should follow \.
var esc = [256]byte{
'\a': 'a',
'\b': 'b',
'\f': 'f',
'\n': 'n',
'\r': 'r',
'\t': 't',
'\v': 'v',
'\\': '\\',
'\'': '\'',
'"': '"',
}
// notEsc is a list of characters that can follow a \ in a string value
// without having to escape the \. That is, since ( is in this list, we
// quote the Go string "foo\\(bar" as the Python literal "foo\(bar".
// This really does happen in BUILD files, especially in strings
// being used as shell arguments containing regular expressions.
const notEsc = " !#$%&()*+,-./:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~"
// unquote unquotes the quoted string, returning the actual
// string value, whether the original was triple-quoted, and
// an error describing invalid input.
func unquote(quoted string) (s string, triple bool, err error) {
// Check for raw prefix: means don't interpret the inner \.
raw := false
if strings.HasPrefix(quoted, "r") {
raw = true
quoted = quoted[1:]
}
if len(quoted) < 2 {
err = fmt.Errorf("string literal too short")
return
}
if quoted[0] != '"' && quoted[0] != '\'' || quoted[0] != quoted[len(quoted)-1] {
err = fmt.Errorf("string literal has invalid quotes")
return
}
// Check for triple quoted string.
quote := quoted[0]
if len(quoted) >= 6 && quoted[1] == quote && quoted[2] == quote && quoted[:3] == quoted[len(quoted)-3:] {
triple = true
quoted = quoted[3 : len(quoted)-3]
} else {
quoted = quoted[1 : len(quoted)-1]
}
// Now quoted is the quoted data, but no quotes.
// If we're in raw mode or there are no escapes or
// carriage returns, we're done.
var unquoteChars string
if raw {
unquoteChars = "\r"
} else {
unquoteChars = "\\\r"
}
if !strings.ContainsAny(quoted, unquoteChars) {
s = quoted
return
}
// Otherwise process quoted string.
// Each iteration processes one escape sequence along with the
// plain text leading up to it.
buf := new(strings.Builder)
for {
// Remove prefix before escape sequence.
i := strings.IndexAny(quoted, unquoteChars)
if i < 0 {
i = len(quoted)
}
buf.WriteString(quoted[:i])
quoted = quoted[i:]
if len(quoted) == 0 {
break
}
// Process carriage return.
if quoted[0] == '\r' {
buf.WriteByte('\n')
if len(quoted) > 1 && quoted[1] == '\n' {
quoted = quoted[2:]
} else {
quoted = quoted[1:]
}
continue
}
// Process escape sequence.
if len(quoted) == 1 {
err = fmt.Errorf(`truncated escape sequence \`)
return
}
switch quoted[1] {
default:
// In Python, if \z (for some byte z) is not a known escape sequence
// then it appears as literal text in the string.
buf.WriteString(quoted[:2])
quoted = quoted[2:]
case '\n':
// Ignore the escape and the line break.
quoted = quoted[2:]
case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '\'', '"':
// One-char escape
buf.WriteByte(unesc[quoted[1]])
quoted = quoted[2:]
case '0', '1', '2', '3', '4', '5', '6', '7':
// Octal escape, up to 3 digits.
n := int(quoted[1] - '0')
quoted = quoted[2:]
for i := 1; i < 3; i++ {
if len(quoted) == 0 || quoted[0] < '0' || '7' < quoted[0] {
break
}
n = n*8 + int(quoted[0]-'0')
quoted = quoted[1:]
}
if n >= 256 {
// NOTE: Python silently discards the high bit,
// so that '\541' == '\141' == 'a'.
// Let's see if we can avoid doing that in BUILD files.
err = fmt.Errorf(`invalid escape sequence \%03o`, n)
return
}
buf.WriteByte(byte(n))
case 'x':
// Hexadecimal escape, exactly 2 digits.
if len(quoted) < 4 {
err = fmt.Errorf(`truncated escape sequence %s`, quoted)
return
}
n, err1 := strconv.ParseUint(quoted[2:4], 16, 0)
if err1 != nil {
err = fmt.Errorf(`invalid escape sequence %s`, quoted[:4])
return
}
buf.WriteByte(byte(n))
quoted = quoted[4:]
}
}
s = buf.String()
return
}
// indexByte returns the index of the first instance of b in s, or else -1.
func indexByte(s string, b byte) int {
for i := 0; i < len(s); i++ {
if s[i] == b {
return i
}
}
return -1
}
// hex is a list of the hexadecimal digits, for use in quoting.
// We always print lower-case hexadecimal.
const hex = "0123456789abcdef"
// quote returns the quoted form of the string value "x".
// If triple is true, quote uses the triple-quoted form """x""".
func quote(unquoted string, triple bool) string {
q := `"`
if triple {
q = `"""`
}
buf := new(strings.Builder)
buf.WriteString(q)
for i := 0; i < len(unquoted); i++ {
c := unquoted[i]
if c == '"' && triple && (i+1 < len(unquoted) && unquoted[i+1] != '"' || i+2 < len(unquoted) && unquoted[i+2] != '"') {
// Can pass up to two quotes through, because they are followed by a non-quote byte.
buf.WriteByte(c)
if i+1 < len(unquoted) && unquoted[i+1] == '"' {
buf.WriteByte(c)
i++
}
continue
}
if triple && c == '\n' {
// Can allow newline in triple-quoted string.
buf.WriteByte(c)
continue
}
if c == '\'' {
// Can allow ' since we always use ".
buf.WriteByte(c)
continue
}
if c == '\\' {
if i+1 < len(unquoted) && indexByte(notEsc, unquoted[i+1]) >= 0 {
// Can pass \ through when followed by a byte that
// known not to be a valid escape sequence and also
// that does not trigger an escape sequence of its own.
// Use this, because various BUILD files do.
buf.WriteByte('\\')
buf.WriteByte(unquoted[i+1])
i++
continue
}
}
if esc[c] != 0 {
buf.WriteByte('\\')
buf.WriteByte(esc[c])
continue
}
if c < 0x20 || c >= 0x80 {
// BUILD files are supposed to be Latin-1, so escape all control and high bytes.
// I'd prefer to use \x here, but Blaze does not implement
// \x in quoted strings (b/7272572).
buf.WriteByte('\\')
buf.WriteByte(hex[c>>6]) // actually octal but reusing hex digits 0-7.
buf.WriteByte(hex[(c>>3)&7])
buf.WriteByte(hex[c&7])
/*
buf.WriteByte('\\')
buf.WriteByte('x')
buf.WriteByte(hex[c>>4])
buf.WriteByte(hex[c&0xF])
*/
continue
}
buf.WriteByte(c)
continue
}
buf.WriteString(q)
return buf.String()
}

1089
vendor/go.starlark.net/syntax/scan.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

529
vendor/go.starlark.net/syntax/syntax.go generated vendored Normal file
View File

@@ -0,0 +1,529 @@
// Copyright 2017 The Bazel Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package syntax provides a Starlark parser and abstract syntax tree.
package syntax // import "go.starlark.net/syntax"
// A Node is a node in a Starlark syntax tree.
type Node interface {
// Span returns the start and end position of the expression.
Span() (start, end Position)
// Comments returns the comments associated with this node.
// It returns nil if RetainComments was not specified during parsing,
// or if AllocComments was not called.
Comments() *Comments
// AllocComments allocates a new Comments node if there was none.
// This makes possible to add new comments using Comments() method.
AllocComments()
}
// A Comment represents a single # comment.
type Comment struct {
Start Position
Text string // without trailing newline
}
// Comments collects the comments associated with an expression.
type Comments struct {
Before []Comment // whole-line comments before this expression
Suffix []Comment // end-of-line comments after this expression (up to 1)
// For top-level expressions only, After lists whole-line
// comments following the expression.
After []Comment
}
// A commentsRef is a possibly-nil reference to a set of comments.
// A commentsRef is embedded in each type of syntax node,
// and provides its Comments and AllocComments methods.
type commentsRef struct{ ref *Comments }
// Comments returns the comments associated with a syntax node,
// or nil if AllocComments has not yet been called.
func (cr commentsRef) Comments() *Comments { return cr.ref }
// AllocComments enables comments to be associated with a syntax node.
func (cr *commentsRef) AllocComments() {
if cr.ref == nil {
cr.ref = new(Comments)
}
}
// Start returns the start position of the expression.
func Start(n Node) Position {
start, _ := n.Span()
return start
}
// End returns the end position of the expression.
func End(n Node) Position {
_, end := n.Span()
return end
}
// A File represents a Starlark file.
type File struct {
commentsRef
Path string
Stmts []Stmt
Module interface{} // a *resolve.Module, set by resolver
}
func (x *File) Span() (start, end Position) {
if len(x.Stmts) == 0 {
return
}
start, _ = x.Stmts[0].Span()
_, end = x.Stmts[len(x.Stmts)-1].Span()
return start, end
}
// A Stmt is a Starlark statement.
type Stmt interface {
Node
stmt()
}
func (*AssignStmt) stmt() {}
func (*BranchStmt) stmt() {}
func (*DefStmt) stmt() {}
func (*ExprStmt) stmt() {}
func (*ForStmt) stmt() {}
func (*WhileStmt) stmt() {}
func (*IfStmt) stmt() {}
func (*LoadStmt) stmt() {}
func (*ReturnStmt) stmt() {}
// An AssignStmt represents an assignment:
// x = 0
// x, y = y, x
// x += 1
type AssignStmt struct {
commentsRef
OpPos Position
Op Token // = EQ | {PLUS,MINUS,STAR,PERCENT}_EQ
LHS Expr
RHS Expr
}
func (x *AssignStmt) Span() (start, end Position) {
start, _ = x.LHS.Span()
_, end = x.RHS.Span()
return
}
// A DefStmt represents a function definition.
type DefStmt struct {
commentsRef
Def Position
Name *Ident
Params []Expr // param = ident | ident=expr | * | *ident | **ident
Body []Stmt
Function interface{} // a *resolve.Function, set by resolver
}
func (x *DefStmt) Span() (start, end Position) {
_, end = x.Body[len(x.Body)-1].Span()
return x.Def, end
}
// An ExprStmt is an expression evaluated for side effects.
type ExprStmt struct {
commentsRef
X Expr
}
func (x *ExprStmt) Span() (start, end Position) {
return x.X.Span()
}
// An IfStmt is a conditional: If Cond: True; else: False.
// 'elseif' is desugared into a chain of IfStmts.
type IfStmt struct {
commentsRef
If Position // IF or ELIF
Cond Expr
True []Stmt
ElsePos Position // ELSE or ELIF
False []Stmt // optional
}
func (x *IfStmt) Span() (start, end Position) {
body := x.False
if body == nil {
body = x.True
}
_, end = body[len(body)-1].Span()
return x.If, end
}
// A LoadStmt loads another module and binds names from it:
// load(Module, "x", y="foo").
//
// The AST is slightly unfaithful to the concrete syntax here because
// Starlark's load statement, so that it can be implemented in Python,
// binds some names (like y above) with an identifier and some (like x)
// without. For consistency we create fake identifiers for all the
// strings.
type LoadStmt struct {
commentsRef
Load Position
Module *Literal // a string
From []*Ident // name defined in loading module
To []*Ident // name in loaded module
Rparen Position
}
func (x *LoadStmt) Span() (start, end Position) {
return x.Load, x.Rparen
}
// ModuleName returns the name of the module loaded by this statement.
func (x *LoadStmt) ModuleName() string { return x.Module.Value.(string) }
// A BranchStmt changes the flow of control: break, continue, pass.
type BranchStmt struct {
commentsRef
Token Token // = BREAK | CONTINUE | PASS
TokenPos Position
}
func (x *BranchStmt) Span() (start, end Position) {
return x.TokenPos, x.TokenPos.add(x.Token.String())
}
// A ReturnStmt returns from a function.
type ReturnStmt struct {
commentsRef
Return Position
Result Expr // may be nil
}
func (x *ReturnStmt) Span() (start, end Position) {
if x.Result == nil {
return x.Return, x.Return.add("return")
}
_, end = x.Result.Span()
return x.Return, end
}
// An Expr is a Starlark expression.
type Expr interface {
Node
expr()
}
func (*BinaryExpr) expr() {}
func (*CallExpr) expr() {}
func (*Comprehension) expr() {}
func (*CondExpr) expr() {}
func (*DictEntry) expr() {}
func (*DictExpr) expr() {}
func (*DotExpr) expr() {}
func (*Ident) expr() {}
func (*IndexExpr) expr() {}
func (*LambdaExpr) expr() {}
func (*ListExpr) expr() {}
func (*Literal) expr() {}
func (*ParenExpr) expr() {}
func (*SliceExpr) expr() {}
func (*TupleExpr) expr() {}
func (*UnaryExpr) expr() {}
// An Ident represents an identifier.
type Ident struct {
commentsRef
NamePos Position
Name string
Binding interface{} // a *resolver.Binding, set by resolver
}
func (x *Ident) Span() (start, end Position) {
return x.NamePos, x.NamePos.add(x.Name)
}
// A Literal represents a literal string or number.
type Literal struct {
commentsRef
Token Token // = STRING | INT
TokenPos Position
Raw string // uninterpreted text
Value interface{} // = string | int64 | *big.Int
}
func (x *Literal) Span() (start, end Position) {
return x.TokenPos, x.TokenPos.add(x.Raw)
}
// A ParenExpr represents a parenthesized expression: (X).
type ParenExpr struct {
commentsRef
Lparen Position
X Expr
Rparen Position
}
func (x *ParenExpr) Span() (start, end Position) {
return x.Lparen, x.Rparen.add(")")
}
// A CallExpr represents a function call expression: Fn(Args).
type CallExpr struct {
commentsRef
Fn Expr
Lparen Position
Args []Expr // arg = expr | ident=expr | *expr | **expr
Rparen Position
}
func (x *CallExpr) Span() (start, end Position) {
start, _ = x.Fn.Span()
return start, x.Rparen.add(")")
}
// A DotExpr represents a field or method selector: X.Name.
type DotExpr struct {
commentsRef
X Expr
Dot Position
NamePos Position
Name *Ident
}
func (x *DotExpr) Span() (start, end Position) {
start, _ = x.X.Span()
_, end = x.Name.Span()
return
}
// A Comprehension represents a list or dict comprehension:
// [Body for ... if ...] or {Body for ... if ...}
type Comprehension struct {
commentsRef
Curly bool // {x:y for ...} or {x for ...}, not [x for ...]
Lbrack Position
Body Expr
Clauses []Node // = *ForClause | *IfClause
Rbrack Position
}
func (x *Comprehension) Span() (start, end Position) {
return x.Lbrack, x.Rbrack.add("]")
}
// A ForStmt represents a loop: for Vars in X: Body.
type ForStmt struct {
commentsRef
For Position
Vars Expr // name, or tuple of names
X Expr
Body []Stmt
}
func (x *ForStmt) Span() (start, end Position) {
_, end = x.Body[len(x.Body)-1].Span()
return x.For, end
}
// A WhileStmt represents a while loop: while X: Body.
type WhileStmt struct {
commentsRef
While Position
Cond Expr
Body []Stmt
}
func (x *WhileStmt) Span() (start, end Position) {
_, end = x.Body[len(x.Body)-1].Span()
return x.While, end
}
// A ForClause represents a for clause in a list comprehension: for Vars in X.
type ForClause struct {
commentsRef
For Position
Vars Expr // name, or tuple of names
In Position
X Expr
}
func (x *ForClause) Span() (start, end Position) {
_, end = x.X.Span()
return x.For, end
}
// An IfClause represents an if clause in a list comprehension: if Cond.
type IfClause struct {
commentsRef
If Position
Cond Expr
}
func (x *IfClause) Span() (start, end Position) {
_, end = x.Cond.Span()
return x.If, end
}
// A DictExpr represents a dictionary literal: { List }.
type DictExpr struct {
commentsRef
Lbrace Position
List []Expr // all *DictEntrys
Rbrace Position
}
func (x *DictExpr) Span() (start, end Position) {
return x.Lbrace, x.Rbrace.add("}")
}
// A DictEntry represents a dictionary entry: Key: Value.
// Used only within a DictExpr.
type DictEntry struct {
commentsRef
Key Expr
Colon Position
Value Expr
}
func (x *DictEntry) Span() (start, end Position) {
start, _ = x.Key.Span()
_, end = x.Value.Span()
return start, end
}
// A LambdaExpr represents an inline function abstraction.
//
// Although they may be added in future, lambda expressions are not
// currently part of the Starlark spec, so their use is controlled by the
// resolver.AllowLambda flag.
type LambdaExpr struct {
commentsRef
Lambda Position
Params []Expr // param = ident | ident=expr | * | *ident | **ident
Body Expr
Function interface{} // a *resolve.Function, set by resolver
}
func (x *LambdaExpr) Span() (start, end Position) {
_, end = x.Body.Span()
return x.Lambda, end
}
// A ListExpr represents a list literal: [ List ].
type ListExpr struct {
commentsRef
Lbrack Position
List []Expr
Rbrack Position
}
func (x *ListExpr) Span() (start, end Position) {
return x.Lbrack, x.Rbrack.add("]")
}
// CondExpr represents the conditional: X if COND else ELSE.
type CondExpr struct {
commentsRef
If Position
Cond Expr
True Expr
ElsePos Position
False Expr
}
func (x *CondExpr) Span() (start, end Position) {
start, _ = x.True.Span()
_, end = x.False.Span()
return start, end
}
// A TupleExpr represents a tuple literal: (List).
type TupleExpr struct {
commentsRef
Lparen Position // optional (e.g. in x, y = 0, 1), but required if List is empty
List []Expr
Rparen Position
}
func (x *TupleExpr) Span() (start, end Position) {
if x.Lparen.IsValid() {
return x.Lparen, x.Rparen
} else {
return Start(x.List[0]), End(x.List[len(x.List)-1])
}
}
// A UnaryExpr represents a unary expression: Op X.
//
// As a special case, UnaryOp{Op:Star} may also represent
// the star parameter in def f(*args) or def f(*, x).
type UnaryExpr struct {
commentsRef
OpPos Position
Op Token
X Expr // may be nil if Op==STAR
}
func (x *UnaryExpr) Span() (start, end Position) {
if x.X != nil {
_, end = x.X.Span()
} else {
end = x.OpPos.add("*")
}
return x.OpPos, end
}
// A BinaryExpr represents a binary expression: X Op Y.
//
// As a special case, BinaryExpr{Op:EQ} may also
// represent a named argument in a call f(k=v)
// or a named parameter in a function declaration
// def f(param=default).
type BinaryExpr struct {
commentsRef
X Expr
OpPos Position
Op Token
Y Expr
}
func (x *BinaryExpr) Span() (start, end Position) {
start, _ = x.X.Span()
_, end = x.Y.Span()
return start, end
}
// A SliceExpr represents a slice or substring expression: X[Lo:Hi:Step].
type SliceExpr struct {
commentsRef
X Expr
Lbrack Position
Lo, Hi, Step Expr // all optional
Rbrack Position
}
func (x *SliceExpr) Span() (start, end Position) {
start, _ = x.X.Span()
return start, x.Rbrack
}
// An IndexExpr represents an index expression: X[Y].
type IndexExpr struct {
commentsRef
X Expr
Lbrack Position
Y Expr
Rbrack Position
}
func (x *IndexExpr) Span() (start, end Position) {
start, _ = x.X.Span()
return start, x.Rbrack
}

163
vendor/go.starlark.net/syntax/walk.go generated vendored Normal file
View File

@@ -0,0 +1,163 @@
// Copyright 2017 The Bazel Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package syntax
// Walk traverses a syntax tree in depth-first order.
// It starts by calling f(n); n must not be nil.
// If f returns true, Walk calls itself
// recursively for each non-nil child of n.
// Walk then calls f(nil).
func Walk(n Node, f func(Node) bool) {
if n == nil {
panic("nil")
}
if !f(n) {
return
}
// TODO(adonovan): opt: order cases using profile data.
switch n := n.(type) {
case *File:
walkStmts(n.Stmts, f)
case *ExprStmt:
Walk(n.X, f)
case *BranchStmt:
// no-op
case *IfStmt:
Walk(n.Cond, f)
walkStmts(n.True, f)
walkStmts(n.False, f)
case *AssignStmt:
Walk(n.LHS, f)
Walk(n.RHS, f)
case *DefStmt:
Walk(n.Name, f)
for _, param := range n.Params {
Walk(param, f)
}
walkStmts(n.Body, f)
case *ForStmt:
Walk(n.Vars, f)
Walk(n.X, f)
walkStmts(n.Body, f)
case *ReturnStmt:
if n.Result != nil {
Walk(n.Result, f)
}
case *LoadStmt:
Walk(n.Module, f)
for _, from := range n.From {
Walk(from, f)
}
for _, to := range n.To {
Walk(to, f)
}
case *Ident, *Literal:
// no-op
case *ListExpr:
for _, x := range n.List {
Walk(x, f)
}
case *ParenExpr:
Walk(n.X, f)
case *CondExpr:
Walk(n.Cond, f)
Walk(n.True, f)
Walk(n.False, f)
case *IndexExpr:
Walk(n.X, f)
Walk(n.Y, f)
case *DictEntry:
Walk(n.Key, f)
Walk(n.Value, f)
case *SliceExpr:
Walk(n.X, f)
if n.Lo != nil {
Walk(n.Lo, f)
}
if n.Hi != nil {
Walk(n.Hi, f)
}
if n.Step != nil {
Walk(n.Step, f)
}
case *Comprehension:
Walk(n.Body, f)
for _, clause := range n.Clauses {
Walk(clause, f)
}
case *IfClause:
Walk(n.Cond, f)
case *ForClause:
Walk(n.Vars, f)
Walk(n.X, f)
case *TupleExpr:
for _, x := range n.List {
Walk(x, f)
}
case *DictExpr:
for _, entry := range n.List {
entry := entry.(*DictEntry)
Walk(entry.Key, f)
Walk(entry.Value, f)
}
case *UnaryExpr:
if n.X != nil {
Walk(n.X, f)
}
case *BinaryExpr:
Walk(n.X, f)
Walk(n.Y, f)
case *DotExpr:
Walk(n.X, f)
Walk(n.Name, f)
case *CallExpr:
Walk(n.Fn, f)
for _, arg := range n.Args {
Walk(arg, f)
}
case *LambdaExpr:
for _, param := range n.Params {
Walk(param, f)
}
Walk(n.Body, f)
default:
panic(n)
}
f(nil)
}
func walkStmts(stmts []Stmt, f func(Node) bool) {
for _, stmt := range stmts {
Walk(stmt, f)
}
}