github.com/aretext/aretext@v1.3.0/syntax/languages/golang_test.go (about) 1 package languages 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/assert" 7 8 "github.com/aretext/aretext/syntax/parser" 9 ) 10 11 func TestGolangParseFunc(t *testing.T) { 12 testCases := []struct { 13 name string 14 text string 15 expected []TokenWithText 16 }{ 17 { 18 name: "line comment", 19 text: "// comment", 20 expected: []TokenWithText{ 21 {Text: `// comment`, Role: parser.TokenRoleComment}, 22 }, 23 }, 24 { 25 name: "empty comment at end of file", 26 text: "//", 27 expected: []TokenWithText{ 28 {Text: "//", Role: parser.TokenRoleComment}, 29 }, 30 }, 31 { 32 name: "general comment", 33 text: "/* abcd\n123 */", 34 expected: []TokenWithText{ 35 {Text: "/* abcd\n123 */", Role: parser.TokenRoleComment}, 36 }, 37 }, 38 { 39 name: "variable declaration", 40 text: `var foo []int`, 41 expected: []TokenWithText{ 42 {Text: "var", Role: parser.TokenRoleKeyword}, 43 {Text: "int", Role: parser.TokenRoleKeyword}, 44 }, 45 }, 46 { 47 name: "operators", 48 text: "a + b / c", 49 expected: []TokenWithText{ 50 {Text: "+", Role: parser.TokenRoleOperator}, 51 {Text: "/", Role: parser.TokenRoleOperator}, 52 }, 53 }, 54 { 55 name: "raw string", 56 text: "`abcd\n123`", 57 expected: []TokenWithText{ 58 {Text: "`abcd\n123`", Role: parser.TokenRoleString}, 59 }, 60 }, 61 { 62 name: "interpreted string", 63 text: `"abcd"`, 64 expected: []TokenWithText{ 65 {Text: `"abcd"`, Role: parser.TokenRoleString}, 66 }, 67 }, 68 { 69 name: "interpreted string empty", 70 text: `""`, 71 expected: []TokenWithText{ 72 {Text: `""`, Role: parser.TokenRoleString}, 73 }, 74 }, 75 { 76 name: "interpreted string with escaped quote", 77 text: `"ab\"cd"`, 78 expected: []TokenWithText{ 79 {Text: `"ab\"cd"`, Role: parser.TokenRoleString}, 80 }, 81 }, 82 { 83 name: "interpreted string ending with escaped backslash", 84 text: `"abc\\"`, 85 expected: []TokenWithText{ 86 {Text: `"abc\\"`, Role: parser.TokenRoleString}, 87 }, 88 }, 89 { 90 name: "incomplete interpreted string ending with escaped quote", 91 text: `"abc\" 123`, 92 expected: []TokenWithText{ 93 {Text: `123`, Role: parser.TokenRoleNumber}, 94 }, 95 }, 96 { 97 name: "incomplete interpreted string with newline before quote", 98 text: "\"abc\n\"", 99 expected: []TokenWithText{}, 100 }, 101 { 102 name: "rune", 103 text: `'a'`, 104 expected: []TokenWithText{ 105 {Text: "'a'", Role: parser.TokenRoleString}, 106 }, 107 }, 108 { 109 name: "rune with escaped newline", 110 text: `'\n'`, 111 expected: []TokenWithText{ 112 {Text: `'\n'`, Role: parser.TokenRoleString}, 113 }, 114 }, 115 { 116 name: "rune with escaped quote", 117 text: `'\''`, 118 expected: []TokenWithText{ 119 {Text: `'\''`, Role: parser.TokenRoleString}, 120 }, 121 }, 122 { 123 name: "rune with escaped backslash", 124 text: `'\\'`, 125 expected: []TokenWithText{ 126 {Text: `'\\'`, Role: parser.TokenRoleString}, 127 }, 128 }, 129 { 130 name: "incomplete rune with newline before quote", 131 text: "'\n'", 132 expected: []TokenWithText{}, 133 }, 134 { 135 name: "identifier with underscore prefix", 136 text: "_x9", 137 expected: []TokenWithText{}, 138 }, 139 { 140 name: "identifier with mixed case", 141 text: "ThisVariableIsExported", 142 expected: []TokenWithText{}, 143 }, 144 { 145 name: "identifier with non-ascii unicode", 146 text: "αβ", 147 expected: []TokenWithText{}, 148 }, 149 { 150 name: "integer with underscore", 151 text: "4_2", 152 expected: []TokenWithText{ 153 {Text: `4_2`, Role: parser.TokenRoleNumber}, 154 }, 155 }, 156 { 157 name: "octal without o separator", 158 text: "0600", 159 expected: []TokenWithText{ 160 {Text: `0600`, Role: parser.TokenRoleNumber}, 161 }, 162 }, 163 { 164 name: "integer with leading zero and underscore", 165 text: "0_600", 166 expected: []TokenWithText{ 167 {Text: `0_600`, Role: parser.TokenRoleNumber}, 168 }, 169 }, 170 { 171 name: "octal with lowercase o", 172 text: "0o600", 173 expected: []TokenWithText{ 174 {Text: `0o600`, Role: parser.TokenRoleNumber}, 175 }, 176 }, 177 { 178 name: "octal with uppercase O", 179 text: "0O600", 180 expected: []TokenWithText{ 181 {Text: `0O600`, Role: parser.TokenRoleNumber}, 182 }, 183 }, 184 { 185 name: "octal denoted by leading zero", 186 text: "0123", 187 expected: []TokenWithText{ 188 {Text: "0123", Role: parser.TokenRoleNumber}, 189 }, 190 }, 191 { 192 name: "hex with lowercase x", 193 text: "0xBadFace", 194 expected: []TokenWithText{ 195 {Text: `0xBadFace`, Role: parser.TokenRoleNumber}, 196 }, 197 }, 198 { 199 name: "hex with lowercase x and underscore", 200 text: "0xBad_Face", 201 expected: []TokenWithText{ 202 {Text: `0xBad_Face`, Role: parser.TokenRoleNumber}, 203 }, 204 }, 205 { 206 name: "hex with leading underscore", 207 text: "0x_67_7a_2f_cc_40_c6", 208 expected: []TokenWithText{ 209 {Text: `0x_67_7a_2f_cc_40_c6`, Role: parser.TokenRoleNumber}, 210 }, 211 }, 212 { 213 name: "long number no underscores", 214 text: "170141183460469231731687303715884105727", 215 expected: []TokenWithText{ 216 {Text: `170141183460469231731687303715884105727`, Role: parser.TokenRoleNumber}, 217 }, 218 }, 219 { 220 name: "long number with underscores", 221 text: "170_141183_460469_231731_687303_715884_105727", 222 expected: []TokenWithText{ 223 {Text: `170_141183_460469_231731_687303_715884_105727`, Role: parser.TokenRoleNumber}, 224 }, 225 }, 226 { 227 name: "identifier with leading underscore and digits", 228 text: "_42", 229 expected: []TokenWithText{}, 230 }, 231 { 232 name: "invalid number with digits and trailing underscore", 233 text: "42_", 234 expected: []TokenWithText{ 235 {Text: `42`, Role: parser.TokenRoleNumber}, 236 }, 237 }, 238 { 239 name: "invalid number with multiple underscores", 240 text: "4__2", 241 expected: []TokenWithText{ 242 {Text: `4`, Role: parser.TokenRoleNumber}, 243 }, 244 }, 245 { 246 name: "invalid hex with leading underscore", 247 text: "0_xBadFace", 248 expected: []TokenWithText{ 249 {Text: `0`, Role: parser.TokenRoleNumber}, 250 }, 251 }, 252 { 253 name: "floating point zero with decimal", 254 text: "0.", 255 expected: []TokenWithText{ 256 {Text: `0.`, Role: parser.TokenRoleNumber}, 257 }, 258 }, 259 { 260 name: "floating point with decimal", 261 text: "72.40", 262 expected: []TokenWithText{ 263 {Text: `72.40`, Role: parser.TokenRoleNumber}, 264 }, 265 }, 266 { 267 name: "floating point with decimal and leading zero", 268 text: "072.40", 269 expected: []TokenWithText{ 270 {Text: `072.40`, Role: parser.TokenRoleNumber}, 271 }, 272 }, 273 { 274 name: "floating point with single leading decimal", 275 text: "2.71828", 276 expected: []TokenWithText{ 277 {Text: `2.71828`, Role: parser.TokenRoleNumber}, 278 }, 279 }, 280 { 281 name: "floating point with exponent zero", 282 text: "1.e+0", 283 expected: []TokenWithText{ 284 {Text: `1.e+0`, Role: parser.TokenRoleNumber}, 285 }, 286 }, 287 { 288 name: "floating point with negative exponent", 289 text: "6.67428e-11", 290 expected: []TokenWithText{ 291 {Text: `6.67428e-11`, Role: parser.TokenRoleNumber}, 292 }, 293 }, 294 { 295 name: "exponent with uppercase E", 296 text: "1E6", 297 expected: []TokenWithText{ 298 {Text: `1E6`, Role: parser.TokenRoleNumber}, 299 }, 300 }, 301 { 302 name: "floating point decimal no leading zero", 303 text: ".25", 304 expected: []TokenWithText{ 305 {Text: `.25`, Role: parser.TokenRoleNumber}, 306 }, 307 }, 308 { 309 name: "floating point decimal no leading zero with exponent", 310 text: ".12345E+5", 311 expected: []TokenWithText{ 312 {Text: `.12345E+5`, Role: parser.TokenRoleNumber}, 313 }, 314 }, 315 { 316 name: "floating point decimal with underscore", 317 text: "1_5.", 318 expected: []TokenWithText{ 319 {Text: `1_5.`, Role: parser.TokenRoleNumber}, 320 }, 321 }, 322 { 323 name: "floating point exponent with underscore", 324 text: "0.15e+0_2", 325 expected: []TokenWithText{ 326 {Text: `0.15e+0_2`, Role: parser.TokenRoleNumber}, 327 }, 328 }, 329 { 330 name: "floating point hex with negative exponent", 331 text: "0x1p-2", 332 expected: []TokenWithText{ 333 {Text: `0x1p-2`, Role: parser.TokenRoleNumber}, 334 }, 335 }, 336 { 337 name: "floating point hex with positive exponent", 338 text: "0x2.p10", 339 expected: []TokenWithText{ 340 {Text: `0x2.p10`, Role: parser.TokenRoleNumber}, 341 }, 342 }, 343 { 344 name: "floating point hex with plus zero exponent", 345 text: "0x1.Fp+0", 346 expected: []TokenWithText{ 347 {Text: `0x1.Fp+0`, Role: parser.TokenRoleNumber}, 348 }, 349 }, 350 { 351 name: "floating point hex with minus zero exponent", 352 text: "0X.8p-0", 353 expected: []TokenWithText{ 354 {Text: `0X.8p-0`, Role: parser.TokenRoleNumber}, 355 }, 356 }, 357 { 358 name: "floating point hex with underscores", 359 text: "0X_1FFFP-16", 360 expected: []TokenWithText{ 361 {Text: `0X_1FFFP-16`, Role: parser.TokenRoleNumber}, 362 }, 363 }, 364 { 365 name: "floating point hex minus integer", 366 text: "0x15e-2", 367 expected: []TokenWithText{ 368 {Text: `0x15e`, Role: parser.TokenRoleNumber}, 369 {Text: `-`, Role: parser.TokenRoleOperator}, 370 {Text: `2`, Role: parser.TokenRoleNumber}, 371 }, 372 }, 373 { 374 name: "floating point hex invalid, mantissa has no digits", 375 text: "0x.p1", 376 expected: []TokenWithText{ 377 {Text: `0`, Role: parser.TokenRoleNumber}, 378 }, 379 }, 380 { 381 name: "floating point hex invalid, p exponent requires hexadecimal mantissa", 382 text: "1p-2", 383 expected: []TokenWithText{ 384 {Text: `1`, Role: parser.TokenRoleNumber}, 385 {Text: `-`, Role: parser.TokenRoleOperator}, 386 {Text: `2`, Role: parser.TokenRoleNumber}, 387 }, 388 }, 389 { 390 name: "floating point hex invalid, hexadecimal mantissa requires p exponent", 391 text: "0x1.5e-2", 392 expected: []TokenWithText{ 393 {Text: `0x1`, Role: parser.TokenRoleNumber}, 394 {Text: `.5e-2`, Role: parser.TokenRoleNumber}, 395 }, 396 }, 397 { 398 name: "floating point hex invalid, _ must separate successive digits before decimal point", 399 text: "1_.5", 400 expected: []TokenWithText{ 401 {Text: `1`, Role: parser.TokenRoleNumber}, 402 {Text: `.5`, Role: parser.TokenRoleNumber}, 403 }, 404 }, 405 { 406 name: "floating point hex invalid, _ must separate successive digits after decimal point", 407 text: "1._5", 408 expected: []TokenWithText{ 409 {Text: `1.`, Role: parser.TokenRoleNumber}, 410 }, 411 }, 412 { 413 name: "floating point hex invalid, _ must separate successive digits before exponent", 414 text: "1.5_e1", 415 expected: []TokenWithText{ 416 {Text: `1.5`, Role: parser.TokenRoleNumber}, 417 }, 418 }, 419 { 420 name: "floating point hex invalid, _ must separate successive digits after exponent", 421 text: "1.5e_1", 422 expected: []TokenWithText{ 423 {Text: `1.5`, Role: parser.TokenRoleNumber}, 424 }, 425 }, 426 { 427 name: "floating point hex invalid, _ must separate successive digits at end", 428 text: "1.5e1_", 429 expected: []TokenWithText{ 430 {Text: `1.5e1`, Role: parser.TokenRoleNumber}, 431 }, 432 }, 433 { 434 name: "imaginary zero", 435 text: "0i", 436 expected: []TokenWithText{ 437 {Text: `0i`, Role: parser.TokenRoleNumber}, 438 }, 439 }, 440 { 441 name: "imaginary decimal with leading zero", 442 text: "0123i", 443 expected: []TokenWithText{ 444 {Text: `0123i`, Role: parser.TokenRoleNumber}, 445 }, 446 }, 447 { 448 name: "imaginary octal", 449 text: "0o123i", 450 expected: []TokenWithText{ 451 {Text: `0o123i`, Role: parser.TokenRoleNumber}, 452 }, 453 }, 454 { 455 name: "imaginary hex", 456 text: "0xabci", 457 expected: []TokenWithText{ 458 {Text: `0xabci`, Role: parser.TokenRoleNumber}, 459 }, 460 }, 461 { 462 name: "imaginary floating point zero", 463 text: "0.i", 464 expected: []TokenWithText{ 465 {Text: `0.i`, Role: parser.TokenRoleNumber}, 466 }, 467 }, 468 { 469 name: "imaginary floating point with decimal", 470 text: "2.71828i", 471 expected: []TokenWithText{ 472 {Text: `2.71828i`, Role: parser.TokenRoleNumber}, 473 }, 474 }, 475 { 476 name: "imaginary floating point zero exponent", 477 text: "1.e+0i", 478 expected: []TokenWithText{ 479 {Text: `1.e+0i`, Role: parser.TokenRoleNumber}, 480 }, 481 }, 482 { 483 name: "imaginary floating point negative exponent", 484 text: "6.67428e-11i", 485 expected: []TokenWithText{ 486 {Text: `6.67428e-11i`, Role: parser.TokenRoleNumber}, 487 }, 488 }, 489 { 490 name: "imaginary floating point uppercase exponent", 491 text: "1E6i", 492 expected: []TokenWithText{ 493 {Text: `1E6i`, Role: parser.TokenRoleNumber}, 494 }, 495 }, 496 { 497 name: "imaginary floating point no leading zero", 498 text: ".25i", 499 expected: []TokenWithText{ 500 {Text: `.25i`, Role: parser.TokenRoleNumber}, 501 }, 502 }, 503 { 504 name: "imaginary floating point no leading zero with exponent", 505 text: ".12345E+5i", 506 expected: []TokenWithText{ 507 {Text: `.12345E+5i`, Role: parser.TokenRoleNumber}, 508 }, 509 }, 510 { 511 name: "imaginary floating point hex with negative exponent", 512 text: "0x1p-2i", 513 expected: []TokenWithText{ 514 {Text: `0x1p-2i`, Role: parser.TokenRoleNumber}, 515 }, 516 }, 517 { 518 name: "const declaration", 519 text: `const foo = "test"`, 520 expected: []TokenWithText{ 521 {Text: "const", Role: parser.TokenRoleKeyword}, 522 {Text: "=", Role: parser.TokenRoleOperator}, 523 {Text: `"test"`, Role: parser.TokenRoleString}, 524 }, 525 }, 526 { 527 name: "interface with underlying type", 528 text: ` 529 interface { 530 ~int 531 String() string 532 }`, 533 expected: []TokenWithText{ 534 {Text: "interface", Role: parser.TokenRoleKeyword}, 535 {Text: "~", Role: parser.TokenRoleOperator}, 536 {Text: "int", Role: parser.TokenRoleKeyword}, 537 {Text: "string", Role: parser.TokenRoleKeyword}, 538 }, 539 }, 540 } 541 542 for _, tc := range testCases { 543 t.Run(tc.name, func(t *testing.T) { 544 tokens := ParseTokensWithText(GolangParseFunc(), tc.text) 545 assert.Equal(t, tc.expected, tokens) 546 }) 547 } 548 } 549 550 func BenchmarkGolangParser(b *testing.B) { 551 BenchmarkParser(b, GolangParseFunc(), "testdata/golang/fib.go") 552 }