summaryrefslogtreecommitdiff
path: root/sphinx/pycode
diff options
context:
space:
mode:
authorGeorg Brandl <georg@python.org>2009-01-04 19:35:03 +0100
committerGeorg Brandl <georg@python.org>2009-01-04 19:35:03 +0100
commit686c154eea969fe7eecc4aec27d922d301be46fc (patch)
tree3f3e712cad6c04106141043717cfdedb98e65ac4 /sphinx/pycode
parent939e3f37d96e29c260244476caf60ee33c2761ed (diff)
downloadsphinx-686c154eea969fe7eecc4aec27d922d301be46fc.tar.gz
Support all types of string literals in literals.py.
Diffstat (limited to 'sphinx/pycode')
-rw-r--r--sphinx/pycode/pgen2/literals.py54
1 files changed, 44 insertions, 10 deletions
diff --git a/sphinx/pycode/pgen2/literals.py b/sphinx/pycode/pgen2/literals.py
index 0b3948a5..78667df0 100644
--- a/sphinx/pycode/pgen2/literals.py
+++ b/sphinx/pycode/pgen2/literals.py
@@ -1,6 +1,8 @@
# Copyright 2004-2005 Elemental Security, Inc. All Rights Reserved.
# Licensed to PSF under a Contributor Agreement.
+# Extended to handle raw and unicode literals by Georg Brandl.
+
"""Safely evaluate Python string literals without using eval()."""
import re
@@ -16,28 +18,60 @@ simple_escapes = {"a": "\a",
'"': '"',
"\\": "\\"}
+def convert_hex(x, n):
+ if len(x) < n+1:
+ raise ValueError("invalid hex string escape ('\\%s')" % x)
+ try:
+ return int(x[1:], 16)
+ except ValueError:
+ raise ValueError("invalid hex string escape ('\\%s')" % x)
+
def escape(m):
all, tail = m.group(0, 1)
assert all.startswith("\\")
esc = simple_escapes.get(tail)
if esc is not None:
return esc
- if tail.startswith("x"):
- hexes = tail[1:]
- if len(hexes) < 2:
- raise ValueError("invalid hex string escape ('\\%s')" % tail)
+ elif tail.startswith("x"):
+ return chr(convert_hex(tail, 2))
+ elif tail.startswith('u'):
+ return unichr(convert_hex(tail, 4))
+ elif tail.startswith('U'):
+ return unichr(convert_hex(tail, 8))
+ elif tail.startswith('N'):
+ import unicodedata
try:
- i = int(hexes, 16)
- except ValueError:
- raise ValueError("invalid hex string escape ('\\%s')" % tail)
+ return unicodedata.lookup(tail[1:-1])
+ except KeyError:
+ raise ValueError("undefined character name %r" % tail[1:-1])
else:
try:
- i = int(tail, 8)
+ return chr(int(tail, 8))
except ValueError:
raise ValueError("invalid octal string escape ('\\%s')" % tail)
- return chr(i)
+
+def escaperaw(m):
+ all, tail = m.group(0, 1)
+ if tail.startswith('u'):
+ return unichr(convert_hex(tail, 4))
+ elif tail.startswith('U'):
+ return unichr(convert_hex(tail, 8))
+ else:
+ return all
+
+escape_re = re.compile(r"\\(\'|\"|\\|[abfnrtv]|x.{0,2}|[0-7]{1,3})")
+uni_escape_re = re.compile(r"\\(\'|\"|\\|[abfnrtv]|x.{0,2}|[0-7]{1,3}|"
+ r"u[0-9a-fA-F]{0,4}|U[0-9a-fA-F]{0,8}|N\{.+?\})")
def evalString(s):
+ regex = escape_re
+ repl = escape
+ if s.startswith('u') or s.startswith('U'):
+ regex = uni_escape_re
+ s = s[1:]
+ if s.startswith('r') or s.startswith('R'):
+ repl = escaperaw
+ s = s[1:]
assert s.startswith("'") or s.startswith('"'), repr(s[:1])
q = s[0]
if s[:3] == q*3:
@@ -45,7 +79,7 @@ def evalString(s):
assert s.endswith(q), repr(s[-len(q):])
assert len(s) >= 2*len(q)
s = s[len(q):-len(q)]
- return re.sub(r"\\(\'|\"|\\|[abfnrtv]|x.{0,2}|[0-7]{1,3})", escape, s)
+ return regex.sub(repl, s)
def test():
for i in range(256):