Commit 3f83a9b3 authored by Stefan Behnel's avatar Stefan Behnel

merge

parents 329fe5e8 287b5d83
...@@ -757,8 +757,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -757,8 +757,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def generate_cfunction_predeclarations(self, env, code, definition): def generate_cfunction_predeclarations(self, env, code, definition):
for entry in env.cfunc_entries: for entry in env.cfunc_entries:
if not entry.in_cinclude and (definition if entry.inline_func_in_pxd or (not entry.in_cinclude and (definition
or entry.defined_in_pxd or entry.visibility == 'extern'): or entry.defined_in_pxd or entry.visibility == 'extern')):
if entry.visibility in ('public', 'extern'): if entry.visibility in ('public', 'extern'):
dll_linkage = "DL_EXPORT" dll_linkage = "DL_EXPORT"
else: else:
......
...@@ -1212,9 +1212,12 @@ class CFuncDefNode(FuncDefNode): ...@@ -1212,9 +1212,12 @@ class CFuncDefNode(FuncDefNode):
# type CFuncType # type CFuncType
# py_func wrapper for calling from Python # py_func wrapper for calling from Python
# overridable whether or not this is a cpdef function # overridable whether or not this is a cpdef function
# inline_in_pxd whether this is an inline function in a pxd file
child_attrs = ["base_type", "declarator", "body", "py_func"] child_attrs = ["base_type", "declarator", "body", "py_func"]
inline_in_pxd = False
def unqualified_name(self): def unqualified_name(self):
return self.entry.name return self.entry.name
...@@ -1251,6 +1254,7 @@ class CFuncDefNode(FuncDefNode): ...@@ -1251,6 +1254,7 @@ class CFuncDefNode(FuncDefNode):
cname = cname, visibility = self.visibility, cname = cname, visibility = self.visibility,
defining = self.body is not None, defining = self.body is not None,
api = self.api, modifiers = self.modifiers) api = self.api, modifiers = self.modifiers)
self.entry.inline_func_in_pxd = self.inline_in_pxd
self.return_type = type.return_type self.return_type = type.return_type
if self.overridable: if self.overridable:
......
...@@ -212,8 +212,12 @@ class PxdPostParse(CythonTransform): ...@@ -212,8 +212,12 @@ class PxdPostParse(CythonTransform):
- "def" functions are let through only if they fill the - "def" functions are let through only if they fill the
getbuffer/releasebuffer slots getbuffer/releasebuffer slots
- cdef functions are let through only if they are on the
top level and are declared "inline"
""" """
ERR_FUNCDEF_NOT_ALLOWED = 'function definition not allowed here' ERR_INLINE_ONLY = "function definition in pxd file must be declared 'cdef inline'"
ERR_NOGO_WITH_INLINE = "inline function definition in pxd file cannot be '%s'"
def __call__(self, node): def __call__(self, node):
self.scope_type = 'pxd' self.scope_type = 'pxd'
...@@ -229,31 +233,37 @@ class PxdPostParse(CythonTransform): ...@@ -229,31 +233,37 @@ class PxdPostParse(CythonTransform):
def visit_FuncDefNode(self, node): def visit_FuncDefNode(self, node):
# FuncDefNode always come with an implementation (without # FuncDefNode always come with an implementation (without
# an imp they are CVarDefNodes..) # an imp they are CVarDefNodes..)
ok = False err = self.ERR_INLINE_ONLY
if (isinstance(node, DefNode) and self.scope_type == 'cclass' if (isinstance(node, DefNode) and self.scope_type == 'cclass'
and node.name in ('__getbuffer__', '__releasebuffer__')): and node.name in ('__getbuffer__', '__releasebuffer__')):
ok = True err = None # allow these slots
if isinstance(node, CFuncDefNode): if isinstance(node, CFuncDefNode):
ok = True if u'inline' in node.modifiers and self.scope_type == 'pxd':
for stat in node.body.stats: node.inline_in_pxd = True
if not isinstance(stat, CVarDefNode): if node.visibility != 'private':
self.context.error("C function definition not allowed here") err = self.ERR_NOGO_WITH_INLINE % node.visibility
ok = False elif node.api:
break err = self.ERR_NOGO_WITH_INLINE % 'api'
node = CVarDefNode(node.pos, else:
visibility = node.visibility, err = None # allow inline function
base_type = node.base_type, else:
declarators = [node.declarator], err = None
in_pxd = True, for stat in node.body.stats:
api = node.api, if not isinstance(stat, CVarDefNode):
overridable = node.overridable, err = self.ERR_INLINE_ONLY
pxd_locals = node.body.stats) break
node = CVarDefNode(node.pos,
if not ok: visibility = node.visibility,
self.context.nonfatal_error(PostParseError(node.pos, base_type = node.base_type,
self.ERR_FUNCDEF_NOT_ALLOWED)) declarators = [node.declarator],
in_pxd = True,
api = node.api,
overridable = node.overridable,
pxd_locals = node.body.stats)
if err:
self.context.nonfatal_error(PostParseError(node.pos, err))
return None return None
else: else:
return node return node
......
...@@ -97,7 +97,10 @@ class Entry: ...@@ -97,7 +97,10 @@ class Entry:
# utility_code string Utility code needed when this entry is used # utility_code string Utility code needed when this entry is used
# #
# buffer_aux BufferAux or None Extra information needed for buffer variables # buffer_aux BufferAux or None Extra information needed for buffer variables
# inline_func_in_pxd boolean Hacky special case for inline function in pxd file.
# Ideally this should not be necesarry.
inline_func_in_pxd = False
borrowed = 0 borrowed = 0
init = "" init = ""
visibility = 'private' visibility = 'private'
......
...@@ -132,58 +132,9 @@ cdef extern from "numpy/arrayobject.h": ...@@ -132,58 +132,9 @@ cdef extern from "numpy/arrayobject.h":
return return
else: else:
info.format = <char*>stdlib.malloc(255) # static size info.format = <char*>stdlib.malloc(255) # static size
f = info.format f = _util_dtypestring(descr, info.format, info.format + 255)
stack = [iter(descr.fields.iteritems())] f[0] = 0 # Terminate format string
while True:
iterator = stack[-1]
descr = None
while descr is None:
try:
descr = iterator.next()[1][0]
except StopIteration:
stack.pop()
if len(stack) > 0:
f[0] = 125 #"}"
f += 1
iterator = stack[-1]
else:
f[0] = 0 # Terminate string!
return
hasfields = PyDataType_HASFIELDS(descr)
if not hasfields:
t = descr.type_num
if f - info.format > 240: # this should leave room for "T{" and "}" as well
raise RuntimeError("Format string allocated too short.")
# Until ticket #99 is fixed, use integers to avoid warnings
if t == NPY_BYTE: f[0] = 98 #"b"
elif t == NPY_UBYTE: f[0] = 66 #"B"
elif t == NPY_SHORT: f[0] = 104 #"h"
elif t == NPY_USHORT: f[0] = 72 #"H"
elif t == NPY_INT: f[0] = 105 #"i"
elif t == NPY_UINT: f[0] = 73 #"I"
elif t == NPY_LONG: f[0] = 108 #"l"
elif t == NPY_ULONG: f[0] = 76 #"L"
elif t == NPY_LONGLONG: f[0] = 113 #"q"
elif t == NPY_ULONGLONG: f[0] = 81 #"Q"
elif t == NPY_FLOAT: f[0] = 102 #"f"
elif t == NPY_DOUBLE: f[0] = 100 #"d"
elif t == NPY_LONGDOUBLE: f[0] = 103 #"g"
elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1
elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1
elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1
elif t == NPY_OBJECT: f[0] = 79 #"O"
else:
raise ValueError("unknown dtype code in numpy.pxd (%d)" % t)
f += 1
else:
f[0] = 84 #"T"
f[1] = 123 #"{"
f += 2
stack.append(iter(descr.fields.iteritems()))
def __releasebuffer__(ndarray self, Py_buffer* info): def __releasebuffer__(ndarray self, Py_buffer* info):
if PyArray_HASFIELDS(self): if PyArray_HASFIELDS(self):
stdlib.free(info.format) stdlib.free(info.format)
...@@ -292,3 +243,48 @@ ctypedef npy_longdouble longdouble_t ...@@ -292,3 +243,48 @@ ctypedef npy_longdouble longdouble_t
ctypedef npy_cfloat cfloat_t ctypedef npy_cfloat cfloat_t
ctypedef npy_cdouble cdouble_t ctypedef npy_cdouble cdouble_t
ctypedef npy_clongdouble clongdouble_t ctypedef npy_clongdouble clongdouble_t
cdef inline char* _util_dtypestring(dtype descr, char* f, char* end) except NULL:
# Recursive utility function used in __getbuffer__ to get format
# string. The new location in the format string is returned.
cdef dtype child
cdef tuple i
for i in descr.fields.itervalues():
child = i[0]
if not PyDataType_HASFIELDS(child):
t = child.type_num
if end - f < 15: # this should leave room for "T{" and "}" as well
raise RuntimeError("Format string allocated too short.")
# Until ticket #99 is fixed, use integers to avoid warnings
if t == NPY_BYTE: f[0] = 98 #"b"
elif t == NPY_UBYTE: f[0] = 66 #"B"
elif t == NPY_SHORT: f[0] = 104 #"h"
elif t == NPY_USHORT: f[0] = 72 #"H"
elif t == NPY_INT: f[0] = 105 #"i"
elif t == NPY_UINT: f[0] = 73 #"I"
elif t == NPY_LONG: f[0] = 108 #"l"
elif t == NPY_ULONG: f[0] = 76 #"L"
elif t == NPY_LONGLONG: f[0] = 113 #"q"
elif t == NPY_ULONGLONG: f[0] = 81 #"Q"
elif t == NPY_FLOAT: f[0] = 102 #"f"
elif t == NPY_DOUBLE: f[0] = 100 #"d"
elif t == NPY_LONGDOUBLE: f[0] = 103 #"g"
elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1
elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1
elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1
elif t == NPY_OBJECT: f[0] = 79 #"O"
else:
raise ValueError("unknown dtype code in numpy.pxd (%d)" % t)
f += 1
else:
f[0] = 84 #"T"
f[1] = 123 #"{"
f += 2
f = _util_dtypestring(child, f, end)
f[0] = 125 #"}"
f += 1
return f
cimport e_func_in_pxd_support
_ERRORS = u"""
1:5: function definition in pxd file must be declared 'cdef inline'
4:5: inline function definition in pxd file cannot be 'public'
7:5: inline function definition in pxd file cannot be 'api'
"""
cdef foo():
return 1
cdef public inline foo2():
return 1
cdef api inline foo3():
return 1
cdef inline int my_add(int a, int b):
return a + b
"""
>>> f()
3
>>> g()
6
>>> h()
6
"""
cimport inlinepxd_support
from inlinepxd_support cimport my_add as my_add3
def f():
return my_add(1, 2)
def g():
return inlinepxd_support.my_add(1, 2, 3)
def h():
return my_add3(1, 2, 3)
cdef inline int my_add(int a, int b, int c):
return a + b + c
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