Commit b4c2c4c2 authored by Robert Bradshaw's avatar Robert Bradshaw

Better integer literal parsing.

Now accepts U and LL suffixes, and large integer literals are longs rather than being truncated as Python objects.
parent ae9630e5
...@@ -646,13 +646,19 @@ class CharNode(ConstNode): ...@@ -646,13 +646,19 @@ class CharNode(ConstNode):
class IntNode(ConstNode): class IntNode(ConstNode):
# unsigned "" or "U"
# longness "" or "L" or "LL"
unsigned = ""
longness = ""
type = PyrexTypes.c_long_type type = PyrexTypes.c_long_type
def coerce_to(self, dst_type, env): def coerce_to(self, dst_type, env):
# Arrange for a Python version of the string to be pre-allocated # Arrange for a Python version of the string to be pre-allocated
# when coercing to a Python type. # when coercing to a Python type.
if dst_type.is_pyobject: if dst_type.is_pyobject:
self.entry = env.get_py_num(self.value) self.entry = env.get_py_num(self.value, self.longness)
self.type = PyrexTypes.py_object_type self.type = PyrexTypes.py_object_type
# We still need to perform normal coerce_to processing on the # We still need to perform normal coerce_to processing on the
# result, because we might be coercing to an extension type, # result, because we might be coercing to an extension type,
...@@ -663,7 +669,7 @@ class IntNode(ConstNode): ...@@ -663,7 +669,7 @@ class IntNode(ConstNode):
if self.type.is_pyobject: if self.type.is_pyobject:
return self.entry.cname return self.entry.cname
else: else:
return str(self.value) return str(self.value) + self.unsigned + self.longness
def compile_time_value(self, denv): def compile_time_value(self, denv):
return int(self.value, 0) return int(self.value, 0)
......
...@@ -27,7 +27,8 @@ def make_lexicon(): ...@@ -27,7 +27,8 @@ def make_lexicon():
name = letter + Rep(letter | digit) name = letter + Rep(letter | digit)
intconst = decimal | (Str("0x") + Rep1(hexdigit)) intconst = decimal | (Str("0x") + Rep1(hexdigit))
longconst = intconst + Str("L") intsuffix = (Opt(Any("Uu")) + Opt(Any("Ll")) + Opt(Any("Ll"))) | (Opt(Any("Ll")) + Opt(Any("Ll")) + Opt(Any("Uu")))
intliteral = intconst + intsuffix
fltconst = (decimal_fract + Opt(exponent)) | (decimal + exponent) fltconst = (decimal_fract + Opt(exponent)) | (decimal + exponent)
imagconst = (intconst | fltconst) + Any("jJ") imagconst = (intconst | fltconst) + Any("jJ")
...@@ -79,8 +80,7 @@ def make_lexicon(): ...@@ -79,8 +80,7 @@ def make_lexicon():
return Lexicon([ return Lexicon([
(name, 'IDENT'), (name, 'IDENT'),
(intconst, 'INT'), (intliteral, 'INT'),
(longconst, 'LONG'),
(fltconst, 'FLOAT'), (fltconst, 'FLOAT'),
(imagconst, 'IMAG'), (imagconst, 'IMAG'),
(deco, 'DECORATOR'), (deco, 'DECORATOR'),
......
...@@ -1718,10 +1718,16 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1718,10 +1718,16 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def generate_intern_code(self, env, code): def generate_intern_code(self, env, code):
for entry in env.pynum_entries: for entry in env.pynum_entries:
code.putln("%s = PyInt_FromLong(%s); %s;" % ( if entry.init[-1] == "L":
entry.cname, code.putln('%s = PyLong_FromString("%s", 0, 0); %s;' % (
entry.init, entry.cname,
code.error_goto_if_null(entry.cname, self.pos))) entry.init,
code.error_goto_if_null(entry.cname, self.pos)))
else:
code.putln("%s = PyInt_FromLong(%s); %s;" % (
entry.cname,
entry.init,
code.error_goto_if_null(entry.cname, self.pos)))
def generate_string_init_code(self, env, code): def generate_string_init_code(self, env, code):
if env.all_pystring_entries: if env.all_pystring_entries:
......
...@@ -466,11 +466,18 @@ def p_atom(s): ...@@ -466,11 +466,18 @@ def p_atom(s):
elif sy == 'INT': elif sy == 'INT':
value = s.systring value = s.systring
s.next() s.next()
return ExprNodes.IntNode(pos, value = value) unsigned = ""
elif sy == 'LONG': longness = ""
value = s.systring while value[-1] in "UuLl":
s.next() if value[-1] in "Ll":
return ExprNodes.LongNode(pos, value = value) longness += "L"
else:
unsigned += "U"
value = value[:-1]
return ExprNodes.IntNode(pos,
value = value,
unsigned = unsigned,
longness = longness)
elif sy == 'FLOAT': elif sy == 'FLOAT':
value = s.systring value = s.systring
s.next() s.next()
...@@ -516,7 +523,7 @@ def p_name(s, name): ...@@ -516,7 +523,7 @@ def p_name(s, name):
elif isinstance(value, int): elif isinstance(value, int):
return ExprNodes.IntNode(pos, value = rep) return ExprNodes.IntNode(pos, value = rep)
elif isinstance(value, long): elif isinstance(value, long):
return ExprNodes.LongNode(pos, value = rep) return ExprNodes.IntNode(pos, value = rep, longness = "L")
elif isinstance(value, float): elif isinstance(value, float):
return ExprNodes.FloatNode(pos, value = rep) return ExprNodes.FloatNode(pos, value = rep)
elif isinstance(value, unicode): elif isinstance(value, unicode):
......
...@@ -544,9 +544,11 @@ class Scope: ...@@ -544,9 +544,11 @@ class Scope:
self.interned_nums.append(entry) self.interned_nums.append(entry)
return entry return entry
def get_py_num(self, value): def get_py_num(self, value, longness):
# Get entry for int constant. Returns an existing # Get entry for int constant. Returns an existing
# one if possible, otherwise creates a new one. # one if possible, otherwise creates a new one.
if longness or Utils.long_literal(value):
value += "L"
genv = self.global_scope() genv = self.global_scope()
entry = genv.num_to_entry.get(value) entry = genv.num_to_entry.get(value)
if not entry: if not entry:
......
...@@ -115,3 +115,13 @@ def escape_byte_string(s): ...@@ -115,3 +115,13 @@ def escape_byte_string(s):
else: else:
append(c) append(c)
return ''.join(l) return ''.join(l)
def long_literal(value):
if isinstance(value, basestring):
if len(value) < 2:
value = int(value)
elif value[0] == 0:
return int(value, 8)
elif value[1] in 'xX':
return int(value[2:], 16)
return not -2**31 <= value < 2**31
__doc__ = """
>>> c_longs()
(1, 1L, -1L, 18446744073709551615L)
>>> py_longs()
(1, 1L, 100000000000000000000000000000000L, -100000000000000000000000000000000L)
"""
def c_longs():
cdef long a = 1L
cdef unsigned long ua = 1UL
cdef long long aa = 0xFFFFFFFFFFFFFFFFLL
cdef unsigned long long uaa = 0xFFFFFFFFFFFFFFFFULL
return a, ua, aa, uaa
def py_longs():
return 1, 1L, 100000000000000000000000000000000, -100000000000000000000000000000000
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment