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