1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package astutil
16
17 import (
18 "encoding/hex"
19 "fmt"
20 "hash/fnv"
21 "reflect"
22
23 "cuelang.org/go/cue/ast"
24 )
25
26
27
28
29
30
31
32
33
34 type Cursor interface {
35
36 Node() ast.Node
37
38
39 Parent() Cursor
40
41
42
43
44 Index() int
45
46
47
48
49 Import(path string) *ast.Ident
50
51
52
53
54
55 Replace(n ast.Node)
56
57
58
59 Delete()
60
61
62
63
64 InsertAfter(n ast.Node)
65
66
67
68
69 InsertBefore(n ast.Node)
70
71 self() *cursor
72 }
73
74
75
76 func ApplyRecursively(n ast.Node) ast.Node {
77 return recursive{n}
78 }
79
80 type recursive struct {
81 ast.Node
82 }
83
84 type info struct {
85 f *ast.File
86 current *declsCursor
87
88 importPatch []*ast.Ident
89 }
90
91 type cursor struct {
92 file *info
93 parent Cursor
94 node ast.Node
95 typ interface{}
96 index int
97 replaced bool
98 }
99
100 func newCursor(parent Cursor, n ast.Node, typ interface{}) *cursor {
101 return &cursor{
102 parent: parent,
103 typ: typ,
104 node: n,
105 index: -1,
106 }
107 }
108
109 func fileInfo(c Cursor) (info *info) {
110 for ; c != nil; c = c.Parent() {
111 if i := c.self().file; i != nil {
112 return i
113 }
114 }
115 return nil
116 }
117
118 func (c *cursor) self() *cursor { return c }
119 func (c *cursor) Parent() Cursor { return c.parent }
120 func (c *cursor) Index() int { return c.index }
121 func (c *cursor) Node() ast.Node { return c.node }
122
123 func (c *cursor) Import(importPath string) *ast.Ident {
124 info := fileInfo(c)
125 if info == nil {
126 return nil
127 }
128
129 name := ImportPathName(importPath)
130
131
132
133
134 hash := fnv.New32()
135 name += hex.EncodeToString(hash.Sum([]byte(importPath)))[:6]
136
137 spec := insertImport(&info.current.decls, &ast.ImportSpec{
138 Name: ast.NewIdent(name),
139 Path: ast.NewString(importPath),
140 })
141
142 ident := &ast.Ident{Node: spec}
143 info.importPatch = append(info.importPatch, ident)
144
145 ident.Name = name
146
147 return ident
148 }
149
150 func (c *cursor) Replace(n ast.Node) {
151
152 reflect.ValueOf(n).Convert(reflect.TypeOf(c.typ).Elem())
153 if ast.Comments(n) != nil {
154 CopyComments(n, c.node)
155 }
156 if r, ok := n.(recursive); ok {
157 n = r.Node
158 } else {
159 c.replaced = true
160 }
161 c.node = n
162 }
163
164 func (c *cursor) InsertAfter(n ast.Node) { panic("unsupported") }
165 func (c *cursor) InsertBefore(n ast.Node) { panic("unsupported") }
166 func (c *cursor) Delete() { panic("unsupported") }
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187 func Apply(node ast.Node, before, after func(Cursor) bool) ast.Node {
188 apply(&applier{before: before, after: after}, nil, &node)
189 return node
190 }
191
192
193
194
195 type applyVisitor interface {
196 Before(Cursor) applyVisitor
197 After(Cursor) bool
198 }
199
200
201
202 func applyExprList(v applyVisitor, parent Cursor, list []ast.Expr) {
203 c := newCursor(parent, nil, nil)
204 for i, x := range list {
205 c.index = i
206 c.node = x
207 c.typ = &list[i]
208 applyCursor(v, c)
209 if x != c.node {
210 list[i] = c.node.(ast.Expr)
211 }
212 }
213 }
214
215 type declsCursor struct {
216 *cursor
217 decls, after, process []ast.Decl
218 delete bool
219 }
220
221 func (c *declsCursor) InsertAfter(n ast.Node) {
222 if r, ok := n.(recursive); ok {
223 n = r.Node
224 c.process = append(c.process, n.(ast.Decl))
225 }
226 c.after = append(c.after, n.(ast.Decl))
227 }
228
229 func (c *declsCursor) InsertBefore(n ast.Node) {
230 if r, ok := n.(recursive); ok {
231 n = r.Node
232 c.process = append(c.process, n.(ast.Decl))
233 }
234 c.decls = append(c.decls, n.(ast.Decl))
235 }
236
237 func (c *declsCursor) Delete() { c.delete = true }
238
239 func applyDeclList(v applyVisitor, parent Cursor, list []ast.Decl) []ast.Decl {
240 c := &declsCursor{
241 cursor: newCursor(parent, nil, nil),
242 decls: make([]ast.Decl, 0, len(list)),
243 }
244 if file, ok := parent.Node().(*ast.File); ok {
245 c.cursor.file = &info{f: file, current: c}
246 }
247 for i, x := range list {
248 c.node = x
249 c.typ = &list[i]
250 applyCursor(v, c)
251 if !c.delete {
252 c.decls = append(c.decls, c.node.(ast.Decl))
253 }
254 c.delete = false
255 for i := 0; i < len(c.process); i++ {
256 x := c.process[i]
257 c.node = x
258 c.typ = &c.process[i]
259 applyCursor(v, c)
260 if c.delete {
261 panic("cannot delete a node that was added with InsertBefore or InsertAfter")
262 }
263 }
264 c.decls = append(c.decls, c.after...)
265 c.after = c.after[:0]
266 c.process = c.process[:0]
267 }
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286 return c.decls
287 }
288
289 func apply[N ast.Node](v applyVisitor, parent Cursor, nodePtr *N) {
290 node := *nodePtr
291 c := newCursor(parent, node, nodePtr)
292 applyCursor(v, c)
293 if ast.Node(node) != c.node {
294 *nodePtr = c.node.(N)
295 }
296 }
297
298
299
300
301
302
303 func applyCursor(v applyVisitor, c Cursor) {
304 if v = v.Before(c); v == nil {
305 return
306 }
307
308 node := c.Node()
309
310
311
312 comments := node.Comments()
313 for _, cm := range comments {
314 apply(v, c, &cm)
315 }
316
317
318
319
320 switch n := node.(type) {
321
322 case *ast.Comment:
323
324
325 case *ast.CommentGroup:
326 for _, cg := range n.List {
327 apply(v, c, &cg)
328 }
329
330 case *ast.Attribute:
331
332
333 case *ast.Field:
334 apply(v, c, &n.Label)
335 if n.Value != nil {
336 apply(v, c, &n.Value)
337 }
338 for _, a := range n.Attrs {
339 apply(v, c, &a)
340 }
341
342 case *ast.StructLit:
343 n.Elts = applyDeclList(v, c, n.Elts)
344
345
346 case *ast.BottomLit, *ast.BadExpr, *ast.Ident, *ast.BasicLit:
347
348
349 case *ast.Interpolation:
350 applyExprList(v, c, n.Elts)
351
352 case *ast.ListLit:
353 applyExprList(v, c, n.Elts)
354
355 case *ast.Ellipsis:
356 if n.Type != nil {
357 apply(v, c, &n.Type)
358 }
359
360 case *ast.ParenExpr:
361 apply(v, c, &n.X)
362
363 case *ast.SelectorExpr:
364 apply(v, c, &n.X)
365 apply(v, c, &n.Sel)
366
367 case *ast.IndexExpr:
368 apply(v, c, &n.X)
369 apply(v, c, &n.Index)
370
371 case *ast.SliceExpr:
372 apply(v, c, &n.X)
373 if n.Low != nil {
374 apply(v, c, &n.Low)
375 }
376 if n.High != nil {
377 apply(v, c, &n.High)
378 }
379
380 case *ast.CallExpr:
381 apply(v, c, &n.Fun)
382 applyExprList(v, c, n.Args)
383
384 case *ast.UnaryExpr:
385 apply(v, c, &n.X)
386
387 case *ast.BinaryExpr:
388 apply(v, c, &n.X)
389 apply(v, c, &n.Y)
390
391
392 case *ast.ImportSpec:
393 if n.Name != nil {
394 apply(v, c, &n.Name)
395 }
396 apply(v, c, &n.Path)
397
398 case *ast.BadDecl:
399
400
401 case *ast.ImportDecl:
402 for _, s := range n.Specs {
403 apply(v, c, &s)
404 }
405
406 case *ast.EmbedDecl:
407 apply(v, c, &n.Expr)
408
409 case *ast.LetClause:
410 apply(v, c, &n.Ident)
411 apply(v, c, &n.Expr)
412
413 case *ast.Alias:
414 apply(v, c, &n.Ident)
415 apply(v, c, &n.Expr)
416
417 case *ast.Comprehension:
418 clauses := n.Clauses
419 for i := range n.Clauses {
420 apply(v, c, &clauses[i])
421 }
422 apply(v, c, &n.Value)
423
424
425 case *ast.File:
426 n.Decls = applyDeclList(v, c, n.Decls)
427
428 case *ast.Package:
429 apply(v, c, &n.Name)
430
431 case *ast.ForClause:
432 if n.Key != nil {
433 apply(v, c, &n.Key)
434 }
435 apply(v, c, &n.Value)
436 apply(v, c, &n.Source)
437
438 case *ast.IfClause:
439 apply(v, c, &n.Condition)
440
441 default:
442 panic(fmt.Sprintf("Walk: unexpected node type %T", n))
443 }
444
445 v.After(c)
446 }
447
448 type applier struct {
449 before func(Cursor) bool
450 after func(Cursor) bool
451
452 commentStack []commentFrame
453 current commentFrame
454 }
455
456 type commentFrame struct {
457 cg []*ast.CommentGroup
458 pos int8
459 }
460
461 func (f *applier) Before(c Cursor) applyVisitor {
462 node := c.Node()
463 if f.before == nil || (f.before(c) && node == c.Node()) {
464 f.commentStack = append(f.commentStack, f.current)
465 f.current = commentFrame{cg: node.Comments()}
466 f.visitComments(c, f.current.pos)
467 return f
468 }
469 return nil
470 }
471
472 func (f *applier) After(c Cursor) bool {
473 f.visitComments(c, 127)
474 p := len(f.commentStack) - 1
475 f.current = f.commentStack[p]
476 f.commentStack = f.commentStack[:p]
477 f.current.pos++
478 if f.after != nil {
479 f.after(c)
480 }
481 return true
482 }
483
484 func (f *applier) visitComments(p Cursor, pos int8) {
485 c := &f.current
486 for i := 0; i < len(c.cg); i++ {
487 cg := c.cg[i]
488 if cg.Position == pos {
489 continue
490 }
491 cursor := newCursor(p, cg, cg)
492 if f.before == nil || (f.before(cursor) && !cursor.replaced) {
493 for j, c := range cg.List {
494 cursor := newCursor(p, c, &c)
495 if f.before == nil || (f.before(cursor) && !cursor.replaced) {
496 if f.after != nil {
497 f.after(cursor)
498 }
499 }
500 cg.List[j] = cursor.node.(*ast.Comment)
501 }
502 if f.after != nil {
503 f.after(cursor)
504 }
505 }
506 c.cg[i] = cursor.node.(*ast.CommentGroup)
507 }
508 }
509
View as plain text