Commit 6a57acd5 authored by Vitja Makarov's avatar Vitja Makarov

Merge remote branch 'upstream/master' into ticket_668

parents 0b25d4b9 0a56c99d
...@@ -434,9 +434,12 @@ def create_extension_list(patterns, exclude=[], ctx=None, aliases=None): ...@@ -434,9 +434,12 @@ def create_extension_list(patterns, exclude=[], ctx=None, aliases=None):
for key, value in base.values.items(): for key, value in base.values.items():
if key not in kwds: if key not in kwds:
kwds[key] = value kwds[key] = value
sources = [file]
if template is not None:
sources += template.sources[1:]
module_list.append(exn_type( module_list.append(exn_type(
name=module_name, name=module_name,
sources=[file], sources=sources,
**kwds)) **kwds))
m = module_list[-1] m = module_list[-1]
seen.add(name) seen.add(name)
......
...@@ -26,12 +26,12 @@ class LinesResult(object): ...@@ -26,12 +26,12 @@ class LinesResult(object):
self.put(s) self.put(s)
self.newline() self.newline()
class CodeWriter(TreeVisitor): class DeclarationWriter(TreeVisitor):
indent_string = u" " indent_string = u" "
def __init__(self, result = None): def __init__(self, result = None):
super(CodeWriter, self).__init__() super(DeclarationWriter, self).__init__()
if result is None: if result is None:
result = LinesResult() result = LinesResult()
self.result = result self.result = result
...@@ -41,6 +41,7 @@ class CodeWriter(TreeVisitor): ...@@ -41,6 +41,7 @@ class CodeWriter(TreeVisitor):
def write(self, tree): def write(self, tree):
self.visit(tree) self.visit(tree)
return self.result
def indent(self): def indent(self):
self.numindents += 1 self.numindents += 1
...@@ -54,6 +55,9 @@ class CodeWriter(TreeVisitor): ...@@ -54,6 +55,9 @@ class CodeWriter(TreeVisitor):
def put(self, s): def put(self, s):
self.result.put(s) self.result.put(s)
def putline(self, s):
self.result.putline(self.indent_string * self.numindents + s)
def endline(self, s = u""): def endline(self, s = u""):
self.result.putline(s) self.result.putline(s)
...@@ -80,22 +84,44 @@ class CodeWriter(TreeVisitor): ...@@ -80,22 +84,44 @@ class CodeWriter(TreeVisitor):
def visit_StatListNode(self, node): def visit_StatListNode(self, node):
self.visitchildren(node) self.visitchildren(node)
def visit_FuncDefNode(self, node): def visit_CDefExternNode(self, node):
self.startline(u"def %s(" % node.name) if node.include_file is None:
self.comma_separated_list(node.args) file = u'*'
self.endline(u"):") else:
file = u'"%s"' % node.include_file
self.putline(u"cdef extern from %s:" % file)
self.indent() self.indent()
self.visit(node.body) self.visit(node.body)
self.dedent() self.dedent()
def visit_CArgDeclNode(self, node): def visit_CPtrDeclaratorNode(self, node):
if node.base_type.name is not None: self.put('*')
self.visit(node.base_type) self.visit(node.base)
self.put(u" ")
self.visit(node.declarator) def visit_CReferenceDeclaratorNode(self, node):
if node.default is not None: self.put('&')
self.put(u" = ") self.visit(node.base)
self.visit(node.default)
def visit_CArrayDeclaratorNode(self, node):
self.visit(node.base)
self.put(u'[')
if node.dimension is not None:
self.visit(node.dimension)
self.put(u']')
def visit_CArrayDeclaratorNode(self, node):
self.visit(node.base)
self.put(u'[')
if node.dimension is not None:
self.visit(node.dimension)
self.put(u']')
def visit_CFuncDeclaratorNode(self, node):
# TODO: except, gil, etc.
self.visit(node.base)
self.put(u'(')
self.comma_separated_list(node.args)
self.endline(u')')
def visit_CNameDeclaratorNode(self, node): def visit_CNameDeclaratorNode(self, node):
self.put(node.name) self.put(node.name)
...@@ -108,22 +134,149 @@ class CodeWriter(TreeVisitor): ...@@ -108,22 +134,149 @@ class CodeWriter(TreeVisitor):
self.put("short " * -node.longness) self.put("short " * -node.longness)
elif node.longness > 0: elif node.longness > 0:
self.put("long " * node.longness) self.put("long " * node.longness)
self.put(node.name)
def visit_CComplexBaseTypeNode(self, node):
self.put(u'(')
self.visit(node.base_type)
self.visit(node.declarator)
self.put(u')')
def visit_CNestedBaseTypeNode(self, node):
self.visit(node.base_type)
self.put(u'.')
self.put(node.name) self.put(node.name)
def visit_SingleAssignmentNode(self, node): def visit_TemplatedTypeNode(self, node):
self.startline() self.visit(node.base_type_node)
self.visit(node.lhs) self.put(u'[')
self.comma_separated_list(node.positional_args + node.keyword_args.key_value_pairs)
self.put(u']')
def visit_CVarDefNode(self, node):
self.startline(u"cdef ")
self.visit(node.base_type)
self.put(u" ")
self.comma_separated_list(node.declarators, output_rhs=True)
self.endline()
def visit_container_node(self, node, decl, extras, attributes):
# TODO: visibility
self.startline(decl)
if node.name:
self.put(u' ')
self.put(node.name)
if node.cname is not None:
self.put(u' "%s"' % node.cname)
if extras:
self.put(extras)
self.endline(':')
self.indent()
if not attributes:
self.putline('pass')
else:
for attribute in attributes:
self.visit(attribute)
self.dedent()
def visit_CStructOrUnionDefNode(self, node):
if node.typedef_flag:
decl = u'ctypedef '
else:
decl = u'cdef '
if node.visibility == 'public':
decl += u'public '
if node.packed:
decl += u'packed '
decl += node.kind
self.visit_container_node(node, decl, None, node.attributes)
def visit_CppClassNode(self, node):
extras = ""
if node.templates:
extras = u"[%s]" % ", ".join(node.templates)
if node.base_classes:
extras += "(%s)" % ", ".join(node.base_classes)
self.visit_container_node(node, u"cdef cppclass", extras, node.attributes)
def visit_CEnumDefNode(self, node):
self.visit_container_node(node, u"cdef enum", None, node.items)
def visit_CEnumDefItemNode(self, node):
self.startline(node.name)
if node.cname:
self.put(u' "%s"' % node.cname)
if node.value:
self.put(u" = ") self.put(u" = ")
self.visit(node.rhs) self.visit(node.value)
self.endline() self.endline()
def visit_CascadedAssignmentNode(self, node): def visit_CClassDefNode(self, node):
self.startline() assert not node.module_name
for lhs in node.lhs_list: if node.decorators:
self.visit(lhs) for decorator in node.decorators:
self.visit(decorator)
self.startline(u"cdef class ")
self.put(node.class_name)
if node.base_class_name:
self.put(u"(")
if node.base_class_module:
self.put(node.base_class_module)
self.put(u".")
self.put(node.base_class_name)
self.put(u")")
self.endline(u":")
self.indent()
self.visit(node.body)
self.dedent()
def visit_CTypeDefNode(self, node):
self.startline(u"ctypedef ")
self.visit(node.base_type)
self.put(u" ")
self.visit(node.declarator)
self.endline()
def visit_FuncDefNode(self, node):
self.startline(u"def %s(" % node.name)
self.comma_separated_list(node.args)
self.endline(u"):")
self.indent()
self.visit(node.body)
self.dedent()
def visit_CArgDeclNode(self, node):
if node.base_type.name is not None:
self.visit(node.base_type)
self.put(u" ")
self.visit(node.declarator)
if node.default is not None:
self.put(u" = ") self.put(u" = ")
self.visit(node.rhs) self.visit(node.default)
def visit_CImportStatNode(self, node):
self.startline(u"cimport ")
self.put(node.module_name)
if node.as_name:
self.put(u" as ")
self.put(node.as_name)
self.endline()
def visit_FromCImportStatNode(self, node):
self.startline(u"from ")
self.put(node.module_name)
self.put(u" cimport ")
first = True
for pos, name, as_name, kind in node.imported_names:
assert kind is None
if first:
first = False
else:
self.put(u", ")
self.put(name)
if as_name:
self.put(u" as ")
self.put(as_name)
self.endline() self.endline()
def visit_NameNode(self, node): def visit_NameNode(self, node):
...@@ -132,6 +285,31 @@ class CodeWriter(TreeVisitor): ...@@ -132,6 +285,31 @@ class CodeWriter(TreeVisitor):
def visit_IntNode(self, node): def visit_IntNode(self, node):
self.put(node.value) self.put(node.value)
def visit_NoneNode(self, node):
self.put(u"None")
def visit_NotNode(self, node):
self.put(u"(not ")
self.visit(node.operand)
self.put(u")")
def visit_DecoratorNode(self, node):
self.startline("@")
self.visit(node.decorator)
self.endline()
def visit_BinopNode(self, node):
self.visit(node.operand1)
self.put(u" %s " % node.operator)
self.visit(node.operand2)
def visit_AttributeNode(self, node):
self.visit(node.obj)
self.put(u".%s" % node.attribute)
def visit_BoolNode(self, node):
self.put(str(node.value))
# FIXME: represent string nodes correctly # FIXME: represent string nodes correctly
def visit_StringNode(self, node): def visit_StringNode(self, node):
value = node.value value = node.value
...@@ -139,32 +317,27 @@ class CodeWriter(TreeVisitor): ...@@ -139,32 +317,27 @@ class CodeWriter(TreeVisitor):
value = value.encode(value.encoding) value = value.encode(value.encoding)
self.put(repr(value)) self.put(repr(value))
def visit_IfStatNode(self, node):
# The IfClauseNode is handled directly without a seperate match
# for clariy.
self.startline(u"if ")
self.visit(node.if_clauses[0].condition)
self.endline(":")
self.indent()
self.visit(node.if_clauses[0].body)
self.dedent()
for clause in node.if_clauses[1:]:
self.startline("elif ")
self.visit(clause.condition)
self.endline(":")
self.indent()
self.visit(clause.body)
self.dedent()
if node.else_clause is not None:
self.line("else:")
self.indent()
self.visit(node.else_clause)
self.dedent()
def visit_PassStatNode(self, node): def visit_PassStatNode(self, node):
self.startline(u"pass") self.startline(u"pass")
self.endline() self.endline()
class CodeWriter(DeclarationWriter):
def visit_SingleAssignmentNode(self, node):
self.startline()
self.visit(node.lhs)
self.put(u" = ")
self.visit(node.rhs)
self.endline()
def visit_CascadedAssignmentNode(self, node):
self.startline()
for lhs in node.lhs_list:
self.visit(lhs)
self.put(u" = ")
self.visit(node.rhs)
self.endline()
def visit_PrintStatNode(self, node): def visit_PrintStatNode(self, node):
self.startline(u"print ") self.startline(u"print ")
self.comma_separated_list(node.arg_tuple.args) self.comma_separated_list(node.arg_tuple.args)
...@@ -172,18 +345,6 @@ class CodeWriter(TreeVisitor): ...@@ -172,18 +345,6 @@ class CodeWriter(TreeVisitor):
self.put(u",") self.put(u",")
self.endline() self.endline()
def visit_BinopNode(self, node):
self.visit(node.operand1)
self.put(u" %s " % node.operator)
self.visit(node.operand2)
def visit_CVarDefNode(self, node):
self.startline(u"cdef ")
self.visit(node.base_type)
self.put(u" ")
self.comma_separated_list(node.declarators, output_rhs=True)
self.endline()
def visit_ForInStatNode(self, node): def visit_ForInStatNode(self, node):
self.startline(u"for ") self.startline(u"for ")
self.visit(node.target) self.visit(node.target)
...@@ -199,6 +360,28 @@ class CodeWriter(TreeVisitor): ...@@ -199,6 +360,28 @@ class CodeWriter(TreeVisitor):
self.visit(node.else_clause) self.visit(node.else_clause)
self.dedent() self.dedent()
def visit_IfStatNode(self, node):
# The IfClauseNode is handled directly without a seperate match
# for clariy.
self.startline(u"if ")
self.visit(node.if_clauses[0].condition)
self.endline(":")
self.indent()
self.visit(node.if_clauses[0].body)
self.dedent()
for clause in node.if_clauses[1:]:
self.startline("elif ")
self.visit(clause.condition)
self.endline(":")
self.indent()
self.visit(clause.body)
self.dedent()
if node.else_clause is not None:
self.line("else:")
self.indent()
self.visit(node.else_clause)
self.dedent()
def visit_SequenceNode(self, node): def visit_SequenceNode(self, node):
self.comma_separated_list(node.args) # Might need to discover whether we need () around tuples...hmm... self.comma_separated_list(node.args) # Might need to discover whether we need () around tuples...hmm...
...@@ -244,13 +427,6 @@ class CodeWriter(TreeVisitor): ...@@ -244,13 +427,6 @@ class CodeWriter(TreeVisitor):
self.visit(node.body) self.visit(node.body)
self.dedent() self.dedent()
def visit_AttributeNode(self, node):
self.visit(node.obj)
self.put(u".%s" % node.attribute)
def visit_BoolNode(self, node):
self.put(str(node.value))
def visit_TryFinallyStatNode(self, node): def visit_TryFinallyStatNode(self, node):
self.line(u"try:") self.line(u"try:")
self.indent() self.indent()
...@@ -289,25 +465,12 @@ class CodeWriter(TreeVisitor): ...@@ -289,25 +465,12 @@ class CodeWriter(TreeVisitor):
self.visit(node.value) self.visit(node.value)
self.endline() self.endline()
def visit_DecoratorNode(self, node):
self.startline("@")
self.visit(node.decorator)
self.endline()
def visit_ReraiseStatNode(self, node): def visit_ReraiseStatNode(self, node):
self.line("raise") self.line("raise")
def visit_NoneNode(self, node):
self.put(u"None")
def visit_ImportNode(self, node): def visit_ImportNode(self, node):
self.put(u"(import %s)" % node.module_name.value) self.put(u"(import %s)" % node.module_name.value)
def visit_NotNode(self, node):
self.put(u"(not ")
self.visit(node.operand)
self.put(u")")
def visit_TempsBlockNode(self, node): def visit_TempsBlockNode(self, node):
""" """
Temporaries are output like $1_1', where the first number is Temporaries are output like $1_1', where the first number is
...@@ -323,3 +486,28 @@ class CodeWriter(TreeVisitor): ...@@ -323,3 +486,28 @@ class CodeWriter(TreeVisitor):
def visit_TempRefNode(self, node): def visit_TempRefNode(self, node):
self.put(self.tempnames[node.handle]) self.put(self.tempnames[node.handle])
class PxdWriter(DeclarationWriter):
def __call__(self, node):
print u'\n'.join(self.write(node).lines)
return node
def visit_CFuncDefNode(self, node):
if 'inline' in node.modifiers:
return
if node.overridable:
self.startline(u'cpdef ')
else:
self.startline(u'cdef ')
if node.visibility != 'private':
self.put(node.visibility)
self.put(u' ')
if node.api:
self.put(u'api ')
self.visit(node.declarator)
def visit_StatNode(self, node):
pass
\ No newline at end of file
...@@ -650,17 +650,27 @@ class GlobalState(object): ...@@ -650,17 +650,27 @@ class GlobalState(object):
if self.should_declare(entry.cname, entry): if self.should_declare(entry.cname, entry):
self.put_pyobject_decl(entry) self.put_pyobject_decl(entry)
w = self.parts['cached_builtins'] w = self.parts['cached_builtins']
conditional_name = False
if entry.name == 'xrange': if entry.name == 'xrange':
# replaced by range() in Py3 # replaced by range() in Py3
conditional_name = True
w.putln('#if PY_MAJOR_VERSION >= 3') w.putln('#if PY_MAJOR_VERSION >= 3')
self.put_cached_builtin_init( self.put_cached_builtin_init(
entry.pos, StringEncoding.EncodedString('range'), entry.pos, StringEncoding.EncodedString('range'),
entry.cname) entry.cname)
elif entry.name == 'BaseException':
# replace BaseException by Exception in Py<2.5
conditional_name = True
w.putln('#if PY_VERSION_HEX < 0x02050000')
self.put_cached_builtin_init(
entry.pos, StringEncoding.EncodedString('Exception'),
entry.cname)
if conditional_name:
w.putln('#else') w.putln('#else')
self.put_cached_builtin_init( self.put_cached_builtin_init(
entry.pos, StringEncoding.EncodedString(entry.name), entry.pos, StringEncoding.EncodedString(entry.name),
entry.cname) entry.cname)
if entry.name == 'xrange': if conditional_name:
w.putln('#endif') w.putln('#endif')
def put_cached_builtin_init(self, pos, name, cname): def put_cached_builtin_init(self, pos, name, cname):
......
...@@ -861,9 +861,8 @@ class IntNode(ConstNode): ...@@ -861,9 +861,8 @@ class IntNode(ConstNode):
return self return self
elif dst_type.is_float: elif dst_type.is_float:
if self.constant_result is not not_a_constant: if self.constant_result is not not_a_constant:
float_value = float(self.constant_result) return FloatNode(self.pos, value='%d.0' % int(self.constant_result), type=dst_type,
return FloatNode(self.pos, value=repr(float_value), type=dst_type, constant_result=float(self.constant_result))
constant_result=float_value)
else: else:
return FloatNode(self.pos, value=self.value, type=dst_type, return FloatNode(self.pos, value=self.value, type=dst_type,
constant_result=not_a_constant) constant_result=not_a_constant)
...@@ -3054,7 +3053,11 @@ class SimpleCallNode(CallNode): ...@@ -3054,7 +3053,11 @@ class SimpleCallNode(CallNode):
# nogil anyway) # nogil anyway)
pass pass
else: else:
self.args[i] = arg.coerce_to_temp(env) #self.args[i] = arg.coerce_to_temp(env)
# instead: issue a warning
if i > 0 or i == 1 and self.self is not None: # skip first arg
warning(arg.pos, "Argument evaluation order in C function call is undefined and may not be as expected", 0)
break
# Calc result type and code fragment # Calc result type and code fragment
if isinstance(self.function, NewExprNode): if isinstance(self.function, NewExprNode):
self.type = PyrexTypes.CPtrType(self.function.class_type) self.type = PyrexTypes.CPtrType(self.function.class_type)
......
...@@ -96,14 +96,16 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -96,14 +96,16 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
f.close() f.close()
def generate_h_code(self, env, options, result): def generate_h_code(self, env, options, result):
def h_entries(entries, pxd = 0): def h_entries(entries, api=0, pxd=0):
return [entry for entry in entries return [entry for entry in entries
if entry.visibility == 'public' or pxd and entry.defined_in_pxd] if ((entry.visibility == 'public') or
h_types = h_entries(env.type_entries) (api and entry.api) or
(pxd and entry.defined_in_pxd))]
h_types = h_entries(env.type_entries, api=1)
h_vars = h_entries(env.var_entries) h_vars = h_entries(env.var_entries)
h_funcs = h_entries(env.cfunc_entries) h_funcs = h_entries(env.cfunc_entries)
h_extension_types = h_entries(env.c_class_entries) h_extension_types = h_entries(env.c_class_entries)
if h_types or h_vars or h_funcs or h_extension_types: if (h_types or h_vars or h_funcs or h_extension_types):
result.h_file = replace_suffix(result.c_file, ".h") result.h_file = replace_suffix(result.c_file, ".h")
h_code = Code.CCodeWriter() h_code = Code.CCodeWriter()
Code.GlobalState(h_code) Code.GlobalState(h_code)
...@@ -112,32 +114,40 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -112,32 +114,40 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
i_code = Code.PyrexCodeWriter(result.i_file) i_code = Code.PyrexCodeWriter(result.i_file)
else: else:
i_code = None i_code = None
guard = Naming.h_guard_prefix + env.qualified_name.replace(".", "__")
h_code.put_h_guard(guard) h_guard = Naming.h_guard_prefix + self.api_name(env)
self.generate_extern_c_macro_definition(h_code) h_code.put_h_guard(h_guard)
h_code.putln("")
self.generate_type_header_code(h_types, h_code) self.generate_type_header_code(h_types, h_code)
h_code.putln("") h_code.putln("")
h_code.putln("#ifndef %s" % Naming.api_guard_prefix + self.api_name(env)) api_guard = Naming.api_guard_prefix + self.api_name(env)
if h_vars: h_code.putln("#ifndef %s" % api_guard)
h_code.putln("") h_code.putln("")
for entry in h_vars: self.generate_extern_c_macro_definition(h_code)
self.generate_public_declaration(entry, h_code, i_code)
if h_funcs:
h_code.putln("")
for entry in h_funcs:
self.generate_public_declaration(entry, h_code, i_code)
if h_extension_types: if h_extension_types:
h_code.putln("") h_code.putln("")
for entry in h_extension_types: for entry in h_extension_types:
self.generate_cclass_header_code(entry.type, h_code) self.generate_cclass_header_code(entry.type, h_code)
if i_code: if i_code:
self.generate_cclass_include_code(entry.type, i_code) self.generate_cclass_include_code(entry.type, i_code)
if h_funcs:
h_code.putln("") h_code.putln("")
h_code.putln("#endif") for entry in h_funcs:
self.generate_public_declaration(entry, h_code, i_code)
if h_vars:
h_code.putln("") h_code.putln("")
h_code.putln("PyMODINIT_FUNC init%s(void);" % env.module_name) for entry in h_vars:
self.generate_public_declaration(entry, h_code, i_code)
h_code.putln("")
h_code.putln("#endif /* !%s */" % api_guard)
h_code.putln("") h_code.putln("")
h_code.putln("#if PY_MAJOR_VERSION < 3")
h_code.putln("PyMODINIT_FUNC init%s(void);" % env.module_name)
h_code.putln("#else")
h_code.putln("PyMODINIT_FUNC PyInit_%s(void);" % env.module_name)
h_code.putln("#endif") h_code.putln("#endif")
h_code.putln("")
h_code.putln("#endif /* !%s */" % h_guard)
f = open_new_file(result.h_file) f = open_new_file(result.h_file)
try: try:
...@@ -158,63 +168,68 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -158,63 +168,68 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
return env.qualified_name.replace(".", "__") return env.qualified_name.replace(".", "__")
def generate_api_code(self, env, result): def generate_api_code(self, env, result):
api_funcs = [] def api_entries(entries, pxd=1):
public_extension_types = [] return [entry for entry in entries
has_api_extension_types = 0 if entry.api or (pxd and entry.defined_in_pxd)]
for entry in env.cfunc_entries: api_vars = api_entries(env.var_entries)
if entry.api: api_funcs = api_entries(env.cfunc_entries)
api_funcs.append(entry) api_extension_types = api_entries(env.c_class_entries)
for entry in env.c_class_entries: if api_vars or api_funcs or api_extension_types:
if entry.visibility == 'public':
public_extension_types.append(entry)
if entry.api:
has_api_extension_types = 1
if api_funcs or has_api_extension_types:
result.api_file = replace_suffix(result.c_file, "_api.h") result.api_file = replace_suffix(result.c_file, "_api.h")
h_code = Code.CCodeWriter() h_code = Code.CCodeWriter()
Code.GlobalState(h_code) Code.GlobalState(h_code)
name = self.api_name(env) api_guard = Naming.api_guard_prefix + self.api_name(env)
guard = Naming.api_guard_prefix + name h_code.put_h_guard(api_guard)
h_code.put_h_guard(guard)
h_code.putln('#include "Python.h"') h_code.putln('#include "Python.h"')
if result.h_file: if result.h_file:
h_code.putln('#include "%s"' % os.path.basename(result.h_file)) h_code.putln('#include "%s"' % os.path.basename(result.h_file))
for entry in public_extension_types: if api_extension_types:
type = entry.type
h_code.putln("") h_code.putln("")
h_code.putln("static PyTypeObject *%s;" % type.typeptr_cname) for entry in api_extension_types:
type = entry.type
h_code.putln("static PyTypeObject *%s = 0;" % type.typeptr_cname)
h_code.putln("#define %s (*%s)" % ( h_code.putln("#define %s (*%s)" % (
type.typeobj_cname, type.typeptr_cname)) type.typeobj_cname, type.typeptr_cname))
if api_funcs: if api_funcs:
h_code.putln("") h_code.putln("")
for entry in api_funcs: for entry in api_funcs:
type = CPtrType(entry.type) type = CPtrType(entry.type)
h_code.putln("static %s;" % type.declaration_code(entry.cname)) cname = env.mangle(Naming.func_prefix, entry.name)
h_code.putln("static %s = 0;" % type.declaration_code(cname))
h_code.putln("#define %s %s" % (entry.name, cname))
if api_vars:
h_code.putln("") h_code.putln("")
h_code.put_h_guard(Naming.api_func_guard + "import_module") for entry in api_vars:
type = CPtrType(entry.type)
cname = env.mangle(Naming.var_prefix, entry.name)
h_code.putln("static %s = 0;" % type.declaration_code(cname))
h_code.putln("#define %s (*%s)" % (entry.name, cname))
h_code.put(import_module_utility_code.impl) h_code.put(import_module_utility_code.impl)
h_code.putln("") if api_vars:
h_code.putln("#endif") h_code.put(voidptr_import_utility_code.impl)
if api_funcs: if api_funcs:
h_code.putln("")
h_code.put(function_import_utility_code.impl) h_code.put(function_import_utility_code.impl)
if public_extension_types: if api_extension_types:
h_code.putln("")
h_code.put(type_import_utility_code.impl) h_code.put(type_import_utility_code.impl)
h_code.putln("") h_code.putln("")
h_code.putln("static int import_%s(void) {" % name) h_code.putln("static int import_%s(void) {" % self.api_name(env))
h_code.putln("PyObject *module = 0;") h_code.putln("PyObject *module = 0;")
h_code.putln('module = __Pyx_ImportModule("%s");' % env.qualified_name) h_code.putln('module = __Pyx_ImportModule("%s");' % env.qualified_name)
h_code.putln("if (!module) goto bad;") h_code.putln("if (!module) goto bad;")
for entry in api_funcs: for entry in api_funcs:
cname = env.mangle(Naming.func_prefix, entry.name)
sig = entry.type.signature_string() sig = entry.type.signature_string()
h_code.putln( h_code.putln(
'if (__Pyx_ImportFunction(module, "%s", (void (**)(void))&%s, "%s") < 0) goto bad;' % ( 'if (__Pyx_ImportFunction(module, "%s", (void (**)(void))&%s, "%s") < 0) goto bad;'
entry.name, % (entry.name, cname, sig))
entry.cname, for entry in api_vars:
sig)) cname = env.mangle(Naming.var_prefix, entry.name)
sig = entry.type.declaration_code("")
h_code.putln(
'if (__Pyx_ImportVoidPtr(module, "%s", (void **)&%s, "%s") < 0) goto bad;'
% (entry.name, cname, sig))
h_code.putln("Py_DECREF(module); module = 0;") h_code.putln("Py_DECREF(module); module = 0;")
for entry in public_extension_types: for entry in api_extension_types:
self.generate_type_import_call( self.generate_type_import_call(
entry.type, h_code, entry.type, h_code,
"if (!%s) goto bad;" % entry.type.typeptr_cname) "if (!%s) goto bad;" % entry.type.typeptr_cname)
...@@ -224,7 +239,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -224,7 +239,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
h_code.putln("return -1;") h_code.putln("return -1;")
h_code.putln("}") h_code.putln("}")
h_code.putln("") h_code.putln("")
h_code.putln("#endif") h_code.putln("#endif /* !%s */" % api_guard)
f = open_new_file(result.api_file) f = open_new_file(result.api_file)
try: try:
...@@ -233,8 +248,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -233,8 +248,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
f.close() f.close()
def generate_cclass_header_code(self, type, h_code): def generate_cclass_header_code(self, type, h_code):
h_code.putln("%s DL_IMPORT(PyTypeObject) %s;" % ( h_code.putln("%s %s %s;" % (
Naming.extern_c_macro, Naming.extern_c_macro,
PyrexTypes.public_decl("PyTypeObject", "DL_IMPORT"),
type.typeobj_cname)) type.typeobj_cname))
def generate_cclass_include_code(self, type, i_code): def generate_cclass_include_code(self, type, i_code):
...@@ -424,8 +440,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -424,8 +440,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.generate_objstruct_definition(type, code) self.generate_objstruct_definition(type, code)
for entry in vtabslot_list: for entry in vtabslot_list:
self.generate_objstruct_definition(entry.type, code) self.generate_objstruct_definition(entry.type, code)
self.generate_typeobj_predeclaration(entry, code)
for entry in vtab_list: for entry in vtab_list:
self.generate_typeobject_predeclaration(entry, code) self.generate_typeobj_predeclaration(entry, code)
self.generate_exttype_vtable_struct(entry, code) self.generate_exttype_vtable_struct(entry, code)
self.generate_exttype_vtabptr_declaration(entry, code) self.generate_exttype_vtabptr_declaration(entry, code)
...@@ -685,6 +702,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -685,6 +702,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("#define _USE_MATH_DEFINES") code.putln("#define _USE_MATH_DEFINES")
code.putln("#endif") code.putln("#endif")
code.putln("#include <math.h>") code.putln("#include <math.h>")
code.putln("#define %s" % Naming.h_guard_prefix + self.api_name(env))
code.putln("#define %s" % Naming.api_guard_prefix + self.api_name(env)) code.putln("#define %s" % Naming.api_guard_prefix + self.api_name(env))
self.generate_includes(env, cimported_modules, code) self.generate_includes(env, cimported_modules, code)
code.putln("") code.putln("")
...@@ -721,10 +739,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -721,10 +739,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def generate_extern_c_macro_definition(self, code): def generate_extern_c_macro_definition(self, code):
name = Naming.extern_c_macro name = Naming.extern_c_macro
code.putln("#ifdef __cplusplus") code.putln("#ifndef %s" % name)
code.putln('#define %s extern "C"' % name) code.putln(" #ifdef __cplusplus")
code.putln("#else") code.putln(' #define %s extern "C"' % name)
code.putln("#define %s extern" % name) code.putln(" #else")
code.putln(" #define %s extern" % name)
code.putln(" #endif")
code.putln("#endif") code.putln("#endif")
def generate_includes(self, env, cimported_modules, code): def generate_includes(self, env, cimported_modules, code):
...@@ -786,10 +806,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -786,10 +806,13 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def generate_typedef(self, entry, code): def generate_typedef(self, entry, code):
base_type = entry.type.typedef_base_type base_type = entry.type.typedef_base_type
if base_type.is_numeric: if base_type.is_numeric:
try:
writer = code.globalstate['numeric_typedefs'] writer = code.globalstate['numeric_typedefs']
except KeyError:
writer = code
else: else:
writer = code writer = code
writer.putln("") writer.mark_pos(entry.pos)
writer.putln("typedef %s;" % base_type.declaration_code(entry.cname)) writer.putln("typedef %s;" % base_type.declaration_code(entry.cname))
def sue_header_footer(self, type, kind, name): def sue_header_footer(self, type, kind, name):
...@@ -813,7 +836,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -813,7 +836,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.globalstate.use_utility_code(packed_struct_utility_code) code.globalstate.use_utility_code(packed_struct_utility_code)
header, footer = \ header, footer = \
self.sue_header_footer(type, kind, type.cname) self.sue_header_footer(type, kind, type.cname)
code.putln("")
if packed: if packed:
code.putln("#if defined(__SUNPRO_C)") code.putln("#if defined(__SUNPRO_C)")
code.putln(" #pragma pack(1)") code.putln(" #pragma pack(1)")
...@@ -844,7 +866,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -844,7 +866,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
name = entry.cname or entry.name or "" name = entry.cname or entry.name or ""
header, footer = \ header, footer = \
self.sue_header_footer(type, "enum", name) self.sue_header_footer(type, "enum", name)
code.putln("")
code.putln(header) code.putln(header)
enum_values = entry.enum_values enum_values = entry.enum_values
if not enum_values: if not enum_values:
...@@ -870,21 +891,23 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -870,21 +891,23 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln(value_code) code.putln(value_code)
code.putln(footer) code.putln(footer)
def generate_typeobject_predeclaration(self, entry, code): def generate_typeobj_predeclaration(self, entry, code):
code.putln("") code.putln("")
name = entry.type.typeobj_cname name = entry.type.typeobj_cname
if name: if name:
if entry.visibility == 'extern' and not entry.in_cinclude: if entry.visibility == 'extern' and not entry.in_cinclude:
code.putln("%s DL_IMPORT(PyTypeObject) %s;" % ( code.putln("%s %s %s;" % (
Naming.extern_c_macro, Naming.extern_c_macro,
PyrexTypes.public_decl("PyTypeObject", "DL_IMPORT"),
name)) name))
elif entry.visibility == 'public': elif entry.visibility == 'public':
code.putln("%s DL_EXPORT(PyTypeObject) %s;" % ( code.putln("%s %s %s;" % (
Naming.extern_c_macro, Naming.extern_c_macro,
PyrexTypes.public_decl("PyTypeObject", "DL_EXPORT"),
name)) name))
# ??? Do we really need the rest of this? ??? # ??? Do we really need the rest of this? ???
#else: #else:
# code.putln("staticforward PyTypeObject %s;" % name) # code.putln("static PyTypeObject %s;" % name)
def generate_exttype_vtable_struct(self, entry, code): def generate_exttype_vtable_struct(self, entry, code):
code.mark_pos(entry.pos) code.mark_pos(entry.pos)
...@@ -924,7 +947,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -924,7 +947,6 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
return # Forward declared but never defined return # Forward declared but never defined
header, footer = \ header, footer = \
self.sue_header_footer(type, "struct", type.objstruct_cname) self.sue_header_footer(type, "struct", type.objstruct_cname)
code.putln("")
code.putln(header) code.putln(header)
base_type = type.base_type base_type = type.base_type
if base_type: if base_type:
...@@ -963,24 +985,26 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -963,24 +985,26 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
for entry in env.cfunc_entries: for entry in env.cfunc_entries:
if entry.inline_func_in_pxd or (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 == 'public':
storage_class = "%s " % Naming.extern_c_macro
dll_linkage = "DL_EXPORT" dll_linkage = "DL_EXPORT"
elif entry.visibility == 'extern':
storage_class = "%s " % Naming.extern_c_macro
dll_linkage = "DL_IMPORT"
elif entry.visibility == 'private':
storage_class = "static "
dll_linkage = None
else: else:
storage_class = "static "
dll_linkage = None dll_linkage = None
type = entry.type type = entry.type
if not definition and entry.defined_in_pxd: if not definition and entry.defined_in_pxd:
type = CPtrType(type) type = CPtrType(type)
header = type.declaration_code(entry.cname, header = type.declaration_code(entry.cname,
dll_linkage = dll_linkage) dll_linkage = dll_linkage)
if entry.visibility == 'private':
storage_class = "static "
elif entry.visibility == 'public':
storage_class = ""
else:
storage_class = "%s " % Naming.extern_c_macro
if entry.func_modifiers: if entry.func_modifiers:
modifiers = '%s ' % ' '.join([ modifiers = "%s " % ' '.join(entry.func_modifiers).upper()
modifier.upper() for modifier in entry.func_modifiers])
else: else:
modifiers = '' modifiers = ''
code.putln("%s%s%s; /*proto*/" % ( code.putln("%s%s%s; /*proto*/" % (
...@@ -1803,6 +1827,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1803,6 +1827,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("/*--- Global init code ---*/") code.putln("/*--- Global init code ---*/")
self.generate_global_init_code(env, code) self.generate_global_init_code(env, code)
code.putln("/*--- Variable export code ---*/")
self.generate_c_variable_export_code(env, code)
code.putln("/*--- Function export code ---*/") code.putln("/*--- Function export code ---*/")
self.generate_c_function_export_code(env, code) self.generate_c_function_export_code(env, code)
...@@ -1990,6 +2017,18 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1990,6 +2017,18 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
if entry.type.is_pyobject and entry.used: if entry.type.is_pyobject and entry.used:
code.put_init_var_to_py_none(entry, nanny=False) code.put_init_var_to_py_none(entry, nanny=False)
def generate_c_variable_export_code(self, env, code):
# Generate code to create PyCFunction wrappers for exported C functions.
for entry in env.var_entries:
if entry.api or entry.defined_in_pxd:
env.use_utility_code(voidptr_export_utility_code)
signature = entry.type.declaration_code("")
code.putln('if (__Pyx_ExportVoidPtr("%s", (void *)&%s, "%s") < 0) %s' % (
entry.name,
entry.cname,
signature,
code.error_goto(self.pos)))
def generate_c_function_export_code(self, env, code): def generate_c_function_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.
for entry in env.cfunc_entries: for entry in env.cfunc_entries:
...@@ -2333,6 +2372,45 @@ bad: ...@@ -2333,6 +2372,45 @@ bad:
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
voidptr_export_utility_code = UtilityCode(
proto = """
static int __Pyx_ExportVoidPtr(const char *name, void *p, const char *sig); /*proto*/
""",
impl = r"""
static int __Pyx_ExportVoidPtr(const char *name, void *p, const char *sig) {
PyObject *d = 0;
PyObject *cobj = 0;
d = PyObject_GetAttrString(%(MODULE)s, (char *)"%(API)s");
if (!d) {
PyErr_Clear();
d = PyDict_New();
if (!d)
goto bad;
Py_INCREF(d);
if (PyModule_AddObject(%(MODULE)s, (char *)"%(API)s", d) < 0)
goto bad;
}
#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
cobj = PyCapsule_New(p, sig, 0);
#else
cobj = PyCObject_FromVoidPtrAndDesc(p, (void *)sig, 0);
#endif
if (!cobj)
goto bad;
if (PyDict_SetItemString(d, name, cobj) < 0)
goto bad;
Py_DECREF(cobj);
Py_DECREF(d);
return 0;
bad:
Py_XDECREF(cobj);
Py_XDECREF(d);
return -1;
}
""" % {'MODULE': Naming.module_cname, 'API': Naming.api_name}
)
function_export_utility_code = UtilityCode( function_export_utility_code = UtilityCode(
proto = """ proto = """
static int __Pyx_ExportFunction(const char *name, void (*f)(void), const char *sig); /*proto*/ static int __Pyx_ExportFunction(const char *name, void (*f)(void), const char *sig); /*proto*/
...@@ -2377,6 +2455,62 @@ bad: ...@@ -2377,6 +2455,62 @@ bad:
""" % {'MODULE': Naming.module_cname, 'API': Naming.api_name} """ % {'MODULE': Naming.module_cname, 'API': Naming.api_name}
) )
voidptr_import_utility_code = UtilityCode(
proto = """
static int __Pyx_ImportVoidPtr(PyObject *module, const char *name, void **p, const char *sig); /*proto*/
""",
impl = """
#ifndef __PYX_HAVE_RT_ImportVoidPtr
#define __PYX_HAVE_RT_ImportVoidPtr
static int __Pyx_ImportVoidPtr(PyObject *module, const char *name, void **p, const char *sig) {
PyObject *d = 0;
PyObject *cobj = 0;
d = PyObject_GetAttrString(module, (char *)"%(API)s");
if (!d)
goto bad;
cobj = PyDict_GetItemString(d, name);
if (!cobj) {
PyErr_Format(PyExc_ImportError,
"%%s does not export expected C variable %%s",
PyModule_GetName(module), name);
goto bad;
}
#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION==3&&PY_MINOR_VERSION==0)
if (!PyCapsule_IsValid(cobj, sig)) {
PyErr_Format(PyExc_TypeError,
"C variable %%s.%%s has wrong signature (expected %%s, got %%s)",
PyModule_GetName(module), name, sig, PyCapsule_GetName(cobj));
goto bad;
}
*p = PyCapsule_GetPointer(cobj, sig);
#else
{const char *desc, *s1, *s2;
desc = (const char *)PyCObject_GetDesc(cobj);
if (!desc)
goto bad;
s1 = desc; s2 = sig;
while (*s1 != '\\0' && *s1 == *s2) { s1++; s2++; }
if (*s1 != *s2) {
PyErr_Format(PyExc_TypeError,
"C variable %%s.%%s has wrong signature (expected %%s, got %%s)",
PyModule_GetName(module), name, sig, desc);
goto bad;
}
*p = PyCObject_AsVoidPtr(cobj);}
#endif
if (!(*p))
goto bad;
Py_DECREF(d);
return 0;
bad:
Py_XDECREF(d);
return -1;
}
#endif
""" % dict(API = Naming.api_name)
)
function_import_utility_code = UtilityCode( function_import_utility_code = UtilityCode(
proto = """ proto = """
static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**f)(void), const char *sig); /*proto*/ static int __Pyx_ImportFunction(PyObject *module, const char *funcname, void (**f)(void), const char *sig); /*proto*/
......
...@@ -970,7 +970,7 @@ class CVarDefNode(StatNode): ...@@ -970,7 +970,7 @@ class CVarDefNode(StatNode):
error(self.pos, error(self.pos,
"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, is_cdef = 1) cname=cname, visibility=visibility, api=self.api, is_cdef=1)
entry.needs_property = need_property entry.needs_property = need_property
...@@ -980,6 +980,7 @@ class CStructOrUnionDefNode(StatNode): ...@@ -980,6 +980,7 @@ class CStructOrUnionDefNode(StatNode):
# kind "struct" or "union" # kind "struct" or "union"
# typedef_flag boolean # typedef_flag boolean
# visibility "public" or "private" # visibility "public" or "private"
# api boolean
# in_pxd boolean # in_pxd boolean
# attributes [CVarDefNode] or None # attributes [CVarDefNode] or None
# entry Entry # entry Entry
...@@ -995,7 +996,8 @@ class CStructOrUnionDefNode(StatNode): ...@@ -995,7 +996,8 @@ class CStructOrUnionDefNode(StatNode):
scope = StructOrUnionScope(self.name) scope = StructOrUnionScope(self.name)
self.entry = env.declare_struct_or_union( self.entry = env.declare_struct_or_union(
self.name, self.kind, scope, self.typedef_flag, self.pos, self.name, self.kind, scope, self.typedef_flag, self.pos,
self.cname, visibility = self.visibility, packed = self.packed) self.cname, visibility = self.visibility, api = self.api,
packed = self.packed)
if self.attributes is not None: if self.attributes is not None:
if self.in_pxd and not env.in_cinclude: if self.in_pxd and not env.in_cinclude:
self.entry.defined_in_pxd = 1 self.entry.defined_in_pxd = 1
...@@ -1078,6 +1080,7 @@ class CEnumDefNode(StatNode): ...@@ -1078,6 +1080,7 @@ class CEnumDefNode(StatNode):
# items [CEnumDefItemNode] # items [CEnumDefItemNode]
# typedef_flag boolean # typedef_flag boolean
# visibility "public" or "private" # visibility "public" or "private"
# api boolean
# in_pxd boolean # in_pxd boolean
# entry Entry # entry Entry
...@@ -1086,7 +1089,7 @@ class CEnumDefNode(StatNode): ...@@ -1086,7 +1089,7 @@ class CEnumDefNode(StatNode):
def analyse_declarations(self, env): def analyse_declarations(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) visibility = self.visibility, api = self.api)
if self.items is not None: if self.items is not None:
if self.in_pxd and not env.in_cinclude: if self.in_pxd and not env.in_cinclude:
self.entry.defined_in_pxd = 1 self.entry.defined_in_pxd = 1
...@@ -1097,7 +1100,7 @@ class CEnumDefNode(StatNode): ...@@ -1097,7 +1100,7 @@ class CEnumDefNode(StatNode):
pass pass
def generate_execution_code(self, code): def generate_execution_code(self, code):
if self.visibility == 'public': if self.visibility == 'public' or self.api:
temp = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True) temp = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True)
for item in self.entry.enum_values: for item in self.entry.enum_values:
code.putln("%s = PyInt_FromLong(%s); %s" % ( code.putln("%s = PyInt_FromLong(%s); %s" % (
...@@ -1129,7 +1132,7 @@ class CEnumDefItemNode(StatNode): ...@@ -1129,7 +1132,7 @@ class CEnumDefItemNode(StatNode):
self.value.analyse_const_expression(env) 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) visibility = enum_entry.visibility, api = enum_entry.api)
enum_entry.enum_values.append(entry) enum_entry.enum_values.append(entry)
...@@ -1137,6 +1140,7 @@ class CTypeDefNode(StatNode): ...@@ -1137,6 +1140,7 @@ class CTypeDefNode(StatNode):
# base_type CBaseTypeNode # base_type CBaseTypeNode
# declarator CDeclaratorNode # declarator CDeclaratorNode
# visibility "public" or "private" # visibility "public" or "private"
# api boolean
# in_pxd boolean # in_pxd boolean
child_attrs = ["base_type", "declarator"] child_attrs = ["base_type", "declarator"]
...@@ -1147,7 +1151,7 @@ class CTypeDefNode(StatNode): ...@@ -1147,7 +1151,7 @@ class CTypeDefNode(StatNode):
name = name_declarator.name name = name_declarator.name
cname = name_declarator.cname cname = name_declarator.cname
entry = env.declare_typedef(name, type, self.pos, entry = env.declare_typedef(name, type, self.pos,
cname = cname, visibility = self.visibility) cname = cname, visibility = self.visibility, api = self.api)
if self.in_pxd and not env.in_cinclude: if self.in_pxd and not env.in_cinclude:
entry.defined_in_pxd = 1 entry.defined_in_pxd = 1
...@@ -1740,7 +1744,6 @@ class CFuncDefNode(FuncDefNode): ...@@ -1740,7 +1744,6 @@ class CFuncDefNode(FuncDefNode):
def generate_function_header(self, code, with_pymethdef, with_opt_args = 1, with_dispatch = 1, cname = None): def generate_function_header(self, code, with_pymethdef, with_opt_args = 1, with_dispatch = 1, cname = None):
arg_decls = [] arg_decls = []
type = self.type type = self.type
visibility = self.entry.visibility
for arg in type.args[:len(type.args)-type.optional_arg_count]: for arg in type.args[:len(type.args)-type.optional_arg_count]:
arg_decls.append(arg.declaration_code()) arg_decls.append(arg.declaration_code())
if with_dispatch and self.overridable: if with_dispatch and self.overridable:
...@@ -1754,24 +1757,20 @@ class CFuncDefNode(FuncDefNode): ...@@ -1754,24 +1757,20 @@ class CFuncDefNode(FuncDefNode):
if cname is None: if cname is None:
cname = self.entry.func_cname cname = self.entry.func_cname
entity = type.function_header_code(cname, ', '.join(arg_decls)) entity = type.function_header_code(cname, ', '.join(arg_decls))
if visibility == 'public': if self.entry.visibility == 'private':
dll_linkage = "DL_EXPORT" storage_class = "static "
else: else:
dll_linkage = None
header = self.return_type.declaration_code(entity,
dll_linkage = dll_linkage)
if visibility == 'extern':
storage_class = "%s " % Naming.extern_c_macro
elif visibility == 'public':
storage_class = "" storage_class = ""
else: dll_linkage = None
storage_class = "static " modifiers = ""
if 'inline' in self.modifiers: if 'inline' in self.modifiers:
self.modifiers[self.modifiers.index('inline')] = 'cython_inline' self.modifiers[self.modifiers.index('inline')] = 'cython_inline'
code.putln("%s%s %s {" % ( if self.modifiers:
storage_class, modifiers = "%s " % ' '.join(self.modifiers).upper()
' '.join(self.modifiers).upper(), # macro forms
header)) header = self.return_type.declaration_code(entity, dll_linkage=dll_linkage)
#print (storage_class, modifiers, header)
code.putln("%s%s%s {" % (storage_class, modifiers, header))
def generate_argument_declarations(self, env, code): def generate_argument_declarations(self, env, code):
for arg in self.args: for arg in self.args:
......
...@@ -64,7 +64,6 @@ class SkipDeclarations(object): ...@@ -64,7 +64,6 @@ class SkipDeclarations(object):
def visit_CStructOrUnionDefNode(self, node): def visit_CStructOrUnionDefNode(self, node):
return node return node
class NormalizeTree(CythonTransform): class NormalizeTree(CythonTransform):
""" """
This transform fixes up a few things after parsing This transform fixes up a few things after parsing
......
...@@ -2003,7 +2003,7 @@ def looking_at_expr(s): ...@@ -2003,7 +2003,7 @@ def looking_at_expr(s):
is_type = True is_type = True
elif s.sy == '*' or s.sy == '**': elif s.sy == '*' or s.sy == '**':
s.next() s.next()
is_type = s.sy == ')' is_type = s.sy in (')', ']')
s.put_back(*saved) s.put_back(*saved)
elif s.sy == '(': elif s.sy == '(':
s.next() s.next()
...@@ -2420,7 +2420,7 @@ def p_c_enum_definition(s, pos, ctx): ...@@ -2420,7 +2420,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,
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):
if s.sy != 'pass': if s.sy != 'pass':
...@@ -2481,7 +2481,7 @@ def p_c_struct_or_union_definition(s, pos, ctx): ...@@ -2481,7 +2481,7 @@ def p_c_struct_or_union_definition(s, pos, ctx):
return Nodes.CStructOrUnionDefNode(pos, return Nodes.CStructOrUnionDefNode(pos,
name = name, cname = cname, kind = kind, attributes = attributes, name = name, cname = cname, kind = kind, attributes = attributes,
typedef_flag = ctx.typedef_flag, visibility = ctx.visibility, typedef_flag = ctx.typedef_flag, visibility = ctx.visibility,
in_pxd = ctx.level == 'module_pxd', packed = packed) api = ctx.api, in_pxd = ctx.level == 'module_pxd', packed = packed)
def p_visibility(s, prev_visibility): def p_visibility(s, prev_visibility):
pos = s.position() pos = s.position()
...@@ -2566,7 +2566,8 @@ def p_ctypedef_statement(s, ctx): ...@@ -2566,7 +2566,8 @@ def p_ctypedef_statement(s, ctx):
s.expect_newline("Syntax error in ctypedef statement") s.expect_newline("Syntax error in ctypedef statement")
return Nodes.CTypeDefNode( return Nodes.CTypeDefNode(
pos, base_type = base_type, pos, base_type = base_type,
declarator = declarator, visibility = visibility, declarator = declarator,
visibility = visibility, api = api,
in_pxd = ctx.level == 'module_pxd') in_pxd = ctx.level == 'module_pxd')
def p_decorators(s): def p_decorators(s):
...@@ -2693,8 +2694,8 @@ def p_c_class_definition(s, pos, ctx): ...@@ -2693,8 +2694,8 @@ def p_c_class_definition(s, pos, ctx):
base_class_module = ".".join(base_class_path[:-1]) base_class_module = ".".join(base_class_path[:-1])
base_class_name = base_class_path[-1] base_class_name = base_class_path[-1]
if s.sy == '[': if s.sy == '[':
if ctx.visibility not in ('public', 'extern'): if ctx.visibility not in ('public', 'extern') and not ctx.api:
error(s.position(), "Name options only allowed for 'public' or 'extern' C class") error(s.position(), "Name options only allowed for 'public', 'api', or 'extern' C class")
objstruct_name, typeobj_name = p_c_class_options(s) objstruct_name, typeobj_name = p_c_class_options(s)
if s.sy == ':': if s.sy == ':':
if ctx.level == 'module_pxd': if ctx.level == 'module_pxd':
...@@ -2718,7 +2719,10 @@ def p_c_class_definition(s, pos, ctx): ...@@ -2718,7 +2719,10 @@ def p_c_class_definition(s, pos, ctx):
error(pos, "Type object name specification required for 'public' C class") error(pos, "Type object name specification required for 'public' C class")
elif ctx.visibility == 'private': elif ctx.visibility == 'private':
if ctx.api: if ctx.api:
error(pos, "Only 'public' C class can be declared 'api'") if not objstruct_name:
error(pos, "Object struct name specification required for 'api' C class")
if not typeobj_name:
error(pos, "Type object name specification required for 'api' C class")
else: else:
error(pos, "Invalid class visibility '%s'" % ctx.visibility) error(pos, "Invalid class visibility '%s'" % ctx.visibility)
return Nodes.CClassDefNode(pos, return Nodes.CClassDefNode(pos,
......
...@@ -1190,8 +1190,8 @@ class CComplexType(CNumericType): ...@@ -1190,8 +1190,8 @@ class CComplexType(CNumericType):
visibility="extern") visibility="extern")
scope.parent_type = self scope.parent_type = self
scope.directives = {} scope.directives = {}
scope.declare_var("real", self.real_type, None, "real", is_cdef=True) scope.declare_var("real", self.real_type, None, cname="real", is_cdef=True)
scope.declare_var("imag", self.real_type, None, "imag", is_cdef=True) scope.declare_var("imag", self.real_type, None, cname="imag", is_cdef=True)
entry = scope.declare_cfunction( entry = scope.declare_cfunction(
"conjugate", "conjugate",
CFuncType(self, [CFuncTypeArg("self", self, None)], nogil=True), CFuncType(self, [CFuncTypeArg("self", self, None)], nogil=True),
......
...@@ -361,10 +361,10 @@ class Scope(object): ...@@ -361,10 +361,10 @@ 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'): def declare_const(self, name, type, value, pos, cname = None, visibility = 'private', api = 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': 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)
...@@ -374,21 +374,22 @@ class Scope(object): ...@@ -374,21 +374,22 @@ class Scope(object):
return entry return entry
def declare_type(self, name, type, pos, def declare_type(self, name, type, pos,
cname = None, visibility = 'private', defining = 1, shadow = 0): cname = None, visibility = 'private', api = 0, defining = 1, shadow = 0):
# Add an entry for a type definition. # Add an entry for a type definition.
if not cname: if not cname:
cname = name cname = name
entry = self.declare(name, cname, type, pos, visibility, shadow) entry = self.declare(name, cname, type, pos, visibility, shadow)
entry.is_type = 1 entry.is_type = 1
entry.api = api
if defining: if defining:
self.type_entries.append(entry) self.type_entries.append(entry)
# here we would set as_variable to an object representing this type # here we would set as_variable to an object representing this type
return entry return entry
def declare_typedef(self, name, base_type, pos, cname = None, def declare_typedef(self, name, base_type, pos, cname = None,
visibility = 'private'): visibility = 'private', api = 0):
if not cname: if not cname:
if self.in_cinclude or visibility == 'public': if self.in_cinclude or (visibility == 'public' or api):
cname = name cname = name
else: else:
cname = self.mangle(Naming.type_prefix, name) cname = self.mangle(Naming.type_prefix, name)
...@@ -398,16 +399,18 @@ class Scope(object): ...@@ -398,16 +399,18 @@ class Scope(object):
except ValueError, e: except ValueError, e:
error(pos, e.args[0]) error(pos, e.args[0])
type = PyrexTypes.error_type type = PyrexTypes.error_type
entry = self.declare_type(name, type, pos, cname, visibility) entry = self.declare_type(name, type, pos, cname,
visibility = visibility, api = api)
type.qualified_name = entry.qualified_name type.qualified_name = entry.qualified_name
return entry return entry
def declare_struct_or_union(self, name, kind, scope, def declare_struct_or_union(self, name, kind, scope,
typedef_flag, pos, cname = None, visibility = 'private', typedef_flag, pos, cname = None,
visibility = 'private', api = 0,
packed = False): packed = False):
# Add an entry for a struct or union definition. # Add an entry for a struct or union definition.
if not cname: if not cname:
if self.in_cinclude or visibility == 'public': if self.in_cinclude or (visibility == 'public' or api):
cname = name cname = name
else: else:
cname = self.mangle(Naming.type_prefix, name) cname = self.mangle(Naming.type_prefix, name)
...@@ -416,7 +419,8 @@ class Scope(object): ...@@ -416,7 +419,8 @@ class Scope(object):
type = PyrexTypes.CStructOrUnionType( type = PyrexTypes.CStructOrUnionType(
name, kind, scope, typedef_flag, cname, packed) name, kind, scope, typedef_flag, cname, packed)
entry = self.declare_type(name, type, pos, cname, entry = self.declare_type(name, type, pos, cname,
visibility = visibility, defining = scope is not None) visibility = visibility, api = api,
defining = scope is not None)
self.sue_entries.append(entry) self.sue_entries.append(entry)
type.entry = entry type.entry = entry
else: else:
...@@ -484,10 +488,10 @@ class Scope(object): ...@@ -484,10 +488,10 @@ 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'): visibility = 'private', api = 0):
if name: if name:
if not cname: if not cname:
if self.in_cinclude or visibility == 'public': if self.in_cinclude or (visibility == 'public' or api):
cname = name cname = name
else: else:
cname = self.mangle(Naming.type_prefix, name) cname = self.mangle(Naming.type_prefix, name)
...@@ -495,13 +499,13 @@ class Scope(object): ...@@ -495,13 +499,13 @@ class Scope(object):
else: else:
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) visibility = visibility, api = api)
entry.enum_values = [] entry.enum_values = []
self.sue_entries.append(entry) self.sue_entries.append(entry)
return entry return entry
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'private', is_cdef = 0): cname = None, visibility = 'private', api = 0, is_cdef = 0):
# Add an entry for a variable. # Add an entry for a variable.
if not cname: if not cname:
if visibility != 'private': if visibility != 'private':
...@@ -514,6 +518,7 @@ class Scope(object): ...@@ -514,6 +518,7 @@ class Scope(object):
error(pos, "C++ class must have a default constructor to be stack allocated") error(pos, "C++ class must have a default constructor to be stack allocated")
entry = self.declare(name, cname, type, pos, visibility) entry = self.declare(name, cname, type, pos, visibility)
entry.is_variable = 1 entry.is_variable = 1
entry.api = api
self.control_flow.set_state((), (name, 'initialized'), False) self.control_flow.set_state((), (name, 'initialized'), False)
return entry return entry
...@@ -902,8 +907,8 @@ class ModuleScope(Scope): ...@@ -902,8 +907,8 @@ class ModuleScope(Scope):
return self.outer_scope.lookup(name, language_level = self.context.language_level) return self.outer_scope.lookup(name, language_level = self.context.language_level)
def declare_builtin(self, name, pos): def declare_builtin(self, name, pos):
if not hasattr(builtins, name) and name != 'xrange': if not hasattr(builtins, name) and name not in ('xrange', 'BaseException'):
# 'xrange' is special cased in Code.py # 'xrange' and 'BaseException' are special cased in Code.py
if self.has_import_star: if self.has_import_star:
entry = self.declare_var(name, py_object_type, pos) entry = self.declare_var(name, py_object_type, pos)
return entry return entry
...@@ -995,13 +1000,13 @@ class ModuleScope(Scope): ...@@ -995,13 +1000,13 @@ class ModuleScope(Scope):
return entry return entry
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'private', is_cdef = 0): cname = None, visibility = 'private', api = 0, is_cdef = 0):
# Add an entry for a global variable. If it is a Python # Add an entry for a global variable. If it is a Python
# object type, and not declared with cdef, it will live # object type, and not declared with cdef, it will live
# in the module dictionary, otherwise it will be a C # in the module dictionary, otherwise it will be a C
# global variable. # global variable.
entry = Scope.declare_var(self, name, type, pos, entry = Scope.declare_var(self, name, type, pos,
cname, visibility, is_cdef) cname=cname, visibility=visibility, api=api, is_cdef=is_cdef)
if not visibility in ('private', 'public', 'extern'): if not visibility in ('private', 'public', 'extern'):
error(pos, "Module-level variable cannot be declared %s" % visibility) error(pos, "Module-level variable cannot be declared %s" % visibility)
if not is_cdef: if not is_cdef:
...@@ -1035,8 +1040,8 @@ class ModuleScope(Scope): ...@@ -1035,8 +1040,8 @@ class ModuleScope(Scope):
# the non-typedef struct internally to avoid needing forward # the non-typedef struct internally to avoid needing forward
# declarations for anonymous structs. # declarations for anonymous structs.
if typedef_flag and visibility != 'extern': if typedef_flag and visibility != 'extern':
if visibility != 'public': if not (visibility == 'public' or api):
warning(pos, "ctypedef only valid for public and extern classes", 2) warning(pos, "ctypedef only valid for 'extern' , 'public', and 'api'", 2)
objtypedef_cname = objstruct_cname objtypedef_cname = objstruct_cname
typedef_flag = 0 typedef_flag = 0
else: else:
...@@ -1283,12 +1288,12 @@ class LocalScope(Scope): ...@@ -1283,12 +1288,12 @@ class LocalScope(Scope):
return entry return entry
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'private', is_cdef = 0): cname = None, visibility = 'private', api = 0, is_cdef = 0):
# Add an entry for a local variable. # Add an entry for a local variable.
if visibility in ('public', 'readonly'): if visibility in ('public', 'readonly'):
error(pos, "Local variable cannot be declared %s" % visibility) error(pos, "Local variable cannot be declared %s" % visibility)
entry = Scope.declare_var(self, name, type, pos, entry = Scope.declare_var(self, name, type, pos,
cname, visibility, is_cdef) cname=cname, visibility=visibility, api=api, is_cdef=is_cdef)
if type.is_pyobject and not Options.init_local_none: if type.is_pyobject and not Options.init_local_none:
entry.init = "0" entry.init = "0"
entry.init_to_none = (type.is_pyobject or type.is_unspecified) and Options.init_local_none entry.init_to_none = (type.is_pyobject or type.is_unspecified) and Options.init_local_none
...@@ -1354,7 +1359,7 @@ class GeneratorExpressionScope(Scope): ...@@ -1354,7 +1359,7 @@ class GeneratorExpressionScope(Scope):
return '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(prefix, name)) return '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(prefix, name))
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'private', is_cdef = True): cname = None, visibility = 'private', api = 0, is_cdef = True):
if type is unspecified_type: if type is unspecified_type:
# if the outer scope defines a type for this variable, inherit it # if the outer scope defines a type for this variable, inherit it
outer_entry = self.outer_scope.lookup(name) outer_entry = self.outer_scope.lookup(name)
...@@ -1397,7 +1402,7 @@ class StructOrUnionScope(Scope): ...@@ -1397,7 +1402,7 @@ class StructOrUnionScope(Scope):
Scope.__init__(self, name, None, None) Scope.__init__(self, name, None, None)
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'private', is_cdef = 0, allow_pyobject = 0): cname = None, visibility = 'private', api = 0, is_cdef = 0, allow_pyobject = 0):
# Add an entry for an attribute. # Add an entry for an attribute.
if not cname: if not cname:
cname = name cname = name
...@@ -1419,7 +1424,8 @@ class StructOrUnionScope(Scope): ...@@ -1419,7 +1424,8 @@ class StructOrUnionScope(Scope):
def declare_cfunction(self, name, type, pos, def declare_cfunction(self, name, type, pos,
cname = None, visibility = 'private', defining = 0, cname = None, visibility = 'private', defining = 0,
api = 0, in_pxd = 0, modifiers = ()): # currently no utility code ... api = 0, in_pxd = 0, modifiers = ()): # currently no utility code ...
return self.declare_var(name, type, pos, cname, visibility) return self.declare_var(name, type, pos,
cname=cname, visibility=visibility)
class ClassScope(Scope): class ClassScope(Scope):
# Abstract base class for namespace of # Abstract base class for namespace of
...@@ -1463,12 +1469,12 @@ class PyClassScope(ClassScope): ...@@ -1463,12 +1469,12 @@ class PyClassScope(ClassScope):
is_py_class_scope = 1 is_py_class_scope = 1
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'private', is_cdef = 0): cname = None, visibility = 'private', api = 0, is_cdef = 0):
if type is unspecified_type: if type is unspecified_type:
type = py_object_type type = py_object_type
# Add an entry for a class attribute. # Add an entry for a class attribute.
entry = Scope.declare_var(self, name, type, pos, entry = Scope.declare_var(self, name, type, pos,
cname, visibility, is_cdef) cname=cname, visibility=visibility, api=api, is_cdef=is_cdef)
entry.is_pyglobal = 1 entry.is_pyglobal = 1
entry.is_pyclass_attr = 1 entry.is_pyclass_attr = 1
return entry return entry
...@@ -1513,7 +1519,7 @@ class CClassScope(ClassScope): ...@@ -1513,7 +1519,7 @@ class CClassScope(ClassScope):
self.parent_type.base_type.scope.needs_gc()) self.parent_type.base_type.scope.needs_gc())
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'private', is_cdef = 0): cname = None, visibility = 'private', api = 0, is_cdef = 0):
if is_cdef: if is_cdef:
# Add an entry for an attribute. # Add an entry for an attribute.
if self.defined: if self.defined:
...@@ -1553,7 +1559,7 @@ class CClassScope(ClassScope): ...@@ -1553,7 +1559,7 @@ class CClassScope(ClassScope):
type = py_object_type type = py_object_type
# Add an entry for a class attribute. # Add an entry for a class attribute.
entry = Scope.declare_var(self, name, type, pos, entry = Scope.declare_var(self, name, type, pos,
cname, visibility, is_cdef) cname=cname, visibility=visibility, api=api, is_cdef=is_cdef)
entry.is_member = 1 entry.is_member = 1
entry.is_pyglobal = 1 # xxx: is_pyglobal changes behaviour in so many places that entry.is_pyglobal = 1 # xxx: is_pyglobal changes behaviour in so many places that
# I keep it in for now. is_member should be enough # I keep it in for now. is_member should be enough
...@@ -1569,7 +1575,8 @@ class CClassScope(ClassScope): ...@@ -1569,7 +1575,8 @@ class CClassScope(ClassScope):
if name == "__new__": if name == "__new__":
error(pos, "__new__ method of extension type will change semantics " error(pos, "__new__ method of extension type will change semantics "
"in a future version of Pyrex and Cython. Use __cinit__ instead.") "in a future version of Pyrex and Cython. Use __cinit__ instead.")
entry = self.declare_var(name, py_object_type, pos, visibility='extern') entry = self.declare_var(name, py_object_type, pos,
visibility='extern')
special_sig = get_special_method_signature(name) special_sig = get_special_method_signature(name)
if special_sig: if special_sig:
# Special methods get put in the method table with a particular # Special methods get put in the method table with a particular
...@@ -1694,7 +1701,8 @@ class CppClassScope(Scope): ...@@ -1694,7 +1701,8 @@ class CppClassScope(Scope):
self.inherited_var_entries = [] self.inherited_var_entries = []
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'extern', is_cdef = 0, allow_pyobject = 0): cname = None, visibility = 'extern', api = 0,
is_cdef = 0, allow_pyobject = 0):
# Add an entry for an attribute. # Add an entry for an attribute.
if not cname: if not cname:
cname = name cname = name
...@@ -1735,15 +1743,16 @@ class CppClassScope(Scope): ...@@ -1735,15 +1743,16 @@ class CppClassScope(Scope):
error(pos, "no matching function for call to %s::%s()" % error(pos, "no matching function for call to %s::%s()" %
(self.default_constructor, self.default_constructor)) (self.default_constructor, self.default_constructor))
def declare_cfunction(self, name, type, pos, def declare_cfunction(self, name, type, pos, cname = None,
cname = None, visibility = 'extern', defining = 0, visibility = 'extern', api = 0, defining = 0,
api = 0, in_pxd = 0, modifiers = (), utility_code = None): in_pxd = 0, modifiers = (), utility_code = None):
if name == self.name.split('::')[-1] and cname is None: if name == self.name.split('::')[-1] and cname is None:
self.check_base_default_constructor(pos) self.check_base_default_constructor(pos)
name = '<init>' name = '<init>'
type.return_type = self.lookup(self.name).type type.return_type = self.lookup(self.name).type
prev_entry = self.lookup_here(name) prev_entry = self.lookup_here(name)
entry = self.declare_var(name, type, pos, cname, visibility) entry = self.declare_var(name, type, pos,
cname=cname, visibility=visibility)
if prev_entry: if prev_entry:
entry.overloaded_alternatives = prev_entry.all_alternatives() entry.overloaded_alternatives = prev_entry.all_alternatives()
entry.utility_code = utility_code entry.utility_code = utility_code
...@@ -1768,7 +1777,8 @@ class CppClassScope(Scope): ...@@ -1768,7 +1777,8 @@ class CppClassScope(Scope):
for base_entry in base_scope.cfunc_entries: for base_entry in base_scope.cfunc_entries:
entry = self.declare_cfunction(base_entry.name, base_entry.type, entry = self.declare_cfunction(base_entry.name, base_entry.type,
base_entry.pos, base_entry.cname, base_entry.pos, base_entry.cname,
base_entry.visibility, base_entry.func_modifiers, base_entry.visibility, 0,
modifiers = base_entry.func_modifiers,
utility_code = base_entry.utility_code) utility_code = base_entry.utility_code)
entry.is_inherited = 1 entry.is_inherited = 1
......
...@@ -378,6 +378,32 @@ class TestExec(DebugTestCase): ...@@ -378,6 +378,32 @@ class TestExec(DebugTestCase):
gdb.execute('cy exec some_random_var = 14') gdb.execute('cy exec some_random_var = 14')
self.assertEqual('14', self.eval_command('some_random_var')) self.assertEqual('14', self.eval_command('some_random_var'))
class CySet(DebugTestCase):
def test_cyset(self):
self.break_and_run('os.path.join("foo", "bar")')
gdb.execute('cy set a = $cy_eval("{None: []}")')
stringvalue = self.read_var("a", cast_to=str)
self.assertEqual(stringvalue, "{None: []}")
class TestCyEval(DebugTestCase):
"Test the $cy_eval() gdb function."
def test_cy_eval(self):
# This function leaks a few objects in the GDB python process. This
# is no biggie
self.break_and_run('os.path.join("foo", "bar")')
result = gdb.execute('print $cy_eval("None")', to_string=True)
assert re.match(r'\$\d+ = None\n', result), result
result = gdb.execute('print $cy_eval("[a]")', to_string=True)
assert re.match(r'\$\d+ = \[0\]', result), result
class TestClosure(DebugTestCase): class TestClosure(DebugTestCase):
def break_and_run_func(self, funcname): def break_and_run_func(self, funcname):
......
...@@ -113,5 +113,3 @@ class TestPrettyPrinters(test_libcython_in_gdb.DebugTestCase): ...@@ -113,5 +113,3 @@ class TestPrettyPrinters(test_libcython_in_gdb.DebugTestCase):
frame = self.pyobject_fromcode('PyEval_GetFrame()') frame = self.pyobject_fromcode('PyEval_GetFrame()')
self.assertEqual(type(frame), libpython.PyFrameObjectPtr) self.assertEqual(type(frame), libpython.PyFrameObjectPtr)
...@@ -592,6 +592,7 @@ class CyCy(CythonCommand): ...@@ -592,6 +592,7 @@ class CyCy(CythonCommand):
cy bt / cy backtrace cy bt / cy backtrace
cy list cy list
cy print cy print
cy set
cy locals cy locals
cy globals cy globals
cy exec cy exec
...@@ -607,6 +608,7 @@ class CyCy(CythonCommand): ...@@ -607,6 +608,7 @@ class CyCy(CythonCommand):
completer_class, prefix=True) completer_class, prefix=True)
commands = dict( commands = dict(
# GDB commands
import_ = CyImport.register(), import_ = CyImport.register(),
break_ = CyBreak.register(), break_ = CyBreak.register(),
step = CyStep.register(), step = CyStep.register(),
...@@ -624,9 +626,13 @@ class CyCy(CythonCommand): ...@@ -624,9 +626,13 @@ class CyCy(CythonCommand):
globals = CyGlobals.register(), globals = CyGlobals.register(),
exec_ = libpython.FixGdbCommand('cy exec', '-cy-exec'), exec_ = libpython.FixGdbCommand('cy exec', '-cy-exec'),
_exec = CyExec.register(), _exec = CyExec.register(),
set = CySet.register(),
# GDB functions
cy_cname = CyCName('cy_cname'), cy_cname = CyCName('cy_cname'),
cy_cvalue = CyCValue('cy_cvalue'), cy_cvalue = CyCValue('cy_cvalue'),
cy_lineno = CyLine('cy_lineno'), cy_lineno = CyLine('cy_lineno'),
cy_eval = CyEval('cy_eval'),
) )
for command_name, command in commands.iteritems(): for command_name, command in commands.iteritems():
...@@ -1169,15 +1175,14 @@ class CyGlobals(CyLocals): ...@@ -1169,15 +1175,14 @@ class CyGlobals(CyLocals):
max_name_length, ' ') max_name_length, ' ')
class CyExec(CythonCommand, libpython.PyExec):
class EvaluateOrExecuteCodeMixin(object):
""" """
Execute Python code in the nearest Python or Cython frame. Evaluate or execute Python code in a Cython or Python frame. The 'evalcode'
method evaluations Python code, prints a traceback if an exception went
uncaught, and returns any return value as a gdb.Value (NULL on exception).
""" """
name = '-cy-exec'
command_class = gdb.COMMAND_STACK
completer_class = gdb.COMPLETE_NONE
def _fill_locals_dict(self, executor, local_dict_pointer): def _fill_locals_dict(self, executor, local_dict_pointer):
"Fill a remotely allocated dict with values from the Cython C stack" "Fill a remotely allocated dict with values from the Cython C stack"
cython_func = self.get_cython_function() cython_func = self.get_cython_function()
...@@ -1208,28 +1213,22 @@ class CyExec(CythonCommand, libpython.PyExec): ...@@ -1208,28 +1213,22 @@ class CyExec(CythonCommand, libpython.PyExec):
raise gdb.GdbError("Unable to execute Python code.") raise gdb.GdbError("Unable to execute Python code.")
finally: finally:
# PyDict_SetItem doesn't steal our reference # PyDict_SetItem doesn't steal our reference
executor.decref(pystringp) executor.xdecref(pystringp)
def _find_first_cython_or_python_frame(self): def _find_first_cython_or_python_frame(self):
frame = gdb.selected_frame() frame = gdb.selected_frame()
while frame: while frame:
if (self.is_cython_function(frame) or if (self.is_cython_function(frame) or
self.is_python_function(frame)): self.is_python_function(frame)):
frame.select()
return frame return frame
frame = frame.older() frame = frame.older()
raise gdb.GdbError("There is no Cython or Python frame on the stack.") raise gdb.GdbError("There is no Cython or Python frame on the stack.")
def invoke(self, expr, from_tty):
frame = self._find_first_cython_or_python_frame()
if self.is_python_function(frame):
libpython.py_exec.invoke(expr, from_tty)
return
expr, input_type = self.readcode(expr)
executor = libpython.PythonCodeExecutor()
def _evalcode_cython(self, executor, code, input_type):
with libpython.FetchAndRestoreError(): with libpython.FetchAndRestoreError():
# get the dict of Cython globals and construct a dict in the # get the dict of Cython globals and construct a dict in the
# inferior with Cython locals # inferior with Cython locals
...@@ -1240,9 +1239,65 @@ class CyExec(CythonCommand, libpython.PyExec): ...@@ -1240,9 +1239,65 @@ class CyExec(CythonCommand, libpython.PyExec):
try: try:
self._fill_locals_dict(executor, self._fill_locals_dict(executor,
libpython.pointervalue(local_dict)) libpython.pointervalue(local_dict))
executor.evalcode(expr, input_type, global_dict, local_dict) result = executor.evalcode(code, input_type, global_dict,
local_dict)
finally: finally:
executor.decref(libpython.pointervalue(local_dict)) executor.xdecref(libpython.pointervalue(local_dict))
return result
def evalcode(self, code, input_type):
"""
Evaluate `code` in a Python or Cython stack frame using the given
`input_type`.
"""
frame = self._find_first_cython_or_python_frame()
executor = libpython.PythonCodeExecutor()
if self.is_python_function(frame):
return libpython._evalcode_python(executor, code, input_type)
return self._evalcode_cython(executor, code, input_type)
class CyExec(CythonCommand, libpython.PyExec, EvaluateOrExecuteCodeMixin):
"""
Execute Python code in the nearest Python or Cython frame.
"""
name = '-cy-exec'
command_class = gdb.COMMAND_STACK
completer_class = gdb.COMPLETE_NONE
def invoke(self, expr, from_tty):
expr, input_type = self.readcode(expr)
executor = libpython.PythonCodeExecutor()
executor.xdecref(self.evalcode(expr, executor.Py_single_input))
class CySet(CythonCommand):
"""
Set a Cython variable to a certain value
cy set my_cython_c_variable = 10
cy set my_cython_py_variable = $cy_eval("{'doner': 'kebab'}")
This is equivalent to
set $cy_value("my_cython_variable") = 10
"""
name = 'cy set'
command_class = gdb.COMMAND_DATA
completer_class = gdb.COMPLETE_NONE
@require_cython_frame
def invoke(self, expr, from_tty):
name_and_expr = expr.split('=', 1)
if len(name_and_expr) != 2:
raise gdb.GdbError("Invalid expression. Use 'cy set var = expr'.")
varname, expr = name_and_expr
cname = self.cy.cy_cname.invoke(varname.strip())
gdb.execute("set %s = %s" % (cname, expr))
# Functions # Functions
...@@ -1312,6 +1367,18 @@ class CyLine(gdb.Function, CythonBase): ...@@ -1312,6 +1367,18 @@ class CyLine(gdb.Function, CythonBase):
def invoke(self): def invoke(self):
return self.get_cython_lineno() return self.get_cython_lineno()
class CyEval(gdb.Function, CythonBase, EvaluateOrExecuteCodeMixin):
"""
Evaluate Python code in the nearest Python or Cython frame and return
"""
@gdb_function_value_to_unicode
def invoke(self, python_expression):
input_type = libpython.PythonCodeExecutor.Py_eval_input
return self.evalcode(python_expression, input_type)
cython_info = CythonInfo() cython_info = CythonInfo()
cy = CyCy.register() cy = CyCy.register()
cython_info.cy = cy cython_info.cy = cy
......
...@@ -1949,27 +1949,41 @@ class ExecutionControlCommandBase(gdb.Command): ...@@ -1949,27 +1949,41 @@ class ExecutionControlCommandBase(gdb.Command):
gdb.execute("delete %s" % bp) gdb.execute("delete %s" % bp)
def filter_output(self, result): def filter_output(self, result):
output = []
match_finish = re.search(r'^Value returned is \$\d+ = (.*)', result,
re.MULTILINE)
if match_finish:
output.append('Value returned: %s' % match_finish.group(1))
reflags = re.MULTILINE reflags = re.MULTILINE
regexes = [
output_on_halt = [
(r'^Program received signal .*', reflags|re.DOTALL), (r'^Program received signal .*', reflags|re.DOTALL),
(r'.*[Ww]arning.*', 0), (r'.*[Ww]arning.*', 0),
(r'^Program exited .*', reflags), (r'^Program exited .*', reflags),
] ]
output_always = [
# output when halting on a watchpoint
(r'^(Old|New) value = .*', reflags),
# output from the 'display' command
(r'^\d+: \w+ = .*', reflags),
]
def filter_output(regexes):
output = []
for regex, flags in regexes: for regex, flags in regexes:
match = re.search(regex, result, flags) for match in re.finditer(regex, result, flags):
if match:
output.append(match.group(0)) output.append(match.group(0))
return '\n'.join(output) return '\n'.join(output)
# Filter the return value output of the 'finish' command
match_finish = re.search(r'^Value returned is \$\d+ = (.*)', result,
re.MULTILINE)
if match_finish:
finish_output = 'Value returned: %s\n' % match_finish.group(1)
else:
finish_output = ''
return (filter_output(output_on_halt),
finish_output + filter_output(output_always))
def stopped(self): def stopped(self):
return get_selected_inferior().pid == 0 return get_selected_inferior().pid == 0
...@@ -1979,17 +1993,23 @@ class ExecutionControlCommandBase(gdb.Command): ...@@ -1979,17 +1993,23 @@ class ExecutionControlCommandBase(gdb.Command):
of source code or the result of the last executed gdb command (passed of source code or the result of the last executed gdb command (passed
in as the `result` argument). in as the `result` argument).
""" """
result = self.filter_output(result) output_on_halt, output_always = self.filter_output(result)
if self.stopped(): if self.stopped():
print result.strip() print output_always
print output_on_halt
else: else:
frame = gdb.selected_frame() frame = gdb.selected_frame()
source_line = self.lang_info.get_source_line(frame)
if self.lang_info.is_relevant_function(frame): if self.lang_info.is_relevant_function(frame):
raised_exception = self.lang_info.exc_info(frame) raised_exception = self.lang_info.exc_info(frame)
if raised_exception: if raised_exception:
print raised_exception print raised_exception
print self.lang_info.get_source_line(frame) or result
if source_line:
if output_always.rstrip():
print output_always.rstrip()
print source_line
else: else:
print result print result
...@@ -2190,12 +2210,12 @@ class PythonInfo(LanguageInfo): ...@@ -2190,12 +2210,12 @@ class PythonInfo(LanguageInfo):
try: try:
tstate = frame.read_var('tstate').dereference() tstate = frame.read_var('tstate').dereference()
if gdb.parse_and_eval('tstate->frame == f'): if gdb.parse_and_eval('tstate->frame == f'):
# tstate local variable initialized # tstate local variable initialized, check for an exception
inf_type = tstate['curexc_type'] inf_type = tstate['curexc_type']
inf_value = tstate['curexc_value'] inf_value = tstate['curexc_value']
if inf_type: if inf_type:
return 'An exception was raised: %s(%s)' % (inf_type, return 'An exception was raised: %s' % (inf_value,)
inf_value)
except (ValueError, RuntimeError), e: except (ValueError, RuntimeError), e:
# Could not read the variable tstate or it's memory, it's ok # Could not read the variable tstate or it's memory, it's ok
pass pass
...@@ -2342,7 +2362,7 @@ class PythonCodeExecutor(object): ...@@ -2342,7 +2362,7 @@ class PythonCodeExecutor(object):
"Increment the reference count of a Python object in the inferior." "Increment the reference count of a Python object in the inferior."
gdb.parse_and_eval('Py_IncRef((PyObject *) %d)' % pointer) gdb.parse_and_eval('Py_IncRef((PyObject *) %d)' % pointer)
def decref(self, pointer): def xdecref(self, pointer):
"Decrement the reference count of a Python object in the inferior." "Decrement the reference count of a Python object in the inferior."
# Py_DecRef is like Py_XDECREF, but a function. So we don't have # Py_DecRef is like Py_XDECREF, but a function. So we don't have
# to check for NULL. This should also decref all our allocated # to check for NULL. This should also decref all our allocated
...@@ -2382,10 +2402,11 @@ class PythonCodeExecutor(object): ...@@ -2382,10 +2402,11 @@ class PythonCodeExecutor(object):
with FetchAndRestoreError(): with FetchAndRestoreError():
try: try:
self.decref(gdb.parse_and_eval(code)) pyobject_return_value = gdb.parse_and_eval(code)
finally: finally:
self.free(pointer) self.free(pointer)
return pyobject_return_value
class FetchAndRestoreError(PythonCodeExecutor): class FetchAndRestoreError(PythonCodeExecutor):
""" """
...@@ -2462,6 +2483,20 @@ class FixGdbCommand(gdb.Command): ...@@ -2462,6 +2483,20 @@ class FixGdbCommand(gdb.Command):
self.fix_gdb() self.fix_gdb()
def _evalcode_python(executor, code, input_type):
"""
Execute Python code in the most recent stack frame.
"""
global_dict = gdb.parse_and_eval('PyEval_GetGlobals()')
local_dict = gdb.parse_and_eval('PyEval_GetLocals()')
if (pointervalue(global_dict) == 0 or pointervalue(local_dict) == 0):
raise gdb.GdbError("Unable to find the locals or globals of the "
"most recent Python function (relative to the "
"selected frame).")
return executor.evalcode(code, input_type, global_dict, local_dict)
class PyExec(gdb.Command): class PyExec(gdb.Command):
def readcode(self, expr): def readcode(self, expr):
...@@ -2484,17 +2519,9 @@ class PyExec(gdb.Command): ...@@ -2484,17 +2519,9 @@ class PyExec(gdb.Command):
def invoke(self, expr, from_tty): def invoke(self, expr, from_tty):
expr, input_type = self.readcode(expr) expr, input_type = self.readcode(expr)
executor = PythonCodeExecutor() executor = PythonCodeExecutor()
global_dict = gdb.parse_and_eval('PyEval_GetGlobals()') executor.xdecref(_evalcode_python(executor, input_type, global_dict,
local_dict = gdb.parse_and_eval('PyEval_GetLocals()') local_dict))
if pointervalue(global_dict) == 0 or pointervalue(local_dict) == 0:
raise gdb.GdbError("Unable to find the locals or globals of the "
"most recent Python function (relative to the "
"selected frame).")
executor.evalcode(expr, input_type, global_dict, local_dict)
gdb.execute('set breakpoint pending on') gdb.execute('set breakpoint pending on')
......
...@@ -894,7 +894,7 @@ class EmbedTest(unittest.TestCase): ...@@ -894,7 +894,7 @@ class EmbedTest(unittest.TestCase):
# report the error for the original directory # report the error for the original directory
libdir = sysconfig.get_config_var('LIBDIR') libdir = sysconfig.get_config_var('LIBDIR')
cython = 'cython.py' cython = 'cython.py'
if sys.version_info[0] >=3: if sys.version_info[0] >=3 and CY3_DIR:
cython = os.path.join(CY3_DIR, cython) cython = os.path.join(CY3_DIR, cython)
cython = os.path.abspath(os.path.join('..', '..', cython)) cython = os.path.abspath(os.path.join('..', '..', cython))
self.assert_(os.system( self.assert_(os.system(
......
...@@ -18,6 +18,7 @@ pure_mode_cmethod_inheritance_T583 ...@@ -18,6 +18,7 @@ pure_mode_cmethod_inheritance_T583
genexpr_iterable_lookup_T600 genexpr_iterable_lookup_T600
for_from_pyvar_loop_T601 for_from_pyvar_loop_T601
decorators_T593 decorators_T593
temp_sideeffects_T654
# CPython regression tests that don't current work: # CPython regression tests that don't current work:
pyregr.test_threadsignals pyregr.test_threadsignals
......
...@@ -11,6 +11,12 @@ cdef public class C[type C_Type, object C_Obj]: ...@@ -11,6 +11,12 @@ cdef public class C[type C_Type, object C_Obj]:
cdef public Zax *blarg cdef public Zax *blarg
cdef public C c_pub = C()
cdef api C c_api = C()
cdef public dict o_pub = C()
cdef api list o_api = C()
cdef api float f(Foo *x): cdef api float f(Foo *x):
pass pass
...@@ -19,3 +25,6 @@ cdef public void g(Blarg *x): ...@@ -19,3 +25,6 @@ cdef public void g(Blarg *x):
cdef public api void h(Zax *x): cdef public api void h(Zax *x):
pass pass
cdef extern from "a_capi.h":
pass
# --
ctypedef int Int0
ctypedef api int Int1
ctypedef enum EnumA0: EA0
ctypedef api enum EnumA1: EA1
cdef enum EnumB0: EB0=0
cdef api enum EnumB1: EB1=1
cdef Int0 i0 = 0
cdef EnumA0 ea0 = EA0
cdef EnumB0 eb0 = EB0
cdef api Int1 i1 = 0
cdef api EnumA1 ea1 = EA1
cdef api EnumB1 eb1 = EB1
# --
ctypedef struct StructA0:
int SA0
ctypedef api struct StructA1:
int SA1
cdef struct StructB0:
int SB0
cdef api struct StructB1:
int SB1
cdef StructA0 sa0 = {'SA0':0}
cdef StructB0 sb0 = {'SB0':2}
cdef api StructA1 sa1 = {'SA1':1}
cdef api StructB1 sb1 = {'SB1':3}
# --
ctypedef class Foo0: pass
ctypedef api class Foo1 [type PyFoo1_Type, object PyFoo1_Object]: pass
cdef class Bar0: pass
cdef api class Bar1 [type PyBar1_Type, object PyBar1_Object]: pass
cdef Foo0 f0 = None
cdef Bar0 b0 = None
cdef api Foo1 f1 = None
cdef api Bar1 b1 = None
# --
cdef void bar0(): pass
cdef api void bar1(): pass
cdef void* spam0(object o) except NULL: return NULL
cdef api void* spam1(object o) except NULL: return NULL
bar0()
bar1()
spam0(None)
spam1(None)
# --
# --
ctypedef int Int0
ctypedef public int Int1
ctypedef api int Int2
ctypedef public api int Int3
ctypedef enum EnumA0: EA0
ctypedef public enum EnumA1: EA1
ctypedef api enum EnumA2: EA2
ctypedef public api enum EnumA3: EA3
cdef enum EnumB0: EB0=0
cdef public enum EnumB1: EB1=1
cdef api enum EnumB2: EB2=2
cdef public api enum EnumB3: EB3=3
# --
ctypedef struct StructA0:
int SA0
ctypedef public struct StructA1:
int SA1
ctypedef api struct StructA2:
int SA2
ctypedef public api struct StructA3:
int SA3
cdef struct StructB0:
int SB0
cdef public struct StructB1:
int SB1
cdef api struct StructB2:
int SB2
cdef public api struct StructB3:
int SB3
# --
ctypedef class Foo0: pass
ctypedef public class Foo1 [type PyFoo1_Type, object PyFoo1_Object]: pass
ctypedef api class Foo2 [type PyFoo2_Type, object PyFoo2_Object]: pass
ctypedef public api class Foo3 [type PyFoo3_Type, object PyFoo3_Object]: pass
cdef class Bar0: pass
cdef public class Bar1 [type PyBar1_Type, object PyBar1_Object]: pass
cdef api class Bar2 [type PyBar2_Type, object PyBar2_Object]: pass
cdef public api class Bar3 [type PyBar3_Type, object PyBar3_Object]: pass
# --
cdef void bar0(): pass
cdef public void bar1(): pass
cdef api void bar2(): pass
cdef public api void bar3(): pass
cdef void* spam0(object o) except NULL: return NULL
cdef public void* spam1(object o) except NULL: return NULL
cdef api void* spam2(object o) except NULL: return NULL
cdef public api void* spam3(object o) except NULL: return NULL
bar0()
spam0(None)
# --
cdef double d0 = 0
cdef public double d1 = 1
cdef api double d2 = 2
cdef public api double d3 = 3
cdef object o0 = None
cdef public object o1 = None
cdef api object o2 = None
cdef public api object o3 = None
# --
# --
ctypedef int Int0
ctypedef public int Int1
ctypedef enum EnumA0: EA0
ctypedef public enum EnumA1: EA1
cdef enum EnumB0: EB0=0
cdef public enum EnumB1: EB1=1
cdef Int0 i0 = 0
cdef EnumA0 ea0 = EA0
cdef EnumB0 eb0 = EB0
cdef public Int1 i1 = 0
cdef public EnumA1 ea1 = EA1
cdef public EnumB1 eb1 = EB1
# --
ctypedef struct StructA0:
int SA0
ctypedef public struct StructA1:
int SA1
cdef struct StructB0:
int SB0
cdef public struct StructB1:
int SB1
cdef StructA0 sa0 = {'SA0':0}
cdef StructB0 sb0 = {'SB0':2}
cdef public StructA1 sa1 = {'SA1':1}
cdef public StructB1 sb1 = {'SB1':3}
# --
ctypedef class Foo0: pass
ctypedef public class Foo1 [type PyFoo1_Type, object PyFoo1_Object]: pass
cdef class Bar0: pass
cdef public class Bar1 [type PyBar1_Type, object PyBar1_Object]: pass
cdef Foo0 f0 = None
cdef Bar0 b0 = None
cdef public Foo1 f1 = None
cdef public Bar1 b1 = None
# --
cdef void bar0(): pass
cdef public void bar1(): pass
cdef void* spam0(object o) except NULL: return NULL
cdef public void* spam1(object o) except NULL: return NULL
bar0()
bar1()
spam0(None)
spam1(None)
# --
# --
ctypedef int Int0
ctypedef public int Int1
ctypedef api int Int2
ctypedef public api int Int3
ctypedef enum EnumA0: EA0
ctypedef public enum EnumA1: EA1
ctypedef api enum EnumA2: EA2
ctypedef public api enum EnumA3: EA3
cdef enum EnumB0: EB0=0
cdef public enum EnumB1: EB1=1
cdef api enum EnumB2: EB2=2
cdef public api enum EnumB3: EB3=3
# --
ctypedef struct StructA0:
int SA0
ctypedef public struct StructA1:
int SA1
ctypedef api struct StructA2:
int SA2
ctypedef public api struct StructA3:
int SA3
cdef struct StructB0:
int SB0
cdef public struct StructB1:
int SB1
cdef api struct StructB2:
int SB2
cdef public api struct StructB3:
int SB3
# --
ctypedef class Foo0: pass
ctypedef public class Foo1 [type PyFoo1_Type, object PyFoo1_Object]: pass
ctypedef api class Foo2 [type PyFoo2_Type, object PyFoo2_Object]: pass
ctypedef public api class Foo3 [type PyFoo3_Type, object PyFoo3_Object]: pass
cdef class Bar0: pass
cdef public class Bar1 [type PyBar1_Type, object PyBar1_Object]: pass
cdef api class Bar2 [type PyBar2_Type, object PyBar2_Object]: pass
cdef public api class Bar3 [type PyBar3_Type, object PyBar3_Object]: pass
# --
cdef inline void bar0(): pass
cdef public void bar1()
cdef api void bar2()
cdef public api void bar3()
cdef inline void* spam0(object o) except NULL: return NULL
cdef public void* spam1(object o) except NULL
cdef api void* spam2(object o) nogil except NULL
cdef public api void* spam3(object o) except NULL with gil
# --
#cdef public int i1
#cdef api int i2
#cdef public api int i3
# --
cdef class Foo1: pass
cdef class Foo2: pass
cdef class Foo3: pass
cdef class Bar1: pass
cdef class Bar2: pass
cdef class Bar3: pass
cdef public void bar1(): pass
cdef api void bar2(): pass
cdef public api void bar3(): pass
cdef public void* spam1(object o) except NULL: return NULL
cdef api void* spam2(object o) nogil except NULL: return NULL
cdef public api void* spam3(object o) except NULL with gil: return NULL
...@@ -56,3 +56,14 @@ def test_for_in_range(arg): ...@@ -56,3 +56,14 @@ def test_for_in_range(arg):
for c in range(arg): for c in range(arg):
l.append(c) l.append(c)
return l return l
def raise_and_catch_BaseException():
"""
>>> raise_and_catch_BaseException()
1
"""
try:
raise BaseException
except BaseException:
return 1
return 2
...@@ -2,8 +2,20 @@ __doc__ = u""" ...@@ -2,8 +2,20 @@ __doc__ = u"""
>>> import sys >>> import sys
>>> sys.getrefcount(Foo.__pyx_vtable__) >>> sys.getrefcount(Foo.__pyx_vtable__)
2 2
>>> sys.getrefcount(__pyx_capi__['spam']) >>> sys.getrefcount(__pyx_capi__['ten'])
2 2
>>> sys.getrefcount(__pyx_capi__['pi'])
2
>>> sys.getrefcount(__pyx_capi__['obj'])
2
>>> sys.getrefcount(__pyx_capi__['dct'])
2
>>> sys.getrefcount(__pyx_capi__['one'])
2
>>> sys.getrefcount(__pyx_capi__['two'])
Traceback (most recent call last):
...
KeyError: 'two'
""" """
cdef public api class Foo [type FooType, object FooObject]: cdef public api class Foo [type FooType, object FooObject]:
...@@ -12,3 +24,12 @@ cdef public api class Foo [type FooType, object FooObject]: ...@@ -12,3 +24,12 @@ cdef public api class Foo [type FooType, object FooObject]:
cdef api void spam(): cdef api void spam():
pass pass
cdef api int ten = 10
cdef api double pi = 3.14
cdef api object obj = object()
cdef api dict dct = {}
cdef public api int one = 1
cdef public int two = 2
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