convert.go raw
1 package pattern
2
3 import (
4 "fmt"
5 "go/ast"
6 "go/token"
7 "go/types"
8 "reflect"
9 )
10
11 var astTypes = map[string]reflect.Type{
12 "Ellipsis": reflect.TypeOf(ast.Ellipsis{}),
13 "RangeStmt": reflect.TypeOf(ast.RangeStmt{}),
14 "AssignStmt": reflect.TypeOf(ast.AssignStmt{}),
15 "IndexExpr": reflect.TypeOf(ast.IndexExpr{}),
16 "IndexListExpr": reflect.TypeOf(ast.IndexListExpr{}),
17 "Ident": reflect.TypeOf(ast.Ident{}),
18 "ValueSpec": reflect.TypeOf(ast.ValueSpec{}),
19 "GenDecl": reflect.TypeOf(ast.GenDecl{}),
20 "BinaryExpr": reflect.TypeOf(ast.BinaryExpr{}),
21 "ForStmt": reflect.TypeOf(ast.ForStmt{}),
22 "ArrayType": reflect.TypeOf(ast.ArrayType{}),
23 "DeferStmt": reflect.TypeOf(ast.DeferStmt{}),
24 "MapType": reflect.TypeOf(ast.MapType{}),
25 "ReturnStmt": reflect.TypeOf(ast.ReturnStmt{}),
26 "SliceExpr": reflect.TypeOf(ast.SliceExpr{}),
27 "StarExpr": reflect.TypeOf(ast.StarExpr{}),
28 "UnaryExpr": reflect.TypeOf(ast.UnaryExpr{}),
29 "SendStmt": reflect.TypeOf(ast.SendStmt{}),
30 "SelectStmt": reflect.TypeOf(ast.SelectStmt{}),
31 "ImportSpec": reflect.TypeOf(ast.ImportSpec{}),
32 "IfStmt": reflect.TypeOf(ast.IfStmt{}),
33 "GoStmt": reflect.TypeOf(ast.GoStmt{}),
34 "Field": reflect.TypeOf(ast.Field{}),
35 "SelectorExpr": reflect.TypeOf(ast.SelectorExpr{}),
36 "StructType": reflect.TypeOf(ast.StructType{}),
37 "KeyValueExpr": reflect.TypeOf(ast.KeyValueExpr{}),
38 "FuncType": reflect.TypeOf(ast.FuncType{}),
39 "FuncLit": reflect.TypeOf(ast.FuncLit{}),
40 "FuncDecl": reflect.TypeOf(ast.FuncDecl{}),
41 "ChanType": reflect.TypeOf(ast.ChanType{}),
42 "CallExpr": reflect.TypeOf(ast.CallExpr{}),
43 "CaseClause": reflect.TypeOf(ast.CaseClause{}),
44 "CommClause": reflect.TypeOf(ast.CommClause{}),
45 "CompositeLit": reflect.TypeOf(ast.CompositeLit{}),
46 "EmptyStmt": reflect.TypeOf(ast.EmptyStmt{}),
47 "SwitchStmt": reflect.TypeOf(ast.SwitchStmt{}),
48 "TypeSwitchStmt": reflect.TypeOf(ast.TypeSwitchStmt{}),
49 "TypeAssertExpr": reflect.TypeOf(ast.TypeAssertExpr{}),
50 "TypeSpec": reflect.TypeOf(ast.TypeSpec{}),
51 "InterfaceType": reflect.TypeOf(ast.InterfaceType{}),
52 "BranchStmt": reflect.TypeOf(ast.BranchStmt{}),
53 "IncDecStmt": reflect.TypeOf(ast.IncDecStmt{}),
54 "BasicLit": reflect.TypeOf(ast.BasicLit{}),
55 }
56
57 func ASTToNode(node interface{}) Node {
58 switch node := node.(type) {
59 case *ast.File:
60 panic("cannot convert *ast.File to Node")
61 case nil:
62 return Nil{}
63 case string:
64 return String(node)
65 case token.Token:
66 return Token(node)
67 case *ast.ExprStmt:
68 return ASTToNode(node.X)
69 case *ast.BlockStmt:
70 if node == nil {
71 return Nil{}
72 }
73 return ASTToNode(node.List)
74 case *ast.FieldList:
75 if node == nil {
76 return Nil{}
77 }
78 return ASTToNode(node.List)
79 case *ast.BasicLit:
80 if node == nil {
81 return Nil{}
82 }
83 case *ast.ParenExpr:
84 return ASTToNode(node.X)
85 }
86
87 if node, ok := node.(ast.Node); ok {
88 name := reflect.TypeOf(node).Elem().Name()
89 T, ok := structNodes[name]
90 if !ok {
91 panic(fmt.Sprintf("internal error: unhandled type %T", node))
92 }
93
94 if reflect.ValueOf(node).IsNil() {
95 return Nil{}
96 }
97 v := reflect.ValueOf(node).Elem()
98 objs := make([]Node, T.NumField())
99 for i := 0; i < T.NumField(); i++ {
100 f := v.FieldByName(T.Field(i).Name)
101 objs[i] = ASTToNode(f.Interface())
102 }
103
104 n, err := populateNode(name, objs, false)
105 if err != nil {
106 panic(fmt.Sprintf("internal error: %s", err))
107 }
108 return n
109 }
110
111 s := reflect.ValueOf(node)
112 if s.Kind() == reflect.Slice {
113 if s.Len() == 0 {
114 return List{}
115 }
116 if s.Len() == 1 {
117 return ASTToNode(s.Index(0).Interface())
118 }
119
120 tail := List{}
121 for i := s.Len() - 1; i >= 0; i-- {
122 head := ASTToNode(s.Index(i).Interface())
123 l := List{
124 Head: head,
125 Tail: tail,
126 }
127 tail = l
128 }
129 return tail
130 }
131
132 panic(fmt.Sprintf("internal error: unhandled type %T", node))
133 }
134
135 func NodeToAST(node Node, state State) interface{} {
136 switch node := node.(type) {
137 case Binding:
138 v, ok := state[node.Name]
139 if !ok {
140 // really we want to return an error here
141 panic("XXX")
142 }
143 switch v := v.(type) {
144 case types.Object:
145 return &ast.Ident{Name: v.Name()}
146 default:
147 return v
148 }
149 case Builtin, Any, Object, Symbol, Not, Or:
150 panic("XXX")
151 case List:
152 if (node == List{}) {
153 return []ast.Node{}
154 }
155 x := []ast.Node{NodeToAST(node.Head, state).(ast.Node)}
156 x = append(x, NodeToAST(node.Tail, state).([]ast.Node)...)
157 return x
158 case Token:
159 return token.Token(node)
160 case String:
161 return string(node)
162 case Nil:
163 return nil
164 }
165
166 name := reflect.TypeOf(node).Name()
167 T, ok := astTypes[name]
168 if !ok {
169 panic(fmt.Sprintf("internal error: unhandled type %T", node))
170 }
171 v := reflect.ValueOf(node)
172 out := reflect.New(T)
173 for i := 0; i < T.NumField(); i++ {
174 fNode := v.FieldByName(T.Field(i).Name)
175 if (fNode == reflect.Value{}) {
176 continue
177 }
178 fAST := out.Elem().FieldByName(T.Field(i).Name)
179 switch fAST.Type().Kind() {
180 case reflect.Slice:
181 c := reflect.ValueOf(NodeToAST(fNode.Interface().(Node), state))
182 if c.Kind() != reflect.Slice {
183 // it's a single node in the pattern, we have to wrap
184 // it in a slice
185 slice := reflect.MakeSlice(fAST.Type(), 1, 1)
186 slice.Index(0).Set(c)
187 c = slice
188 }
189 switch fAST.Interface().(type) {
190 case []ast.Node:
191 switch cc := c.Interface().(type) {
192 case []ast.Node:
193 fAST.Set(c)
194 case []ast.Expr:
195 var slice []ast.Node
196 for _, el := range cc {
197 slice = append(slice, el)
198 }
199 fAST.Set(reflect.ValueOf(slice))
200 default:
201 panic("XXX")
202 }
203 case []ast.Expr:
204 switch cc := c.Interface().(type) {
205 case []ast.Node:
206 var slice []ast.Expr
207 for _, el := range cc {
208 slice = append(slice, el.(ast.Expr))
209 }
210 fAST.Set(reflect.ValueOf(slice))
211 case []ast.Expr:
212 fAST.Set(c)
213 default:
214 panic("XXX")
215 }
216 default:
217 panic("XXX")
218 }
219 case reflect.Int:
220 c := reflect.ValueOf(NodeToAST(fNode.Interface().(Node), state))
221 switch c.Kind() {
222 case reflect.String:
223 tok, ok := tokensByString[c.Interface().(string)]
224 if !ok {
225 // really we want to return an error here
226 panic("XXX")
227 }
228 fAST.SetInt(int64(tok))
229 case reflect.Int:
230 fAST.Set(c)
231 default:
232 panic(fmt.Sprintf("internal error: unexpected kind %s", c.Kind()))
233 }
234 default:
235 r := NodeToAST(fNode.Interface().(Node), state)
236 if r != nil {
237 fAST.Set(reflect.ValueOf(r))
238 }
239 }
240 }
241
242 return out.Interface().(ast.Node)
243 }
244