1
2
3
4
5 package syntax
6
7 import (
8 "fmt"
9 "strings"
10 "testing"
11 )
12
13
14
15
16 type test struct {
17 nodetyp string
18 snippet string
19 }
20
21 var decls = []test{
22
23
24
25 {"ImportDecl", `import @"math"`},
26 {"ImportDecl", `import @mymath "math"`},
27 {"ImportDecl", `import @. "math"`},
28 {"ImportDecl", `import (@"math")`},
29 {"ImportDecl", `import (@mymath "math")`},
30 {"ImportDecl", `import (@. "math")`},
31
32 {"ConstDecl", `const @x`},
33 {"ConstDecl", `const @x = 0`},
34 {"ConstDecl", `const @x, y, z = 0, 1, 2`},
35 {"ConstDecl", `const (@x)`},
36 {"ConstDecl", `const (@x = 0)`},
37 {"ConstDecl", `const (@x, y, z = 0, 1, 2)`},
38
39 {"TypeDecl", `type @T int`},
40 {"TypeDecl", `type @T = int`},
41 {"TypeDecl", `type (@T int)`},
42 {"TypeDecl", `type (@T = int)`},
43
44 {"VarDecl", `var @x int`},
45 {"VarDecl", `var @x, y, z int`},
46 {"VarDecl", `var @x int = 0`},
47 {"VarDecl", `var @x, y, z int = 1, 2, 3`},
48 {"VarDecl", `var @x = 0`},
49 {"VarDecl", `var @x, y, z = 1, 2, 3`},
50 {"VarDecl", `var (@x int)`},
51 {"VarDecl", `var (@x, y, z int)`},
52 {"VarDecl", `var (@x int = 0)`},
53 {"VarDecl", `var (@x, y, z int = 1, 2, 3)`},
54 {"VarDecl", `var (@x = 0)`},
55 {"VarDecl", `var (@x, y, z = 1, 2, 3)`},
56
57 {"FuncDecl", `func @f() {}`},
58 {"FuncDecl", `func @(T) f() {}`},
59 {"FuncDecl", `func @(x T) f() {}`},
60 }
61
62 var exprs = []test{
63
64
65
66 {"Name", `@x`},
67
68 {"BasicLit", `@0`},
69 {"BasicLit", `@0x123`},
70 {"BasicLit", `@3.1415`},
71 {"BasicLit", `@.2718`},
72 {"BasicLit", `@1i`},
73 {"BasicLit", `@'a'`},
74 {"BasicLit", `@"abc"`},
75 {"BasicLit", "@`abc`"},
76
77 {"CompositeLit", `@{}`},
78 {"CompositeLit", `T@{}`},
79 {"CompositeLit", `struct{x, y int}@{}`},
80
81 {"KeyValueExpr", `"foo"@: true`},
82 {"KeyValueExpr", `"a"@: b`},
83
84 {"FuncLit", `@func (){}`},
85 {"ParenExpr", `@(x)`},
86 {"SelectorExpr", `a@.b`},
87 {"IndexExpr", `a@[i]`},
88
89 {"SliceExpr", `a@[:]`},
90 {"SliceExpr", `a@[i:]`},
91 {"SliceExpr", `a@[:j]`},
92 {"SliceExpr", `a@[i:j]`},
93 {"SliceExpr", `a@[i:j:k]`},
94
95 {"AssertExpr", `x@.(T)`},
96
97 {"Operation", `@*b`},
98 {"Operation", `@+b`},
99 {"Operation", `@-b`},
100 {"Operation", `@!b`},
101 {"Operation", `@^b`},
102 {"Operation", `@&b`},
103 {"Operation", `@<-b`},
104
105 {"Operation", `a @|| b`},
106 {"Operation", `a @&& b`},
107 {"Operation", `a @== b`},
108 {"Operation", `a @+ b`},
109 {"Operation", `a @* b`},
110
111 {"CallExpr", `f@()`},
112 {"CallExpr", `f@(x, y, z)`},
113 {"CallExpr", `obj.f@(1, 2, 3)`},
114 {"CallExpr", `func(x int) int { return x + 1 }@(y)`},
115
116
117 }
118
119 var types = []test{
120 {"Operation", `@*T`},
121 {"Operation", `@*struct{}`},
122
123 {"ArrayType", `@[10]T`},
124 {"ArrayType", `@[...]T`},
125
126 {"SliceType", `@[]T`},
127 {"DotsType", `@...T`},
128 {"StructType", `@struct{}`},
129 {"InterfaceType", `@interface{}`},
130 {"FuncType", `func@()`},
131 {"MapType", `@map[T]T`},
132
133 {"ChanType", `@chan T`},
134 {"ChanType", `@chan<- T`},
135 {"ChanType", `@<-chan T`},
136 }
137
138 var fields = []test{
139 {"Field", `@T`},
140 {"Field", `@(T)`},
141 {"Field", `@x T`},
142 {"Field", `@x *(T)`},
143 {"Field", `@x, y, z T`},
144 {"Field", `@x, y, z (*T)`},
145 }
146
147 var stmts = []test{
148 {"EmptyStmt", `@`},
149
150 {"LabeledStmt", `L@:`},
151 {"LabeledStmt", `L@: ;`},
152 {"LabeledStmt", `L@: f()`},
153
154 {"BlockStmt", `@{}`},
155
156
157 {"ExprStmt", `@<-ch`},
158 {"ExprStmt", `f@()`},
159 {"ExprStmt", `append@(s, 1, 2, 3)`},
160
161 {"SendStmt", `ch @<- x`},
162
163 {"DeclStmt", `@const x = 0`},
164 {"DeclStmt", `@const (x = 0)`},
165 {"DeclStmt", `@type T int`},
166 {"DeclStmt", `@type T = int`},
167 {"DeclStmt", `@type (T1 = int; T2 = float32)`},
168 {"DeclStmt", `@var x = 0`},
169 {"DeclStmt", `@var x, y, z int`},
170 {"DeclStmt", `@var (a, b = 1, 2)`},
171
172 {"AssignStmt", `x @= y`},
173 {"AssignStmt", `a, b, x @= 1, 2, 3`},
174 {"AssignStmt", `x @+= y`},
175 {"AssignStmt", `x @:= y`},
176 {"AssignStmt", `x, ok @:= f()`},
177 {"AssignStmt", `x@++`},
178 {"AssignStmt", `a[i]@--`},
179
180 {"BranchStmt", `@break`},
181 {"BranchStmt", `@break L`},
182 {"BranchStmt", `@continue`},
183 {"BranchStmt", `@continue L`},
184 {"BranchStmt", `@fallthrough`},
185 {"BranchStmt", `@goto L`},
186
187 {"CallStmt", `@defer f()`},
188 {"CallStmt", `@go f()`},
189
190 {"ReturnStmt", `@return`},
191 {"ReturnStmt", `@return x`},
192 {"ReturnStmt", `@return a, b, a + b*f(1, 2, 3)`},
193
194 {"IfStmt", `@if cond {}`},
195 {"IfStmt", `@if cond { f() } else {}`},
196 {"IfStmt", `@if cond { f() } else { g(); h() }`},
197 {"ForStmt", `@for {}`},
198 {"ForStmt", `@for { f() }`},
199 {"SwitchStmt", `@switch {}`},
200 {"SwitchStmt", `@switch { default: }`},
201 {"SwitchStmt", `@switch { default: x++ }`},
202 {"SelectStmt", `@select {}`},
203 {"SelectStmt", `@select { default: }`},
204 {"SelectStmt", `@select { default: ch <- false }`},
205 }
206
207 var ranges = []test{
208 {"RangeClause", `@range s`},
209 {"RangeClause", `i = @range s`},
210 {"RangeClause", `i := @range s`},
211 {"RangeClause", `_, x = @range s`},
212 {"RangeClause", `i, x = @range s`},
213 {"RangeClause", `_, x := @range s.f`},
214 {"RangeClause", `i, x := @range f(i)`},
215 }
216
217 var guards = []test{
218 {"TypeSwitchGuard", `x@.(type)`},
219 {"TypeSwitchGuard", `x := x@.(type)`},
220 }
221
222 var cases = []test{
223 {"CaseClause", `@case x:`},
224 {"CaseClause", `@case x, y, z:`},
225 {"CaseClause", `@case x == 1, y == 2:`},
226 {"CaseClause", `@default:`},
227 }
228
229 var comms = []test{
230 {"CommClause", `@case <-ch:`},
231 {"CommClause", `@case x <- ch:`},
232 {"CommClause", `@case x = <-ch:`},
233 {"CommClause", `@case x := <-ch:`},
234 {"CommClause", `@case x, ok = <-ch: f(1, 2, 3)`},
235 {"CommClause", `@case x, ok := <-ch: x++`},
236 {"CommClause", `@default:`},
237 {"CommClause", `@default: ch <- true`},
238 }
239
240 func TestPos(t *testing.T) {
241
242
243
244
245 testPos(t, decls, "package p; ", "",
246 func(f *File) Node { return f.DeclList[0] },
247 )
248
249
250 testPos(t, exprs, "package p; var _ = T{ ", " }",
251 func(f *File) Node { return f.DeclList[0].(*VarDecl).Values.(*CompositeLit).ElemList[0] },
252 )
253
254
255 testPos(t, types, "package p; func f(", ")",
256 func(f *File) Node { return f.DeclList[0].(*FuncDecl).Type.ParamList[0].Type },
257 )
258
259 testPos(t, fields, "package p; func f(", ")",
260 func(f *File) Node { return f.DeclList[0].(*FuncDecl).Type.ParamList[0] },
261 )
262
263 testPos(t, stmts, "package p; func _() { ", "; }",
264 func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body.List[0] },
265 )
266
267 testPos(t, ranges, "package p; func _() { for ", " {} }",
268 func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body.List[0].(*ForStmt).Init.(*RangeClause) },
269 )
270
271 testPos(t, guards, "package p; func _() { switch ", " {} }",
272 func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body.List[0].(*SwitchStmt).Tag.(*TypeSwitchGuard) },
273 )
274
275 testPos(t, cases, "package p; func _() { switch { ", " } }",
276 func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body.List[0].(*SwitchStmt).Body[0] },
277 )
278
279 testPos(t, comms, "package p; func _() { select { ", " } }",
280 func(f *File) Node { return f.DeclList[0].(*FuncDecl).Body.List[0].(*SelectStmt).Body[0] },
281 )
282 }
283
284 func testPos(t *testing.T, list []test, prefix, suffix string, extract func(*File) Node) {
285 for _, test := range list {
286
287 src, index := stripAt(prefix + test.snippet + suffix)
288 if index < 0 {
289 t.Errorf("missing @: %s (%s)", src, test.nodetyp)
290 continue
291 }
292
293
294 file, err := Parse(nil, strings.NewReader(src), nil, nil, 0)
295 if err != nil {
296 t.Errorf("parse error: %s: %v (%s)", src, err, test.nodetyp)
297 continue
298 }
299
300
301 node := extract(file)
302 if typ := typeOf(node); typ != test.nodetyp {
303 t.Errorf("type error: %s: type = %s, want %s", src, typ, test.nodetyp)
304 continue
305 }
306
307
308 if pos := int(node.Pos().Col()); pos != index+colbase {
309 t.Errorf("pos error: %s: pos = %d, want %d (%s)", src, pos, index+colbase, test.nodetyp)
310 continue
311 }
312 }
313 }
314
315 func stripAt(s string) (string, int) {
316 if i := strings.Index(s, "@"); i >= 0 {
317 return s[:i] + s[i+1:], i
318 }
319 return s, -1
320 }
321
322 func typeOf(n Node) string {
323 const prefix = "*syntax."
324 k := fmt.Sprintf("%T", n)
325 return strings.TrimPrefix(k, prefix)
326 }
327
View as plain text