Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b5269fb

Browse files
committedJan 31, 2025··
feat: make it possible for the rewriter to revisit any node type
Signed-off-by: Andres Taylor <andres@planetscale.com>
1 parent 770dcf0 commit b5269fb

File tree

7 files changed

+1163
-373
lines changed

7 files changed

+1163
-373
lines changed
 

‎go/tools/asthelpergen/asthelpergen.go

+1-10
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,6 @@ type (
7777
}
7878
)
7979

80-
// exprInterfacePath is the path of the sqlparser.Expr interface.
81-
const exprInterfacePath = "vitess.io/vitess/go/vt/sqlparser.Expr"
82-
8380
func (gen *astHelperGen) iface() *types.Interface {
8481
return gen._iface
8582
}
@@ -207,19 +204,13 @@ func GenerateASTHelpers(options *Options) (map[string]*jen.File, error) {
207204
return nil, err
208205
}
209206

210-
exprType, _ := findTypeObject(exprInterfacePath, scopes)
211-
var exprInterface *types.Interface
212-
if exprType != nil {
213-
exprInterface = exprType.Type().(*types.Named).Underlying().(*types.Interface)
214-
}
215-
216207
nt := tt.Type().(*types.Named)
217208
pName := nt.Obj().Pkg().Name()
218209
generator := newGenerator(loaded[0].Module, loaded[0].TypesSizes, nt,
219210
newEqualsGen(pName, &options.Equals),
220211
newCloneGen(pName, &options.Clone),
221212
newVisitGen(pName),
222-
newRewriterGen(pName, types.TypeString(nt, noQualifier), exprInterface),
213+
newRewriterGen(pName, types.TypeString(nt, noQualifier)),
223214
newCOWGen(pName, nt),
224215
)
225216

‎go/tools/asthelpergen/asthelpergen_test.go

+19
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
"strings"
2222
"testing"
2323

24+
"vitess.io/vitess/go/tools/codegen"
25+
2426
"github.com/stretchr/testify/require"
2527
)
2628

@@ -45,3 +47,20 @@ func TestFullGeneration(t *testing.T) {
4547
require.False(t, applyIdx == 0 && cloneIdx == 0, "file doesn't contain expected contents")
4648
}
4749
}
50+
51+
func TestRecreateAllFiles(t *testing.T) {
52+
// t.Skip("This test recreates all files in the integration directory. It should only be run when the ASTHelperGen code has changed.")
53+
result, err := GenerateASTHelpers(&Options{
54+
Packages: []string{"./integration/..."},
55+
RootInterface: "vitess.io/vitess/go/tools/asthelpergen/integration.AST",
56+
Clone: CloneOptions{
57+
Exclude: []string{"*NoCloneType"},
58+
},
59+
})
60+
require.NoError(t, err)
61+
62+
for fullPath, file := range result {
63+
err := codegen.SaveJenFile(fullPath, file)
64+
require.NoError(t, err)
65+
}
66+
}

‎go/tools/asthelpergen/integration/ast_rewrite.go

+75-18
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎go/tools/asthelpergen/integration/integration_rewriter_test.go

+60-19
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,46 @@ func TestRewriteAndRevisitInterfaceSlice(t *testing.T) {
204204
})
205205
}
206206

