Commit 42ac1407 authored by Stefan Behnel's avatar Stefan Behnel

merge

parents 5a3da515 9f0aec26
...@@ -9,6 +9,10 @@ Latest ...@@ -9,6 +9,10 @@ Latest
Features added Features added
-------------- --------------
* Enums can now be declared as cpdef to export their values to
the module's Python namespace. Cpdef enums in pxd files export
their values to their own module, iff it exists.
* Calls to ``slice()`` are translated to a straight C-API call. * Calls to ``slice()`` are translated to a straight C-API call.
* Taking a ``char*`` from a temporary Python string object is safer * Taking a ``char*`` from a temporary Python string object is safer
......
...@@ -2112,6 +2112,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -2112,6 +2112,11 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.body.generate_execution_code(code) self.body.generate_execution_code(code)
code.putln()
code.putln("/*--- Wrapped vars code ---*/")
self.generate_wrapped_entries_code(env, code)
code.putln()
if Options.generate_cleanup_code: if Options.generate_cleanup_code:
code.globalstate.use_utility_code( code.globalstate.use_utility_code(
UtilityCode.load_cached("RegisterModuleCleanup", "ModuleSetupCode.c")) UtilityCode.load_cached("RegisterModuleCleanup", "ModuleSetupCode.c"))
...@@ -2370,6 +2375,23 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -2370,6 +2375,23 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
if entry.used: if entry.used:
entry.type.global_init_code(entry, code) entry.type.global_init_code(entry, code)
def generate_wrapped_entries_code(self, env, code):
for name, entry in env.entries.items():
if entry.create_wrapper and not entry.is_type:
if not entry.type.create_to_py_utility_code(env):
error(entry.pos, "Cannot convert '%s' to Python object" % entry.type)
code.putln("{")
code.putln("PyObject* wrapped = %s(%s);" % (
entry.type.to_py_function,
entry.cname))
code.putln(code.error_goto_if_null("wrapped", entry.pos))
code.putln(
'if (__Pyx_SetAttrString(%s, "%s", wrapped) < 0) %s;' % (
env.module_cname,
name,
code.error_goto(entry.pos)))
code.putln("}")
def generate_c_variable_export_code(self, env, code): def generate_c_variable_export_code(self, env, code):
# Generate code to create PyCFunction wrappers for exported C functions. # Generate code to create PyCFunction wrappers for exported C functions.
entries = [] entries = []
......
...@@ -1424,9 +1424,10 @@ class CEnumDefNode(StatNode): ...@@ -1424,9 +1424,10 @@ class CEnumDefNode(StatNode):
# cname string or None # cname string or None
# items [CEnumDefItemNode] # items [CEnumDefItemNode]
# typedef_flag boolean # typedef_flag boolean
# visibility "public" or "private" # visibility "public" or "private" or "extern"
# api boolean # api boolean
# in_pxd boolean # in_pxd boolean
# create_wrapper boolean
# entry Entry # entry Entry
child_attrs = ["items"] child_attrs = ["items"]
...@@ -1434,7 +1435,8 @@ class CEnumDefNode(StatNode): ...@@ -1434,7 +1435,8 @@ class CEnumDefNode(StatNode):
def declare(self, env): def declare(self, env):
self.entry = env.declare_enum(self.name, self.pos, self.entry = env.declare_enum(self.name, self.pos,
cname = self.cname, typedef_flag = self.typedef_flag, cname = self.cname, typedef_flag = self.typedef_flag,
visibility = self.visibility, api = self.api) visibility = self.visibility, api = self.api,
create_wrapper = self.create_wrapper)
def analyse_declarations(self, env): def analyse_declarations(self, env):
if self.items is not None: if self.items is not None:
...@@ -1479,7 +1481,8 @@ class CEnumDefItemNode(StatNode): ...@@ -1479,7 +1481,8 @@ class CEnumDefItemNode(StatNode):
self.value = self.value.analyse_const_expression(env) self.value = self.value.analyse_const_expression(env)
entry = env.declare_const(self.name, enum_entry.type, entry = env.declare_const(self.name, enum_entry.type,
self.value, self.pos, cname = self.cname, self.value, self.pos, cname = self.cname,
visibility = enum_entry.visibility, api = enum_entry.api) visibility = enum_entry.visibility, api = enum_entry.api,
create_wrapper = enum_entry.create_wrapper)
enum_entry.enum_values.append(entry) enum_entry.enum_values.append(entry)
......
...@@ -2622,7 +2622,8 @@ def p_cdef_statement(s, ctx): ...@@ -2622,7 +2622,8 @@ def p_cdef_statement(s, ctx):
if ctx.level not in ('module', 'module_pxd'): if ctx.level not in ('module', 'module_pxd'):
error(pos, "C struct/union/enum definition not allowed here") error(pos, "C struct/union/enum definition not allowed here")
if ctx.overridable: if ctx.overridable:
error(pos, "C struct/union/enum cannot be declared cpdef") if s.systring != 'enum':
error(pos, "C struct/union cannot be declared cpdef")
return p_struct_enum(s, pos, ctx) return p_struct_enum(s, pos, ctx)
elif s.sy == 'IDENT' and s.systring == 'fused': elif s.sy == 'IDENT' and s.systring == 'fused':
return p_fused_definition(s, pos, ctx) return p_fused_definition(s, pos, ctx)
...@@ -2679,6 +2680,7 @@ def p_c_enum_definition(s, pos, ctx): ...@@ -2679,6 +2680,7 @@ def p_c_enum_definition(s, pos, ctx):
return Nodes.CEnumDefNode( return Nodes.CEnumDefNode(
pos, name = name, cname = cname, items = items, pos, name = name, cname = cname, items = items,
typedef_flag = ctx.typedef_flag, visibility = ctx.visibility, typedef_flag = ctx.typedef_flag, visibility = ctx.visibility,
create_wrapper = ctx.overridable,
api = ctx.api, in_pxd = ctx.level == 'module_pxd') api = ctx.api, in_pxd = ctx.level == 'module_pxd')
def p_c_enum_line(s, ctx, items): def p_c_enum_line(s, ctx, items):
......
...@@ -407,7 +407,7 @@ class Scope(object): ...@@ -407,7 +407,7 @@ class Scope(object):
""" Return the module-level scope containing this scope. """ """ Return the module-level scope containing this scope. """
return self.outer_scope.builtin_scope() return self.outer_scope.builtin_scope()
def declare(self, name, cname, type, pos, visibility, shadow = 0, is_type = 0): def declare(self, name, cname, type, pos, visibility, shadow = 0, is_type = 0, create_wrapper = 0):
# Create new entry, and add to dictionary if # Create new entry, and add to dictionary if
# name is not None. Reports a warning if already # name is not None. Reports a warning if already
# declared. # declared.
...@@ -424,6 +424,7 @@ class Scope(object): ...@@ -424,6 +424,7 @@ class Scope(object):
error(pos, "'%s' redeclared " % name) error(pos, "'%s' redeclared " % name)
entry = Entry(name, cname, type, pos = pos) entry = Entry(name, cname, type, pos = pos)
entry.in_cinclude = self.in_cinclude entry.in_cinclude = self.in_cinclude
entry.create_wrapper = create_wrapper
if name: if name:
entry.qualified_name = self.qualify_name(name) entry.qualified_name = self.qualify_name(name)
# if name in entries and self.is_cpp(): # if name in entries and self.is_cpp():
...@@ -444,14 +445,14 @@ class Scope(object): ...@@ -444,14 +445,14 @@ class Scope(object):
def qualify_name(self, name): def qualify_name(self, name):
return EncodedString("%s.%s" % (self.qualified_name, name)) return EncodedString("%s.%s" % (self.qualified_name, name))
def declare_const(self, name, type, value, pos, cname = None, visibility = 'private', api = 0): def declare_const(self, name, type, value, pos, cname = None, visibility = 'private', api = 0, create_wrapper = 0):
# Add an entry for a named constant. # Add an entry for a named constant.
if not cname: if not cname:
if self.in_cinclude or (visibility == 'public' or api): if self.in_cinclude or (visibility == 'public' or api):
cname = name cname = name
else: else:
cname = self.mangle(Naming.enum_prefix, name) cname = self.mangle(Naming.enum_prefix, name)
entry = self.declare(name, cname, type, pos, visibility) entry = self.declare(name, cname, type, pos, visibility, create_wrapper = create_wrapper)
entry.is_const = 1 entry.is_const = 1
entry.value_node = value entry.value_node = value
return entry return entry
...@@ -588,7 +589,7 @@ class Scope(object): ...@@ -588,7 +589,7 @@ class Scope(object):
entry.name, entry.visibility)) entry.name, entry.visibility))
def declare_enum(self, name, pos, cname, typedef_flag, def declare_enum(self, name, pos, cname, typedef_flag,
visibility = 'private', api = 0): visibility = 'private', api = 0, create_wrapper = 0):
if name: if name:
if not cname: if not cname:
if self.in_cinclude or (visibility == 'public' or api): if self.in_cinclude or (visibility == 'public' or api):
...@@ -600,6 +601,7 @@ class Scope(object): ...@@ -600,6 +601,7 @@ class Scope(object):
type = PyrexTypes.c_anon_enum_type type = PyrexTypes.c_anon_enum_type
entry = self.declare_type(name, type, pos, cname = cname, entry = self.declare_type(name, type, pos, cname = cname,
visibility = visibility, api = api) visibility = visibility, api = api)
entry.create_wrapper = create_wrapper
entry.enum_values = [] entry.enum_values = []
self.sue_entries.append(entry) self.sue_entries.append(entry)
return entry return entry
......
...@@ -4,8 +4,19 @@ from posix.types cimport (blkcnt_t, blksize_t, dev_t, gid_t, ino_t, mode_t, ...@@ -4,8 +4,19 @@ from posix.types cimport (blkcnt_t, blksize_t, dev_t, gid_t, ino_t, mode_t,
cdef extern from "sys/stat.h" nogil: cdef extern from "sys/stat.h" nogil:
cdef struct struct_stat "stat": cdef struct struct_stat "stat":
dev_t st_dev dev_t st_dev
ino_t st_ino ino_t st_ino
mode_t st_mode
nlink_t st_nlink
uid_t st_uid
gid_t st_gid
dev_t st_rdev
off_t st_size
blksize_t st_blksize
blkcnt_t st_blocks
time_t st_atime
time_t st_mtime
time_t st_ctime
# POSIX prescribes including both <sys/stat.h> and <unistd.h> for these # POSIX prescribes including both <sys/stat.h> and <unistd.h> for these
cdef extern from "unistd.h" nogil: cdef extern from "unistd.h" nogil:
......
cdef extern from *:
cpdef enum ExternPxdEnum:
FOUR "4"
EIGHT "8"
cdef enum ExternSecretPxdEnum:
SIXTEEN "16"
cpdef enum PxdEnum:
RANK_0 = 11
RANK_1 = 37
RANK_2 = 389
cdef enum PxdSecretEnum:
RANK_3 = 5077
"""
>>> ONE, TEN, HUNDRED
(1, 10, 100)
>>> THOUSAND # doctest: +ELLIPSIS
Traceback (most recent call last):
NameError: ...name 'THOUSAND' is not defined
>>> TWO, THREE, FIVE
(2, 3, 5)
>>> SEVEN # doctest: +ELLIPSIS
Traceback (most recent call last):
NameError: ...name 'SEVEN' is not defined
>>> FOUR, EIGHT
(4, 8)
>>> SIXTEEN # doctest: +ELLIPSIS
Traceback (most recent call last):
NameError: ...name 'SIXTEEN' is not defined
>>> RANK_0, RANK_1, RANK_2
(11, 37, 389)
>>> RANK_3 # doctest: +ELLIPSIS
Traceback (most recent call last):
NameError: ...name 'RANK_3' is not defined
"""
cdef extern from *:
cpdef enum ExternPyxEnum:
ONE "1"
TEN "10"
HUNDRED "100"
cdef enum ExternSecretPyxEnum:
THOUSAND "1000"
cpdef enum PyxEnum:
TWO = 2
THREE = 3
FIVE = 5
cdef enum SecretPyxEnum:
SEVEN = 7
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