github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/asm/internal/lex/lex_test.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 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 /* This one fails. See comment in Slice.Col. 248 { 249 "nested #define with args", 250 lines( 251 "#define A #define B (x) x", 252 "A", 253 "B(THIS)", 254 ), 255 "x.\n", 256 }, 257 */ 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 // lines joins the arguments together as complete lines. 272 func lines(a ...string) string { 273 return strings.Join(a, "\n") + "\n" 274 } 275 276 // drain returns a single string representing the processed input tokens. 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 buf.Len() > 0 { 285 buf.WriteByte('.') 286 } 287 buf.WriteString(input.Text()) 288 } 289 } 290 291 type badLexTest struct { 292 input string 293 error string 294 } 295 296 var badLexTests = []badLexTest{ 297 { 298 "3 #define foo bar\n", 299 "'#' must be first item on line", 300 }, 301 { 302 "#ifdef foo\nhello", 303 "unclosed #ifdef or #ifndef", 304 }, 305 { 306 "#ifndef foo\nhello", 307 "unclosed #ifdef or #ifndef", 308 }, 309 { 310 "#ifdef foo\nhello\n#else\nbye", 311 "unclosed #ifdef or #ifndef", 312 }, 313 { 314 "#define A() A()\nA()", 315 "recursive macro invocation", 316 }, 317 { 318 "#define A a\n#define A a\n", 319 "redefinition of macro", 320 }, 321 { 322 "#define A a", 323 "no newline after macro definition", 324 }, 325 } 326 327 func TestBadLex(t *testing.T) { 328 for _, test := range badLexTests { 329 input := NewInput(test.error) 330 input.Push(NewTokenizer(test.error, strings.NewReader(test.input), nil)) 331 err := firstError(input) 332 if err == nil { 333 t.Errorf("%s: got no error", test.error) 334 continue 335 } 336 if !strings.Contains(err.Error(), test.error) { 337 t.Errorf("got error %q expected %q", err.Error(), test.error) 338 } 339 } 340 } 341 342 // firstError returns the first error value triggered by the input. 343 func firstError(input *Input) (err error) { 344 panicOnError = true 345 defer func() { 346 panicOnError = false 347 switch e := recover(); e := e.(type) { 348 case nil: 349 case error: 350 err = e 351 default: 352 panic(e) 353 } 354 }() 355 356 for { 357 tok := input.Next() 358 if tok == scanner.EOF { 359 return 360 } 361 } 362 }