| 314 | ) |
| 315 | |
| 316 | def _class_escape(source, escape): |
| 317 | # handle escape code inside character class |
| 318 | code = ESCAPES.get(escape) |
| 319 | if code: |
| 320 | return code |
| 321 | code = CATEGORIES.get(escape) |
| 322 | if code and code[0] is IN: |
| 323 | return code |
| 324 | try: |
| 325 | c = escape[1:2] |
| 326 | if c == "x": |
| 327 | # hexadecimal escape (exactly two digits) |
| 328 | escape += source.getwhile(2, HEXDIGITS) |
| 329 | if len(escape) != 4: |
| 330 | raise source.error("incomplete escape %s" % escape, len(escape)) |
| 331 | return LITERAL, int(escape[2:], 16) |
| 332 | elif c == "u" and source.istext: |
| 333 | # unicode escape (exactly four digits) |
| 334 | escape += source.getwhile(4, HEXDIGITS) |
| 335 | if len(escape) != 6: |
| 336 | raise source.error("incomplete escape %s" % escape, len(escape)) |
| 337 | return LITERAL, int(escape[2:], 16) |
| 338 | elif c == "U" and source.istext: |
| 339 | # unicode escape (exactly eight digits) |
| 340 | escape += source.getwhile(8, HEXDIGITS) |
| 341 | if len(escape) != 10: |
| 342 | raise source.error("incomplete escape %s" % escape, len(escape)) |
| 343 | c = int(escape[2:], 16) |
| 344 | chr(c) # raise ValueError for invalid code |
| 345 | return LITERAL, c |
| 346 | elif c == "N" and source.istext: |
| 347 | import unicodedata |
| 348 | # named unicode escape e.g. \N{EM DASH} |
| 349 | if not source.match('{'): |
| 350 | raise source.error("missing {") |
| 351 | charname = source.getuntil('}', 'character name') |
| 352 | try: |
| 353 | c = ord(unicodedata.lookup(charname)) |
| 354 | except (KeyError, TypeError): |
| 355 | raise source.error("undefined character name %r" % charname, |
| 356 | len(charname) + len(r'\N{}')) from None |
| 357 | return LITERAL, c |
| 358 | elif c in OCTDIGITS: |
| 359 | # octal escape (up to three digits) |
| 360 | escape += source.getwhile(2, OCTDIGITS) |
| 361 | c = int(escape[1:], 8) |
| 362 | if c > 0o377: |
| 363 | raise source.error('octal escape value %s outside of ' |
| 364 | 'range 0-0o377' % escape, len(escape)) |
| 365 | return LITERAL, c |
| 366 | elif c in DIGITS: |
| 367 | raise ValueError |
| 368 | if len(escape) == 2: |
| 369 | if c in ASCIILETTERS: |
| 370 | raise source.error('bad escape %s' % escape, len(escape)) |
| 371 | return LITERAL, ord(escape[1]) |
| 372 | except ValueError: |
| 373 | pass |