summaryrefslogtreecommitdiffstats
path: root/debian/pyrex/pyrex-0.9.9/Pyrex/Compiler/Nodes.py
diff options
context:
space:
mode:
Diffstat (limited to 'debian/pyrex/pyrex-0.9.9/Pyrex/Compiler/Nodes.py')
-rw-r--r--debian/pyrex/pyrex-0.9.9/Pyrex/Compiler/Nodes.py3249
1 files changed, 3249 insertions, 0 deletions
diff --git a/debian/pyrex/pyrex-0.9.9/Pyrex/Compiler/Nodes.py b/debian/pyrex/pyrex-0.9.9/Pyrex/Compiler/Nodes.py
new file mode 100644
index 00000000..fb974df0
--- /dev/null
+++ b/debian/pyrex/pyrex-0.9.9/Pyrex/Compiler/Nodes.py
@@ -0,0 +1,3249 @@
+#
+# Pyrex - Parse tree nodes
+#
+
+import string, sys
+
+import Code
+from Errors import error, one_time_warning, InternalError
+import Naming
+import PyrexTypes
+from PyrexTypes import py_object_type, c_int_type, error_type, \
+ CTypedefType, CFuncType
+from Symtab import ModuleScope, LocalScope, \
+ StructOrUnionScope, PyClassScope, CClassScope
+from Pyrex.Utils import open_new_file, replace_suffix
+import Options
+
+from DebugFlags import debug_disposal_code
+
+class Node:
+ # pos (string, int, int) Source file position
+ # is_name boolean Is a NameNode
+ # is_literal boolean Is a ConstNode
+
+ is_name = 0
+ is_literal = 0
+
+ def __init__(self, pos, **kw):
+ self.pos = pos
+ self.__dict__.update(kw)
+
+ gil_message = "Operation"
+
+ def gil_check(self, env):
+ if env.nogil:
+ self.gil_error()
+
+ def gil_error(self, message = None):
+ error(self.pos, "%s not allowed without gil" % (message or self.gil_message))
+
+ #
+ # There are 3 phases of parse tree processing, applied in order to
+ # all the statements in a given scope-block:
+ #
+ # (1) analyse_declarations
+ # Make symbol table entries for all declarations at the current
+ # level, both explicit (def, cdef, etc.) and implicit (assignment
+ # to an otherwise undeclared name).
+ #
+ # (2) analyse_expressions
+ # Determine the result types of expressions and fill in the
+ # 'type' attribute of each ExprNode. Insert coercion nodes into the
+ # tree where needed to convert to and from Python objects.
+ # Allocate temporary locals for intermediate results.
+ #
+ # (3) generate_code
+ # Emit C code for all declarations, statements and expressions.
+ # Recursively applies the 3 processing phases to the bodies of
+ # functions.
+ #
+
+ def analyse_declarations(self, env):
+ pass
+
+ def analyse_expressions(self, env):
+ raise InternalError("analyse_expressions not implemented for %s" % \
+ self.__class__.__name__)
+
+ def generate_code(self, code):
+ raise InternalError("generate_code not implemented for %s" % \
+ self.__class__.__name__)
+
+
+class BlockNode:
+ # Mixin class for nodes representing a declaration block.
+ pass
+
+# def generate_const_definitions(self, env, code):
+# if env.const_entries:
+# code.putln("")
+# for entry in env.const_entries:
+# if not entry.is_interned:
+# code.put_var_declaration(entry, static = 1)
+
+# def generate_interned_name_decls(self, env, code):
+# # Flush accumulated interned names from the global scope
+# # and generate declarations for them.
+# genv = env.global_scope()
+# intern_map = genv.intern_map
+# names = genv.interned_names
+# if names:
+# code.putln("")
+# for name in names:
+# code.putln(
+# "static PyObject *%s;" % intern_map[name])
+# del names[:]
+
+# def generate_py_string_decls(self, env, code):
+# entries = env.pystring_entries
+# if entries:
+# code.putln("")
+# for entry in entries:
+# code.putln(
+# "static PyObject *%s;" % entry.pystring_cname)
+
+
+class StatListNode(Node):
+ # stats a list of StatNode
+
+ def analyse_declarations(self, env):
+ #print "StatListNode.analyse_declarations" ###
+ for stat in self.stats:
+ stat.analyse_declarations(env)
+
+ def analyse_expressions(self, env):
+ #print "StatListNode.analyse_expressions" ###
+ for stat in self.stats:
+ stat.analyse_expressions(env)
+
+ def generate_function_definitions(self, env, code):
+ #print "StatListNode.generate_function_definitions" ###
+ for stat in self.stats:
+ stat.generate_function_definitions(env, code)
+
+ def generate_execution_code(self, code):
+ #print "StatListNode.generate_execution_code" ###
+ for stat in self.stats:
+ code.mark_pos(stat.pos)
+ stat.generate_execution_code(code)
+
+
+class StatNode(Node):
+ #
+ # Code generation for statements is split into the following subphases:
+ #
+ # (1) generate_function_definitions
+ # Emit C code for the definitions of any structs,
+ # unions, enums and functions defined in the current
+ # scope-block.
+ #
+ # (2) generate_execution_code
+ # Emit C code for executable statements.
+ #
+
+ def generate_function_definitions(self, env, code):
+ pass
+
+ def generate_execution_code(self, code):
+ raise InternalError("generate_execution_code not implemented for %s" % \
+ self.__class__.__name__)
+
+
+class CDefExternNode(StatNode):
+ # include_file string or None
+ # body StatNode
+
+ def analyse_declarations(self, env):
+ if self.include_file:
+ env.add_include_file(self.include_file)
+ old_cinclude_flag = env.in_cinclude
+ env.in_cinclude = 1
+ self.body.analyse_declarations(env)
+ env.in_cinclude = old_cinclude_flag
+
+ def analyse_expressions(self, env):
+ pass
+
+ def generate_execution_code(self, code):
+ pass
+
+
+class CDeclaratorNode(Node):
+ # Part of a C declaration.
+ #
+ # Processing during analyse_declarations phase:
+ #
+ # analyse
+ # Returns (name, type) pair where name is the
+ # CNameDeclaratorNode of the name being declared
+ # and type is the type it is being declared as.
+ #
+ # calling_convention string Calling convention of CFuncDeclaratorNode
+ # for which this is a base
+
+ calling_convention = ""
+
+
+class CNameDeclaratorNode(CDeclaratorNode):
+ # name string The Pyrex name being declared
+ # cname string or None C name, if specified
+
+ def analyse(self, base_type, env):
+ return self, base_type
+
+
+class CPtrDeclaratorNode(CDeclaratorNode):
+ # base CDeclaratorNode
+
+ def analyse(self, base_type, env):
+ if base_type.is_pyobject:
+ error(self.pos,
+ "Pointer base type cannot be a Python object")
+ ptr_type = PyrexTypes.c_ptr_type(base_type)
+ return self.base.analyse(ptr_type, env)
+
+
+class CArrayDeclaratorNode(CDeclaratorNode):
+ # base CDeclaratorNode
+ # dimension ExprNode
+
+ def analyse(self, base_type, env):
+ if self.dimension:
+ self.dimension.analyse_const_expression(env)
+ if not self.dimension.type.is_int:
+ error(self.dimension.pos, "Array dimension not integer")
+ size = self.dimension.result()
+ else:
+ size = None
+ if not base_type.is_complete():
+ error(self.pos,
+ "Array element type '%s' is incomplete" % base_type)
+ if base_type.is_pyobject:
+ error(self.pos,
+ "Array element cannot be a Python object")
+ if base_type.is_cfunction:
+ error(self.pos,
+ "Array element cannot be a function")
+ array_type = PyrexTypes.c_array_type(base_type, size)
+ return self.base.analyse(array_type, env)
+
+
+class CFuncDeclaratorNode(CDeclaratorNode):
+ # base CDeclaratorNode
+ # args [CArgDeclNode]
+ # has_varargs boolean
+ # exception_value ConstNode
+ # exception_check boolean True if PyErr_Occurred check needed
+ # nogil boolean Can be called without gil
+ # with_gil boolean Acquire gil around function body
+
+ def analyse(self, return_type, env):
+ func_type_args = []
+ for arg_node in self.args:
+ name_declarator, type = arg_node.analyse(env)
+ name = name_declarator.name
+ if name_declarator.cname:
+ error(self.pos,
+ "Function argument cannot have C name specification")
+ # Turn *[] argument into **
+ if type.is_array:
+ type = PyrexTypes.c_ptr_type(type.base_type)
+ # Catch attempted C-style func(void) decl
+ if type.is_void:
+ error(arg_node.pos, "Function argument cannot be void")
+ func_type_args.append(
+ PyrexTypes.CFuncTypeArg(name, type, arg_node.pos))
+ if arg_node.default:
+ error(arg_node.pos, "C function argument cannot have default value")
+ exc_val = None
+ exc_check = 0
+ if return_type.is_pyobject \
+ and (self.exception_value or self.exception_check):
+ error(self.pos,
+ "Exception clause not allowed for function returning Python object")
+ else:
+ if self.exception_value:
+ self.exception_value.analyse_const_expression(env)
+ exc_val = self.exception_value.result()
+ if not return_type.assignable_from(self.exception_value.type):
+ error(self.exception_value.pos,
+ "Exception value incompatible with function return type")
+ exc_check = self.exception_check
+ if return_type.is_array:
+ error(self.pos,
+ "Function cannot return an array")
+ if return_type.is_cfunction:
+ error(self.pos,
+ "Function cannot return a function")
+ func_type = PyrexTypes.CFuncType(
+ return_type, func_type_args, self.has_varargs,
+ exception_value = exc_val, exception_check = exc_check,
+ calling_convention = self.base.calling_convention,
+ nogil = self.nogil, with_gil = self.with_gil)
+ return self.base.analyse(func_type, env)
+
+
+class CArgDeclNode(Node):
+ # Item in a function declaration argument list.
+ #
+ # base_type CBaseTypeNode
+ # declarator CDeclaratorNode
+ # #not_none boolean Tagged with 'not None'
+ # allow_none tristate True == 'or None', False == 'not None', None = unspecified
+ # default ExprNode or None
+ # default_entry Symtab.Entry Entry for the variable holding the default value
+ # is_self_arg boolean Is the "self" arg of an extension type method
+ # is_kw_only boolean Is a keyword-only argument
+
+ is_self_arg = 0
+
+ def analyse(self, env):
+ #print "CArgDeclNode.analyse: is_self_arg =", self.is_self_arg ###
+ base_type = self.base_type.analyse(env)
+ return self.declarator.analyse(base_type, env)
+
+
+class CBaseTypeNode(Node):
+ # Abstract base class for C base type nodes.
+ #
+ # Processing during analyse_declarations phase:
+ #
+ # analyse
+ # Returns the type.
+
+ pass
+
+
+class CSimpleBaseTypeNode(CBaseTypeNode):
+ # name string
+ # module_path [string] Qualifying name components
+ # is_basic_c_type boolean
+ # signed boolean
+ # longness integer
+ # is_self_arg boolean Is self argument of C method
+
+ def analyse(self, env):
+ # Return type descriptor.
+ #print "CSimpleBaseTypeNode.analyse: is_self_arg =", self.is_self_arg ###
+ type = None
+ if self.is_basic_c_type:
+ type = PyrexTypes.simple_c_type(self.signed, self.longness, self.name)
+ if not type:
+ error(self.pos, "Unrecognised type modifier combination")
+ elif self.name == "object" and not self.module_path:
+ type = py_object_type
+ elif self.name is None:
+ if self.is_self_arg and env.is_c_class_scope:
+ #print "CSimpleBaseTypeNode.analyse: defaulting to parent type" ###
+ type = env.parent_type
+ else:
+ type = py_object_type
+ else:
+ scope = env.find_imported_module(self.module_path, self.pos)
+ if scope:
+ entry = scope.find(self.name, self.pos)
+ if entry and entry.is_type:
+ type = entry.type
+ else:
+ error(self.pos, "'%s' is not a type identifier" % self.name)
+ if type:
+ return type
+ else:
+ return PyrexTypes.error_type
+
+
+class CComplexBaseTypeNode(CBaseTypeNode):
+ # base_type CBaseTypeNode
+ # declarator CDeclaratorNode
+
+ def analyse(self, env):
+ base = self.base_type.analyse(env)
+ _, type = self.declarator.analyse(base, env)
+ return type
+
+
+class CVarDefNode(StatNode):
+ # C variable definition or forward/extern function declaration.
+ #
+ # visibility 'private' or 'public' or 'extern'
+ # base_type CBaseTypeNode
+ # declarators [CDeclaratorNode]
+ # in_pxd boolean
+ # api boolean
+
+ def analyse_declarations(self, env, dest_scope = None):
+ if not dest_scope:
+ dest_scope = env
+ base_type = self.base_type.analyse(env)
+ for declarator in self.declarators:
+ name_declarator, type = declarator.analyse(base_type, env)
+ if not type.is_complete():
+ if not (self.visibility == 'extern' and type.is_array):
+ error(declarator.pos,
+ "Variable type '%s' is incomplete" % type)
+ if self.visibility == 'extern' and type.is_pyobject:
+ error(declarator.pos,
+ "Python object cannot be declared extern")
+ name = name_declarator.name
+ cname = name_declarator.cname
+ if type.is_cfunction:
+ entry = dest_scope.declare_cfunction(name, type, declarator.pos,
+ cname = cname, visibility = self.visibility, in_pxd = self.in_pxd,
+ api = self.api)
+ else:
+ if self.in_pxd and self.visibility <> 'extern':
+ error(self.pos,
+ "Only 'extern' C variable declaration allowed in .pxd file")
+ dest_scope.declare_var(name, type, declarator.pos,
+ cname = cname, visibility = self.visibility, is_cdef = 1)
+
+ def analyse_expressions(self, env):
+ pass
+
+ def generate_execution_code(self, code):
+ pass
+
+
+class CStructOrUnionDefNode(StatNode):
+ # name string
+ # cname string or None
+ # module_path [string]
+ # kind "struct" or "union"
+ # typedef_flag boolean
+ # cplus_flag boolean
+ # visibility "public" or "private"
+ # in_pxd boolean
+ # attributes [CVarDefNode] or None
+ # entry Entry
+ # bases [([name, ...], name), ...]
+
+ def analyse_declarations(self, env):
+ scope = None
+ base_scopes = []
+ for base in self.bases:
+ base_entry = env.find_qualified_name(base, self.pos)
+ if base_entry:
+ if base_entry.is_type and base_entry.type.is_struct_or_union \
+ and base_entry.type.scope.is_cplus:
+ base_scopes.append(base_entry.type.scope)
+ else:
+ error(self.pos, "Base type '%s' is not a C++ struct" %
+ ".".join(base[0] + [base[1]]))
+ if self.attributes is not None:
+ scope = StructOrUnionScope(base_scopes = base_scopes, is_cplus = self.cplus_flag)
+ if self.module_path:
+ home_scope = env.find_imported_module(self.module_path, self.pos)
+ if not home_scope:
+ return
+ else:
+ home_scope = env
+ def declare():
+ self.entry = home_scope.declare_struct_or_union(
+ self.name, self.kind, scope, self.typedef_flag, self.pos,
+ self.cname, visibility = self.visibility)
+ if self.attributes is not None:
+ if self.in_pxd and not env.in_cinclude:
+ self.entry.defined_in_pxd = 1
+ if not self.typedef_flag:
+ declare()
+ if self.attributes is not None:
+ for attr in self.attributes:
+ attr.analyse_declarations(env, scope)
+ if self.typedef_flag:
+ declare()
+
+ def analyse_expressions(self, env):
+ pass
+
+ def generate_execution_code(self, code):
+ pass
+
+
+class CEnumDefNode(StatNode):
+ # name string or None
+ # cname string or None
+ # items [CEnumDefItemNode]
+ # typedef_flag boolean
+ # visibility "public" or "private"
+ # in_pxd boolean
+ # entry Entry
+
+ def analyse_declarations(self, env):
+ self.entry = env.declare_enum(self.name, self.pos,
+ cname = self.cname, typedef_flag = self.typedef_flag,
+ visibility = self.visibility)
+ if self.items is not None:
+ if self.in_pxd and not env.in_cinclude:
+ self.entry.defined_in_pxd = 1
+ for item in self.items:
+ item.analyse_declarations(env, self.entry)
+
+ def analyse_expressions(self, env):
+ pass
+
+ def generate_execution_code(self, code):
+ pass
+
+
+class CEnumDefItemNode(StatNode):
+ # name string
+ # cname string or None
+ # value ExprNode or None
+
+ def analyse_declarations(self, env, enum_entry):
+ value_node = self.value
+ if value_node:
+ value_node.analyse_const_expression(env)
+ type = value_node.type
+ if type.is_int or type.is_enum:
+ value = value_node.result()
+ else:
+ error(self.pos,
+ "Type '%s' is not a valid enum value" % type)
+ value = "<error>"
+ else:
+ value = self.name
+ entry = env.declare_const(self.name, enum_entry.type,
+ value, self.pos, cname = self.cname)
+ enum_entry.enum_values.append(entry)
+
+
+class CTypeDefNode(StatNode):
+ # base_type CBaseTypeNode
+ # declarator CDeclaratorNode
+ # visibility "public" or "private"
+ # in_pxd boolean
+
+ def analyse_declarations(self, env):
+ base = self.base_type.analyse(env)
+ name_declarator, type = self.declarator.analyse(base, env)
+ name = name_declarator.name
+ cname = name_declarator.cname
+ entry = env.declare_typedef(name, type, self.pos,
+ cname = cname, visibility = self.visibility)
+ if self.in_pxd and not env.in_cinclude:
+ entry.defined_in_pxd = 1
+
+ def analyse_expressions(self, env):
+ pass
+
+ def generate_execution_code(self, code):
+ pass
+
+
+class FuncDefNode(StatNode, BlockNode):
+ # Base class for function definition nodes.
+ #
+ # return_type PyrexType
+ # #filename string C name of filename string const
+ # entry Symtab.Entry
+
+ def analyse_expressions(self, env):
+ pass
+
+ def need_gil_acquisition(self, lenv):
+ return 0
+
+ def generate_function_definitions(self, env, code):
+ # Generate C code for header and body of function
+ genv = env.global_scope()
+ lenv = LocalScope(name = self.entry.name, outer_scope = genv)
+ lenv.return_type = self.return_type
+ type = self.entry.type
+ if type.is_cfunction:
+ lenv.nogil = type.nogil and not type.with_gil
+ code.init_labels()
+ self.declare_arguments(lenv)
+ self.body.analyse_declarations(lenv)
+ self.body.analyse_expressions(lenv)
+ # Code for nested function definitions would go here
+ # if we supported them, which we probably won't.
+ # ----- Function header
+ code.putln("")
+ self.generate_function_header(code,
+ with_pymethdef = env.is_py_class_scope)
+ # ----- Local variable declarations
+ self.generate_argument_declarations(lenv, code)
+ code.put_var_declarations(lenv.var_entries)
+ init = ""
+ if not self.return_type.is_void:
+ code.putln(
+ "%s%s;" %
+ (self.return_type.declaration_code(
+ Naming.retval_cname),
+ init))
+ code.put_var_declarations(lenv.temp_entries)
+ self.generate_keyword_list(code)
+ # ----- Extern library function declarations
+ lenv.generate_library_function_declarations(code)
+ # ----- GIL acquisition
+ acquire_gil = self.need_gil_acquisition(lenv)
+ if acquire_gil:
+ lenv.global_scope().gil_used = 1
+ code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
+ # ----- Fetch arguments
+ self.generate_argument_parsing_code(code)
+ self.generate_argument_increfs(lenv, code)
+ # ----- Initialise local variables
+ for entry in lenv.var_entries:
+ if entry.type.is_pyobject and entry.init_to_none and entry.used:
+ code.put_init_var_to_py_none(entry)
+ # ----- Check and convert arguments
+ self.generate_argument_conversion_code(code)
+ self.generate_argument_type_tests(code)
+ # ----- Function body
+ self.body.generate_execution_code(code)
+ # ----- Default return value
+ code.putln("")
+ if self.return_type.is_pyobject:
+ #if self.return_type.is_extension_type:
+ # lhs = "(PyObject *)%s" % Naming.retval_cname
+ #else:
+ lhs = Naming.retval_cname
+ code.put_init_to_py_none(lhs, self.return_type)
+ else:
+ val = self.return_type.default_value
+ if val:
+ code.putln("%s = %s;" % (Naming.retval_cname, val))
+ #code.putln("goto %s;" % code.return_label)
+ # ----- Error cleanup
+ if code.error_label in code.labels_used:
+ code.put_goto(code.return_label)
+ code.put_label(code.error_label)
+ code.put_var_xdecrefs(lenv.temp_entries)
+ default_retval = self.return_type.default_value
+ err_val = self.error_value()
+ exc_check = self.caller_will_check_exceptions()
+ if err_val or exc_check:
+ code.putln(
+ '__Pyx_AddTraceback("%s");' %
+ self.entry.qualified_name)
+ val = err_val or default_retval
+ if val:
+ code.putln(
+ "%s = %s;" % (
+ Naming.retval_cname,
+ val))
+ else:
+ code.use_utility_code(unraisable_exception_utility_code)
+ code.putln(
+ '__Pyx_WriteUnraisable("%s");' %
+ self.entry.qualified_name)
+ #if not self.return_type.is_void:
+ if default_retval:
+ code.putln(
+ "%s = %s;" % (
+ Naming.retval_cname,
+ default_retval))
+ #self.return_type.default_value))
+ # ----- Return cleanup
+ code.put_label(code.return_label)
+ code.put_var_decrefs(lenv.var_entries, used_only = 1)
+ #code.put_var_decrefs(lenv.arg_entries)
+ self.generate_argument_decrefs(lenv, code)
+ self.put_stararg_decrefs(code)
+ if acquire_gil:
+ code.putln("PyGILState_Release(_save);")
+ if not self.return_type.is_void:
+ code.putln("return %s;" % Naming.retval_cname)
+ code.putln("}")
+
+ def put_stararg_decrefs(self, code):
+ pass
+
+ def declare_argument(self, env, arg, readonly = 0):
+ if arg.type.is_void:
+ error(arg.pos, "Invalid use of 'void'")
+ elif not arg.type.is_complete() and not arg.type.is_array:
+ error(arg.pos,
+ "Argument type '%s' is incomplete" % arg.type)
+ return env.declare_arg(arg.name, arg.type, arg.pos,
+ readonly = readonly)
+
+ def generate_argument_increfs(self, env, code):
+ # Turn writable borrowed argument refs into owned refs.
+ # This is necessary, because if the argument is assigned to,
+ # it will be decrefed.
+ for entry in env.arg_entries:
+ if not entry.is_readonly:
+ code.put_var_incref(entry)
+
+ def generate_argument_decrefs(self, env, code):
+ for entry in env.arg_entries:
+ if not entry.is_readonly:
+ code.put_var_decref(entry)
+
+ def generate_execution_code(self, code):
+ pass
+
+
+class CFuncDefNode(FuncDefNode):
+ # C function definition.
+ #
+ # visibility 'private' or 'public' or 'extern'
+ # base_type CBaseTypeNode
+ # declarator CDeclaratorNode
+ # body StatListNode
+ # api boolean
+ #
+ # with_gil boolean Acquire GIL around body
+ # type CFuncType
+
+ def unqualified_name(self):
+ return self.entry.name
+
+ def analyse_declarations(self, env):
+ base_type = self.base_type.analyse(env)
+ name_declarator, type = self.declarator.analyse(base_type, env)
+ if not type.is_cfunction:
+ error(self.pos,
+ "Suite attached to non-function declaration")
+ # Remember the actual type according to the function header
+ # written here, because the type in the symbol table entry
+ # may be different if we're overriding a C method inherited
+ # from the base type of an extension type.
+ self.type = type
+ name = name_declarator.name
+ cname = name_declarator.cname
+ self.entry = env.declare_cfunction(
+ name, type, self.pos,
+ cname = cname, visibility = self.visibility,
+ defining = self.body is not None,
+ api = self.api)
+ self.return_type = type.return_type
+
+ def declare_arguments(self, env):
+ type = self.type
+ without_gil = type.nogil and not type.with_gil
+ for arg in type.args:
+ if not arg.name:
+ error(arg.pos, "Missing argument name")
+ self.declare_argument(env, arg,
+ readonly = without_gil and arg.type.is_pyobject)
+
+ def need_gil_acquisition(self, lenv):
+ type = self.type
+ with_gil = type.with_gil
+ if type.nogil and not with_gil:
+# for arg in type.args:
+# if arg.type.is_pyobject:
+# error(self.pos,
+# "Function with Python argument cannot be declared nogil")
+ if type.return_type.is_pyobject:
+ error(self.pos,
+ "Function with Python return type cannot be declared nogil")
+ for entry in lenv.var_entries + lenv.temp_entries:
+ #print "CFuncDefNode.need_gil_acquisition:", entry.name, entry.cname, "readonly =", entry.is_readonly ###
+ if entry.type.is_pyobject and not entry.is_readonly:
+ error(self.pos, "Function declared nogil has Python locals or temporaries")
+ return with_gil
+
+ def generate_function_header(self, code, with_pymethdef):
+ arg_decls = []
+ type = self.type
+ visibility = self.entry.visibility
+ for arg in type.args:
+ arg_decls.append(arg.declaration_code())
+ if type.has_varargs:
+ arg_decls.append("...")
+ if not arg_decls:
+ arg_decls = ["void"]
+ entity = type.function_header_code(self.entry.func_cname,
+ string.join(arg_decls, ","))
+ if visibility == 'public':
+ dll_linkage = "DL_EXPORT"
+ else:
+ dll_linkage = None
+ header = self.return_type.declaration_code(entity,
+ dll_linkage = dll_linkage)
+ if visibility <> 'private':
+ storage_class = "%s " % Naming.extern_c_macro
+ else:
+ storage_class = "static "
+ code.putln("%s%s {" % (
+ storage_class,
+ header))
+
+ def generate_argument_declarations(self, env, code):
+ # Arguments already declared in function header
+ pass
+
+ def generate_keyword_list(self, code):
+ pass
+
+ def generate_argument_parsing_code(self, code):
+ pass
+
+ def generate_argument_conversion_code(self, code):
+ pass
+
+ def generate_argument_type_tests(self, code):
+ pass
+
+ def error_value(self):
+ if self.return_type.is_pyobject:
+ return "0"
+ else:
+ #return None
+ return self.entry.type.exception_value
+
+ def caller_will_check_exceptions(self):
+ return self.entry.type.exception_check
+
+
+class PyArgDeclNode(Node):
+ # Argument which must be a Python object (used
+ # for * and ** arguments).
+ #
+ # name string
+ # entry Symtab.Entry
+
+ pass
+
+
+class DefNode(FuncDefNode):
+ # A Python function definition.
+ #
+ # name string the Python name of the function
+ # args [CArgDeclNode] formal arguments
+ # star_arg PyArgDeclNode or None * argument
+ # starstar_arg PyArgDeclNode or None ** argument
+ # doc string or None
+ # body StatListNode
+ #
+ # The following subnode is constructed internally
+ # when the def statement is inside a Python class definition.
+ #
+ # assmt AssignmentNode Function construction/assignment
+
+ assmt = None
+ num_kwonly_args = 0
+ reqd_kw_flags_cname = "0"
+ has_star_or_kwonly_args = 0
+
+ def __init__(self, pos, **kwds):
+ FuncDefNode.__init__(self, pos, **kwds)
+ n = 0
+ for arg in self.args:
+ if arg.kw_only:
+ n += 1
+ self.num_kwonly_args = n
+ if self.star_arg or self.starstar_arg or n > 0:
+ self.has_star_or_kwonly_args = 1
+
+ def analyse_declarations(self, env):
+ for arg in self.args:
+ base_type = arg.base_type.analyse(env)
+ name_declarator, type = \
+ arg.declarator.analyse(base_type, env)
+ arg.name = name_declarator.name
+ if name_declarator.cname:
+ error(self.pos,
+ "Python function argument cannot have C name specification")
+ arg.type = type.as_argument_type()
+ arg.hdr_type = None
+ arg.needs_conversion = 0
+ arg.needs_type_test = 0
+ arg.is_generic = 1
+ if arg.allow_none is not None and not arg.type.is_extension_type:
+ error(self.pos,
+ "Only extension type arguments can have 'or None' or 'not None'")
+ self.declare_pyfunction(env)
+ self.analyse_signature(env)
+ self.return_type = self.entry.signature.return_type()
+# if self.has_star_or_kwonly_args:
+# env.use_utility_code(get_starargs_utility_code)
+
+ def analyse_signature(self, env):
+ any_type_tests_needed = 0
+ sig = self.entry.signature
+ nfixed = sig.num_fixed_args()
+ for i in range(nfixed):
+ if i < len(self.args):
+ arg = self.args[i]
+ arg.is_generic = 0
+ if sig.is_self_arg(i):
+ arg.is_self_arg = 1
+ arg.hdr_type = arg.type = env.parent_type
+ arg.needs_conversion = 0
+ else:
+ arg.hdr_type = sig.fixed_arg_type(i)
+ if not arg.type.same_as(arg.hdr_type):
+ if arg.hdr_type.is_pyobject and arg.type.is_pyobject:
+ arg.needs_type_test = 1
+ any_type_tests_needed = 1
+ else:
+ arg.needs_conversion = 1
+ if arg.needs_conversion:
+ arg.hdr_cname = Naming.arg_prefix + arg.name
+ else:
+ arg.hdr_cname = Naming.var_prefix + arg.name
+ else:
+ self.bad_signature()
+ return
+ if nfixed < len(self.args):
+ if not sig.has_generic_args:
+ self.bad_signature()
+ for arg in self.args:
+ if arg.is_generic and arg.type.is_extension_type:
+ arg.needs_type_test = 1
+ any_type_tests_needed = 1
+# if any_type_tests_needed:
+# env.use_utility_code(arg_type_test_utility_code)
+
+ def bad_signature(self):
+ sig = self.entry.signature
+ expected_str = "%d" % sig.num_fixed_args()
+ if sig.has_generic_args:
+ expected_str = expected_str + " or more"
+ name = self.name
+ if name.startswith("__") and name.endswith("__"):
+ desc = "Special method"
+ else:
+ desc = "Method"
+ error(self.pos,
+ "%s %s has wrong number of arguments "
+ "(%d declared, %s expected)" % (
+ desc, self.name, len(self.args), expected_str))
+
+ def declare_pyfunction(self, env):
+ #print "DefNode.declare_pyfunction:", self.name, "in", env ###
+ name = self.name
+ entry = env.declare_pyfunction(self.name, self.pos)
+ self.entry = entry
+ prefix = env.scope_prefix
+ entry.func_cname = \
+ Naming.func_prefix + prefix + name
+ entry.pymethdef_cname = \
+ Naming.pymethdef_prefix + prefix + name
+ if not entry.is_special:
+ entry.doc = self.doc
+ entry.doc_cname = \
+ Naming.funcdoc_prefix + prefix + name
+
+ def declare_arguments(self, env):
+ for arg in self.args:
+ if not arg.name:
+ error(arg.pos, "Missing argument name")
+ if arg.needs_conversion:
+ arg.entry = env.declare_var(arg.name, arg.type, arg.pos)
+ if arg.type.is_pyobject:
+ arg.entry.init = "0"
+ arg.entry.init_to_none = 0
+ else:
+ arg.entry = self.declare_argument(env, arg)
+ arg.entry.used = 1
+ arg.entry.is_self_arg = arg.is_self_arg
+ if arg.hdr_type:
+ if arg.is_self_arg or \
+ (arg.type.is_extension_type and not arg.hdr_type.is_extension_type):
+ arg.entry.is_declared_generic = 1
+ self.declare_python_arg(env, self.star_arg)
+ self.declare_python_arg(env, self.starstar_arg)
+
+ def declare_python_arg(self, env, arg):
+ if arg:
+ entry = env.declare_var(arg.name,
+ PyrexTypes.py_object_type, arg.pos)
+ entry.used = 1
+ entry.init = "0"
+ entry.init_to_none = 0
+ entry.xdecref_cleanup = 1
+ arg.entry = entry
+
+ def analyse_expressions(self, env):
+ self.analyse_default_values(env)
+ if env.is_py_class_scope:
+ self.synthesize_assignment_node(env)
+
+ def analyse_default_values(self, env):
+ for arg in self.args:
+ if arg.default:
+ if arg.is_generic:
+ arg.default.analyse_types(env)
+ arg.default = arg.default.coerce_to(arg.type, env)
+ arg.default.allocate_temps(env)
+ arg.default_entry = env.add_default_value(arg.type)
+ arg.default_entry.used = 1
+ else:
+ error(arg.pos,
+ "This argument cannot have a default value")
+ arg.default = None
+
+ def synthesize_assignment_node(self, env):
+ import ExprNodes
+ self.assmt = SingleAssignmentNode(self.pos,
+ lhs = ExprNodes.NameNode(self.pos, name = self.name),
+ rhs = ExprNodes.UnboundMethodNode(self.pos,
+ class_cname = env.class_obj_cname,
+ function = ExprNodes.PyCFunctionNode(self.pos,
+ pymethdef_cname = self.entry.pymethdef_cname)))
+ self.assmt.analyse_declarations(env)
+ self.assmt.analyse_expressions(env)
+
+ def generate_function_header(self, code, with_pymethdef):
+ arg_code_list = []
+ sig = self.entry.signature
+ if sig.has_dummy_arg:
+ arg_code_list.append(
+ "PyObject *%s" % Naming.self_cname)
+ for arg in self.args:
+ if not arg.is_generic:
+ if arg.is_self_arg:
+ arg_code_list.append("PyObject *%s" % arg.hdr_cname)
+ else:
+ arg_code_list.append(
+ arg.hdr_type.declaration_code(arg.hdr_cname))
+ if sig.has_generic_args:
+ arg_code_list.append(
+ "PyObject *%s, PyObject *%s"
+ % (Naming.args_cname, Naming.kwds_cname))
+ arg_code = ", ".join(arg_code_list)
+ dc = self.return_type.declaration_code(self.entry.func_cname)
+ header = "static %s(%s)" % (dc, arg_code)
+ code.putln("%s; /*proto*/" % header)
+ if self.entry.doc:
+ code.putln(
+ 'static char %s[] = "%s";' % (
+ self.entry.doc_cname,
+ self.entry.doc))
+ if with_pymethdef:
+ code.put(
+ "static PyMethodDef %s = " %
+ self.entry.pymethdef_cname)
+ code.put_pymethoddef(self.entry, ";")
+ code.putln("%s {" % header)
+
+ def generate_argument_declarations(self, env, code):
+ for arg in self.args:
+ if arg.is_generic: # or arg.needs_conversion:
+ code.put_var_declaration(arg.entry)
+
+ def generate_keyword_list(self, code):
+ if self.entry.signature.has_generic_args:
+ reqd_kw_flags = []
+ has_reqd_kwds = False
+ code.put(
+ "static char *%s[] = {" %
+ Naming.kwdlist_cname)
+ for arg in self.args:
+ if arg.is_generic:
+ code.put(
+ '"%s",' %
+ arg.name)
+ if arg.kw_only and not arg.default:
+ has_reqd_kwds = 1
+ flag = "1"
+ else:
+ flag = "0"
+ reqd_kw_flags.append(flag)
+ code.putln(
+ "0};")
+ if has_reqd_kwds:
+ flags_name = Naming.reqd_kwds_cname
+ self.reqd_kw_flags_cname = flags_name
+ code.putln(
+ "static char %s[] = {%s};" % (
+ flags_name,
+ ",".join(reqd_kw_flags)))
+
+ def generate_argument_parsing_code(self, code):
+ # Generate PyArg_ParseTuple call for generic
+ # arguments, if any.
+ has_kwonly_args = self.num_kwonly_args > 0
+ has_star_or_kw_args = self.star_arg is not None \
+ or self.starstar_arg is not None or has_kwonly_args
+ if not self.entry.signature.has_generic_args:
+ if has_star_or_kw_args:
+ error(self.pos, "This method cannot have * or keyword arguments")
+ else:
+ arg_addrs = []
+ arg_formats = []
+ default_seen = 0
+ for arg in self.args:
+ arg_entry = arg.entry
+ if arg.is_generic:
+ if arg.default:
+ code.putln(
+ "%s = %s;" % (
+ arg_entry.cname,
+ arg.default_entry.cname))
+ if not default_seen:
+ arg_formats.append("|")
+ default_seen = 1
+ elif default_seen and not arg.kw_only:
+ error(arg.pos, "Non-default argument following default argument")
+ arg_addrs.append("&" + arg_entry.cname)
+ format = arg_entry.type.parsetuple_format
+ if format:
+ arg_formats.append(format)
+ else:
+ error(arg.pos,
+ "Cannot convert Python object argument to type '%s'"
+ % arg.type)
+ error_return_code = "return %s;" % self.error_value()
+ argformat = '"%s"' % string.join(arg_formats, "")
+ if has_star_or_kw_args:
+ self.generate_stararg_getting_code(code)
+ pt_arglist = [Naming.args_cname, Naming.kwds_cname, argformat,
+ Naming.kwdlist_cname] + arg_addrs
+ pt_argstring = string.join(pt_arglist, ", ")
+ code.put(
+ 'if (!PyArg_ParseTupleAndKeywords(%s)) ' %
+ pt_argstring)
+ if has_star_or_kw_args:
+ code.putln("{")
+ code.put_xdecref(Naming.args_cname, py_object_type)
+ code.put_xdecref(Naming.kwds_cname, py_object_type)
+ self.generate_arg_xdecref(self.star_arg, code)
+ self.generate_arg_xdecref(self.starstar_arg, code)
+ code.putln(error_return_code)
+ code.putln("}")
+ else:
+ code.putln(error_return_code)
+
+ def put_stararg_decrefs(self, code):
+ if self.has_star_or_kwonly_args:
+ code.put_xdecref(Naming.args_cname, py_object_type)
+ code.put_xdecref(Naming.kwds_cname, py_object_type)
+
+ def generate_arg_xdecref(self, arg, code):
+ if arg:
+ code.put_var_xdecref(arg.entry)
+
+ def arg_address(self, arg):
+ if arg:
+ return "&%s" % arg.entry.cname
+ else:
+ return 0
+
+ def generate_stararg_getting_code(self, code):
+ num_kwonly = self.num_kwonly_args
+ nargs = len(self.args) - num_kwonly - self.entry.signature.num_fixed_args()
+ star_arg_addr = self.arg_address(self.star_arg)
+ starstar_arg_addr = self.arg_address(self.starstar_arg)
+ code.use_utility_code(get_starargs_utility_code)
+ code.putln(
+ "if (__Pyx_GetStarArgs(&%s, &%s, %s, %s, %s, %s, %s) < 0) return %s;" % (
+ Naming.args_cname,
+ Naming.kwds_cname,
+ Naming.kwdlist_cname,
+ nargs,
+ star_arg_addr,
+ starstar_arg_addr,
+ self.reqd_kw_flags_cname,
+ self.error_value()))
+
+ def generate_argument_conversion_code(self, code):
+ # Generate code to convert arguments from
+ # signature type to declared type, if needed.
+ for arg in self.args:
+ if arg.needs_conversion:
+ self.generate_arg_conversion(arg, code)
+
+ def generate_arg_conversion(self, arg, code):
+ # Generate conversion code for one argument.
+ old_type = arg.hdr_type
+ new_type = arg.type
+ if old_type.is_pyobject:
+ self.generate_arg_conversion_from_pyobject(arg, code)
+ elif new_type.is_pyobject:
+ self.generate_arg_conversion_to_pyobject(arg, code)
+ else:
+ if new_type.assignable_from(old_type):
+ code.putln(
+ "%s = %s;" % (arg.entry.cname, arg.hdr_cname))
+ else:
+ error(arg.pos,
+ "Cannot convert argument from '%s' to '%s'" %
+ (old_type, new_type))
+
+ def generate_arg_conversion_from_pyobject(self, arg, code):
+ new_type = arg.type
+ func = new_type.from_py_function
+ if func:
+ code.putln("%s = %s(%s); if (PyErr_Occurred()) %s" % (
+ arg.entry.cname,
+ func,
+ arg.hdr_cname,
+ code.error_goto(arg.pos)))
+ else:
+ error(arg.pos,
+ "Cannot convert Python object argument to type '%s'"
+ % new_type)
+
+ def generate_arg_conversion_to_pyobject(self, arg, code):
+ old_type = arg.hdr_type
+ func = old_type.to_py_function
+ if func:
+ code.putln("%s = %s(%s); if (!%s) %s" % (
+ arg.entry.cname,
+ func,
+ arg.hdr_cname,
+ arg.entry.cname,
+ code.error_goto(arg.pos)))
+ else:
+ error(arg.pos,
+ "Cannot convert argument of type '%s' to Python object"
+ % old_type)
+
+ def generate_argument_type_tests(self, code):
+ # Generate type tests for args whose signature
+ # type is PyObject * and whose declared type is
+ # a subtype thereof.
+ for arg in self.args:
+ if arg.needs_type_test:
+ self.generate_arg_type_test(arg, code)
+
+ def generate_arg_type_test(self, arg, code):
+ # Generate type test for one argument.
+ if arg.type.typeobj_is_available():
+ typeptr_cname = arg.type.typeptr_cname
+ arg_code = "((PyObject *)%s)" % arg.entry.cname
+ code.use_utility_code(arg_type_test_utility_code)
+ code.putln(
+ 'if (!__Pyx_ArgTypeTest(%s, %s, %d, "%s")) %s' % (
+ arg_code,
+ typeptr_cname,
+ #not arg.not_none,
+ arg.allow_none <> False,
+ arg.name,
+ code.error_goto(arg.pos)))
+ if arg.allow_none is None:
+ one_time_warning(arg.pos, 'or_none',
+ "'not None' will become the default in a future version of Pyrex. "
+ "Use 'or None' to allow passing None.")
+ else:
+ error(arg.pos, "Cannot test type of extern C class "
+ "without type object name specification")
+
+ def generate_execution_code(self, code):
+ # Evaluate and store argument default values
+ for arg in self.args:
+ default = arg.default
+ if default:
+ default.generate_evaluation_code(code)
+ default.make_owned_reference(code)
+ code.putln(
+ "%s = %s;" % (
+ arg.default_entry.cname,
+ default.result_as(arg.default_entry.type)))
+ default.generate_post_assignment_code(code)
+# if default.is_temp and default.type.is_pyobject:
+# code.putln(
+# "%s = 0;" %
+# default.result())
+ # For Python class methods, create and store function object
+ if self.assmt:
+ self.assmt.generate_execution_code(code)
+
+ def error_value(self):
+ return self.entry.signature.error_value
+
+ def caller_will_check_exceptions(self):
+ return 1
+
+
+class PyClassDefNode(StatNode, BlockNode):
+ # A Python class definition.
+ #
+ # name string Name of the class
+ # doc string or None
+ # body StatNode Attribute definition code
+ # entry Symtab.Entry
+ # scope PyClassScope
+ #
+ # The following subnodes are constructed internally:
+ #
+ # dict DictNode Class dictionary
+ # classobj ClassNode Class object
+ # target NameNode Variable to assign class object to
+
+ def __init__(self, pos, name, bases, doc, body):
+ StatNode.__init__(self, pos)
+ self.name = name
+ self.doc = doc
+ self.body = body
+ import ExprNodes
+ self.dict = ExprNodes.DictNode(pos, key_value_pairs = [])
+ if self.doc:
+ doc_node = ExprNodes.StringNode(pos, value = self.doc)
+ else:
+ doc_node = None
+ self.classobj = ExprNodes.ClassNode(pos,
+ name = ExprNodes.StringNode(pos, value = name),
+ bases = bases, dict = self.dict, doc = doc_node)
+ self.target = ExprNodes.NameNode(pos, name = name)
+
+ def analyse_declarations(self, env):
+ self.target.analyse_target_declaration(env)
+
+ def analyse_expressions(self, env):
+ self.dict.analyse_expressions(env)
+ self.classobj.analyse_expressions(env)
+ genv = env.global_scope()
+ cenv = PyClassScope(name = self.name, outer_scope = genv)
+ cenv.class_dict_cname = self.dict.result()
+ cenv.class_obj_cname = self.classobj.result()
+ self.scope = cenv
+ self.body.analyse_declarations(cenv)
+ self.body.analyse_expressions(cenv)
+ self.target.analyse_target_expression(env, self.classobj)
+ self.dict.release_temp(env)
+ #self.classobj.release_temp(env)
+ #self.target.release_target_temp(env)
+
+ def generate_function_definitions(self, env, code):
+ #self.generate_py_string_decls(self.scope, code)
+ self.body.generate_function_definitions(
+ self.scope, code)
+
+ def generate_execution_code(self, code):
+ self.dict.generate_evaluation_code(code)
+ self.classobj.generate_evaluation_code(code)
+ self.body.generate_execution_code(code)
+ self.target.generate_assignment_code(self.classobj, code)
+ self.dict.generate_disposal_code(code)
+
+
+class CClassDefNode(StatNode):
+ # An extension type definition.
+ #
+ # visibility 'private' or 'public' or 'extern'
+ # typedef_flag boolean
+ # api boolean
+ # module_name string or None For import of extern type objects
+ # class_name string Unqualified name of class
+ # as_name string or None Name to declare as in this scope
+ # base_class_module string or None Module containing the base class
+ # base_class_name string or None Name of the base class
+ # options CClassOptions:
+ # objstruct_name string or None Specified C name of object struct
+ # typeobj_name string or None Specified C name of type object
+ # no_gc boolean Suppress GC support
+ # in_pxd boolean Is in a .pxd file
+ # doc string or None
+ # body StatNode or None
+ # entry Symtab.Entry
+ # base_type PyExtensionType or None
+
+ entry = None
+
+ def analyse_declarations(self, env):
+ #print "CClassDefNode.analyse_declarations:", self.class_name
+ #print "...visibility =", self.visibility
+ #print "...module_name =", self.module_name
+ if env.in_cinclude and not self.options.objstruct_cname:
+ error(self.pos, "Object struct name specification required for "
+ "C class defined in 'extern from' block")
+ self.base_type = None
+ has_body = self.body is not None
+ if self.base_class_name:
+ if self.base_class_module:
+ base_class_scope = env.find_module(self.base_class_module, self.pos)
+ else:
+ base_class_scope = env
+ if base_class_scope:
+ base_class_entry = base_class_scope.find(self.base_class_name, self.pos)
+ if base_class_entry:
+ if not base_class_entry.is_type:
+ error(self.pos, "'%s' is not a type name" % self.base_class_name)
+ elif not base_class_entry.type.is_extension_type:
+ error(self.pos, "'%s' is not an extension type" % self.base_class_name)
+ elif has_body and base_class_entry.visibility <> 'extern' and not base_class_entry.type.is_defined():
+ error(self.pos, "Base class '%s' is incomplete" % self.base_class_name)
+ else:
+ self.base_type = base_class_entry.type
+ if self.module_name and self.visibility <> 'extern':
+ module_path = self.module_name.split(".")
+ home_scope = env.find_imported_module(module_path, self.pos)
+ if not home_scope:
+ return
+ else:
+ home_scope = env
+ self.entry = home_scope.declare_c_class(
+ name = self.class_name,
+ pos = self.pos,
+ defining = has_body and self.in_pxd,
+ implementing = has_body and not self.in_pxd,
+ module_name = self.module_name,
+ base_type = self.base_type,
+ visibility = self.visibility,
+ typedef_flag = self.typedef_flag,
+ api = self.api,
+ options = self.options)
+ if home_scope is not env and self.visibility == 'extern':
+ env.add_imported_entry(self.class_name, self.entry, pos)
+ scope = self.entry.type.scope
+ if self.doc:
+ scope.doc = self.doc
+ if has_body:
+ self.body.analyse_declarations(scope)
+ if self.in_pxd:
+ scope.defined = 1
+ else:
+ scope.implemented = 1
+ env.allocate_vtable_names(self.entry)
+
+ def analyse_expressions(self, env):
+ if self.body:
+ self.body.analyse_expressions(env)
+
+ def generate_function_definitions(self, env, code):
+ if self.entry and self.body:
+# self.body.generate_function_definitions(
+# self.entry.type.scope, code)
+ self.body.generate_function_definitions(env, code)
+
+ def generate_execution_code(self, code):
+ # This is needed to generate evaluation code for
+ # default values of method arguments.
+ if self.body:
+ self.body.generate_execution_code(code)
+
+
+class PropertyNode(StatNode):
+ # Definition of a property in an extension type.
+ #
+ # name string
+ # doc string or None Doc string
+ # body StatListNode
+
+ def analyse_declarations(self, env):
+ #print "PropertyNode.analyse_declarations:", env ###
+ entry = env.declare_property(self.name, self.doc, self.pos)
+ if entry:
+ #if self.doc:
+ # doc_entry = env.get_string_const(self.doc)
+ # entry.doc_cname = doc_entry.cname
+ self.body.analyse_declarations(entry.scope)
+
+ def analyse_expressions(self, env):
+ self.body.analyse_expressions(env)
+
+ def generate_function_definitions(self, env, code):
+ self.body.generate_function_definitions(env, code)
+
+ def generate_execution_code(self, code):
+ pass
+
+
+class GlobalNode(StatNode):
+ # Global variable declaration.
+ #
+ # names [string]
+
+ def analyse_declarations(self, env):
+ for name in self.names:
+ env.declare_global(name, self.pos)
+
+ def analyse_expressions(self, env):
+ pass
+
+ def generate_execution_code(self, code):
+ pass
+
+
+class ExprStatNode(StatNode):
+ # Expression used as a statement.
+ #
+ # expr ExprNode
+
+ def analyse_expressions(self, env):
+ self.expr.analyse_expressions(env)
+ self.expr.release_temp(env)
+
+ def generate_execution_code(self, code):
+ self.expr.generate_evaluation_code(code)
+ if not self.expr.is_temp and self.expr.result():
+ code.putln("%s;" % self.expr.result())
+ self.expr.generate_disposal_code(code)
+
+
+class AssignmentNode(StatNode):
+ # Abstract base class for assignment nodes.
+ #
+ # The analyse_expressions and generate_execution_code
+ # phases of assignments are split into two sub-phases
+ # each, to enable all the right hand sides of a
+ # parallel assignment to be evaluated before assigning
+ # to any of the left hand sides.
+
+ def analyse_expressions(self, env):
+ self.analyse_types(env)
+ self.allocate_rhs_temps(env)
+ self.allocate_lhs_temps(env)
+
+ def generate_execution_code(self, code):
+ self.generate_rhs_evaluation_code(code)
+ self.generate_assignment_code(code)
+
+
+class SingleAssignmentNode(AssignmentNode):
+ # The simplest case:
+ #
+ # a = b
+ #
+ # lhs ExprNode Left hand side
+ # rhs ExprNode Right hand side
+
+ def analyse_declarations(self, env):
+ self.lhs.analyse_target_declaration(env)
+
+ def analyse_types(self, env, use_temp = 0):
+ self.rhs.analyse_types(env)
+ self.lhs.analyse_target_types(env)
+ self.lhs.gil_assignment_check(env)
+ self.rhs = self.rhs.coerce_to(self.lhs.type, env)
+ if use_temp:
+ self.rhs = self.rhs.coerce_to_temp(env)
+
+ def allocate_rhs_temps(self, env):
+ self.rhs.allocate_temps(env)
+
+ def allocate_lhs_temps(self, env):
+ self.lhs.allocate_target_temps(env, self.rhs)
+
+ def generate_rhs_evaluation_code(self, code):
+ self.rhs.generate_evaluation_code(code)
+
+ def generate_assignment_code(self, code):
+ self.lhs.generate_assignment_code(self.rhs, code)
+
+
+class AugmentedAssignmentNode(SingleAssignmentNode):
+ # An in-place operation:
+ #
+ # a op= b
+ #
+ # lhs ExprNode Left hand side
+ # operator string
+ # rhs ExprNode Right hand side
+
+ def analyse_types(self, env):
+ op = self.operator
+ self.rhs.analyse_types(env)
+ self.lhs.analyse_inplace_types(env)
+ type = self.lhs.type
+ if type.is_pyobject:
+ type = py_object_type
+ else:
+ if type.is_ptr and (op == '+=' or op == '-='):
+ type = c_int_type
+ elif op == "**=":
+ error(self.pos, "**= operator not supported for non-Python types")
+ return
+ self.rhs = self.rhs.coerce_to(type, env)
+
+ def allocate_lhs_temps(self, env):
+ self.lhs.allocate_inplace_target_temps(env, self.rhs)
+
+ def generate_assignment_code(self, code):
+ self.lhs.generate_inplace_assignment_code(self.operator, self.rhs, code)
+
+
+class CascadedAssignmentNode(AssignmentNode):
+ # An assignment with multiple left hand sides:
+ #
+ # a = b = c
+ #
+ # lhs_list [ExprNode] Left hand sides
+ # rhs ExprNode Right hand sides
+ #
+ # Used internally:
+ #
+ # coerced_rhs_list [ExprNode] RHS coerced to type of each LHS
+
+ def analyse_declarations(self, env):
+ for lhs in self.lhs_list:
+ lhs.analyse_target_declaration(env)
+
+ def analyse_types(self, env, use_temp = 0):
+ self.rhs.analyse_types(env)
+ if use_temp:
+ self.rhs = self.rhs.coerce_to_temp(env)
+ else:
+ self.rhs = self.rhs.coerce_to_simple(env)
+ from ExprNodes import CloneNode
+ self.coerced_rhs_list = []
+ for lhs in self.lhs_list:
+ lhs.analyse_target_types(env)
+ lhs.gil_assignment_check(env)
+ rhs = CloneNode(self.rhs)
+ rhs = rhs.coerce_to(lhs.type, env)
+ self.coerced_rhs_list.append(rhs)
+
+ def allocate_rhs_temps(self, env):
+ self.rhs.allocate_temps(env)
+
+ def allocate_lhs_temps(self, env):
+ for lhs, rhs in zip(self.lhs_list, self.coerced_rhs_list):
+ rhs.allocate_temps(env)
+ lhs.allocate_target_temps(env, rhs)
+ #lhs.release_target_temp(env)
+ #rhs.release_temp(env)
+ self.rhs.release_temp(env)
+
+ def generate_rhs_evaluation_code(self, code):
+ self.rhs.generate_evaluation_code(code)
+
+ def generate_assignment_code(self, code):
+ for i in range(len(self.lhs_list)):
+ lhs = self.lhs_list[i]
+ rhs = self.coerced_rhs_list[i]
+ rhs.generate_evaluation_code(code)
+ lhs.generate_assignment_code(rhs, code)
+ # Assignment has disposed of the cloned RHS
+ self.rhs.generate_disposal_code(code)
+
+class ParallelAssignmentNode(AssignmentNode):
+ # A combined packing/unpacking assignment:
+ #
+ # a, b, c = d, e, f
+ #
+ # This has been rearranged by the parser into
+ #
+ # a = d ; b = e ; c = f
+ #
+ # but we must evaluate all the right hand sides
+ # before assigning to any of the left hand sides.
+ #
+ # stats [AssignmentNode] The constituent assignments
+
+ def analyse_declarations(self, env):
+ for stat in self.stats:
+ stat.analyse_declarations(env)
+
+ def analyse_expressions(self, env):
+ for stat in self.stats:
+ stat.analyse_types(env, use_temp = 1)
+ stat.allocate_rhs_temps(env)
+ for stat in self.stats:
+ stat.allocate_lhs_temps(env)
+
+ def generate_execution_code(self, code):
+ for stat in self.stats:
+ stat.generate_rhs_evaluation_code(code)
+ for stat in self.stats:
+ stat.generate_assignment_code(code)
+
+
+class PrintStatNode(StatNode):
+ # print statement
+ #
+ # args [ExprNode]
+ # ends_with_comma boolean
+
+ def analyse_expressions(self, env):
+ for i in range(len(self.args)):
+ arg = self.args[i]
+ arg.analyse_types(env)
+ arg = arg.coerce_to_pyobject(env)
+ arg.allocate_temps(env)
+ arg.release_temp(env)
+ self.args[i] = arg
+# env.use_utility_code(printing_utility_code)
+ self.gil_check(env)
+
+ gil_message = "Python print statement"
+
+ def generate_execution_code(self, code):
+ for arg in self.args:
+ arg.generate_evaluation_code(code)
+ code.use_utility_code(printing_utility_code)
+ code.putln(
+ "if (__Pyx_PrintItem(%s) < 0) %s" % (
+ arg.py_result(),
+ code.error_goto(self.pos)))
+ arg.generate_disposal_code(code)
+ if not self.ends_with_comma:
+ code.use_utility_code(printing_utility_code)
+ code.putln(
+ "if (__Pyx_PrintNewline() < 0) %s" %
+ code.error_goto(self.pos))
+
+
+class DelStatNode(StatNode):
+ # del statement
+ #
+ # args [ExprNode]
+
+ def analyse_declarations(self, env):
+ for arg in self.args:
+ arg.analyse_target_declaration(env)
+
+ def analyse_expressions(self, env):
+ for arg in self.args:
+ arg.analyse_target_expression(env, None)
+ type = arg.type
+ if not (type.is_pyobject
+ or (type.is_ptr and type.base_type.is_struct_or_union
+ and type.base_type.scope.is_cplus)):
+ error(arg.pos, "'del' can only be applied to Python object or pointer to C++ type")
+ if type.is_pyobject:
+ self.gil_check(env)
+
+ gil_message = "Deleting Python object"
+
+ def generate_execution_code(self, code):
+ for arg in self.args:
+ if arg.type.is_pyobject:
+ arg.generate_deletion_code(code)
+ else:
+ arg.generate_evaluation_code(code)
+ code.putln("delete %s;" % arg.result())
+ arg.generate_disposal_code(code)
+
+
+class PassStatNode(StatNode):
+ # pass statement
+
+ def analyse_expressions(self, env):
+ pass
+
+ def generate_execution_code(self, code):
+ pass
+
+
+class BreakStatNode(StatNode):
+
+ def analyse_expressions(self, env):
+ pass
+
+ def generate_execution_code(self, code):
+ if not code.break_label:
+ error(self.pos, "break statement not inside loop")
+ else:
+ #code.putln(
+ # "goto %s;" %
+ # code.break_label)
+ code.put_goto(code.break_label)
+
+
+class ContinueStatNode(StatNode):
+
+ def analyse_expressions(self, env):
+ pass
+
+ def generate_execution_code(self, code):
+ if code.in_try_finally:
+ error(self.pos, "continue statement inside try of try...finally")
+ elif not code.continue_label:
+ error(self.pos, "continue statement not inside loop")
+ else:
+ #code.putln(
+ # "goto %s;" %
+ # code.continue_label)
+ code.put_goto(code.continue_label)
+
+
+class ReturnStatNode(StatNode):
+ # return statement
+ #
+ # value ExprNode or None
+ # return_type PyrexType
+ # temps_in_use [Entry] Temps in use at time of return
+
+ def analyse_expressions(self, env):
+ return_type = env.return_type
+ self.return_type = return_type
+ self.temps_in_use = env.temps_in_use()
+ if not return_type:
+ error(self.pos, "Return not inside a function body")
+ return
+ if self.value:
+ self.value.analyse_types(env)
+ if return_type.is_void or return_type.is_returncode:
+ error(self.value.pos,
+ "Return with value in void function")
+ else:
+ self.value = self.value.coerce_to(env.return_type, env)
+ self.value.allocate_temps(env)
+ self.value.release_temp(env)
+ else:
+ if (not return_type.is_void
+ and not return_type.is_pyobject
+ and not return_type.is_returncode):
+ error(self.pos, "Return value required")
+ if return_type.is_pyobject:
+ self.gil_check(env)
+
+ gil_message = "Returning Python object"
+
+ def generate_execution_code(self, code):
+ if not self.return_type:
+ # error reported earlier
+ return
+ if self.value:
+ self.value.generate_evaluation_code(code)
+ self.value.make_owned_reference(code)
+ code.putln(
+ "%s = %s;" % (
+ Naming.retval_cname,
+ self.value.result_as(self.return_type)))
+ self.value.generate_post_assignment_code(code)
+ else:
+ if self.return_type.is_pyobject:
+ code.put_init_to_py_none(Naming.retval_cname, self.return_type)
+ elif self.return_type.is_returncode:
+ code.putln(
+ "%s = %s;" % (
+ Naming.retval_cname,
+ self.return_type.default_value))
+ for entry in self.temps_in_use:
+ code.put_var_decref_clear(entry)
+ #code.putln(
+ # "goto %s;" %
+ # code.return_label)
+ code.put_goto(code.return_label)
+
+
+class RaiseStatNode(StatNode):
+ # raise statement
+ #
+ # exc_type ExprNode or None
+ # exc_value ExprNode or None
+ # exc_tb ExprNode or None
+
+ def analyse_expressions(self, env):
+ if self.exc_type:
+ self.exc_type.analyse_types(env)
+ self.exc_type = self.exc_type.coerce_to_pyobject(env)
+ self.exc_type.allocate_temps(env)
+ if self.exc_value:
+ self.exc_value.analyse_types(env)
+ self.exc_value = self.exc_value.coerce_to_pyobject(env)
+ self.exc_value.allocate_temps(env)
+ if self.exc_tb:
+ self.exc_tb.analyse_types(env)
+ self.exc_tb = self.exc_tb.coerce_to_pyobject(env)
+ self.exc_tb.allocate_temps(env)
+ if self.exc_type:
+ self.exc_type.release_temp(env)
+ if self.exc_value:
+ self.exc_value.release_temp(env)
+ if self.exc_tb:
+ self.exc_tb.release_temp(env)
+ self.gil_check(env)
+
+ gil_message = "Raising exception"
+
+ def generate_execution_code(self, code):
+ if self.exc_type:
+ self.exc_type.generate_evaluation_code(code)
+ type_code = self.exc_type.py_result()
+ else:
+ type_code = 0
+ if self.exc_value:
+ self.exc_value.generate_evaluation_code(code)
+ value_code = self.exc_value.py_result()
+ else:
+ value_code = "0"
+ if self.exc_tb:
+ self.exc_tb.generate_evaluation_code(code)
+ tb_code = self.exc_tb.py_result()
+ else:
+ tb_code = "0"
+ code.use_utility_code(raise_utility_code)
+ code.putln(
+ "__Pyx_Raise(%s, %s, %s);" % (
+ type_code,
+ value_code,
+ tb_code))
+ if self.exc_type:
+ self.exc_type.generate_disposal_code(code)
+ if self.exc_value:
+ self.exc_value.generate_disposal_code(code)
+ if self.exc_tb:
+ self.exc_tb.generate_disposal_code(code)
+ code.putln(
+ code.error_goto(self.pos))
+
+
+class ReraiseStatNode(StatNode):
+
+ def analyse_expressions(self, env):
+ env.reraise_used = 1
+ self.gil_check(env)
+
+ gil_message = "Raising exception"
+
+ def generate_execution_code(self, code):
+ vars = code.exc_vars
+ if vars:
+ tvars = tuple(vars)
+ code.putln("PyErr_Restore(%s, %s, %s);" % tvars)
+ code.putln("%s = %s = %s = 0;" % tvars)
+ code.putln(code.error_goto(self.pos))
+ else:
+ error(self.pos, "Reraise not inside except clause")
+
+
+class AssertStatNode(StatNode):
+ # assert statement
+ #
+ # cond ExprNode
+ # value ExprNode or None
+
+ def analyse_expressions(self, env):
+ self.cond = self.cond.analyse_boolean_expression(env)
+ if self.value:
+ self.value.analyse_types(env)
+ self.value = self.value.coerce_to_pyobject(env)
+ self.value.allocate_temps(env)
+ self.cond.release_temp(env)
+ if self.value:
+ self.value.release_temp(env)
+ self.gil_check(env)
+
+ gil_message = "Raising exception"
+
+ def generate_execution_code(self, code):
+ code.putln("#ifndef PYREX_WITHOUT_ASSERTIONS")
+ self.cond.generate_evaluation_code(code)
+ code.putln(
+ "if (!%s) {" %
+ self.cond.result())
+ if self.value:
+ self.value.generate_evaluation_code(code)
+ if self.value:
+ code.putln(
+ "PyErr_SetObject(PyExc_AssertionError, %s);" %
+ self.value.py_result())
+ else:
+ code.putln(
+ "PyErr_SetNone(PyExc_AssertionError);")
+ code.putln(
+ code.error_goto(self.pos))
+ code.putln(
+ "}")
+ self.cond.generate_disposal_code(code)
+ # Disposal code for value not needed because exception always raised
+ #if self.value:
+ # self.value.generate_disposal_code(code)
+ code.putln("#endif")
+
+class IfStatNode(StatNode):
+ # if statement
+ #
+ # if_clauses [IfClauseNode]
+ # else_clause StatNode or None
+
+ def analyse_declarations(self, env):
+ for if_clause in self.if_clauses:
+ if_clause.analyse_declarations(env)
+ if self.else_clause:
+ self.else_clause.analyse_declarations(env)
+
+ def analyse_expressions(self, env):
+ for if_clause in self.if_clauses:
+ if_clause.analyse_expressions(env)
+ if self.else_clause:
+ self.else_clause.analyse_expressions(env)
+
+ def generate_execution_code(self, code):
+ end_label = code.new_label()
+ for if_clause in self.if_clauses:
+ if_clause.generate_execution_code(code, end_label)
+ if self.else_clause:
+ code.putln("/*else*/ {")
+ self.else_clause.generate_execution_code(code)
+ code.putln("}")
+ code.put_label(end_label)
+
+
+class IfClauseNode(Node):
+ # if or elif clause in an if statement
+ #
+ # condition ExprNode
+ # body StatNode
+
+ def analyse_declarations(self, env):
+ self.condition.analyse_declarations(env)
+ self.body.analyse_declarations(env)
+
+ def analyse_expressions(self, env):
+ self.condition = \
+ self.condition.analyse_temp_boolean_expression(env)
+ self.condition.release_temp(env)
+ self.body.analyse_expressions(env)
+
+ def generate_execution_code(self, code, end_label):
+ self.condition.generate_evaluation_code(code)
+ code.putln(
+ "if (%s) {" %
+ self.condition.result())
+ self.body.generate_execution_code(code)
+ #code.putln(
+ # "goto %s;" %
+ # end_label)
+ code.put_goto(end_label)
+ code.putln("}")
+
+
+class WhileStatNode(StatNode):
+ # while statement
+ #
+ # condition ExprNode
+ # body StatNode
+ # else_clause StatNode
+
+ def analyse_declarations(self, env):
+ self.body.analyse_declarations(env)
+ if self.else_clause:
+ self.else_clause.analyse_declarations(env)
+
+ def analyse_expressions(self, env):
+ self.condition = \
+ self.condition.analyse_temp_boolean_expression(env)
+ self.condition.release_temp(env)
+ #env.recycle_pending_temps() # TEMPORARY
+ self.body.analyse_expressions(env)
+ if self.else_clause:
+ self.else_clause.analyse_expressions(env)
+
+ def generate_execution_code(self, code):
+ old_loop_labels = code.new_loop_labels()
+ code.putln(
+ "while (1) {")
+ self.condition.generate_evaluation_code(code)
+ code.putln(
+ "if (!%s) break;" %
+ self.condition.result())
+ self.body.generate_execution_code(code)
+ code.put_label(code.continue_label)
+ code.putln("}")
+ break_label = code.break_label
+ code.set_loop_labels(old_loop_labels)
+ if self.else_clause:
+ code.putln("/*else*/ {")
+ self.else_clause.generate_execution_code(code)
+ code.putln("}")
+ code.put_label(break_label)
+
+
+class ForInStatNode(StatNode):
+ # for statement
+ #
+ # target ExprNode
+ # iterator IteratorNode
+ # body StatNode
+ # else_clause StatNode
+ # item NextNode used internally
+
+ def analyse_declarations(self, env):
+ self.target.analyse_target_declaration(env)
+ self.body.analyse_declarations(env)
+ if self.else_clause:
+ self.else_clause.analyse_declarations(env)
+
+ def analyse_expressions(self, env):
+ import ExprNodes
+ self.iterator.analyse_expressions(env)
+ self.target.analyse_target_types(env)
+ self.item = ExprNodes.NextNode(self.iterator, env)
+ self.item = self.item.coerce_to(self.target.type, env)
+ self.item.allocate_temps(env)
+ self.target.allocate_target_temps(env, self.item)
+ #self.item.release_temp(env)
+ #self.target.release_target_temp(env)
+ self.body.analyse_expressions(env)
+ if self.else_clause:
+ self.else_clause.analyse_expressions(env)
+ self.iterator.release_temp(env)
+
+ def generate_execution_code(self, code):
+ old_loop_labels = code.new_loop_labels()
+ self.iterator.generate_evaluation_code(code)
+ code.putln(
+ "for (;;) {")
+ self.item.generate_evaluation_code(code)
+ self.target.generate_assignment_code(self.item, code)
+ self.body.generate_execution_code(code)
+ code.put_label(code.continue_label)
+ code.putln(
+ "}")
+ break_label = code.break_label
+ code.set_loop_labels(old_loop_labels)
+ if self.else_clause:
+ code.putln("/*else*/ {")
+ self.else_clause.generate_execution_code(code)
+ code.putln("}")
+ code.put_label(break_label)
+ self.iterator.generate_disposal_code(code)
+
+
+class IntegerForStatNode(StatNode):
+ # for expr rel name rel expr
+ #
+ # bound1 ExprNode
+ # relation1 string
+ # target NameNode
+ # relation2 string
+ # bound2 ExprNode
+ # body StatNode
+ # else_clause StatNode or None
+ #
+ # Used internally:
+ #
+ # is_py_target bool
+ # loopvar_name string
+ # py_loopvar_node PyTempNode or None
+
+ def analyse_declarations(self, env):
+ self.target.analyse_target_declaration(env)
+ self.body.analyse_declarations(env)
+ if self.else_clause:
+ self.else_clause.analyse_declarations(env)
+
+ def analyse_expressions(self, env):
+ import ExprNodes
+ self.target.analyse_target_types(env)
+ self.bound1.analyse_types(env)
+ self.bound2.analyse_types(env)
+ self.bound1 = self.bound1.coerce_to_integer(env)
+ self.bound2 = self.bound2.coerce_to_integer(env)
+ if not (self.bound2.is_name or self.bound2.is_literal):
+ self.bound2 = self.bound2.coerce_to_temp(env)
+ target_type = self.target.type
+ if not (target_type.is_pyobject or target_type.is_int):
+ error(self.target.pos,
+ "Integer for-loop variable must be of type int or Python object")
+ #if not (target_type.is_pyobject
+ # or target_type.assignable_from(PyrexTypes.c_int_type)):
+ # error(self.target.pos,
+ # "Cannot assign integer to variable of type '%s'" % target_type)
+ if target_type.is_int:
+ self.is_py_target = 0
+ self.loopvar_name = self.target.entry.cname
+ self.py_loopvar_node = None
+ else:
+ self.is_py_target = 1
+ c_loopvar_node = ExprNodes.TempNode(self.pos,
+ PyrexTypes.c_long_type, env)
+ c_loopvar_node.allocate_temps(env)
+ self.loopvar_name = c_loopvar_node.result()
+ self.py_loopvar_node = \
+ ExprNodes.CloneNode(c_loopvar_node).coerce_to_pyobject(env)
+ self.bound1.allocate_temps(env)
+ self.bound2.allocate_temps(env)
+ if self.is_py_target:
+ self.py_loopvar_node.allocate_temps(env)
+ self.target.allocate_target_temps(env, self.py_loopvar_node)
+ #self.target.release_target_temp(env)
+ #self.py_loopvar_node.release_temp(env)
+ self.body.analyse_expressions(env)
+ if self.is_py_target:
+ c_loopvar_node.release_temp(env)
+ if self.else_clause:
+ self.else_clause.analyse_expressions(env)
+ self.bound1.release_temp(env)
+ self.bound2.release_temp(env)
+
+ def generate_execution_code(self, code):
+ old_loop_labels = code.new_loop_labels()
+ self.bound1.generate_evaluation_code(code)
+ self.bound2.generate_evaluation_code(code)
+ offset, incop = self.relation_table[self.relation1]
+ code.putln(
+ "for (%s = %s%s; %s %s %s; %s%s) {" % (
+ self.loopvar_name,
+ self.bound1.result(), offset,
+ self.loopvar_name, self.relation2, self.bound2.result(),
+ incop, self.loopvar_name))
+ if self.py_loopvar_node:
+ self.py_loopvar_node.generate_evaluation_code(code)
+ self.target.generate_assignment_code(self.py_loopvar_node, code)
+ self.body.generate_execution_code(code)
+ code.put_label(code.continue_label)
+ code.putln("}")
+ break_label = code.break_label
+ code.set_loop_labels(old_loop_labels)
+ if self.else_clause:
+ code.putln("/*else*/ {")
+ self.else_clause.generate_execution_code(code)
+ code.putln("}")
+ code.put_label(break_label)
+ self.bound1.generate_disposal_code(code)
+ self.bound2.generate_disposal_code(code)
+
+ relation_table = {
+ # {relop : (initial offset, increment op)}
+ '<=': ("", "++"),
+ '<' : ("+1", "++"),
+ '>=': ("", "--"),
+ '>' : ("-1", "--")
+ }
+
+
+class TryExceptStatNode(StatNode):
+ # try .. except statement
+ #
+ # body StatNode
+ # except_clauses [ExceptClauseNode]
+ # else_clause StatNode or None
+ # cleanup_list [Entry] temps to clean up on error
+
+ def analyse_declarations(self, env):
+ self.body.analyse_declarations(env)
+ for except_clause in self.except_clauses:
+ except_clause.analyse_declarations(env)
+ if self.else_clause:
+ self.else_clause.analyse_declarations(env)
+ self.gil_check(env)
+
+ def analyse_expressions(self, env):
+ self.body.analyse_expressions(env)
+ self.cleanup_list = env.free_temp_entries[:]
+ for except_clause in self.except_clauses:
+ except_clause.analyse_expressions(env)
+ if self.else_clause:
+ self.else_clause.analyse_expressions(env)
+ self.gil_check(env)
+
+ gil_message = "Try-except statement"
+
+ def generate_execution_code(self, code):
+ old_error_label = code.new_error_label()
+ our_error_label = code.error_label
+ end_label = code.new_label()
+ code.putln(
+ "/*try:*/ {")
+ self.body.generate_execution_code(code)
+ code.putln(
+ "}")
+ code.error_label = old_error_label
+ if self.else_clause:
+ code.putln(
+ "/*else:*/ {")
+ self.else_clause.generate_execution_code(code)
+ code.putln(
+ "}")
+ code.put_goto(end_label)
+ code.put_label(our_error_label)
+ code.put_var_xdecrefs_clear(self.cleanup_list)
+ default_clause_seen = 0
+ for except_clause in self.except_clauses:
+ if not except_clause.pattern:
+ default_clause_seen = 1
+ else:
+ if default_clause_seen:
+ error(except_clause.pos, "Default except clause not last")
+ except_clause.generate_handling_code(code, end_label)
+ if not default_clause_seen:
+ code.put_goto(code.error_label)
+ code.put_label(end_label)
+
+
+class ExceptClauseNode(Node):
+ # Part of try ... except statement.
+ #
+ # pattern ExprNode
+ # exc_target ExprNode or None
+ # tb_target ExprNode or None
+ # body StatNode
+ # match_flag string result of exception match
+ # exc_value ExcValueNode used internally
+ # tb_value ExcValueNode used internally
+ # function_name string qualified name of enclosing function
+ # exc_vars (string * 3) local exception variables
+ # reraise_used boolean body contains reraise statement
+
+ def analyse_declarations(self, env):
+ if self.exc_target:
+ self.exc_target.analyse_target_declaration(env)
+ if self.tb_target:
+ self.tb_target.analyse_target_declaration(env)
+ self.body.analyse_declarations(env)
+
+ def analyse_expressions(self, env):
+ genv = env.global_scope()
+ self.function_name = env.qualified_name
+ if self.pattern:
+ self.pattern.analyse_expressions(env)
+ self.pattern = self.pattern.coerce_to_pyobject(env)
+ self.match_flag = env.allocate_temp(PyrexTypes.c_int_type)
+ self.pattern.release_temp(env)
+ env.release_temp(self.match_flag)
+ self.exc_vars = [env.allocate_temp(py_object_type) for i in xrange(3)]
+ self.exc_value = self.analyse_target(env, self.exc_target, 1)
+ self.tb_value = self.analyse_target(env, self.tb_target, 2)
+ old_reraise_used = env.reraise_used
+ env.reraise_used = False
+ self.body.analyse_expressions(env)
+ self.reraise_used = env.reraise_used
+ env.reraise_used = old_reraise_used
+ for var in self.exc_vars:
+ env.release_temp(var)
+
+ def analyse_target(self, env, target, var_no):
+ if target:
+ import ExprNodes
+ value = ExprNodes.ExcValueNode(self.pos, env, self.exc_vars[var_no])
+ value.allocate_temps(env)
+ target.analyse_target_expression(env, value)
+ return value
+
+ def generate_handling_code(self, code, end_label):
+ code.mark_pos(self.pos)
+ if self.pattern:
+ self.pattern.generate_evaluation_code(code)
+ code.putln(
+ "%s = PyErr_ExceptionMatches(%s);" % (
+ self.match_flag,
+ self.pattern.py_result()))
+ self.pattern.generate_disposal_code(code)
+ code.putln(
+ "if (%s) {" %
+ self.match_flag)
+ else:
+ code.putln(
+ "/*except:*/ {")
+ any_bindings = self.exc_target or self.tb_target
+ exc_vars_used = any_bindings or self.reraise_used
+ if exc_vars_used:
+ if any_bindings:
+ code.putln(
+ '%s; __Pyx_AddTraceback("%s");' % (
+ code.error_setup(self.pos),
+ self.function_name))
+ exc_args = "&%s, &%s, &%s" % tuple(self.exc_vars)
+ code.putln("PyErr_Fetch(%s);" % exc_args)
+ if any_bindings:
+ code.use_utility_code(normalize_exception_utility_code)
+ code.putln("if (__Pyx_NormalizeException(%s) < 0) %s" % (exc_args,
+ code.error_goto(self.pos)))
+ if self.exc_target:
+ self.exc_value.generate_evaluation_code(code)
+ self.exc_target.generate_assignment_code(self.exc_value, code)
+ if self.tb_target:
+ self.tb_value.generate_evaluation_code(code)
+ self.tb_target.generate_assignment_code(self.tb_value, code)
+ old_exc_vars = code.exc_vars
+ code.exc_vars = self.exc_vars
+ self.body.generate_execution_code(code)
+ code.exc_vars = old_exc_vars
+ if exc_vars_used:
+ for var in self.exc_vars:
+ code.putln("Py_XDECREF(%s); %s = 0;" % (var, var))
+ code.put_goto(end_label)
+ code.putln(
+ "}")
+
+
+class TryFinallyStatNode(StatNode):
+ # try ... finally statement
+ #
+ # body StatNode
+ # finally_clause StatNode
+ #
+ # cleanup_list [Entry] temps to clean up on error
+ #
+ # The plan is that we funnel all continue, break
+ # return and error gotos into the beginning of the
+ # finally block, setting a variable to remember which
+ # one we're doing. At the end of the finally block, we
+ # switch on the variable to figure out where to go.
+ # In addition, if we're doing an error, we save the
+ # exception on entry to the finally block and restore
+ # it on exit.
+
+ preserve_exception = 1
+
+ disallow_continue_in_try_finally = 0
+ # There doesn't seem to be any point in disallowing
+ # continue in the try block, since we have no problem
+ # handling it.
+
+ def analyse_declarations(self, env):
+ self.body.analyse_declarations(env)
+ self.finally_clause.analyse_declarations(env)
+
+ def analyse_expressions(self, env):
+ self.body.analyse_expressions(env)
+ self.cleanup_list = env.free_temp_entries[:]
+ self.finally_clause.analyse_expressions(env)
+ self.gil_check(env)
+
+ gil_message = "Try-finally statement"
+
+ def generate_execution_code(self, code):
+ old_error_label = code.error_label
+ old_labels = code.all_new_labels()
+ new_labels = code.get_all_labels()
+ new_error_label = code.error_label
+ catch_label = code.new_label()
+ code.putln(
+ "/*try:*/ {")
+ if self.disallow_continue_in_try_finally:
+ was_in_try_finally = code.in_try_finally
+ code.in_try_finally = 1
+ self.body.generate_execution_code(code)
+ if self.disallow_continue_in_try_finally:
+ code.in_try_finally = was_in_try_finally
+ code.putln(
+ "}")
+ code.putln(
+ "/*finally:*/ {")
+ cases_used = []
+ error_label_used = 0
+ for i, new_label in enumerate(new_labels):
+ if new_label in code.labels_used:
+ cases_used.append(i)
+ if new_label == new_error_label:
+ error_label_used = 1
+ error_label_case = i
+ if cases_used:
+ code.putln(
+ "int __pyx_why;")
+ if error_label_used and self.preserve_exception:
+ code.putln(
+ "PyObject *%s, *%s, *%s;" % Naming.exc_vars)
+ code.putln(
+ "int %s;" % Naming.exc_lineno_name)
+ code.use_label(catch_label)
+ code.putln(
+ "__pyx_why = 0; goto %s;" % catch_label)
+ for i in cases_used:
+ new_label = new_labels[i]
+ #if new_label and new_label <> "<try>":
+ if new_label == new_error_label and self.preserve_exception:
+ self.put_error_catcher(code,
+ new_error_label, i+1, catch_label)
+ else:
+ code.putln(
+ "%s: __pyx_why = %s; goto %s;" % (
+ new_label,
+ i+1,
+ catch_label))
+ code.put_label(catch_label)
+ code.set_all_labels(old_labels)
+ if error_label_used:
+ code.new_error_label()
+ finally_error_label = code.error_label
+ self.finally_clause.generate_execution_code(code)
+ if error_label_used:
+ if finally_error_label in code.labels_used and self.preserve_exception:
+ over_label = code.new_label()
+ code.put_goto(over_label);
+ code.put_label(finally_error_label)
+ code.putln("if (__pyx_why == %d) {" % (error_label_case + 1))
+ for var in Naming.exc_vars:
+ code.putln("Py_XDECREF(%s);" % var)
+ code.putln("}")
+ code.put_goto(old_error_label)
+ code.put_label(over_label)
+ code.error_label = old_error_label
+ if cases_used:
+ code.putln(
+ "switch (__pyx_why) {")
+ for i in cases_used:
+ old_label = old_labels[i]
+ if old_label == old_error_label and self.preserve_exception:
+ self.put_error_uncatcher(code, i+1, old_error_label)
+ else:
+ code.use_label(old_label)
+ code.putln(
+ "case %s: goto %s;" % (
+ i+1,
+ old_label))
+ code.putln(
+ "}")
+ code.putln(
+ "}")
+
+ def put_error_catcher(self, code, error_label, i, catch_label):
+ code.putln(
+ "%s: {" %
+ error_label)
+ code.putln(
+ "__pyx_why = %s;" %
+ i)
+ code.put_var_xdecrefs_clear(self.cleanup_list)
+ code.putln(
+ "PyErr_Fetch(&%s, &%s, &%s);" %
+ Naming.exc_vars)
+ code.putln(
+ "%s = %s;" % (
+ Naming.exc_lineno_name, Naming.lineno_cname))
+ #code.putln(
+ # "goto %s;" %
+ # catch_label)
+ code.put_goto(catch_label)
+ code.putln(
+ "}")
+
+ def put_error_uncatcher(self, code, i, error_label):
+ code.putln(
+ "case %s: {" %
+ i)
+ code.putln(
+ "PyErr_Restore(%s, %s, %s);" %
+ Naming.exc_vars)
+ code.putln(
+ "%s = %s;" % (
+ Naming.lineno_cname, Naming.exc_lineno_name))
+ for var in Naming.exc_vars:
+ code.putln(
+ "%s = 0;" %
+ var)
+ code.put_goto(error_label)
+ code.putln(
+ "}")
+
+
+class GILStatNode(TryFinallyStatNode):
+ # 'with gil' or 'with nogil' statement
+ #
+ # state string 'gil' or 'nogil'
+
+ preserve_exception = 0
+
+ def __init__(self, pos, state, body):
+ self.state = state
+ TryFinallyStatNode.__init__(self, pos,
+ body = body,
+ finally_clause = GILExitNode(pos, state = state))
+
+ def analyse_expressions(self, env):
+ env.global_scope().gil_used = 1
+ was_nogil = env.nogil
+ env.nogil = 1
+ TryFinallyStatNode.analyse_expressions(self, env)
+ env.nogil = was_nogil
+
+ def gil_check(self, env):
+ pass
+
+ def generate_execution_code(self, code):
+ code.putln("/*with %s:*/ {" % self.state)
+ if self.state == 'gil':
+ code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
+ else:
+ code.putln("PyThreadState *_save;")
+ code.putln("Py_UNBLOCK_THREADS")
+ TryFinallyStatNode.generate_execution_code(self, code)
+ code.putln("}")
+
+
+class GILExitNode(StatNode):
+ # Used as the 'finally' block in a GILStatNode
+ #
+ # state string 'gil' or 'nogil'
+
+ def analyse_expressions(self, env):
+ pass
+
+ def generate_execution_code(self, code):
+ if self.state == 'gil':
+ code.putln("PyGILState_Release();")
+ else:
+ code.putln("Py_BLOCK_THREADS")
+
+
+class CImportStatNode(StatNode):
+ # cimport statement
+ #
+ # module_name string Qualified name of module being imported
+ # as_name string or None Name specified in "as" clause, if any
+
+ def analyse_declarations(self, env):
+ module_scope = env.find_module(self.module_name, self.pos)
+ if "." in self.module_name:
+ names = self.module_name.split(".")
+ top_name = names[0]
+ top_module_scope = env.context.find_submodule(top_name)
+ module_scope = top_module_scope
+ for name in names[1:]:
+ submodule_scope = module_scope.find_submodule(name)
+ module_scope.declare_module(name, submodule_scope, self.pos)
+ if not self.as_name:
+ env.add_imported_module(submodule_scope)
+ module_scope = submodule_scope
+ if self.as_name:
+ env.declare_module(self.as_name, module_scope, self.pos)
+ env.add_imported_module(module_scope)
+ else:
+ env.declare_module(top_name, top_module_scope, self.pos)
+ env.add_imported_module(top_module_scope)
+ else:
+ name = self.as_name or self.module_name
+ env.declare_module(name, module_scope, self.pos)
+ env.add_imported_module(module_scope)
+
+ def analyse_expressions(self, env):
+ pass
+
+ def generate_execution_code(self, code):
+ pass
+
+
+class FromCImportStatNode(StatNode):
+ # from ... cimport statement
+ #
+ # module_name string Qualified name of module
+ # imported_names Parsing.ImportedName Names to be imported
+
+ def analyse_declarations(self, env):
+ module_scope = env.find_module(self.module_name, self.pos)
+ env.add_imported_module(module_scope)
+ for imp in self.imported_names:
+ kind = imp.kind
+ #entry = module_scope.find(imp.name, imp.pos)
+ entry = module_scope.lookup(imp.name)
+ if entry:
+ if kind and not self.declaration_matches(entry, kind):
+ entry.redeclared(pos)
+ else:
+ if kind == 'struct' or kind == 'union':
+ entry = module_scope.declare_struct_or_union(imp.name,
+ kind = kind, scope = None, typedef_flag = 0, pos = imp.pos)
+ elif kind == 'class':
+ entry = module_scope.declare_c_class(imp.name, pos = imp.pos,
+ module_name = self.module_name)
+ else:
+ error(imp.pos, "Name '%s' not declared in module '%s'"
+ % (imp.name, self.module_name))
+ if entry:
+ local_name = imp.as_name or imp.name
+ env.add_imported_entry(local_name, entry, imp.pos)
+
+ def declaration_matches(self, entry, kind):
+ if not entry.is_type:
+ return 0
+ type = entry.type
+ if kind == 'class':
+ if not type.is_extension_type:
+ return 0
+ else:
+ if not type.is_struct_or_union:
+ return 0
+ if kind <> type.kind:
+ return 0
+ return 1
+
+ def analyse_expressions(self, env):
+ pass
+
+ def generate_execution_code(self, code):
+ pass
+
+
+class FromImportStatNode(StatNode):
+ # from ... import statement
+ #
+ # module ImportNode
+ # items [(string, NameNode)]
+ # #interned_items [(string, NameNode)]
+ # item PyTempNode used internally
+
+ def analyse_declarations(self, env):
+ for _, target in self.items:
+ target.analyse_target_declaration(env)
+
+ def analyse_expressions(self, env):
+ import ExprNodes
+ self.module.analyse_expressions(env)
+ self.item = ExprNodes.PyTempNode(self.pos, env)
+ self.item.allocate_temp(env)
+ #self.interned_items = []
+ for name, target in self.items:
+ #self.interned_items.append((env.intern(name), target))
+ target.analyse_target_expression(env, None)
+ self.module.release_temp(env)
+ self.item.release_temp(env)
+
+ def generate_execution_code(self, code):
+ self.module.generate_evaluation_code(code)
+ #for cname, target in self.interned_items:
+ for name, target in self.items:
+ cname = code.intern(name)
+ code.putln(
+ '%s = PyObject_GetAttr(%s, %s); if (!%s) %s' % (
+ self.item.result(),
+ self.module.py_result(),
+ cname,
+ self.item.result(),
+ code.error_goto(self.pos)))
+ target.generate_assignment_code(self.item, code)
+ self.module.generate_disposal_code(code)
+
+#------------------------------------------------------------------------------------
+#
+# Runtime support code
+#
+#------------------------------------------------------------------------------------
+
+#utility_function_predeclarations = \
+#"""
+#typedef struct {PyObject **p; char *s;} __Pyx_InternTabEntry; /*proto*/
+#typedef struct {PyObject **p; char *s; long n;} __Pyx_StringTabEntry; /*proto*/
+#"""
+
+utility_function_predeclarations = \
+"""
+typedef struct {PyObject **p; int i; char *s; long n;} __Pyx_StringTabEntry; /*proto*/
+"""
+
+#get_name_predeclaration = \
+#"static PyObject *__Pyx_GetName(PyObject *dict, char *name); /*proto*/"
+
+#get_name_interned_predeclaration = \
+#"static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/"
+
+#------------------------------------------------------------------------------------
+
+printing_utility_code = [
+"""
+static int __Pyx_PrintItem(PyObject *); /*proto*/
+static int __Pyx_PrintNewline(void); /*proto*/
+""",r"""
+static PyObject *__Pyx_GetStdout(void) {
+ PyObject *f = PySys_GetObject("stdout");
+ if (!f) {
+ PyErr_SetString(PyExc_RuntimeError, "lost sys.stdout");
+ }
+ return f;
+}
+
+static int __Pyx_PrintItem(PyObject *v) {
+ PyObject *f;
+
+ if (!(f = __Pyx_GetStdout()))
+ return -1;
+ if (PyFile_SoftSpace(f, 1)) {
+ if (PyFile_WriteString(" ", f) < 0)
+ return -1;
+ }
+ if (PyFile_WriteObject(v, f, Py_PRINT_RAW) < 0)
+ return -1;
+ if (PyString_Check(v)) {
+ char *s = PyString_AsString(v);
+ Py_ssize_t len = PyString_Size(v);
+ if (len > 0 &&
+ isspace(Py_CHARMASK(s[len-1])) &&
+ s[len-1] != ' ')
+ PyFile_SoftSpace(f, 0);
+ }
+ return 0;
+}
+
+static int __Pyx_PrintNewline(void) {
+ PyObject *f;
+
+ if (!(f = __Pyx_GetStdout()))
+ return -1;
+ if (PyFile_WriteString("\n", f) < 0)
+ return -1;
+ PyFile_SoftSpace(f, 0);
+ return 0;
+}
+"""]
+
+#------------------------------------------------------------------------------------
+
+# The following function is based on do_raise() from ceval.c.
+
+raise_utility_code = [
+"""
+static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
+""","""
+static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
+ if (value == Py_None)
+ value = NULL;
+ if (tb == Py_None)
+ tb = NULL;
+ Py_XINCREF(type);
+ Py_XINCREF(value);
+ Py_XINCREF(tb);
+ if (tb && !PyTraceBack_Check(tb)) {
+ PyErr_SetString(PyExc_TypeError,
+ "raise: arg 3 must be a traceback or None");
+ goto raise_error;
+ }
+ #if PY_VERSION_HEX < 0x02050000
+ if (!PyClass_Check(type))
+ #else
+ if (!PyType_Check(type))
+ #endif
+ {
+ /* Raising an instance. The value should be a dummy. */
+ if (value) {
+ PyErr_SetString(PyExc_TypeError,
+ "instance exception may not have a separate value");
+ goto raise_error;
+ }
+ /* Normalize to raise <class>, <instance> */
+ value = type;
+ #if PY_VERSION_HEX < 0x02050000
+ if (PyInstance_Check(type)) {
+ type = (PyObject*) ((PyInstanceObject*)type)->in_class;
+ Py_INCREF(type);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "raise: exception must be an old-style class or instance");
+ goto raise_error;
+ }
+ #else
+ type = (PyObject*) type->ob_type;
+ Py_INCREF(type);
+ if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) {
+ PyErr_SetString(PyExc_TypeError,
+ "raise: exception class must be a subclass of BaseException");
+ goto raise_error;
+ }
+ #endif
+ }
+ PyErr_Restore(type, value, tb);
+ return;
+raise_error:
+ Py_XDECREF(value);
+ Py_XDECREF(type);
+ Py_XDECREF(tb);
+ return;
+}
+"""]
+
+#------------------------------------------------------------------------------------
+
+#reraise_utility_code = [
+#"""
+#static void __Pyx_ReRaise(void); /*proto*/
+#""","""
+#static void __Pyx_ReRaise(void) {
+# PyThreadState *tstate = PyThreadState_Get();
+# PyObject *type = tstate->exc_type;
+# PyObject *value = tstate->exc_value;
+# PyObject *tb = tstate->exc_traceback;
+# Py_XINCREF(type);
+# Py_XINCREF(value);
+# Py_XINCREF(tb);
+# PyErr_Restore(type, value, tb);
+#}
+#"""]
+
+#------------------------------------------------------------------------------------
+
+arg_type_test_utility_code = [
+"""
+static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed, char *name); /*proto*/
+""","""
+static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed, char *name) {
+ if (!type) {
+ PyErr_Format(PyExc_SystemError, "Missing type object");
+ return 0;
+ }
+ if ((none_allowed && obj == Py_None) || PyObject_TypeCheck(obj, type))
+ return 1;
+ PyErr_Format(PyExc_TypeError,
+ "Argument '%s' has incorrect type (expected %s, got %s)",
+ name, type->tp_name, obj->ob_type->tp_name);
+ return 0;
+}
+"""]
+
+#------------------------------------------------------------------------------------
+#
+# __Pyx_GetStarArgs splits the args tuple and kwds dict into two parts
+# each, one part suitable for passing to PyArg_ParseTupleAndKeywords,
+# and the other containing any extra arguments. On success, replaces
+# the borrowed references *args and *kwds with references to a new
+# tuple and dict, and passes back new references in *args2 and *kwds2.
+# Does not touch any of its arguments on failure.
+#
+# Any of *kwds, args2 and kwds2 may be 0 (but not args or kwds). If
+# *kwds == 0, it is not changed. If kwds2 == 0 and *kwds != 0, a new
+# reference to the same dictionary is passed back in *kwds.
+#
+# If rqd_kwds is not 0, it is an array of booleans corresponding to the
+# names in kwd_list, indicating required keyword arguments. If any of
+# these are not present in kwds, an exception is raised.
+#
+
+get_starargs_utility_code = [
+"""
+static int __Pyx_GetStarArgs(PyObject **args, PyObject **kwds, char *kwd_list[], \
+ Py_ssize_t nargs, PyObject **args2, PyObject **kwds2, char rqd_kwds[]); /*proto*/
+""","""
+static int __Pyx_GetStarArgs(
+ PyObject **args,
+ PyObject **kwds,
+ char *kwd_list[],
+ Py_ssize_t nargs,
+ PyObject **args2,
+ PyObject **kwds2,
+ char rqd_kwds[])
+{
+ PyObject *x = 0, *args1 = 0, *kwds1 = 0;
+ int i;
+ char **p;
+
+ if (args2)
+ *args2 = 0;
+ if (kwds2)
+ *kwds2 = 0;
+
+ if (args2) {
+ args1 = PyTuple_GetSlice(*args, 0, nargs);
+ if (!args1)
+ goto bad;
+ *args2 = PyTuple_GetSlice(*args, nargs, PyTuple_GET_SIZE(*args));
+ if (!*args2)
+ goto bad;
+ }
+ else if (PyTuple_GET_SIZE(*args) > nargs) {
+ int m = nargs;
+ int n = PyTuple_GET_SIZE(*args);
+ PyErr_Format(PyExc_TypeError,
+ "function takes at most %d positional arguments (%d given)",
+ m, n);
+ goto bad;
+ }
+ else {
+ args1 = *args;
+ Py_INCREF(args1);
+ }
+
+ if (rqd_kwds && !*kwds)
+ for (i = 0, p = kwd_list; *p; i++, p++)
+ if (rqd_kwds[i])
+ goto missing_kwarg;
+
+ if (kwds2) {
+ if (*kwds) {
+ kwds1 = PyDict_New();
+ if (!kwds1)
+ goto bad;
+ *kwds2 = PyDict_Copy(*kwds);
+ if (!*kwds2)
+ goto bad;
+ for (i = 0, p = kwd_list; *p; i++, p++) {
+ x = PyDict_GetItemString(*kwds, *p);
+ if (x) {
+ if (PyDict_SetItemString(kwds1, *p, x) < 0)
+ goto bad;
+ if (PyDict_DelItemString(*kwds2, *p) < 0)
+ goto bad;
+ }
+ else if (rqd_kwds && rqd_kwds[i])
+ goto missing_kwarg;
+ }
+ }
+ else {
+ *kwds2 = PyDict_New();
+ if (!*kwds2)
+ goto bad;
+ }
+ }
+ else {
+ kwds1 = *kwds;
+ Py_XINCREF(kwds1);
+ if (rqd_kwds && *kwds)
+ for (i = 0, p = kwd_list; *p; i++, p++)
+ if (rqd_kwds[i] && !PyDict_GetItemString(*kwds, *p))
+ goto missing_kwarg;
+ }
+
+ *args = args1;
+ *kwds = kwds1;
+ return 0;
+missing_kwarg:
+ PyErr_Format(PyExc_TypeError,
+ "required keyword argument '%s' is missing", *p);
+bad:
+ Py_XDECREF(args1);
+ Py_XDECREF(kwds1);
+ if (args2) {
+ Py_XDECREF(*args2);
+ }
+ if (kwds2) {
+ Py_XDECREF(*kwds2);
+ }
+ return -1;
+}
+"""]
+
+#------------------------------------------------------------------------------------
+
+unraisable_exception_utility_code = [
+"""
+static void __Pyx_WriteUnraisable(char *name); /*proto*/
+""","""
+static void __Pyx_WriteUnraisable(char *name) {
+ PyObject *old_exc, *old_val, *old_tb;
+ PyObject *ctx;
+ PyGILState_STATE state = PyGILState_Ensure();
+ PyErr_Fetch(&old_exc, &old_val, &old_tb);
+ ctx = PyString_FromString(name);
+ PyErr_Restore(old_exc, old_val, old_tb);
+ if (!ctx)
+ ctx = Py_None;
+ PyErr_WriteUnraisable(ctx);
+ PyGILState_Release(state);
+}
+"""]
+
+#------------------------------------------------------------------------------------
+
+traceback_utility_code = [
+"""
+static void __Pyx_AddTraceback(char *funcname); /*proto*/
+""","""
+#include "compile.h"
+#include "frameobject.h"
+#include "traceback.h"
+
+static void __Pyx_AddTraceback(char *funcname) {
+ PyObject *py_srcfile = 0;
+ PyObject *py_funcname = 0;
+ PyObject *py_globals = 0;
+ PyObject *empty_tuple = 0;
+ PyObject *empty_string = 0;
+ PyCodeObject *py_code = 0;
+ PyFrameObject *py_frame = 0;
+
+ py_srcfile = PyString_FromString(%(FILENAME)s);
+ if (!py_srcfile) goto bad;
+ py_funcname = PyString_FromString(funcname);
+ if (!py_funcname) goto bad;
+ py_globals = PyModule_GetDict(%(GLOBALS)s);
+ if (!py_globals) goto bad;
+ empty_tuple = PyTuple_New(0);
+ if (!empty_tuple) goto bad;
+ empty_string = PyString_FromString("");
+ if (!empty_string) goto bad;
+ py_code = PyCode_New(
+ 0, /*int argcount,*/
+ 0, /*int nlocals,*/
+ 0, /*int stacksize,*/
+ 0, /*int flags,*/
+ empty_string, /*PyObject *code,*/
+ empty_tuple, /*PyObject *consts,*/
+ empty_tuple, /*PyObject *names,*/
+ empty_tuple, /*PyObject *varnames,*/
+ empty_tuple, /*PyObject *freevars,*/
+ empty_tuple, /*PyObject *cellvars,*/
+ py_srcfile, /*PyObject *filename,*/
+ py_funcname, /*PyObject *name,*/
+ %(LINENO)s, /*int firstlineno,*/
+ empty_string /*PyObject *lnotab*/
+ );
+ if (!py_code) goto bad;
+ py_frame = PyFrame_New(
+ PyThreadState_Get(), /*PyThreadState *tstate,*/
+ py_code, /*PyCodeObject *code,*/
+ py_globals, /*PyObject *globals,*/
+ 0 /*PyObject *locals*/
+ );
+ if (!py_frame) goto bad;
+ py_frame->f_lineno = %(LINENO)s;
+ PyTraceBack_Here(py_frame);
+bad:
+ Py_XDECREF(py_srcfile);
+ Py_XDECREF(py_funcname);
+ Py_XDECREF(empty_tuple);
+ Py_XDECREF(empty_string);
+ Py_XDECREF(py_code);
+ Py_XDECREF(py_frame);
+}
+""" % {
+ 'FILENAME': Naming.filename_cname,
+ 'LINENO': Naming.lineno_cname,
+ 'GLOBALS': Naming.module_cname
+}]
+
+#------------------------------------------------------------------------------------
+
+set_vtable_utility_code = [
+"""
+static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/
+""","""
+static int __Pyx_SetVtable(PyObject *dict, void *vtable) {
+ PyObject *pycobj = 0;
+ int result;
+
+ pycobj = PyCObject_FromVoidPtr(vtable, 0);
+ if (!pycobj)
+ goto bad;
+ if (PyDict_SetItemString(dict, "__pyx_vtable__", pycobj) < 0)
+ goto bad;
+ result = 0;
+ goto done;
+
+bad:
+ result = -1;
+done:
+ Py_XDECREF(pycobj);
+ return result;
+}
+"""]
+
+#------------------------------------------------------------------------------------
+
+get_vtable_utility_code = [
+"""
+static int __Pyx_GetVtable(PyObject *dict, void *vtabptr); /*proto*/
+""",r"""
+static int __Pyx_GetVtable(PyObject *dict, void *vtabptr) {
+ int result;
+ PyObject *pycobj;
+
+ pycobj = PyMapping_GetItemString(dict, "__pyx_vtable__");
+ if (!pycobj)
+ goto bad;
+ *(void **)vtabptr = PyCObject_AsVoidPtr(pycobj);
+ if (!*(void **)vtabptr)
+ goto bad;
+ result = 0;
+ goto done;
+
+bad:
+ result = -1;
+done:
+ Py_XDECREF(pycobj);
+ return result;
+}
+"""]
+
+#------------------------------------------------------------------------------------
+
+#init_intern_tab_utility_code = [
+#"""
+#static int __Pyx_InternStrings(__Pyx_InternTabEntry *t); /*proto*/
+#""","""
+#static int __Pyx_InternStrings(__Pyx_InternTabEntry *t) {
+# while (t->p) {
+# *t->p = PyString_InternFromString(t->s);
+# if (!*t->p)
+# return -1;
+# ++t;
+# }
+# return 0;
+#}
+#"""]
+
+#init_intern_tab_utility_code = [
+#"""
+#static int __Pyx_InternStrings(PyObject **t[]); /*proto*/
+#""","""
+#static int __Pyx_InternStrings(PyObject **t[]) {
+# while (*t) {
+# PyString_InternInPlace(*t);
+# if (!**t)
+# return -1;
+# ++t;
+# }
+# return 0;
+#}
+#"""]
+
+#------------------------------------------------------------------------------------
+
+init_string_tab_utility_code = [
+"""
+static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/
+""","""
+static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
+ while (t->p) {
+ *t->p = PyString_FromStringAndSize(t->s, t->n - 1);
+ if (!*t->p)
+ return -1;
+ if (t->i)
+ PyString_InternInPlace(t->p);
+ ++t;
+ }
+ return 0;
+}
+"""]
+
+#------------------------------------------------------------------------------------
+
+#get_exception_utility_code = [
+#"""
+#static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
+#""","""
+#static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) {
+# PyThreadState *tstate = PyThreadState_Get();
+# PyObject *old_type, *old_value, *old_tb;
+# PyErr_Fetch(type, value, tb);
+# PyErr_NormalizeException(type, value, tb);
+# if (PyErr_Occurred())
+# goto bad;
+# if (!*tb) {
+# printf("no traceback\n");
+# *tb = Py_None;
+# Py_INCREF(*tb);
+# }
+##if 1
+# Py_INCREF(*type);
+# Py_INCREF(*value);
+# Py_INCREF(*tb);
+# old_type = tstate->exc_type;
+# old_value = tstate->exc_value;
+# old_tb = tstate->exc_traceback;
+# tstate->exc_type = *type;
+# tstate->exc_value = *value;
+# tstate->exc_traceback = *tb;
+# Py_XDECREF(old_type);
+# Py_XDECREF(old_value);
+# Py_XDECREF(old_tb);
+##endif
+# return 0;
+#bad:
+# Py_XDECREF(*type);
+# Py_XDECREF(*value);
+# Py_XDECREF(*tb);
+# return -1;
+#}
+#"""]
+
+#------------------------------------------------------------------------------------
+
+#get_exception_utility_code = [
+#"""
+#static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
+#""","""
+#static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) {
+# PyErr_Fetch(type, value, tb);
+# PyErr_NormalizeException(type, value, tb);
+# if (PyErr_Occurred())
+# goto bad;
+# if (!*tb) {
+# *tb = Py_None;
+# Py_INCREF(*tb);
+# }
+# return 0;
+#bad:
+# Py_XDECREF(*type);
+# Py_XDECREF(*value);
+# Py_XDECREF(*tb);
+# return -1;
+#}
+#"""]
+
+#------------------------------------------------------------------------------------
+
+normalize_exception_utility_code = [
+"""
+static int __Pyx_NormalizeException(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
+""","""
+static int __Pyx_NormalizeException(PyObject **type, PyObject **value, PyObject **tb) {
+ PyErr_NormalizeException(type, value, tb);
+ if (PyErr_Occurred())
+ goto bad;
+ if (!*tb) {
+ *tb = Py_None;
+ Py_INCREF(*tb);
+ }
+ return 0;
+bad:
+ Py_XDECREF(*type);
+ Py_XDECREF(*value);
+ Py_XDECREF(*tb);
+ return -1;
+}
+"""]
+
+#------------------------------------------------------------------------------------