(source, escape, state)
| 370 | raise source.error("bad escape %s" % escape, len(escape)) |
| 371 | |
| 372 | def _escape(source, escape, state): |
| 373 | # handle escape code in expression |
| 374 | code = CATEGORIES.get(escape) |
| 375 | if code: |
| 376 | return code |
| 377 | code = ESCAPES.get(escape) |
| 378 | if code: |
| 379 | return code |
| 380 | try: |
| 381 | c = escape[1:2] |
| 382 | if c == "x": |
| 383 | # hexadecimal escape |
| 384 | escape += source.getwhile(2, HEXDIGITS) |
| 385 | if len(escape) != 4: |
| 386 | raise source.error("incomplete escape %s" % escape, len(escape)) |
| 387 | return LITERAL, int(escape[2:], 16) |
| 388 | elif c == "u" and source.istext: |
| 389 | # unicode escape (exactly four digits) |
| 390 | escape += source.getwhile(4, HEXDIGITS) |
| 391 | if len(escape) != 6: |
| 392 | raise source.error("incomplete escape %s" % escape, len(escape)) |
| 393 | return LITERAL, int(escape[2:], 16) |
| 394 | elif c == "U" and source.istext: |
| 395 | # unicode escape (exactly eight digits) |
| 396 | escape += source.getwhile(8, HEXDIGITS) |
| 397 | if len(escape) != 10: |
| 398 | raise source.error("incomplete escape %s" % escape, len(escape)) |
| 399 | c = int(escape[2:], 16) |
| 400 | chr(c) # raise ValueError for invalid code |
| 401 | return LITERAL, c |
| 402 | elif c == "N" and source.istext: |
| 403 | import unicodedata |
| 404 | # named unicode escape e.g. \N{EM DASH} |
| 405 | if not source.match('{'): |
| 406 | raise source.error("missing {") |
| 407 | charname = source.getuntil('}', 'character name') |
| 408 | try: |
| 409 | c = ord(unicodedata.lookup(charname)) |
| 410 | except (KeyError, TypeError): |
| 411 | raise source.error("undefined character name %r" % charname, |
| 412 | len(charname) + len(r'\N{}')) from None |
| 413 | return LITERAL, c |
| 414 | elif c == "0": |
| 415 | # octal escape |
| 416 | escape += source.getwhile(2, OCTDIGITS) |
| 417 | return LITERAL, int(escape[1:], 8) |
| 418 | elif c in DIGITS: |
| 419 | # octal escape *or* decimal group reference (sigh) |
| 420 | if source.next in DIGITS: |
| 421 | escape += source.get() |
| 422 | if (escape[1] in OCTDIGITS and escape[2] in OCTDIGITS and |
| 423 | source.next in OCTDIGITS): |
| 424 | # got three octal digits; this is an octal escape |
| 425 | escape += source.get() |
| 426 | c = int(escape[1:], 8) |
| 427 | if c > 0o377: |
| 428 | raise source.error('octal escape value %s outside of ' |
| 429 | 'range 0-0o377' % escape, |
no test coverage detected
searching dependent graphs…