OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / pelletier / go-toml / query / query.go
1 package query
2
3 import (
4         "time"
5
6         "github.com/pelletier/go-toml"
7 )
8
9 // NodeFilterFn represents a user-defined filter function, for use with
10 // Query.SetFilter().
11 //
12 // The return value of the function must indicate if 'node' is to be included
13 // at this stage of the TOML path.  Returning true will include the node, and
14 // returning false will exclude it.
15 //
16 // NOTE: Care should be taken to write script callbacks such that they are safe
17 // to use from multiple goroutines.
18 type NodeFilterFn func(node interface{}) bool
19
20 // Result is the result of Executing a Query.
21 type Result struct {
22         items     []interface{}
23         positions []toml.Position
24 }
25
26 // appends a value/position pair to the result set.
27 func (r *Result) appendResult(node interface{}, pos toml.Position) {
28         r.items = append(r.items, node)
29         r.positions = append(r.positions, pos)
30 }
31
32 // Values is a set of values within a Result.  The order of values is not
33 // guaranteed to be in document order, and may be different each time a query is
34 // executed.
35 func (r Result) Values() []interface{} {
36         return r.items
37 }
38
39 // Positions is a set of positions for values within a Result.  Each index
40 // in Positions() corresponds to the entry in Value() of the same index.
41 func (r Result) Positions() []toml.Position {
42         return r.positions
43 }
44
45 // runtime context for executing query paths
46 type queryContext struct {
47         result       *Result
48         filters      *map[string]NodeFilterFn
49         lastPosition toml.Position
50 }
51
52 // generic path functor interface
53 type pathFn interface {
54         setNext(next pathFn)
55         // it is the caller's responsibility to set the ctx.lastPosition before invoking call()
56         // node can be one of: *toml.Tree, []*toml.Tree, or a scalar
57         call(node interface{}, ctx *queryContext)
58 }
59
60 // A Query is the representation of a compiled TOML path.  A Query is safe
61 // for concurrent use by multiple goroutines.
62 type Query struct {
63         root    pathFn
64         tail    pathFn
65         filters *map[string]NodeFilterFn
66 }
67
68 func newQuery() *Query {
69         return &Query{
70                 root:    nil,
71                 tail:    nil,
72                 filters: &defaultFilterFunctions,
73         }
74 }
75
76 func (q *Query) appendPath(next pathFn) {
77         if q.root == nil {
78                 q.root = next
79         } else {
80                 q.tail.setNext(next)
81         }
82         q.tail = next
83         next.setNext(newTerminatingFn()) // init the next functor
84 }
85
86 // Compile compiles a TOML path expression. The returned Query can be used
87 // to match elements within a Tree and its descendants. See Execute.
88 func Compile(path string) (*Query, error) {
89         return parseQuery(lexQuery(path))
90 }
91
92 // Execute executes a query against a Tree, and returns the result of the query.
93 func (q *Query) Execute(tree *toml.Tree) *Result {
94         result := &Result{
95                 items:     []interface{}{},
96                 positions: []toml.Position{},
97         }
98         if q.root == nil {
99                 result.appendResult(tree, tree.GetPosition(""))
100         } else {
101                 ctx := &queryContext{
102                         result:  result,
103                         filters: q.filters,
104                 }
105                 ctx.lastPosition = tree.Position()
106                 q.root.call(tree, ctx)
107         }
108         return result
109 }
110
111 // CompileAndExecute is a shorthand for Compile(path) followed by Execute(tree).
112 func CompileAndExecute(path string, tree *toml.Tree) (*Result, error) {
113         query, err := Compile(path)
114         if err != nil {
115                 return nil, err
116         }
117         return query.Execute(tree), nil
118 }
119
120 // SetFilter sets a user-defined filter function.  These may be used inside
121 // "?(..)" query expressions to filter TOML document elements within a query.
122 func (q *Query) SetFilter(name string, fn NodeFilterFn) {
123         if q.filters == &defaultFilterFunctions {
124                 // clone the static table
125                 q.filters = &map[string]NodeFilterFn{}
126                 for k, v := range defaultFilterFunctions {
127                         (*q.filters)[k] = v
128                 }
129         }
130         (*q.filters)[name] = fn
131 }
132
133 var defaultFilterFunctions = map[string]NodeFilterFn{
134         "tree": func(node interface{}) bool {
135                 _, ok := node.(*toml.Tree)
136                 return ok
137         },
138         "int": func(node interface{}) bool {
139                 _, ok := node.(int64)
140                 return ok
141         },
142         "float": func(node interface{}) bool {
143                 _, ok := node.(float64)
144                 return ok
145         },
146         "string": func(node interface{}) bool {
147                 _, ok := node.(string)
148                 return ok
149         },
150         "time": func(node interface{}) bool {
151                 _, ok := node.(time.Time)
152                 return ok
153         },
154         "bool": func(node interface{}) bool {
155                 _, ok := node.(bool)
156                 return ok
157         },
158 }