1
2
3
4
5 package lex
6
7 import (
8 "bytes"
9 "strings"
10 "testing"
11 "text/scanner"
12 )
13
14 type lexTest struct {
15 name string
16 input string
17 output string
18 }
19
20 var lexTests = []lexTest{
21 {
22 "empty",
23 "",
24 "",
25 },
26 {
27 "simple",
28 "1 (a)",
29 "1.(.a.)",
30 },
31 {
32 "simple define",
33 lines(
34 "#define A 1234",
35 "A",
36 ),
37 "1234.\n",
38 },
39 {
40 "define without value",
41 "#define A",
42 "",
43 },
44 {
45 "macro without arguments",
46 "#define A() 1234\n" + "A()\n",
47 "1234.\n",
48 },
49 {
50 "macro with just parens as body",
51 "#define A () \n" + "A\n",
52 "(.).\n",
53 },
54 {
55 "macro with parens but no arguments",
56 "#define A (x) \n" + "A\n",
57 "(.x.).\n",
58 },
59 {
60 "macro with arguments",
61 "#define A(x, y, z) x+z+y\n" + "A(1, 2, 3)\n",
62 "1.+.3.+.2.\n",
63 },
64 {
65 "argumented macro invoked without arguments",
66 lines(
67 "#define X() foo ",
68 "X()",
69 "X",
70 ),
71 "foo.\n.X.\n",
72 },
73 {
74 "multiline macro without arguments",
75 lines(
76 "#define A 1\\",
77 "\t2\\",
78 "\t3",
79 "before",
80 "A",
81 "after",
82 ),
83 "before.\n.1.\n.2.\n.3.\n.after.\n",
84 },
85 {
86 "multiline macro with arguments",
87 lines(
88 "#define A(a, b, c) a\\",
89 "\tb\\",
90 "\tc",
91 "before",
92 "A(1, 2, 3)",
93 "after",
94 ),
95 "before.\n.1.\n.2.\n.3.\n.after.\n",
96 },
97 {
98 "LOAD macro",
99 lines(
100 "#define LOAD(off, reg) \\",
101 "\tMOVBLZX (off*4)(R12), reg \\",
102 "\tADDB reg, DX",
103 "",
104 "LOAD(8, AX)",
105 ),
106 "\n.\n.MOVBLZX.(.8.*.4.).(.R12.).,.AX.\n.ADDB.AX.,.DX.\n",
107 },
108 {
109 "nested multiline macro",
110 lines(
111 "#define KEYROUND(xmm, load, off, r1, r2, index) \\",
112 "\tMOVBLZX (BP)(DX*4), R8 \\",
113 "\tload((off+1), r2) \\",
114 "\tMOVB R8, (off*4)(R12) \\",
115 "\tPINSRW $index, (BP)(R8*4), xmm",
116 "#define LOAD(off, reg) \\",
117 "\tMOVBLZX (off*4)(R12), reg \\",
118 "\tADDB reg, DX",
119 "KEYROUND(X0, LOAD, 8, AX, BX, 0)",
120 ),
121 "\n.MOVBLZX.(.BP.).(.DX.*.4.).,.R8.\n.\n.MOVBLZX.(.(.8.+.1.).*.4.).(.R12.).,.BX.\n.ADDB.BX.,.DX.\n.MOVB.R8.,.(.8.*.4.).(.R12.).\n.PINSRW.$.0.,.(.BP.).(.R8.*.4.).,.X0.\n",
122 },
123 {
124 "taken #ifdef",
125 lines(
126 "#define A",
127 "#ifdef A",
128 "#define B 1234",
129 "#endif",
130 "B",
131 ),
132 "1234.\n",
133 },
134 {
135 "not taken #ifdef",
136 lines(
137 "#ifdef A",
138 "#define B 1234",
139 "#endif",
140 "B",
141 ),
142 "B.\n",
143 },
144 {
145 "taken #ifdef with else",
146 lines(
147 "#define A",
148 "#ifdef A",
149 "#define B 1234",
150 "#else",
151 "#define B 5678",
152 "#endif",
153 "B",
154 ),
155 "1234.\n",
156 },
157 {
158 "not taken #ifdef with else",
159 lines(
160 "#ifdef A",
161 "#define B 1234",
162 "#else",
163 "#define B 5678",
164 "#endif",
165 "B",
166 ),
167 "5678.\n",
168 },
169 {
170 "nested taken/taken #ifdef",
171 lines(
172 "#define A",
173 "#define B",
174 "#ifdef A",
175 "#ifdef B",
176 "#define C 1234",
177 "#else",
178 "#define C 5678",
179 "#endif",
180 "#endif",
181 "C",
182 ),
183 "1234.\n",
184 },
185 {
186 "nested taken/not-taken #ifdef",
187 lines(
188 "#define A",
189 "#ifdef A",
190 "#ifdef B",
191 "#define C 1234",
192 "#else",
193 "#define C 5678",
194 "#endif",
195 "#endif",
196 "C",
197 ),
198 "5678.\n",
199 },
200 {
201 "nested not-taken/would-be-taken #ifdef",
202 lines(
203 "#define B",
204 "#ifdef A",
205 "#ifdef B",
206 "#define C 1234",
207 "#else",
208 "#define C 5678",
209 "#endif",
210 "#endif",
211 "C",
212 ),
213 "C.\n",
214 },
215 {
216 "nested not-taken/not-taken #ifdef",
217 lines(
218 "#ifdef A",
219 "#ifdef B",
220 "#define C 1234",
221 "#else",
222 "#define C 5678",
223 "#endif",
224 "#endif",
225 "C",
226 ),
227 "C.\n",
228 },
229 {
230 "nested #define",
231 lines(
232 "#define A #define B THIS",
233 "A",
234 "B",
235 ),
236 "THIS.\n",
237 },
238 {
239 "nested #define with args",
240 lines(
241 "#define A #define B(x) x",
242 "A",
243 "B(THIS)",
244 ),
245 "THIS.\n",
246 },
247
258 }
259
260 func TestLex(t *testing.T) {
261 for _, test := range lexTests {
262 input := NewInput(test.name)
263 input.Push(NewTokenizer(test.name, strings.NewReader(test.input), nil))
264 result := drain(input)
265 if result != test.output {
266 t.Errorf("%s: got %q expected %q", test.name, result, test.output)
267 }
268 }
269 }
270
271
272 func lines(a ...string) string {
273 return strings.Join(a, "\n") + "\n"
274 }
275
276
277 func drain(input *Input) string {
278 var buf bytes.Buffer
279 for {
280 tok := input.Next()
281 if tok == scanner.EOF {
282 return buf.String()
283 }
284 if tok == '#' {
285 continue
286 }
287 if buf.Len() > 0 {
288 buf.WriteByte('.')
289 }
290 buf.WriteString(input.Text())
291 }
292 }
293
294 type badLexTest struct {
295 input string
296 error string
297 }
298
299 var badLexTests = []badLexTest{
300 {
301 "3 #define foo bar\n",
302 "'#' must be first item on line",
303 },
304 {
305 "#ifdef foo\nhello",
306 "unclosed #ifdef or #ifndef",
307 },
308 {
309 "#ifndef foo\nhello",
310 "unclosed #ifdef or #ifndef",
311 },
312 {
313 "#ifdef foo\nhello\n#else\nbye",
314 "unclosed #ifdef or #ifndef",
315 },
316 {
317 "#define A() A()\nA()",
318 "recursive macro invocation",
319 },
320 {
321 "#define A a\n#define A a\n",
322 "redefinition of macro",
323 },
324 {
325 "#define A a",
326 "no newline after macro definition",
327 },
328 }
329
330 func TestBadLex(t *testing.T) {
331 for _, test := range badLexTests {
332 input := NewInput(test.error)
333 input.Push(NewTokenizer(test.error, strings.NewReader(test.input), nil))
334 err := firstError(input)
335 if err == nil {
336 t.Errorf("%s: got no error", test.error)
337 continue
338 }
339 if !strings.Contains(err.Error(), test.error) {
340 t.Errorf("got error %q expected %q", err.Error(), test.error)
341 }
342 }
343 }
344
345
346 func firstError(input *Input) (err error) {
347 panicOnError = true
348 defer func() {
349 panicOnError = false
350 switch e := recover(); e := e.(type) {
351 case nil:
352 case error:
353 err = e
354 default:
355 panic(e)
356 }
357 }()
358
359 for {
360 tok := input.Next()
361 if tok == scanner.EOF {
362 return
363 }
364 }
365 }
366
View as plain text