1
16
17
18
19 package build
20
21 import (
22 "path/filepath"
23 "strings"
24 )
25
26
27 type Rule struct {
28 Call *CallExpr
29 ImplicitName string
30 }
31
32
33 func NewRule(call *CallExpr) *Rule {
34 return &Rule{call, ""}
35 }
36
37 func (f *File) Rule(call *CallExpr) *Rule {
38 r := &Rule{call, ""}
39 if r.AttrString("name") == "" {
40 r.ImplicitName = f.implicitRuleName()
41 }
42 return r
43 }
44
45 func (f *File) rules(p func(r *Rule) bool) []*Rule {
46 var all []*Rule
47
48 for _, stmt := range f.Stmt {
49 Walk(stmt, func(x Expr, stk []Expr) {
50 call, ok := x.(*CallExpr)
51 if !ok {
52 return
53 }
54
55
56 for _, frame := range stk {
57 if _, ok := frame.(*CallExpr); ok {
58 return
59 }
60 }
61
62
63 rule := f.Rule(call)
64 if !p(rule) {
65 return
66 }
67 all = append(all, rule)
68 })
69 }
70
71 return all
72 }
73
74
75
76 func (f *File) Rules(kind string) []*Rule {
77 return f.rules(func(rule *Rule) bool {
78
79 return kind == "" || rule.Kind() == kind
80 })
81 }
82
83
84 func (f *File) RuleAt(linenum int) *Rule {
85 all := f.rules(func(rule *Rule) bool {
86 start, end := rule.Call.X.Span()
87 return start.Line <= linenum && linenum <= end.Line
88 })
89 if len(all) != 1 {
90 return nil
91 }
92 return all[0]
93 }
94
95
96 func (f *File) RuleNamed(name string) *Rule {
97 all := f.rules(func(rule *Rule) bool {
98 return rule.Name() == name
99 })
100 if len(all) != 1 {
101 return nil
102 }
103 return all[0]
104 }
105
106
107
108
109 func (f *File) DelRules(kind, name string) int {
110 var i int
111 for _, stmt := range f.Stmt {
112 if call, ok := stmt.(*CallExpr); ok {
113 r := f.Rule(call)
114 if (kind == "" || r.Kind() == kind) &&
115 (name == "" || r.Name() == name) {
116 continue
117 }
118 }
119 f.Stmt[i] = stmt
120 i++
121 }
122 n := len(f.Stmt) - i
123 f.Stmt = f.Stmt[:i]
124 return n
125 }
126
127
128
129
130
131 func (f *File) implicitRuleName() string {
132
133 dir := filepath.Dir(f.Path)
134 if dir == "." {
135 return ""
136 }
137 sawAnonymousRule := false
138 possibleImplicitName := filepath.Base(dir)
139
140 for _, stmt := range f.Stmt {
141 call, ok := stmt.(*CallExpr)
142 if !ok {
143 continue
144 }
145 temp := &Rule{call, ""}
146 if temp.AttrString("name") == possibleImplicitName {
147
148 return ""
149 }
150 if temp.Kind() != "" && temp.AttrString("name") == "" {
151 if sawAnonymousRule {
152 return ""
153 }
154 sawAnonymousRule = true
155 }
156 }
157 if sawAnonymousRule {
158 return possibleImplicitName
159 }
160 return ""
161 }
162
163
164
165
166
167 func (r *Rule) Kind() string {
168 var names []string
169 expr := r.Call.X
170 for {
171 x, ok := expr.(*DotExpr)
172 if !ok {
173 break
174 }
175 names = append(names, x.Name)
176 expr = x.X
177 }
178 x, ok := expr.(*Ident)
179 if !ok {
180 return ""
181 }
182 names = append(names, x.Name)
183
184 for l, r := 0, len(names)-1; l < r; l, r = l+1, r-1 {
185 names[l], names[r] = names[r], names[l]
186 }
187 return strings.Join(names, ".")
188 }
189
190
191 func (r *Rule) SetKind(kind string) {
192 names := strings.Split(kind, ".")
193 var expr Expr
194 expr = &Ident{Name: names[0]}
195 for _, name := range names[1:] {
196 expr = &DotExpr{X: expr, Name: name}
197 }
198 r.Call.X = expr
199 }
200
201
202 func (r *Rule) ExplicitName() string {
203 return r.AttrString("name")
204 }
205
206
207
208 func (r *Rule) Name() string {
209 explicitName := r.ExplicitName()
210 if explicitName == "" && r.Kind() != "package" {
211 return r.ImplicitName
212 }
213 return explicitName
214 }
215
216
217 func (r *Rule) AttrKeys() []string {
218 var keys []string
219 for _, expr := range r.Call.List {
220 if as, ok := expr.(*AssignExpr); ok {
221 if keyExpr, ok := as.LHS.(*Ident); ok {
222 keys = append(keys, keyExpr.Name)
223 }
224 }
225 }
226 return keys
227 }
228
229
230
231 func (r *Rule) AttrDefn(key string) *AssignExpr {
232 for _, kv := range r.Call.List {
233 as, ok := kv.(*AssignExpr)
234 if !ok {
235 continue
236 }
237 k, ok := as.LHS.(*Ident)
238 if !ok || k.Name != key {
239 continue
240 }
241 return as
242 }
243 return nil
244 }
245
246
247
248
249 func (r *Rule) Attr(key string) Expr {
250 as := r.AttrDefn(key)
251 if as == nil {
252 return nil
253 }
254 return as.RHS
255 }
256
257
258
259 func (r *Rule) DelAttr(key string) Expr {
260 list := r.Call.List
261 for i, kv := range list {
262 as, ok := kv.(*AssignExpr)
263 if !ok {
264 continue
265 }
266 k, ok := as.LHS.(*Ident)
267 if !ok || k.Name != key {
268 continue
269 }
270 copy(list[i:], list[i+1:])
271 r.Call.List = list[:len(list)-1]
272 return as.RHS
273 }
274 return nil
275 }
276
277
278
279
280 func (r *Rule) SetAttr(key string, val Expr) {
281 as := r.AttrDefn(key)
282 if as != nil {
283 as.RHS = val
284 return
285 }
286
287 r.Call.List = append(r.Call.List,
288 &AssignExpr{
289 LHS: &Ident{Name: key},
290 Op: "=",
291 RHS: val,
292 },
293 )
294 }
295
296
297
298
299
300
301 func (r *Rule) AttrLiteral(key string) string {
302 value := r.Attr(key)
303 if ident, ok := value.(*Ident); ok {
304 return ident.Name
305 }
306 if literal, ok := value.(*LiteralExpr); ok {
307 return literal.Token
308 }
309 return ""
310 }
311
312
313
314
315
316 func (r *Rule) AttrString(key string) string {
317 str, ok := r.Attr(key).(*StringExpr)
318 if !ok {
319 return ""
320 }
321 return str.Value
322 }
323
324
325
326
327
328 func (r *Rule) AttrStrings(key string) []string {
329 return Strings(r.Attr(key))
330 }
331
332
333
334
335
336
337
338 func Strings(expr Expr) []string {
339 list, ok := expr.(*ListExpr)
340 if !ok {
341 return nil
342 }
343 all := []string{}
344 for _, l := range list.List {
345 str, ok := l.(*StringExpr)
346 if !ok {
347 return nil
348 }
349 all = append(all, str.Value)
350 }
351 return all
352 }
353
View as plain text