Commit 53c0810f authored by Dag Sverre Seljebotn's avatar Dag Sverre Seljebotn

Give compiler error on cdef assignments in class bodies, more comments.

parent 689f6281
...@@ -33,6 +33,7 @@ class CompileError(PyrexError): ...@@ -33,6 +33,7 @@ class CompileError(PyrexError):
def __init__(self, position = None, message = ""): def __init__(self, position = None, message = ""):
self.position = position self.position = position
self.message_only = message self.message_only = message
self.reported = False
# Deprecated and withdrawn in 2.6: # Deprecated and withdrawn in 2.6:
# self.message = message # self.message = message
if position: if position:
...@@ -88,17 +89,23 @@ def close_listing_file(): ...@@ -88,17 +89,23 @@ def close_listing_file():
listing_file.close() listing_file.close()
listing_file = None listing_file = None
def error(position, message): def report_error(err):
#print "Errors.error:", repr(position), repr(message) ###
global num_errors global num_errors
err = CompileError(position, message) # See Main.py for why dual reporting occurs. Quick fix for now.
# if position is not None: raise Exception(err) # debug if err.reported: return
err.reported = True
line = "%s\n" % err line = "%s\n" % err
if listing_file: if listing_file:
listing_file.write(line) listing_file.write(line)
if echo_file: if echo_file:
echo_file.write(line) echo_file.write(line)
num_errors = num_errors + 1 num_errors = num_errors + 1
def error(position, message):
#print "Errors.error:", repr(position), repr(message) ###
err = CompileError(position, message)
# if position is not None: raise Exception(err) # debug
report_error(err)
return err return err
LEVEL=1 # warn about all errors level 1 or higher LEVEL=1 # warn about all errors level 1 or higher
......
...@@ -329,8 +329,9 @@ class Context: ...@@ -329,8 +329,9 @@ class Context:
try: try:
for phase in pipeline: for phase in pipeline:
data = phase(data) data = phase(data)
except CompileError: except CompileError, err:
errors_occurred = True errors_occurred = True
Errors.report_error(err)
return (errors_occurred, data) return (errors_occurred, data)
def create_parse(context): def create_parse(context):
......
...@@ -388,7 +388,7 @@ class CNameDeclaratorNode(CDeclaratorNode): ...@@ -388,7 +388,7 @@ class CNameDeclaratorNode(CDeclaratorNode):
self.default.release_temp(env) self.default.release_temp(env)
def generate_execution_code(self, code): def generate_execution_code(self, code):
assert self.default is None raise RuntimeError("Deprecated")
# PostParse creates assignment statements for any # PostParse creates assignment statements for any
# default values # default values
......
...@@ -82,6 +82,7 @@ ERR_BUF_DUP = '"%s" buffer option already supplied' ...@@ -82,6 +82,7 @@ ERR_BUF_DUP = '"%s" buffer option already supplied'
ERR_BUF_MISSING = '"%s" missing' ERR_BUF_MISSING = '"%s" missing'
ERR_BUF_INT = '"%s" must be an integer' ERR_BUF_INT = '"%s" must be an integer'
ERR_BUF_NONNEG = '"%s" must be non-negative' ERR_BUF_NONNEG = '"%s" must be non-negative'
ERR_CDEF_INCLASS = 'Cannot assign default value to cdef class attributes'
class PostParse(CythonTransform): class PostParse(CythonTransform):
""" """
...@@ -92,7 +93,8 @@ class PostParse(CythonTransform): ...@@ -92,7 +93,8 @@ class PostParse(CythonTransform):
Specifically: Specifically:
- Default values to cdef assignments are turned into single - Default values to cdef assignments are turned into single
assignments following the declaration. assignments following the declaration (everywhere but in class
bodies, where they raise a compile error)
- CBufferAccessTypeNode has its options interpreted: - CBufferAccessTypeNode has its options interpreted:
Any first positional argument goes into the "dtype" attribute, Any first positional argument goes into the "dtype" attribute,
any "ndim" keyword argument goes into the "ndim" attribute and any "ndim" keyword argument goes into the "ndim" attribute and
...@@ -103,9 +105,28 @@ class PostParse(CythonTransform): ...@@ -103,9 +105,28 @@ class PostParse(CythonTransform):
if a more pure Abstract Syntax Tree is wanted. if a more pure Abstract Syntax Tree is wanted.
""" """
# Track our context.
in_class_body = False
def visit_ClassDefNode(self, node):
prev = self.in_class_body
self.in_class_body = True
self.visitchildren(node)
self.in_class_body = prev
return node
def visit_FuncDefNode(self, node):
prev = self.in_class_body
self.in_class_body = False
self.visitchildren(node)
self.in_class_body = prev
return node
# cdef variables
def visit_CVarDefNode(self, node): def visit_CVarDefNode(self, node):
# This assumes only plain names and pointers are assignable on # This assumes only plain names and pointers are assignable on
# declaration. # declaration. Also, it makes use of the fact that a cdef decl
# must appear before the first use, so we don't have to deal with
# "i = 3; cdef int i = i" and can simply move the nodes around.
self.visitchildren(node) self.visitchildren(node)
stats = [node] stats = [node]
for decl in node.declarators: for decl in node.declarators:
...@@ -113,13 +134,15 @@ class PostParse(CythonTransform): ...@@ -113,13 +134,15 @@ class PostParse(CythonTransform):
decl = decl.base decl = decl.base
if isinstance(decl, CNameDeclaratorNode): if isinstance(decl, CNameDeclaratorNode):
if decl.default is not None: if decl.default is not None:
if self.in_class_body:
raise PostParseError(decl.pos, ERR_CDEF_INCLASS)
stats.append(SingleAssignmentNode(node.pos, stats.append(SingleAssignmentNode(node.pos,
lhs=NameNode(node.pos, name=decl.name), lhs=NameNode(node.pos, name=decl.name),
rhs=decl.default)) rhs=decl.default))
decl.default = None decl.default = None
return stats return stats
# buffer access
buffer_options = ("dtype", "ndim") # ordered! buffer_options = ("dtype", "ndim") # ordered!
def visit_CBufferAccessTypeNode(self, node): def visit_CBufferAccessTypeNode(self, node):
options = {} options = {}
......
cdef class A:
cdef int value = 3
_ERRORS = u"""
2:13: Cannot assign default value to cdef class attributes
"""
__doc__ = """ __doc__ = """
>>> test(1, 2) >>> test(1, 2)
4 1 2 2 0 4 1 2 2 0 7 8
>>> A().value
4
""" """
cdef class A: cdef int g = 7
cdef int value = 4
def test(x, int y): def test(x, int y):
if True: if True:
before = 0 before = 0
cdef int a = 4, b = x, c = y, *p = &y cdef int a = 4, b = x, c = y, *p = &y
print a, b, c, p[0], before cdef object o = int(8)
print a, b, c, p[0], before, g, o
# Also test that pruning cdefs doesn't hurt # Also test that pruning cdefs doesn't hurt
def empty(): def empty():
......
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