Commit 2e3bcd4b authored by Stefan Behnel's avatar Stefan Behnel

merge

parents 3c52162e adc5a3ea
...@@ -108,8 +108,8 @@ class Context(object): ...@@ -108,8 +108,8 @@ class Context(object):
from ParseTreeTransforms import InterpretCompilerDirectives, TransformBuiltinMethods from ParseTreeTransforms import InterpretCompilerDirectives, TransformBuiltinMethods
from ParseTreeTransforms import ExpandInplaceOperators, ParallelRangeTransform from ParseTreeTransforms import ExpandInplaceOperators, ParallelRangeTransform
from TypeInference import MarkAssignments, MarkOverflowingArithmetic from TypeInference import MarkAssignments, MarkOverflowingArithmetic
from ParseTreeTransforms import AlignFunctionDefinitions, GilCheck from ParseTreeTransforms import AdjustDefByDirectives, AlignFunctionDefinitions
from ParseTreeTransforms import RemoveUnreachableCode from ParseTreeTransforms import RemoveUnreachableCode, GilCheck
from AnalysedTreeTransforms import AutoTestDictTransform from AnalysedTreeTransforms import AutoTestDictTransform
from AutoDocTransforms import EmbedSignature from AutoDocTransforms import EmbedSignature
from Optimize import FlattenInListTransform, SwitchTransform, IterationTransform from Optimize import FlattenInListTransform, SwitchTransform, IterationTransform
...@@ -137,6 +137,8 @@ class Context(object): ...@@ -137,6 +137,8 @@ class Context(object):
_specific_post_parse, _specific_post_parse,
InterpretCompilerDirectives(self, self.compiler_directives), InterpretCompilerDirectives(self, self.compiler_directives),
ParallelRangeTransform(self), ParallelRangeTransform(self),
AdjustDefByDirectives(self),
_align_function_definitions,
MarkClosureVisitor(self), MarkClosureVisitor(self),
_align_function_definitions, _align_function_definitions,
RemoveUnreachableCode(self), RemoveUnreachableCode(self),
......
...@@ -557,6 +557,9 @@ class CFuncDeclaratorNode(CDeclaratorNode): ...@@ -557,6 +557,9 @@ class CFuncDeclaratorNode(CDeclaratorNode):
if name_declarator.cname: if name_declarator.cname:
error(self.pos, error(self.pos,
"Function argument cannot have C name specification") "Function argument cannot have C name specification")
if i==0 and env.is_c_class_scope and type.is_unspecified:
# fix the type of self
type = env.parent_type
# Turn *[] argument into ** # Turn *[] argument into **
if type.is_array: if type.is_array:
type = PyrexTypes.c_ptr_type(type.base_type) type = PyrexTypes.c_ptr_type(type.base_type)
...@@ -945,15 +948,6 @@ class CVarDefNode(StatNode): ...@@ -945,15 +948,6 @@ class CVarDefNode(StatNode):
dest_scope = env dest_scope = env
self.dest_scope = dest_scope self.dest_scope = dest_scope
base_type = self.base_type.analyse(env) base_type = self.base_type.analyse(env)
# If the field is an external typedef, we cannot be sure about the type,
# so do conversion ourself rather than rely on the CPython mechanism (through
# a property; made in AnalyseDeclarationsTransform).
if (dest_scope.is_c_class_scope
and self.visibility in ('public', 'readonly')):
need_property = True
else:
need_property = False
visibility = self.visibility visibility = self.visibility
for declarator in self.declarators: for declarator in self.declarators:
...@@ -987,7 +981,6 @@ class CVarDefNode(StatNode): ...@@ -987,7 +981,6 @@ class CVarDefNode(StatNode):
"Only 'extern' C variable declaration allowed in .pxd file") "Only 'extern' C variable declaration allowed in .pxd file")
entry = dest_scope.declare_var(name, type, declarator.pos, entry = dest_scope.declare_var(name, type, declarator.pos,
cname=cname, visibility=visibility, api=self.api, is_cdef=1) cname=cname, visibility=visibility, api=self.api, is_cdef=1)
entry.needs_property = need_property
class CStructOrUnionDefNode(StatNode): class CStructOrUnionDefNode(StatNode):
...@@ -1970,7 +1963,7 @@ class DefNode(FuncDefNode): ...@@ -1970,7 +1963,7 @@ class DefNode(FuncDefNode):
self.num_required_kw_args = rk self.num_required_kw_args = rk
self.num_required_args = r self.num_required_args = r
def as_cfunction(self, cfunc=None, scope=None): def as_cfunction(self, cfunc=None, scope=None, overridable=True):
if self.star_arg: if self.star_arg:
error(self.star_arg.pos, "cdef function cannot have star argument") error(self.star_arg.pos, "cdef function cannot have star argument")
if self.starstar_arg: if self.starstar_arg:
...@@ -1990,7 +1983,7 @@ class DefNode(FuncDefNode): ...@@ -1990,7 +1983,7 @@ class DefNode(FuncDefNode):
exception_check = False, exception_check = False,
nogil = False, nogil = False,
with_gil = False, with_gil = False,
is_overridable = True) is_overridable = overridable)
cfunc = CVarDefNode(self.pos, type=cfunc_type) cfunc = CVarDefNode(self.pos, type=cfunc_type)
else: else:
if scope is None: if scope is None:
......
...@@ -112,6 +112,9 @@ directive_types = { ...@@ -112,6 +112,9 @@ directive_types = {
'final' : bool, # final cdef classes and methods 'final' : bool, # final cdef classes and methods
'internal' : bool, # cdef class visibility in the module dict 'internal' : bool, # cdef class visibility in the module dict
'infer_types' : bool, # values can be True/None/False 'infer_types' : bool, # values can be True/None/False
'cfunc' : None, # decorators do not take directive value
'ccall' : None,
'cclass' : None,
} }
for key, val in directive_defaults.items(): for key, val in directive_defaults.items():
......
...@@ -1612,6 +1612,58 @@ class ExpandInplaceOperators(EnvTransform): ...@@ -1612,6 +1612,58 @@ class ExpandInplaceOperators(EnvTransform):
# In-place assignments can't happen within an expression. # In-place assignments can't happen within an expression.
return node return node
class AdjustDefByDirectives(CythonTransform, SkipDeclarations):
"""
Adjust function and class definitions by the decorator directives:
@cython.cfunc
@cython.cclass
@cython.ccall
"""
def visit_ModuleNode(self, node):
self.directives = node.directives
self.in_py_class = False
self.visitchildren(node)
return node
def visit_CompilerDirectivesNode(self, node):
old_directives = self.directives
self.directives = node.directives
self.visitchildren(node)
self.directives = old_directives
return node
def visit_DefNode(self, node):
if 'ccall' in self.directives:
node = node.as_cfunction(overridable=True)
return self.visit(node)
if 'cfunc' in self.directives:
if self.in_py_class:
error(node.pos, "cfunc directive is not allowed here")
else:
node = node.as_cfunction(overridable=False)
return self.visit(node)
self.visitchildren(node)
return node
def visit_PyClassDefNode(self, node):
if 'cclass' in self.directives:
node = node.as_cclass()
return self.visit(node)
else:
old_in_pyclass = self.in_py_class
self.in_py_class = True
self.visitchildren(node)
self.in_py_class = old_in_pyclass
return node
def visit_CClassDefNode(self, node):
old_in_pyclass = self.in_py_class
self.in_py_class = False
self.visitchildren(node)
self.in_py_class = old_in_pyclass
return node
class AlignFunctionDefinitions(CythonTransform): class AlignFunctionDefinitions(CythonTransform):
""" """
......
...@@ -1750,7 +1750,7 @@ def p_statement(s, ctx, first_statement = 0): ...@@ -1750,7 +1750,7 @@ def p_statement(s, ctx, first_statement = 0):
elif s.sy == 'IF': elif s.sy == 'IF':
return p_IF_statement(s, ctx) return p_IF_statement(s, ctx)
elif s.sy == 'DECORATOR': elif s.sy == 'DECORATOR':
if ctx.level not in ('module', 'class', 'c_class', 'function', 'property', 'module_pxd', 'c_class_pxd'): if ctx.level not in ('module', 'class', 'c_class', 'function', 'property', 'module_pxd', 'c_class_pxd', 'other'):
s.error('decorator not allowed here') s.error('decorator not allowed here')
s.level = ctx.level s.level = ctx.level
decorators = p_decorators(s) decorators = p_decorators(s)
......
...@@ -1600,6 +1600,10 @@ class CClassScope(ClassScope): ...@@ -1600,6 +1600,10 @@ class CClassScope(ClassScope):
error(pos, error(pos,
"Attribute of extension type cannot be declared %s" % visibility) "Attribute of extension type cannot be declared %s" % visibility)
if visibility in ('public', 'readonly'): if visibility in ('public', 'readonly'):
# If the field is an external typedef, we cannot be sure about the type,
# so do conversion ourself rather than rely on the CPython mechanism (through
# a property; made in AnalyseDeclarationsTransform).
entry.needs_property = True
if name == "__weakref__": if name == "__weakref__":
error(pos, "Special attribute __weakref__ cannot be exposed to Python") error(pos, "Special attribute __weakref__ cannot be exposed to Python")
if not type.is_pyobject: if not type.is_pyobject:
...@@ -1608,6 +1612,8 @@ class CClassScope(ClassScope): ...@@ -1608,6 +1612,8 @@ class CClassScope(ClassScope):
type.create_from_py_utility_code(self))): type.create_from_py_utility_code(self))):
error(pos, error(pos,
"C attribute of type '%s' cannot be accessed from Python" % type) "C attribute of type '%s' cannot be accessed from Python" % type)
else:
entry.needs_property = False
return entry return entry
else: else:
if type is unspecified_type: if type is unspecified_type:
......
...@@ -26,6 +26,8 @@ class _EmptyDecoratorAndManager(object): ...@@ -26,6 +26,8 @@ class _EmptyDecoratorAndManager(object):
def __exit__(self, exc_type, exc_value, traceback): def __exit__(self, exc_type, exc_value, traceback):
pass pass
cclass = ccall = cfunc = _EmptyDecoratorAndManager()
def inline(f, *args, **kwds): def inline(f, *args, **kwds):
if isinstance(f, basestring): if isinstance(f, basestring):
from Cython.Build.Inline import cython_inline from Cython.Build.Inline import cython_inline
...@@ -301,4 +303,4 @@ class CythonDotParallel(object): ...@@ -301,4 +303,4 @@ class CythonDotParallel(object):
import sys import sys
sys.modules['cython.parallel'] = CythonDotParallel() sys.modules['cython.parallel'] = CythonDotParallel()
del sys del sys
\ No newline at end of file
...@@ -171,6 +171,7 @@ VER_DEP_MODULES = { ...@@ -171,6 +171,7 @@ VER_DEP_MODULES = {
'run.cython3', 'run.cython3',
'run.generators_py', # generators, with statement 'run.generators_py', # generators, with statement
'run.pure_py', # decorators, with statement 'run.pure_py', # decorators, with statement
'run.purecdef',
]), ]),
(2,7) : (operator.lt, lambda x: x in ['run.withstat_py', # multi context with statement (2,7) : (operator.lt, lambda x: x in ['run.withstat_py', # multi context with statement
]), ]),
......
class Pyclass(object):
cdef bad(self):
pass
_ERRORS = """
2:9: cdef statement not allowed here
"""
import cython
class Pyclass(object):
@cython.cfunc
def bad(self):
pass
_ERRORS = """
5:4: cfunc directive is not allowed here
"""
import cython
from cython import cfunc, cclass, ccall
@cython.test_assert_path_exists('//CFuncDefNode')
@cython.cfunc
def ftang():
x = 0
@cython.test_assert_path_exists('//CFuncDefNode')
@cfunc
def fpure(a):
return a*2
def test():
"""
>>> test()
4
"""
ftang()
return fpure(2)
with cfunc:
@cython.test_assert_path_exists('//CFuncDefNode')
def fwith1(a):
return a*3
@cython.test_assert_path_exists('//CFuncDefNode')
def fwith2(a):
return a*4
with cclass:
@cython.test_assert_path_exists('//CClassDefNode')
class Egg(object):
pass
@cython.test_assert_path_exists('//CClassDefNode')
class BigEgg(object):
@cython.test_assert_path_exists('//CFuncDefNode')
@cython.cfunc
def f(self, a):
return a*10
def test_with():
"""
>>> test_with()
(3, 4, 50)
"""
return fwith1(1), fwith2(1), BigEgg().f(5)
@cython.test_assert_path_exists('//CClassDefNode')
@cython.cclass
class PureFoo(object):
a = cython.declare(cython.double)
def __init__(self, a):
self.a = a
def __call__(self):
return self.a
@cython.test_assert_path_exists('//CFuncDefNode')
@cython.cfunc
def puremeth(self, a):
return a*2
def test_method():
"""
>>> test_method()
4
True
"""
x = PureFoo(2)
print(x.puremeth(2))
if cython.compiled:
print(isinstance(x(), float))
else:
print(True)
return
@cython.ccall
def ccall_sqr(x):
return x*x
@cclass
class Overidable(object):
@ccall
def meth(self):
return 0
def test_ccall():
"""
>>> test_ccall()
25
>>> ccall_sqr(5)
25
"""
return ccall_sqr(5)
def test_ccall_method(x):
"""
>>> test_ccall_method(Overidable())
0
>>> Overidable().meth()
0
>>> class Foo(Overidable):
... def meth(self):
... return 1
>>> test_ccall_method(Foo())
1
>>> Foo().meth()
1
"""
return x.meth()
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