207+
func TestRewriteAndRevisitRefContainer(t *testing.T) {
208+
leaf1 := &Leaf{1}
209+
leaf2 := &Leaf{2}
210+
ast1 := &RefContainer{
211+
ASTType: leaf1,
212+
ASTImplementationType: leaf2,
213+
}
214+
ast2 := &RefContainer{
215+
ASTType: leaf2,
216+
ASTImplementationType: leaf1,
217+
}
218+
219+
tv := &rewriteTestVisitor{}
220+
221+
a := false
222+
_ = Rewrite(ast1, func(cursor *Cursor) bool {
223+
tv.pre(cursor)
224+
switch cursor.node.(type) {
225+
case *RefContainer:
226+
if a {
227+
break
228+
}
229+
a = true
230+
cursor.ReplaceAndRevisit(ast2)
231+
}
232+
return true
233+
}, tv.post)
234+
235+
tv.assertEquals(t, []step{
236+
Pre{ast1}, // when we visit ast, we want to replace and revisit,
237+
// which means that we don't do a post on this node, or visit the children
238+
Pre{ast2},
239+
Pre{leaf2},
240+
Post{leaf2},
241+
Pre{leaf1},
242+
Post{leaf1},
243+
Post{ast2},
244+
})
245+
}
246+
207247
func TestRewriteVisitRefContainerReplace(t *testing.T) {
208248
ast := &RefContainer{
209249
ASTType: &RefContainer{NotASTType: 12},
@@ -361,29 +401,30 @@ func (tv *rewriteTestVisitor) assertEquals(t *testing.T, expected []step) {
361401
error := false
362402
expectedSize := len(expected)
363403
for i, step := range tv.walk {
364-
if expectedSize <= i {
365-
t.Errorf("❌️ - Expected less elements %v", tv.walk[i:])
366-
break
367-
} else {
368-
e := expected[i]
369-
if reflect.DeepEqual(e, step) {
370-
a := "✔️ - " + e.String()
371-
if error {
372-
fmt.Println(a)
373-
} else {
374-
lines = append(lines, a)
375-
}
404+
t.Run(fmt.Sprintf("step %d", i), func(t *testing.T) {
405+
if expectedSize <= i {
406+
t.Fatalf("❌️ - Expected less elements %v", tv.walk[i:])
376407
} else {
377-
if !error {
378-
// first error we see.
379-
error = true
380-
for _, line := range lines {
381-
fmt.Println(line)
408+
e := expected[i]
409+
if reflect.DeepEqual(e, step) {
410+
a := "✔️ - " + e.String()
411+
if error {
412+
fmt.Println(a)
413+
} else {
414+
lines = append(lines, a)
415+
}
416+
} else {
417+
if !error {
418+
// first error we see.
419+
error = true
420+
for _, line := range lines {
421+
fmt.Println(line)
422+
}
382423
}
424+
t.Fatalf("❌️ - Expected: %s Got: %s\n", e.String(), step.String())
383425
}
384-
t.Errorf("❌️ - Expected: %s Got: %s\n", e.String(), step.String())
385426
}
386-
}
427+
})
387428
}
388429
walkSize := len(tv.walk)
389430
if expectedSize > walkSize {

‎go/tools/asthelpergen/integration/test_helpers.go

-8
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,6 @@ func (c *Cursor) Replace(newNode AST) {
6868
// When used, this will abort the visitation of the current node - no post or children visited,
6969
// and the new node visited.
7070
func (c *Cursor) ReplaceAndRevisit(newNode AST) {
71-
switch newNode.(type) {
72-
case InterfaceSlice:
73-
default:
74-
// We need to add support to the generated code for when to look at the revisit flag. At the moment it is only
75-
// there for slices of AST implementations
76-
panic("no support added for this type yet")
77-
}
78-
7971
c.replacer(newNode, c.parent)
8072
c.node = newNode
8173
c.revisit = true

‎go/tools/asthelpergen/rewrite_gen.go

+17-25
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,18 @@ const (
3030
type rewriteGen struct {
3131
ifaceName string
3232
file *jen.File
33-
// exprInterface is used to store the sqlparser.Expr interface
34-
exprInterface *types.Interface
3533
}
3634

3735
var _ generator = (*rewriteGen)(nil)
3836

39-
func newRewriterGen(pkgname string, ifaceName string, exprInterface *types.Interface) *rewriteGen {
37+
func newRewriterGen(pkgname string, ifaceName string) *rewriteGen {
4038
file := jen.NewFile(pkgname)
4139
file.HeaderComment(licenseFileHeader)
4240
file.HeaderComment("Code generated by ASTHelperGen. DO NOT EDIT.")
4341

4442
return &rewriteGen{
45-
ifaceName: ifaceName,
46-
file: file,
47-
exprInterface: exprInterface,
43+
ifaceName: ifaceName,
44+
file: file,
4845
}
4946
}
5047

@@ -108,7 +105,7 @@ func (r *rewriteGen) structMethod(t types.Type, strct *types.Struct, spi generat
108105
}
109106
fields := r.rewriteAllStructFields(t, strct, spi, true)
110107

111-
stmts := []jen.Code{r.executePre(t)}
108+
stmts := []jen.Code{r.executePre()}
112109
stmts = append(stmts, fields...)
113110
stmts = append(stmts, executePost(len(fields) > 0))
114111
stmts = append(stmts, returnTrue())
@@ -133,7 +130,7 @@ func (r *rewriteGen) ptrToStructMethod(t types.Type, strct *types.Struct, spi ge
133130
return nil
134131
}
135132
*/
136-
stmts = append(stmts, r.executePre(t))
133+
stmts = append(stmts, r.executePre())
137134
fields := r.rewriteAllStructFields(t, strct, spi, false)
138135
stmts = append(stmts, fields...)
139136
stmts = append(stmts, executePost(len(fields) > 0))
@@ -182,15 +179,12 @@ func (r *rewriteGen) sliceMethod(t types.Type, slice *types.Slice, spi generator
182179
jen.If(jen.Id("node == nil").Block(returnTrue())),
183180
}
184181

185-
typeString := types.TypeString(t, noQualifier)
186-
187182
preStmts := setupCursor()
188183
preStmts = append(preStmts,
189184
jen.Id("kontinue").Op(":=").Id("!a.pre(&a.cur)"),
190185
jen.If(jen.Id("a.cur.revisit").Block(
191-
jen.Id("node").Op("=").Id("a.cur.node.("+typeString+")"),
192186
jen.Id("a.cur.revisit").Op("=").False(),
193-
jen.Return(jen.Id("a.rewrite"+typeString+"(parent, node, replacer)")),
187+
jen.Return(jen.Id("a.rewrite"+r.ifaceName+"(parent, a.cur.node, replacer)")),
194188
)),
195189
jen.If(jen.Id("kontinue").Block(jen.Return(jen.True()))),
196190
)
@@ -228,19 +222,17 @@ func setupCursor() []jen.Code {
228222
jen.Id("a.cur.node = node"),
229223
}
230224
}
231-
func (r *rewriteGen) executePre(t types.Type) jen.Code {
225+
226+
func (r *rewriteGen) executePre() jen.Code {
232227
curStmts := setupCursor()
233-
if r.exprInterface != nil && types.Implements(t, r.exprInterface) {
234-
curStmts = append(curStmts, jen.Id("kontinue").Op(":=").Id("!a.pre(&a.cur)"),
235-
jen.If(jen.Id("a.cur.revisit").Block(
236-
jen.Id("a.cur.revisit").Op("=").False(),
237-
jen.Return(jen.Id("a.rewriteExpr(parent, a.cur.node.(Expr), replacer)")),
238-
)),
239-
jen.If(jen.Id("kontinue").Block(jen.Return(jen.True()))),
240-
)
241-
} else {
242-
curStmts = append(curStmts, jen.If(jen.Id("!a.pre(&a.cur)")).Block(returnTrue()))
243-
}
228+
name := fmt.Sprintf("a.rewrite%s(parent, a.cur.node, replacer)", r.ifaceName)
229+
curStmts = append(curStmts, jen.Id("kontinue").Op(":=").Id("!a.pre(&a.cur)"),
230+
jen.If(jen.Id("a.cur.revisit").Block(
231+
jen.Id("a.cur.revisit").Op("=").False(),
232+
jen.Return(jen.Id(name)),
233+
)),
234+
jen.If(jen.Id("kontinue").Block(jen.Return(jen.True()))),
235+
)
244236
return jen.If(jen.Id("a.pre!= nil").Block(curStmts...))
245237
}
246238

@@ -264,7 +256,7 @@ func (r *rewriteGen) basicMethod(t types.Type, _ *types.Basic, spi generatorSPI)
264256
return nil
265257
}
266258

267-
stmts := []jen.Code{r.executePre(t), executePost(false), returnTrue()}
259+
stmts := []jen.Code{r.executePre(), executePost(false), returnTrue()}
268260
r.rewriteFunc(t, stmts)
269261
return nil
270262
}

‎go/vt/sqlparser/ast_rewrite.go

+991-293
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
Please sign in to comment.