open-nomad/vendor/honnef.co/go/tools/pattern/parser.go
Seth Hoenig 435c0d9fc8 deps: Switch to Go modules for dependency management
This PR switches the Nomad repository from using govendor to Go modules
for managing dependencies. Aspects of the Nomad workflow remain pretty
much the same. The usual Makefile targets should continue to work as
they always did. The API submodule simply defers to the parent Nomad
version on the repository, keeping the semantics of API versioning that
currently exists.
2020-06-02 14:30:36 -05:00

456 lines
14 KiB
Go

package pattern
import (
"fmt"
"go/ast"
"go/token"
"reflect"
)
type Pattern struct {
Root Node
// Relevant contains instances of ast.Node that could potentially
// initiate a successful match of the pattern.
Relevant []reflect.Type
}
func MustParse(s string) Pattern {
p := &Parser{AllowTypeInfo: true}
pat, err := p.Parse(s)
if err != nil {
panic(err)
}
return pat
}
func roots(node Node) []reflect.Type {
switch node := node.(type) {
case Or:
var out []reflect.Type
for _, el := range node.Nodes {
out = append(out, roots(el)...)
}
return out
case Not:
return roots(node.Node)
case Binding:
return roots(node.Node)
case Nil, nil:
// this branch is reached via bindings
return allTypes
default:
Ts, ok := nodeToASTTypes[reflect.TypeOf(node)]
if !ok {
panic(fmt.Sprintf("internal error: unhandled type %T", node))
}
return Ts
}
}
var allTypes = []reflect.Type{
reflect.TypeOf((*ast.RangeStmt)(nil)),
reflect.TypeOf((*ast.AssignStmt)(nil)),
reflect.TypeOf((*ast.IndexExpr)(nil)),
reflect.TypeOf((*ast.Ident)(nil)),
reflect.TypeOf((*ast.ValueSpec)(nil)),
reflect.TypeOf((*ast.GenDecl)(nil)),
reflect.TypeOf((*ast.BinaryExpr)(nil)),
reflect.TypeOf((*ast.ForStmt)(nil)),
reflect.TypeOf((*ast.ArrayType)(nil)),
reflect.TypeOf((*ast.DeferStmt)(nil)),
reflect.TypeOf((*ast.MapType)(nil)),
reflect.TypeOf((*ast.ReturnStmt)(nil)),
reflect.TypeOf((*ast.SliceExpr)(nil)),
reflect.TypeOf((*ast.StarExpr)(nil)),
reflect.TypeOf((*ast.UnaryExpr)(nil)),
reflect.TypeOf((*ast.SendStmt)(nil)),
reflect.TypeOf((*ast.SelectStmt)(nil)),
reflect.TypeOf((*ast.ImportSpec)(nil)),
reflect.TypeOf((*ast.IfStmt)(nil)),
reflect.TypeOf((*ast.GoStmt)(nil)),
reflect.TypeOf((*ast.Field)(nil)),
reflect.TypeOf((*ast.SelectorExpr)(nil)),
reflect.TypeOf((*ast.StructType)(nil)),
reflect.TypeOf((*ast.KeyValueExpr)(nil)),
reflect.TypeOf((*ast.FuncType)(nil)),
reflect.TypeOf((*ast.FuncLit)(nil)),
reflect.TypeOf((*ast.FuncDecl)(nil)),
reflect.TypeOf((*ast.ChanType)(nil)),
reflect.TypeOf((*ast.CallExpr)(nil)),
reflect.TypeOf((*ast.CaseClause)(nil)),
reflect.TypeOf((*ast.CommClause)(nil)),
reflect.TypeOf((*ast.CompositeLit)(nil)),
reflect.TypeOf((*ast.EmptyStmt)(nil)),
reflect.TypeOf((*ast.SwitchStmt)(nil)),
reflect.TypeOf((*ast.TypeSwitchStmt)(nil)),
reflect.TypeOf((*ast.TypeAssertExpr)(nil)),
reflect.TypeOf((*ast.TypeSpec)(nil)),
reflect.TypeOf((*ast.InterfaceType)(nil)),
reflect.TypeOf((*ast.BranchStmt)(nil)),
reflect.TypeOf((*ast.IncDecStmt)(nil)),
reflect.TypeOf((*ast.BasicLit)(nil)),
}
var nodeToASTTypes = map[reflect.Type][]reflect.Type{
reflect.TypeOf(String("")): nil,
reflect.TypeOf(Token(0)): nil,
reflect.TypeOf(List{}): {reflect.TypeOf((*ast.BlockStmt)(nil)), reflect.TypeOf((*ast.FieldList)(nil))},
reflect.TypeOf(Builtin{}): {reflect.TypeOf((*ast.Ident)(nil))},
reflect.TypeOf(Object{}): {reflect.TypeOf((*ast.Ident)(nil))},
reflect.TypeOf(Function{}): {reflect.TypeOf((*ast.Ident)(nil)), reflect.TypeOf((*ast.SelectorExpr)(nil))},
reflect.TypeOf(Any{}): allTypes,
reflect.TypeOf(RangeStmt{}): {reflect.TypeOf((*ast.RangeStmt)(nil))},
reflect.TypeOf(AssignStmt{}): {reflect.TypeOf((*ast.AssignStmt)(nil))},
reflect.TypeOf(IndexExpr{}): {reflect.TypeOf((*ast.IndexExpr)(nil))},
reflect.TypeOf(Ident{}): {reflect.TypeOf((*ast.Ident)(nil))},
reflect.TypeOf(ValueSpec{}): {reflect.TypeOf((*ast.ValueSpec)(nil))},
reflect.TypeOf(GenDecl{}): {reflect.TypeOf((*ast.GenDecl)(nil))},
reflect.TypeOf(BinaryExpr{}): {reflect.TypeOf((*ast.BinaryExpr)(nil))},
reflect.TypeOf(ForStmt{}): {reflect.TypeOf((*ast.ForStmt)(nil))},
reflect.TypeOf(ArrayType{}): {reflect.TypeOf((*ast.ArrayType)(nil))},
reflect.TypeOf(DeferStmt{}): {reflect.TypeOf((*ast.DeferStmt)(nil))},
reflect.TypeOf(MapType{}): {reflect.TypeOf((*ast.MapType)(nil))},
reflect.TypeOf(ReturnStmt{}): {reflect.TypeOf((*ast.ReturnStmt)(nil))},
reflect.TypeOf(SliceExpr{}): {reflect.TypeOf((*ast.SliceExpr)(nil))},
reflect.TypeOf(StarExpr{}): {reflect.TypeOf((*ast.StarExpr)(nil))},
reflect.TypeOf(UnaryExpr{}): {reflect.TypeOf((*ast.UnaryExpr)(nil))},
reflect.TypeOf(SendStmt{}): {reflect.TypeOf((*ast.SendStmt)(nil))},
reflect.TypeOf(SelectStmt{}): {reflect.TypeOf((*ast.SelectStmt)(nil))},
reflect.TypeOf(ImportSpec{}): {reflect.TypeOf((*ast.ImportSpec)(nil))},
reflect.TypeOf(IfStmt{}): {reflect.TypeOf((*ast.IfStmt)(nil))},
reflect.TypeOf(GoStmt{}): {reflect.TypeOf((*ast.GoStmt)(nil))},
reflect.TypeOf(Field{}): {reflect.TypeOf((*ast.Field)(nil))},
reflect.TypeOf(SelectorExpr{}): {reflect.TypeOf((*ast.SelectorExpr)(nil))},
reflect.TypeOf(StructType{}): {reflect.TypeOf((*ast.StructType)(nil))},
reflect.TypeOf(KeyValueExpr{}): {reflect.TypeOf((*ast.KeyValueExpr)(nil))},
reflect.TypeOf(FuncType{}): {reflect.TypeOf((*ast.FuncType)(nil))},
reflect.TypeOf(FuncLit{}): {reflect.TypeOf((*ast.FuncLit)(nil))},
reflect.TypeOf(FuncDecl{}): {reflect.TypeOf((*ast.FuncDecl)(nil))},
reflect.TypeOf(ChanType{}): {reflect.TypeOf((*ast.ChanType)(nil))},
reflect.TypeOf(CallExpr{}): {reflect.TypeOf((*ast.CallExpr)(nil))},
reflect.TypeOf(CaseClause{}): {reflect.TypeOf((*ast.CaseClause)(nil))},
reflect.TypeOf(CommClause{}): {reflect.TypeOf((*ast.CommClause)(nil))},
reflect.TypeOf(CompositeLit{}): {reflect.TypeOf((*ast.CompositeLit)(nil))},
reflect.TypeOf(EmptyStmt{}): {reflect.TypeOf((*ast.EmptyStmt)(nil))},
reflect.TypeOf(SwitchStmt{}): {reflect.TypeOf((*ast.SwitchStmt)(nil))},
reflect.TypeOf(TypeSwitchStmt{}): {reflect.TypeOf((*ast.TypeSwitchStmt)(nil))},
reflect.TypeOf(TypeAssertExpr{}): {reflect.TypeOf((*ast.TypeAssertExpr)(nil))},
reflect.TypeOf(TypeSpec{}): {reflect.TypeOf((*ast.TypeSpec)(nil))},
reflect.TypeOf(InterfaceType{}): {reflect.TypeOf((*ast.InterfaceType)(nil))},
reflect.TypeOf(BranchStmt{}): {reflect.TypeOf((*ast.BranchStmt)(nil))},
reflect.TypeOf(IncDecStmt{}): {reflect.TypeOf((*ast.IncDecStmt)(nil))},
reflect.TypeOf(BasicLit{}): {reflect.TypeOf((*ast.BasicLit)(nil))},
}
var requiresTypeInfo = map[string]bool{
"Function": true,
"Builtin": true,
"Object": true,
}
type Parser struct {
// Allow nodes that rely on type information
AllowTypeInfo bool
lex *lexer
cur item
last *item
items chan item
}
func (p *Parser) Parse(s string) (Pattern, error) {
p.cur = item{}
p.last = nil
p.items = nil
fset := token.NewFileSet()
p.lex = &lexer{
f: fset.AddFile("<input>", -1, len(s)),
input: s,
items: make(chan item),
}
go p.lex.run()
p.items = p.lex.items
root, err := p.node()
if err != nil {
// drain lexer if parsing failed
for range p.lex.items {
}
return Pattern{}, err
}
if item := <-p.lex.items; item.typ != itemEOF {
return Pattern{}, fmt.Errorf("unexpected token %s after end of pattern", item.typ)
}
return Pattern{
Root: root,
Relevant: roots(root),
}, nil
}
func (p *Parser) next() item {
if p.last != nil {
n := *p.last
p.last = nil
return n
}
var ok bool
p.cur, ok = <-p.items
if !ok {
p.cur = item{typ: eof}
}
return p.cur
}
func (p *Parser) rewind() {
p.last = &p.cur
}
func (p *Parser) peek() item {
n := p.next()
p.rewind()
return n
}
func (p *Parser) accept(typ itemType) (item, bool) {
n := p.next()
if n.typ == typ {
return n, true
}
p.rewind()
return item{}, false
}
func (p *Parser) unexpectedToken(valid string) error {
if p.cur.typ == itemError {
return fmt.Errorf("error lexing input: %s", p.cur.val)
}
var got string
switch p.cur.typ {
case itemTypeName, itemVariable, itemString:
got = p.cur.val
default:
got = "'" + p.cur.typ.String() + "'"
}
pos := p.lex.f.Position(token.Pos(p.cur.pos))
return fmt.Errorf("%s: expected %s, found %s", pos, valid, got)
}
func (p *Parser) node() (Node, error) {
if _, ok := p.accept(itemLeftParen); !ok {
return nil, p.unexpectedToken("'('")
}
typ, ok := p.accept(itemTypeName)
if !ok {
return nil, p.unexpectedToken("Node type")
}
var objs []Node
for {
if _, ok := p.accept(itemRightParen); ok {
break
} else {
p.rewind()
obj, err := p.object()
if err != nil {
return nil, err
}
objs = append(objs, obj)
}
}
return p.populateNode(typ.val, objs)
}
func populateNode(typ string, objs []Node, allowTypeInfo bool) (Node, error) {
T, ok := structNodes[typ]
if !ok {
return nil, fmt.Errorf("unknown node %s", typ)
}
if !allowTypeInfo && requiresTypeInfo[typ] {
return nil, fmt.Errorf("Node %s requires type information", typ)
}
pv := reflect.New(T)
v := pv.Elem()
if v.NumField() == 1 {
f := v.Field(0)
if f.Type().Kind() == reflect.Slice {
// Variadic node
f.Set(reflect.AppendSlice(f, reflect.ValueOf(objs)))
return v.Interface().(Node), nil
}
}
if len(objs) != v.NumField() {
return nil, fmt.Errorf("tried to initialize node %s with %d values, expected %d", typ, len(objs), v.NumField())
}
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
if f.Kind() == reflect.String {
if obj, ok := objs[i].(String); ok {
f.Set(reflect.ValueOf(string(obj)))
} else {
return nil, fmt.Errorf("first argument of (Binding name node) must be string, but got %s", objs[i])
}
} else {
f.Set(reflect.ValueOf(objs[i]))
}
}
return v.Interface().(Node), nil
}
func (p *Parser) populateNode(typ string, objs []Node) (Node, error) {
return populateNode(typ, objs, p.AllowTypeInfo)
}
var structNodes = map[string]reflect.Type{
"Any": reflect.TypeOf(Any{}),
"Ellipsis": reflect.TypeOf(Ellipsis{}),
"List": reflect.TypeOf(List{}),
"Binding": reflect.TypeOf(Binding{}),
"RangeStmt": reflect.TypeOf(RangeStmt{}),
"AssignStmt": reflect.TypeOf(AssignStmt{}),
"IndexExpr": reflect.TypeOf(IndexExpr{}),
"Ident": reflect.TypeOf(Ident{}),
"Builtin": reflect.TypeOf(Builtin{}),
"ValueSpec": reflect.TypeOf(ValueSpec{}),
"GenDecl": reflect.TypeOf(GenDecl{}),
"BinaryExpr": reflect.TypeOf(BinaryExpr{}),
"ForStmt": reflect.TypeOf(ForStmt{}),
"ArrayType": reflect.TypeOf(ArrayType{}),
"DeferStmt": reflect.TypeOf(DeferStmt{}),
"MapType": reflect.TypeOf(MapType{}),
"ReturnStmt": reflect.TypeOf(ReturnStmt{}),
"SliceExpr": reflect.TypeOf(SliceExpr{}),
"StarExpr": reflect.TypeOf(StarExpr{}),
"UnaryExpr": reflect.TypeOf(UnaryExpr{}),
"SendStmt": reflect.TypeOf(SendStmt{}),
"SelectStmt": reflect.TypeOf(SelectStmt{}),
"ImportSpec": reflect.TypeOf(ImportSpec{}),
"IfStmt": reflect.TypeOf(IfStmt{}),
"GoStmt": reflect.TypeOf(GoStmt{}),
"Field": reflect.TypeOf(Field{}),
"SelectorExpr": reflect.TypeOf(SelectorExpr{}),
"StructType": reflect.TypeOf(StructType{}),
"KeyValueExpr": reflect.TypeOf(KeyValueExpr{}),
"FuncType": reflect.TypeOf(FuncType{}),
"FuncLit": reflect.TypeOf(FuncLit{}),
"FuncDecl": reflect.TypeOf(FuncDecl{}),
"ChanType": reflect.TypeOf(ChanType{}),
"CallExpr": reflect.TypeOf(CallExpr{}),
"CaseClause": reflect.TypeOf(CaseClause{}),
"CommClause": reflect.TypeOf(CommClause{}),
"CompositeLit": reflect.TypeOf(CompositeLit{}),
"EmptyStmt": reflect.TypeOf(EmptyStmt{}),
"SwitchStmt": reflect.TypeOf(SwitchStmt{}),
"TypeSwitchStmt": reflect.TypeOf(TypeSwitchStmt{}),
"TypeAssertExpr": reflect.TypeOf(TypeAssertExpr{}),
"TypeSpec": reflect.TypeOf(TypeSpec{}),
"InterfaceType": reflect.TypeOf(InterfaceType{}),
"BranchStmt": reflect.TypeOf(BranchStmt{}),
"IncDecStmt": reflect.TypeOf(IncDecStmt{}),
"BasicLit": reflect.TypeOf(BasicLit{}),
"Object": reflect.TypeOf(Object{}),
"Function": reflect.TypeOf(Function{}),
"Or": reflect.TypeOf(Or{}),
"Not": reflect.TypeOf(Not{}),
}
func (p *Parser) object() (Node, error) {
n := p.next()
switch n.typ {
case itemLeftParen:
p.rewind()
node, err := p.node()
if err != nil {
return node, err
}
if p.peek().typ == itemColon {
p.next()
tail, err := p.object()
if err != nil {
return node, err
}
return List{Head: node, Tail: tail}, nil
}
return node, nil
case itemLeftBracket:
p.rewind()
return p.array()
case itemVariable:
v := n
if v.val == "nil" {
return Nil{}, nil
}
var b Binding
if _, ok := p.accept(itemAt); ok {
o, err := p.node()
if err != nil {
return nil, err
}
b = Binding{
Name: v.val,
Node: o,
}
} else {
p.rewind()
b = Binding{Name: v.val}
}
if p.peek().typ == itemColon {
p.next()
tail, err := p.object()
if err != nil {
return b, err
}
return List{Head: b, Tail: tail}, nil
}
return b, nil
case itemBlank:
return Any{}, nil
case itemString:
return String(n.val), nil
default:
return nil, p.unexpectedToken("object")
}
}
func (p *Parser) array() (Node, error) {
if _, ok := p.accept(itemLeftBracket); !ok {
return nil, p.unexpectedToken("'['")
}
var objs []Node
for {
if _, ok := p.accept(itemRightBracket); ok {
break
} else {
p.rewind()
obj, err := p.object()
if err != nil {
return nil, err
}
objs = append(objs, obj)
}
}
tail := List{}
for i := len(objs) - 1; i >= 0; i-- {
l := List{
Head: objs[i],
Tail: tail,
}
tail = l
}
return tail, nil
}
/*
Node ::= itemLeftParen itemTypeName Object* itemRightParen
Object ::= Node | Array | Binding | itemVariable | itemBlank | itemString
Array := itemLeftBracket Object* itemRightBracket
Array := Object itemColon Object
Binding ::= itemVariable itemAt Node
*/