Add staticcheck tool
This commit is contained in:
714
vendor/honnef.co/go/tools/pattern/parser.go
vendored
Normal file
714
vendor/honnef.co/go/tools/pattern/parser.go
vendored
Normal file
@@ -0,0 +1,714 @@
|
||||
package pattern
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"iter"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Pattern struct {
|
||||
Root Node
|
||||
// EntryNodes contains instances of ast.Node that could potentially
|
||||
// initiate a successful match of the pattern.
|
||||
EntryNodes []ast.Node
|
||||
|
||||
// SymbolsPattern is a pattern consisting or Any, Or, And, and IndexSymbol,
|
||||
// that can be used to implement fast rejection of whole packages using
|
||||
// typeindex.
|
||||
SymbolsPattern Node
|
||||
|
||||
// If non-empty, all possible candidate nodes for this pattern can be found
|
||||
// by finding all call expressions for this list of symbols.
|
||||
RootCallSymbols []IndexSymbol
|
||||
|
||||
// Mapping from binding index to binding name
|
||||
Bindings []string
|
||||
}
|
||||
|
||||
func MustParse(s string) Pattern {
|
||||
p := &Parser{AllowTypeInfo: true}
|
||||
pat, err := p.Parse(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return pat
|
||||
}
|
||||
|
||||
func symbolToIndexSymbol(name string) IndexSymbol {
|
||||
if len(name) == 0 {
|
||||
return IndexSymbol{}
|
||||
}
|
||||
if name[0] == '(' {
|
||||
end := strings.IndexAny(name, ")")
|
||||
// Ensure there's a ), and also that there are at least two more
|
||||
// characters after it, for a dot and an identifier.
|
||||
if end == -1 || end > len(name)-2 {
|
||||
return IndexSymbol{}
|
||||
}
|
||||
pathAndType := strings.TrimPrefix(name[1:end], "*")
|
||||
dot := strings.LastIndex(pathAndType, ".")
|
||||
if dot == -1 {
|
||||
return IndexSymbol{}
|
||||
}
|
||||
path := pathAndType[:dot]
|
||||
typ := pathAndType[dot+1:]
|
||||
ident := name[end+2:]
|
||||
return IndexSymbol{path, typ, ident}
|
||||
} else {
|
||||
dot := strings.LastIndex(name, ".")
|
||||
if dot == -1 {
|
||||
return IndexSymbol{"", "", name}
|
||||
}
|
||||
path := name[:dot]
|
||||
ident := name[dot+1:]
|
||||
return IndexSymbol{path, "", ident}
|
||||
}
|
||||
}
|
||||
|
||||
func collectSymbols(node Node, inSymbol bool) Node {
|
||||
and := func(c Node, out *And) {
|
||||
switch cc := c.(type) {
|
||||
case And:
|
||||
out.Nodes = append(out.Nodes, cc.Nodes...)
|
||||
case Any:
|
||||
case nil:
|
||||
default:
|
||||
out.Nodes = append(out.Nodes, c)
|
||||
}
|
||||
}
|
||||
|
||||
switch node := node.(type) {
|
||||
case Or:
|
||||
s := Or{}
|
||||
for _, el := range node.Nodes {
|
||||
c := collectSymbols(el, inSymbol)
|
||||
switch cc := c.(type) {
|
||||
case Or:
|
||||
s.Nodes = append(s.Nodes, cc.Nodes...)
|
||||
case Any:
|
||||
return Any{}
|
||||
case nil:
|
||||
default:
|
||||
s.Nodes = append(s.Nodes, c)
|
||||
}
|
||||
}
|
||||
switch len(s.Nodes) {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
return s.Nodes[0]
|
||||
default:
|
||||
return s
|
||||
}
|
||||
case Not, Token, nil:
|
||||
return Any{}
|
||||
case Symbol:
|
||||
return collectSymbols(node.Name, true)
|
||||
case String:
|
||||
if !inSymbol {
|
||||
return Any{}
|
||||
}
|
||||
// In logically correct patterns, all Strings that are children of
|
||||
// Symbols describe the names of symbols.
|
||||
return symbolToIndexSymbol(string(node))
|
||||
case Binding:
|
||||
return collectSymbols(node.Node, inSymbol)
|
||||
case Any:
|
||||
return Any{}
|
||||
case List:
|
||||
var out And
|
||||
and(collectSymbols(node.Head, inSymbol), &out)
|
||||
and(collectSymbols(node.Tail, inSymbol), &out)
|
||||
switch len(out.Nodes) {
|
||||
case 0:
|
||||
return Any{}
|
||||
case 1:
|
||||
return out.Nodes[0]
|
||||
default:
|
||||
return out
|
||||
}
|
||||
default:
|
||||
var out And
|
||||
rv := reflect.ValueOf(node)
|
||||
for i := range rv.NumField() {
|
||||
c := collectSymbols(rv.Field(i).Interface().(Node), inSymbol)
|
||||
and(c, &out)
|
||||
}
|
||||
switch len(out.Nodes) {
|
||||
case 0:
|
||||
return Any{}
|
||||
case 1:
|
||||
return out.Nodes[0]
|
||||
default:
|
||||
return out
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func collectRootCallSymbols(node Node) []IndexSymbol {
|
||||
root, ok := node.(CallExpr)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
var names []String
|
||||
var handleSymName func(name Node) bool
|
||||
handleSymName = func(name Node) bool {
|
||||
switch name := name.(type) {
|
||||
case String:
|
||||
names = append(names, name)
|
||||
case Or:
|
||||
for _, node := range name.Nodes {
|
||||
if name, ok := node.(String); ok {
|
||||
names = append(names, name)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
case Binding:
|
||||
return handleSymName(name.Node)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
var handleRootFun func(node Node) bool
|
||||
handleRootFun = func(node Node) bool {
|
||||
switch fun := node.(type) {
|
||||
case Binding:
|
||||
return handleRootFun(fun.Node)
|
||||
case Symbol:
|
||||
return handleSymName(fun.Name)
|
||||
case Or:
|
||||
for _, node := range fun.Nodes {
|
||||
if sym, ok := node.(Symbol); !ok || !handleSymName(sym.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
if !handleRootFun(root.Fun) {
|
||||
return nil
|
||||
}
|
||||
|
||||
out := make([]IndexSymbol, len(names))
|
||||
for i, name := range names {
|
||||
out[i] = symbolToIndexSymbol(string(name))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func collectEntryNodes(node Node, m map[reflect.Type]struct{}) {
|
||||
switch node := node.(type) {
|
||||
case Or:
|
||||
for _, el := range node.Nodes {
|
||||
collectEntryNodes(el, m)
|
||||
}
|
||||
case Not:
|
||||
collectEntryNodes(node.Node, m)
|
||||
case Binding:
|
||||
collectEntryNodes(node.Node, m)
|
||||
case Nil, nil:
|
||||
// this branch is reached via bindings
|
||||
for _, T := range allTypes {
|
||||
m[T] = struct{}{}
|
||||
}
|
||||
default:
|
||||
Ts, ok := nodeToASTTypes[reflect.TypeOf(node)]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("internal error: unhandled type %T", node))
|
||||
}
|
||||
for _, T := range Ts {
|
||||
m[T] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var allTypes = []reflect.Type{
|
||||
reflect.TypeFor[*ast.RangeStmt](),
|
||||
reflect.TypeFor[*ast.AssignStmt](),
|
||||
reflect.TypeFor[*ast.IndexExpr](),
|
||||
reflect.TypeFor[*ast.Ident](),
|
||||
reflect.TypeFor[*ast.ValueSpec](),
|
||||
reflect.TypeFor[*ast.GenDecl](),
|
||||
reflect.TypeFor[*ast.BinaryExpr](),
|
||||
reflect.TypeFor[*ast.ForStmt](),
|
||||
reflect.TypeFor[*ast.ArrayType](),
|
||||
reflect.TypeFor[*ast.DeferStmt](),
|
||||
reflect.TypeFor[*ast.MapType](),
|
||||
reflect.TypeFor[*ast.ReturnStmt](),
|
||||
reflect.TypeFor[*ast.SliceExpr](),
|
||||
reflect.TypeFor[*ast.StarExpr](),
|
||||
reflect.TypeFor[*ast.UnaryExpr](),
|
||||
reflect.TypeFor[*ast.SendStmt](),
|
||||
reflect.TypeFor[*ast.SelectStmt](),
|
||||
reflect.TypeFor[*ast.ImportSpec](),
|
||||
reflect.TypeFor[*ast.IfStmt](),
|
||||
reflect.TypeFor[*ast.GoStmt](),
|
||||
reflect.TypeFor[*ast.Field](),
|
||||
reflect.TypeFor[*ast.SelectorExpr](),
|
||||
reflect.TypeFor[*ast.StructType](),
|
||||
reflect.TypeFor[*ast.KeyValueExpr](),
|
||||
reflect.TypeFor[*ast.FuncType](),
|
||||
reflect.TypeFor[*ast.FuncLit](),
|
||||
reflect.TypeFor[*ast.FuncDecl](),
|
||||
reflect.TypeFor[*ast.ChanType](),
|
||||
reflect.TypeFor[*ast.CallExpr](),
|
||||
reflect.TypeFor[*ast.CaseClause](),
|
||||
reflect.TypeFor[*ast.CommClause](),
|
||||
reflect.TypeFor[*ast.CompositeLit](),
|
||||
reflect.TypeFor[*ast.EmptyStmt](),
|
||||
reflect.TypeFor[*ast.SwitchStmt](),
|
||||
reflect.TypeFor[*ast.TypeSwitchStmt](),
|
||||
reflect.TypeFor[*ast.TypeAssertExpr](),
|
||||
reflect.TypeFor[*ast.TypeSpec](),
|
||||
reflect.TypeFor[*ast.InterfaceType](),
|
||||
reflect.TypeFor[*ast.BranchStmt](),
|
||||
reflect.TypeFor[*ast.IncDecStmt](),
|
||||
reflect.TypeFor[*ast.BasicLit](),
|
||||
}
|
||||
|
||||
var nodeToASTTypes = map[reflect.Type][]reflect.Type{
|
||||
reflect.TypeFor[String](): nil,
|
||||
reflect.TypeFor[Token](): nil,
|
||||
reflect.TypeFor[List](): {reflect.TypeFor[*ast.BlockStmt](), reflect.TypeFor[*ast.FieldList]()},
|
||||
reflect.TypeFor[Builtin](): {reflect.TypeFor[*ast.Ident]()},
|
||||
reflect.TypeFor[Object](): {reflect.TypeFor[*ast.Ident]()},
|
||||
reflect.TypeFor[Symbol](): {reflect.TypeFor[*ast.Ident](), reflect.TypeFor[*ast.SelectorExpr]()},
|
||||
reflect.TypeFor[Any](): allTypes,
|
||||
reflect.TypeFor[RangeStmt](): {reflect.TypeFor[*ast.RangeStmt]()},
|
||||
reflect.TypeFor[AssignStmt](): {reflect.TypeFor[*ast.AssignStmt]()},
|
||||
reflect.TypeFor[IndexExpr](): {reflect.TypeFor[*ast.IndexExpr]()},
|
||||
reflect.TypeFor[Ident](): {reflect.TypeFor[*ast.Ident]()},
|
||||
reflect.TypeFor[ValueSpec](): {reflect.TypeFor[*ast.ValueSpec]()},
|
||||
reflect.TypeFor[GenDecl](): {reflect.TypeFor[*ast.GenDecl]()},
|
||||
reflect.TypeFor[BinaryExpr](): {reflect.TypeFor[*ast.BinaryExpr]()},
|
||||
reflect.TypeFor[ForStmt](): {reflect.TypeFor[*ast.ForStmt]()},
|
||||
reflect.TypeFor[ArrayType](): {reflect.TypeFor[*ast.ArrayType]()},
|
||||
reflect.TypeFor[DeferStmt](): {reflect.TypeFor[*ast.DeferStmt]()},
|
||||
reflect.TypeFor[MapType](): {reflect.TypeFor[*ast.MapType]()},
|
||||
reflect.TypeFor[ReturnStmt](): {reflect.TypeFor[*ast.ReturnStmt]()},
|
||||
reflect.TypeFor[SliceExpr](): {reflect.TypeFor[*ast.SliceExpr]()},
|
||||
reflect.TypeFor[StarExpr](): {reflect.TypeFor[*ast.StarExpr]()},
|
||||
reflect.TypeFor[UnaryExpr](): {reflect.TypeFor[*ast.UnaryExpr]()},
|
||||
reflect.TypeFor[SendStmt](): {reflect.TypeFor[*ast.SendStmt]()},
|
||||
reflect.TypeFor[SelectStmt](): {reflect.TypeFor[*ast.SelectStmt]()},
|
||||
reflect.TypeFor[ImportSpec](): {reflect.TypeFor[*ast.ImportSpec]()},
|
||||
reflect.TypeFor[IfStmt](): {reflect.TypeFor[*ast.IfStmt]()},
|
||||
reflect.TypeFor[GoStmt](): {reflect.TypeFor[*ast.GoStmt]()},
|
||||
reflect.TypeFor[Field](): {reflect.TypeFor[*ast.Field]()},
|
||||
reflect.TypeFor[SelectorExpr](): {reflect.TypeFor[*ast.SelectorExpr]()},
|
||||
reflect.TypeFor[StructType](): {reflect.TypeFor[*ast.StructType]()},
|
||||
reflect.TypeFor[KeyValueExpr](): {reflect.TypeFor[*ast.KeyValueExpr]()},
|
||||
reflect.TypeFor[FuncType](): {reflect.TypeFor[*ast.FuncType]()},
|
||||
reflect.TypeFor[FuncLit](): {reflect.TypeFor[*ast.FuncLit]()},
|
||||
reflect.TypeFor[FuncDecl](): {reflect.TypeFor[*ast.FuncDecl]()},
|
||||
reflect.TypeFor[ChanType](): {reflect.TypeFor[*ast.ChanType]()},
|
||||
reflect.TypeFor[CallExpr](): {reflect.TypeFor[*ast.CallExpr]()},
|
||||
reflect.TypeFor[CaseClause](): {reflect.TypeFor[*ast.CaseClause]()},
|
||||
reflect.TypeFor[CommClause](): {reflect.TypeFor[*ast.CommClause]()},
|
||||
reflect.TypeFor[CompositeLit](): {reflect.TypeFor[*ast.CompositeLit]()},
|
||||
reflect.TypeFor[EmptyStmt](): {reflect.TypeFor[*ast.EmptyStmt]()},
|
||||
reflect.TypeFor[SwitchStmt](): {reflect.TypeFor[*ast.SwitchStmt]()},
|
||||
reflect.TypeFor[TypeSwitchStmt](): {reflect.TypeFor[*ast.TypeSwitchStmt]()},
|
||||
reflect.TypeFor[TypeAssertExpr](): {reflect.TypeFor[*ast.TypeAssertExpr]()},
|
||||
reflect.TypeFor[TypeSpec](): {reflect.TypeFor[*ast.TypeSpec]()},
|
||||
reflect.TypeFor[InterfaceType](): {reflect.TypeFor[*ast.InterfaceType]()},
|
||||
reflect.TypeFor[BranchStmt](): {reflect.TypeFor[*ast.BranchStmt]()},
|
||||
reflect.TypeFor[IncDecStmt](): {reflect.TypeFor[*ast.IncDecStmt]()},
|
||||
reflect.TypeFor[BasicLit](): {reflect.TypeFor[*ast.BasicLit]()},
|
||||
reflect.TypeFor[IntegerLiteral](): {reflect.TypeFor[*ast.BasicLit](), reflect.TypeFor[*ast.UnaryExpr]()},
|
||||
reflect.TypeFor[TrulyConstantExpression](): allTypes, // this is an over-approximation, which is fine
|
||||
}
|
||||
|
||||
var requiresTypeInfo = map[string]bool{
|
||||
"Symbol": true,
|
||||
"Builtin": true,
|
||||
"Object": true,
|
||||
"IntegerLiteral": true,
|
||||
"TrulyConstantExpression": true,
|
||||
}
|
||||
|
||||
type Parser struct {
|
||||
// Allow nodes that rely on type information
|
||||
AllowTypeInfo bool
|
||||
|
||||
f *token.File
|
||||
cur item
|
||||
last *item
|
||||
nextItem func() (item, bool)
|
||||
|
||||
bindings map[string]int
|
||||
}
|
||||
|
||||
func (p *Parser) bindingIndex(name string) int {
|
||||
if p.bindings == nil {
|
||||
p.bindings = map[string]int{}
|
||||
}
|
||||
if idx, ok := p.bindings[name]; ok {
|
||||
return idx
|
||||
}
|
||||
idx := len(p.bindings)
|
||||
p.bindings[name] = idx
|
||||
return idx
|
||||
}
|
||||
|
||||
func (p *Parser) Parse(s string) (Pattern, error) {
|
||||
f := token.NewFileSet().AddFile("<input>", -1, len(s))
|
||||
|
||||
// Run the lexer iterator as a coroutine.
|
||||
// The parser will call 'next' to consume each item.
|
||||
// After the parser returns, we must call 'stop' to
|
||||
// terminate the coroutine.
|
||||
next, stop := iter.Pull(lex(f, s))
|
||||
defer stop()
|
||||
|
||||
p.cur = item{}
|
||||
p.last = nil
|
||||
p.f = f
|
||||
p.nextItem = next
|
||||
|
||||
// Parse.
|
||||
root, err := p.node()
|
||||
if err != nil {
|
||||
return Pattern{}, err
|
||||
}
|
||||
// Consume final EOF token.
|
||||
if item, ok := next(); !ok || item.typ != itemEOF {
|
||||
return Pattern{}, fmt.Errorf("unexpected token %s after end of pattern", item.typ)
|
||||
}
|
||||
|
||||
if len(p.bindings) > 64 {
|
||||
return Pattern{}, errors.New("encountered more than 64 bindings")
|
||||
}
|
||||
|
||||
bindings := make([]string, len(p.bindings))
|
||||
for name, idx := range p.bindings {
|
||||
bindings[idx] = name
|
||||
}
|
||||
|
||||
_, isSymbol := root.(Symbol)
|
||||
sym := collectSymbols(root, isSymbol)
|
||||
rootSyms := collectRootCallSymbols(root)
|
||||
relevantMap := map[reflect.Type]struct{}{}
|
||||
collectEntryNodes(root, relevantMap)
|
||||
relevantNodes := make([]ast.Node, 0, len(relevantMap))
|
||||
for k := range relevantMap {
|
||||
relevantNodes = append(relevantNodes, reflect.Zero(k).Interface().(ast.Node))
|
||||
}
|
||||
return Pattern{
|
||||
Root: root,
|
||||
EntryNodes: relevantNodes,
|
||||
SymbolsPattern: sym,
|
||||
RootCallSymbols: rootSyms,
|
||||
Bindings: bindings,
|
||||
}, 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.nextItem()
|
||||
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.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)
|
||||
}
|
||||
}
|
||||
|
||||
node, err := p.populateNode(typ.val, objs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if node, ok := node.(Binding); ok {
|
||||
node.idx = p.bindingIndex(node.Name)
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
n := -1
|
||||
for i := 0; i < T.NumField(); i++ {
|
||||
if !T.Field(i).IsExported() {
|
||||
break
|
||||
}
|
||||
n = i
|
||||
}
|
||||
|
||||
if len(objs) != n+1 {
|
||||
return nil, fmt.Errorf("tried to initialize node %s with %d values, expected %d", typ, len(objs), n+1)
|
||||
}
|
||||
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
if !T.Field(i).IsExported() {
|
||||
break
|
||||
}
|
||||
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.TypeFor[Any](),
|
||||
"Ellipsis": reflect.TypeFor[Ellipsis](),
|
||||
"List": reflect.TypeFor[List](),
|
||||
"Binding": reflect.TypeFor[Binding](),
|
||||
"RangeStmt": reflect.TypeFor[RangeStmt](),
|
||||
"AssignStmt": reflect.TypeFor[AssignStmt](),
|
||||
"IndexExpr": reflect.TypeFor[IndexExpr](),
|
||||
"Ident": reflect.TypeFor[Ident](),
|
||||
"Builtin": reflect.TypeFor[Builtin](),
|
||||
"ValueSpec": reflect.TypeFor[ValueSpec](),
|
||||
"GenDecl": reflect.TypeFor[GenDecl](),
|
||||
"BinaryExpr": reflect.TypeFor[BinaryExpr](),
|
||||
"ForStmt": reflect.TypeFor[ForStmt](),
|
||||
"ArrayType": reflect.TypeFor[ArrayType](),
|
||||
"DeferStmt": reflect.TypeFor[DeferStmt](),
|
||||
"MapType": reflect.TypeFor[MapType](),
|
||||
"ReturnStmt": reflect.TypeFor[ReturnStmt](),
|
||||
"SliceExpr": reflect.TypeFor[SliceExpr](),
|
||||
"StarExpr": reflect.TypeFor[StarExpr](),
|
||||
"UnaryExpr": reflect.TypeFor[UnaryExpr](),
|
||||
"SendStmt": reflect.TypeFor[SendStmt](),
|
||||
"SelectStmt": reflect.TypeFor[SelectStmt](),
|
||||
"ImportSpec": reflect.TypeFor[ImportSpec](),
|
||||
"IfStmt": reflect.TypeFor[IfStmt](),
|
||||
"GoStmt": reflect.TypeFor[GoStmt](),
|
||||
"Field": reflect.TypeFor[Field](),
|
||||
"SelectorExpr": reflect.TypeFor[SelectorExpr](),
|
||||
"StructType": reflect.TypeFor[StructType](),
|
||||
"KeyValueExpr": reflect.TypeFor[KeyValueExpr](),
|
||||
"FuncType": reflect.TypeFor[FuncType](),
|
||||
"FuncLit": reflect.TypeFor[FuncLit](),
|
||||
"FuncDecl": reflect.TypeFor[FuncDecl](),
|
||||
"ChanType": reflect.TypeFor[ChanType](),
|
||||
"CallExpr": reflect.TypeFor[CallExpr](),
|
||||
"CaseClause": reflect.TypeFor[CaseClause](),
|
||||
"CommClause": reflect.TypeFor[CommClause](),
|
||||
"CompositeLit": reflect.TypeFor[CompositeLit](),
|
||||
"EmptyStmt": reflect.TypeFor[EmptyStmt](),
|
||||
"SwitchStmt": reflect.TypeFor[SwitchStmt](),
|
||||
"TypeSwitchStmt": reflect.TypeFor[TypeSwitchStmt](),
|
||||
"TypeAssertExpr": reflect.TypeFor[TypeAssertExpr](),
|
||||
"TypeSpec": reflect.TypeFor[TypeSpec](),
|
||||
"InterfaceType": reflect.TypeFor[InterfaceType](),
|
||||
"BranchStmt": reflect.TypeFor[BranchStmt](),
|
||||
"IncDecStmt": reflect.TypeFor[IncDecStmt](),
|
||||
"BasicLit": reflect.TypeFor[BasicLit](),
|
||||
"Object": reflect.TypeFor[Object](),
|
||||
"Symbol": reflect.TypeFor[Symbol](),
|
||||
"Or": reflect.TypeFor[Or](),
|
||||
"Not": reflect.TypeFor[Not](),
|
||||
"IntegerLiteral": reflect.TypeFor[IntegerLiteral](),
|
||||
"TrulyConstantExpression": reflect.TypeFor[TrulyConstantExpression](),
|
||||
}
|
||||
|
||||
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,
|
||||
idx: p.bindingIndex(v.val),
|
||||
}
|
||||
} else {
|
||||
p.rewind()
|
||||
b = Binding{
|
||||
Name: v.val,
|
||||
idx: p.bindingIndex(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:
|
||||
if p.peek().typ == itemColon {
|
||||
p.next()
|
||||
tail, err := p.object()
|
||||
if err != nil {
|
||||
return Any{}, err
|
||||
}
|
||||
return List{Head: Any{}, Tail: tail}, nil
|
||||
}
|
||||
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
|
||||
*/
|
||||
Reference in New Issue
Block a user