snapshot of https://github.com/sqlc-dev/sqlc.git (main, 2026-09-16; blobs > 131072B omitted)
Some checks failed
kotlin / test (push) Has been skipped
python / test (push) Has been skipped
typescript / test (push) Has been skipped
go / build darwin/amd64 (push) Has been cancelled
go / build linux/amd64 (push) Has been cancelled
go / build windows/amd64 (push) Has been cancelled
go / build darwin/arm64 (push) Has been cancelled
go / build linux/arm64 (push) Has been cancelled
go / build windows/arm64 (push) Has been cancelled
go / test (push) Has been cancelled
go / vuln_check (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-16 02:17:34 +05:00
commit 0f4df23290
7340 changed files with 238743 additions and 0 deletions

View File

@@ -0,0 +1,122 @@
# AST Utilities Package - Claude Code Guide
This package provides utilities for traversing and transforming AST nodes.
## Key Functions
### Walk
`Walk(f Visitor, node ast.Node)` traverses the AST depth-first, calling `f.Visit()` on each node.
```go
type Visitor interface {
Visit(node ast.Node) Visitor
}
```
**Important**: When adding new AST node types, you MUST add a case to the switch statement in `walk.go`, otherwise you'll get a panic:
```
panic: walk: unexpected node type *ast.YourNewType
```
### Apply (Rewrite)
`Apply(root ast.Node, pre, post ApplyFunc) ast.Node` traverses and optionally transforms the AST.
```go
type ApplyFunc func(*Cursor) bool
```
The `Cursor` provides:
- `Node()` - current node
- `Parent()` - parent node
- `Name()` - field name in parent
- `Index()` - index if in a list
- `Replace(node)` - replace current node
**Important**: When adding new AST node types, you MUST add a case to the switch statement in `rewrite.go`, otherwise you'll get a panic:
```
panic: Apply: unexpected node type *ast.YourNewType
```
### Search
`Search(root ast.Node, fn func(ast.Node) bool) *ast.List` finds all nodes matching a predicate.
### Join
`Join(list *ast.List, sep string) string` joins string nodes with a separator.
## Adding Support for New AST Nodes
When you create a new AST node type, you must update BOTH `walk.go` and `rewrite.go`:
### In walk.go
Add a case that walks all child nodes:
```go
case *ast.YourNewType:
if n.ChildField != nil {
Walk(f, n.ChildField)
}
if n.ChildList != nil {
Walk(f, n.ChildList)
}
```
For leaf nodes with no children:
```go
case *ast.YourNewType:
// Leaf node - no children to traverse
```
### In rewrite.go
Add a case that applies to all child nodes:
```go
case *ast.YourNewType:
a.apply(n, "ChildField", nil, n.ChildField)
a.apply(n, "ChildList", nil, n.ChildList)
```
For leaf nodes:
```go
case *ast.YourNewType:
// Leaf node - no children to traverse
```
## Common Patterns
### Finding All Tables in a Statement
```go
var tv tableVisitor
astutils.Walk(&tv, stmt.FromClause)
// tv.list now contains all RangeVar nodes
```
### Rewriting Nodes In Place
Apply replaces a node with a new one as the tree is walked:
```go
astutils.Apply(root, func(cr *astutils.Cursor) bool {
if _, ok := cr.Node().(*ast.SomeType); ok {
cr.Replace(&ast.OtherType{})
}
return true
}, nil)
```
Note that sqlc syntax (`sqlc.arg()`, `@name`) is *not* handled here. It is
rewritten to native SQL by `internal/sql/preprocess` before the engine parses a
query, so a node type missing from walk.go/rewrite.go can no longer silently
drop a parameter.
## Node Types That Must Be Handled
All node types in `internal/sql/ast/` must have cases in both walk.go and rewrite.go. Key MySQL-specific nodes:
- `IntervalExpr` - INTERVAL expressions
- `OnDuplicateKeyUpdate` - MySQL ON DUPLICATE KEY UPDATE
- `ParenExpr` - Parenthesized expressions
- `VariableExpr` - MySQL user variables (@var)
## Debugging Tips
If you see a panic like:
```
panic: walk: unexpected node type *ast.SomeType
```
Check that `SomeType` has a case in both `walk.go` and `rewrite.go`.

View File

@@ -0,0 +1,21 @@
package astutils
import (
"strings"
"github.com/sqlc-dev/sqlc/internal/sql/ast"
)
func Join(list *ast.List, sep string) string {
if list == nil {
return ""
}
var items []string
for _, item := range list.Items {
if n, ok := item.(*ast.String); ok {
items = append(items, n.Str)
}
}
return strings.Join(items, sep)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
package astutils
import "github.com/sqlc-dev/sqlc/internal/sql/ast"
type nodeSearch struct {
list *ast.List
check func(ast.Node) bool
}
func (s *nodeSearch) Visit(node ast.Node) Visitor {
if s.check(node) {
s.list.Items = append(s.list.Items, node)
}
return s
}
func Search(root ast.Node, f func(ast.Node) bool) *ast.List {
ns := &nodeSearch{check: f, list: &ast.List{}}
Walk(ns, root)
return ns.list
}

File diff suppressed because it is too large Load Diff