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