Commit 50133b5a authored by Robert Bradshaw's avatar Robert Bradshaw

Allow extern cpdef enum to export values into Python-level namespace.

parent 6a9c3fe9
...@@ -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
......
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