class VisitorTransform(TreeVisitor):
    """
    A tree transform is a base class for visitors that wants to do stream
    processing of the structure (rather than attributes etc.) of a tree.

    It implements __call__ to simply visit the argument node.

    It requires the visitor methods to return the nodes which should take
    the place of the visited node in the result tree (which can be the same
    or one or more replacement). Specifically, if the return value from
    a visitor method is:

    - [] or None; the visited node will be removed (set to None if an attribute and
    removed if in a list)
    - A single node; the visited node will be replaced by the returned node.
    - A list of nodes; the visited nodes will be replaced by all the nodes in the
    list. This will only work if the node was already a member of a list; if it
    was not, an exception will be raised. (Typically you want to ensure that you
    are within a StatListNode or similar before doing this.)
    """
    def visitchildren(self, parent, attrs=None):
        result = self._visitchildren(parent, attrs)
        for attr, newnode in result.iteritems():
            if not type(newnode) is list:
                setattr(parent, attr, newnode)
            else:
                # Flatten the list one level and remove any None
                newlist = []
                for x in newnode:
                    if x is not None:
                        if type(x) is list:
                            newlist += x
                        else:
                            newlist.append(x)
                setattr(parent, attr, newlist)
        return result

    def recurse_to_children(self, node):
        self.visitchildren(node)
        return node

    def __call__(self, root):
        return self._visit(root) 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

    child_attrs = ["base", "args", "exception_value"]

    overridable = 0
    optional_arg_count = 0

    def analyse(self, return_type, env, nonempty = 0, directive_locals = {}):
        if nonempty:
            nonempty -= 1
        func_type_args = []
        for i, arg_node in enumerate(self.args):
            name_declarator, type = arg_node.analyse(env, nonempty = nonempty,
                                                     is_self_arg = (i == 0 and env.is_c_class_scope))
            name = name_declarator.name
            if name in directive_locals:
                type_node = directive_locals[name]
                other_type = type_node.analyse_as_type(env)
                if other_type is None:
                    error(type_node.pos, "Not a type")
                elif (type is not PyrexTypes.py_object_type
                      and not type.same_as(other_type)):
                    error(self.base.pos, "Signature does not agree with previous declaration")
                    error(type_node.pos, "Previous declaration here")
                else:
                    type = other_type
            if name_declarator.cname:
                error(self.pos,
                    "Function argument cannot have C name specification")
            if i==0 and env.is_c_class_scope and type.is_unspecified:
                # fix the type of self
                type = env.parent_type
            # 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, "Use spam() rather than spam(void) to declare a function with no arguments.")
            func_type_args.append(
                PyrexTypes.CFuncTypeArg(name, type, arg_node.pos))
            if arg_node.default:
                self.optional_arg_count += 1
            elif self.optional_arg_count:
                error(self.pos, "Non-default argument follows default argument")

        exc_val = None
        exc_check = 0
        if self.exception_check == '+':
            env.add_include_file('ios')         # for std::ios_base::failure
            env.add_include_file('new')         # for std::bad_alloc
            env.add_include_file('stdexcept')
            env.add_include_file('typeinfo')    # for std::bad_cast
        if return_type.is_pyobject \
            and (self.exception_value or self.exception_check) \
            and 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)
                if self.exception_check == '+':
                    self.exception_value.analyse_types(env)
                    exc_val_type = self.exception_value.type
                    if not exc_val_type.is_error and \
                          not exc_val_type.is_pyobject and \
                          not (exc_val_type.is_cfunction and not exc_val_type.return_type.is_pyobject and len(exc_val_type.args)==0):
                        error(self.exception_value.pos,
                            "Exception value must be a Python exception or cdef function with no arguments.")
                    exc_val = self.exception_value
                else:
                    self.exception_value = self.exception_value.coerce_to(return_type, env)
                    if self.exception_value.analyse_const_expression(env):
                        exc_val = self.exception_value.get_constant_c_result_code()
                        if exc_val is None:
                            raise InternalError("get_constant_c_result_code not implemented for %s" %
                                self.exception_value.__class__.__name__)
                        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_cfunction:
            error(self.pos,
                "Function cannot return a function")
        func_type = PyrexTypes.CFuncType(
            return_type, func_type_args, self.has_varargs,
            optional_arg_count = self.optional_arg_count,
            exception_value = exc_val, exception_check = exc_check,
            calling_convention = self.base.calling_convention,
            nogil = self.nogil, with_gil = self.with_gil, is_overridable = self.overridable)

        if self.optional_arg_count:
            if func_type.is_fused:
                # This is a bit of a hack... When we need to create specialized CFuncTypes
                # on the fly because the cdef is defined in a pxd, we need to declare the specialized optional arg
                # struct
                def declare_opt_arg_struct(func_type, fused_cname):
                    self.declare_optional_arg_struct(func_type, env, fused_cname)

                func_type.declare_opt_arg_struct = declare_opt_arg_struct
            else:
                self.declare_optional_arg_struct(func_type, env)

        callspec = env.directives['callspec']
        if callspec:
            current = func_type.calling_convention
            if current and current != callspec:
                error(self.pos, "cannot have both '%s' and '%s' "
                      "calling conventions" % (current, callspec))
            func_type.calling_convention = callspec
        return self.base.analyse(func_type, env)

    def declare_optional_arg_struct(self, func_type, env, fused_cname=None):
        """
        Declares the optional argument struct (the struct used to hold the
        values for optional arguments). For fused cdef functions, this is
        deferred as analyse_declarations is called only once (on the fused
        cdef function).
        """
        scope = StructOrUnionScope()
        arg_count_member = '%sn' % Naming.pyrex_prefix
        scope.declare_var(arg_count_member, PyrexTypes.c_int_type, self.pos)

        for arg in func_type.args[len(func_type.args)-self.optional_arg_count:]:
            scope.declare_var(arg.name, arg.type, arg.pos, allow_pyobject = 1)

        struct_cname = env.mangle(Naming.opt_arg_prefix, self.base.name)

        if fused_cname is not None:
            struct_cname = PyrexTypes.get_fused_cname(fused_cname, struct_cname)

        op_args_struct = env.global_scope().declare_struct_or_union(
                name = struct_cname,
                kind = 'struct',
                scope = scope,
                typedef_flag = 0,
                pos = self.pos,
                cname = struct_cname)

        op_args_struct.defined_in_pxd = 1
        op_args_struct.used = 1

        func_type.op_arg_struct = PyrexTypes.c_ptr_type(op_args_struct.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
    #  overridable   boolean        whether it is a cpdef

    #  decorators    [cython.locals(...)] or None
    #  directive_locals { string : NameNode } locals defined by cython.locals(...)

    child_attrs = ["base_type", "declarators"]

    decorators = None
    directive_locals = None

    def analyse_declarations(self, env, dest_scope = None):
        if self.directive_locals is None:
            self.directive_locals = {}
        if not dest_scope:
            dest_scope = env
        self.dest_scope = dest_scope
        base_type = self.base_type.analyse(env)

        self.entry = None
        visibility = self.visibility

        for declarator in self.declarators:
            if isinstance(declarator, CFuncDeclaratorNode):
                name_declarator, type = declarator.analyse(base_type, env, directive_locals=self.directive_locals)
            else:
                name_declarator, type = declarator.analyse(base_type, env)
            if not type.is_complete():
                if not (self.visibility == 'extern' and type.is_array or type.is_memoryviewslice):
                    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 name == '':
                error(declarator.pos, "Missing name in declaration.")
                return
            if type.is_cfunction:
                self.entry = dest_scope.declare_cfunction(name, type, declarator.pos,
                    cname = cname, visibility = self.visibility, in_pxd = self.in_pxd,
                    api = self.api)
                if self.entry is not None:
                    self.entry.is_overridable = self.overridable
                    self.entry.directive_locals = copy.copy(self.directive_locals)
            else:
                if self.directive_locals:
                    error(self.pos, "Decorators can only be followed by functions")
                self.entry = dest_scope.declare_var(name, type, declarator.pos,
                            cname=cname, visibility=visibility, in_pxd=self.in_pxd,
                            api=self.api, is_cdef=1) class SingleAssignmentNode(AssignmentNode):
    #  The simplest case:
    #
    #    a = b
    #
    #  lhs      ExprNode      Left hand side
    #  rhs      ExprNode      Right hand side
    #  first    bool          Is this guaranteed the first assignment to lhs?

    child_attrs = ["lhs", "rhs"]
    first = False
    declaration_only = False

    def analyse_declarations(self, env):
        import ExprNodes

        # handle declarations of the form x = cython.foo()
        if isinstance(self.rhs, ExprNodes.CallNode):
            func_name = self.rhs.function.as_cython_attribute()
            if func_name:
                args, kwds = self.rhs.explicit_args_kwds()

                if func_name in ['declare', 'typedef']:
                    if len(args) > 2 or kwds is not None:
                        error(self.rhs.pos, "Can only declare one type at a time.")
                        return

                    type = args[0].analyse_as_type(env)
                    if type is None:
                        error(args[0].pos, "Unknown type")
                        return
                    lhs = self.lhs
                    if func_name == 'declare':
                        if isinstance(lhs, ExprNodes.NameNode):
                            vars = [(lhs.name, lhs.pos)]
                        elif isinstance(lhs, ExprNodes.TupleNode):
                            vars = [(var.name, var.pos) for var in lhs.args]
                        else:
                            error(lhs.pos, "Invalid declaration")
                            return
                        for var, pos in vars:
                            env.declare_var(var, type, pos, is_cdef = True)
                        if len(args) == 2:
                            # we have a value
                            self.rhs = args[1]
                        else:
                            self.declaration_only = True
                    else:
                        self.declaration_only = True
                        if not isinstance(lhs, ExprNodes.NameNode):
                            error(lhs.pos, "Invalid declaration.")
                        env.declare_typedef(lhs.name, type, self.pos, visibility='private')

                elif func_name in ['struct', 'union']:
                    self.declaration_only = True
                    if len(args) > 0 or kwds is None:
                        error(self.rhs.pos, "Struct or union members must be given by name.")
                        return
                    members = []
                    for member, type_node in kwds.key_value_pairs:
                        type = type_node.analyse_as_type(env)
                        if type is None:
                            error(type_node.pos, "Unknown type")
                        else:
                            members.append((member.value, type, member.pos))
                    if len(members) < len(kwds.key_value_pairs):
                        return
                    if not isinstance(self.lhs, ExprNodes.NameNode):
                        error(self.lhs.pos, "Invalid declaration.")
                    name = self.lhs.name
                    scope = StructOrUnionScope(name)
                    env.declare_struct_or_union(name, func_name, scope, False, self.rhs.pos)
                    for member, type, pos in members:
                        scope.declare_var(member, type, pos)

                elif func_name == 'fused_type':
                    # dtype = cython.fused_type(...)
                    self.declaration_only = True
                    if kwds:
                        error(self.rhs.function.pos,
                              "fused_type does not take keyword arguments")

                    fusednode = FusedTypeNode(self.rhs.pos,
                                              name = self.lhs.name, types=args)
                    fusednode.analyse_declarations(env)

        if self.declaration_only:
            return
        else:
            self.lhs.analyse_target_declaration(env)

    def analyse_types(self, env, use_temp = 0):
        import ExprNodes

        self.rhs.analyse_types(env)
        self.lhs.analyse_target_types(env)
        self.lhs.gil_assignment_check(env)

        if self.lhs.memslice_broadcast or self.rhs.memslice_broadcast:
            self.lhs.memslice_broadcast = True
            self.rhs.memslice_broadcast = True

        is_index_node = isinstance(self.lhs, ExprNodes.IndexNode)
        if (is_index_node and not self.rhs.type.is_memoryviewslice and
            (self.lhs.memslice_slice or self.lhs.is_memslice_copy) and
            (self.lhs.type.dtype.assignable_from(self.rhs.type) or
             self.rhs.type.is_pyobject)):
            # scalar slice assignment
            self.lhs.is_memslice_scalar_assignment = True
            dtype = self.lhs.type.dtype
        else:
            dtype = self.lhs.type

        self.rhs = self.rhs.coerce_to(dtype, env)
        if use_temp:
            self.rhs = self.rhs.coerce_to_temp(env)

    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)

    def generate_function_definitions(self, env, code):
        self.rhs.generate_function_definitions(env, code)

    def annotate(self, code):
        self.lhs.annotate(code)
        self.rhs.annotate(code) class CStructOrUnionDefNode(StatNode):
    #  name          string
    #  cname         string or None
    #  kind          "struct" or "union"
    #  typedef_flag  boolean
    #  visibility    "public" or "private"
    #  api           boolean
    #  in_pxd        boolean
    #  attributes    [CVarDefNode] or None
    #  entry         Entry
    #  packed        boolean

    child_attrs = ["attributes"]

    def declare(self, env, scope=None):
        if self.visibility == 'extern' and self.packed and not scope:
            error(self.pos, "Cannot declare extern struct as 'packed'")
        self.entry = env.declare_struct_or_union(
            self.name, self.kind, scope, self.typedef_flag, self.pos,
            self.cname, visibility = self.visibility, api = self.api,
            packed = self.packed)

    def analyse_declarations(self, env):
        scope = None
        if self.attributes is not None:
            scope = StructOrUnionScope(self.name)
        self.declare(env, scope)
        if self.attributes is not None:
            if self.in_pxd and not env.in_cinclude:
                self.entry.defined_in_pxd = 1
            for attr in self.attributes:
                attr.analyse_declarations(env, scope)
            if self.visibility != 'extern':
                for attr in scope.var_entries:
                    type = attr.type
                    while type.is_array:
                        type = type.base_type
                    if type == self.entry.type:
                        error(attr.pos, "Struct cannot contain itself as a member.")

    def analyse_expressions(self, env):
        pass

    def generate_execution_code(self, code):
        pass class PyClassDefNode(ClassDefNode):
    #  A Python class definition.
    #
    #  name     EncodedString   Name of the class
    #  doc      string or None
    #  body     StatNode        Attribute definition code
    #  entry    Symtab.Entry
    #  scope    PyClassScope
    #  decorators    [DecoratorNode]        list of decorators or None
    #
    #  The following subnodes are constructed internally:
    #
    #  dict     DictNode   Class dictionary or Py3 namespace
    #  classobj ClassNode  Class object
    #  target   NameNode   Variable to assign class object to

    child_attrs = ["body", "dict", "metaclass", "mkw", "bases", "class_result",
                   "target", "class_cell"]
    decorators = None
    class_result = None
    py3_style_class = False # Python3 style class (bases+kwargs)

    def __init__(self, pos, name, bases, doc, body, decorators = None,
                 keyword_args = None, starstar_arg = None):
        StatNode.__init__(self, pos)
        self.name = name
        self.doc = doc
        self.body = body
        self.decorators = decorators
        import ExprNodes
        if self.doc and Options.docstrings:
            doc = embed_position(self.pos, self.doc)
            doc_node = ExprNodes.StringNode(pos, value = doc)
        else:
            doc_node = None
        if keyword_args or starstar_arg:
            self.py3_style_class = True
            self.bases = bases
            self.metaclass = None
            if keyword_args and not starstar_arg:
                for i, item in list(enumerate(keyword_args.key_value_pairs))[::-1]:
                    if item.key.value == 'metaclass':
                        if self.metaclass is not None:
                            error(item.pos, "keyword argument 'metaclass' passed multiple times")
                        # special case: we already know the metaclass,
                        # so we don't need to do the "build kwargs,
                        # find metaclass" dance at runtime
                        self.metaclass = item.value
                        del keyword_args.key_value_pairs[i]
            if starstar_arg:
                self.mkw = ExprNodes.KeywordArgsNode(
                    pos, keyword_args = keyword_args and keyword_args.key_value_pairs or [],
                    starstar_arg = starstar_arg)
            elif keyword_args and keyword_args.key_value_pairs:
                self.mkw = keyword_args
            else:
                self.mkw = ExprNodes.NullNode(pos)
            if self.metaclass is None:
                self.metaclass = ExprNodes.PyClassMetaclassNode(
                    pos, mkw = self.mkw, bases = self.bases)
            self.dict = ExprNodes.PyClassNamespaceNode(pos, name = name,
                        doc = doc_node, metaclass = self.metaclass, bases = self.bases,
                        mkw = self.mkw)
            self.classobj = ExprNodes.Py3ClassNode(pos, name = name,
                    bases = self.bases, dict = self.dict, doc = doc_node,
                    metaclass = self.metaclass, mkw = self.mkw)
        else:
            self.dict = ExprNodes.DictNode(pos, key_value_pairs = [])
            self.metaclass = None
            self.mkw = None
            self.bases = None
            self.classobj = ExprNodes.ClassNode(pos, name = name,
                    bases = bases, dict = self.dict, doc = doc_node)
        self.target = ExprNodes.NameNode(pos, name = name)
        self.class_cell = ExprNodes.ClassCellInjectorNode(self.pos)

    def as_cclass(self):
        """
        Return this node as if it were declared as an extension class
        """
        if self.py3_style_class:
            error(self.classobj.pos, "Python3 style class could not be represented as C class")
            return
        bases = self.classobj.bases.args
        if len(bases) == 0:
            base_class_name = None
            base_class_module = None
        elif len(bases) == 1:
            base = bases[0]
            path = []
            from ExprNodes import AttributeNode, NameNode
            while isinstance(base, AttributeNode):
                path.insert(0, base.attribute)
                base = base.obj
            if isinstance(base, NameNode):
                path.insert(0, base.name)
                base_class_name = path[-1]
                if len(path) > 1:
                    base_class_module = u'.'.join(path[:-1])
                else:
                    base_class_module = None
            else:
                error(self.classobj.bases.args.pos, "Invalid base class")
        else:
            error(self.classobj.bases.args.pos, "C class may only have one base class")
            return None

        return CClassDefNode(self.pos,
                             visibility = 'private',
                             module_name = None,
                             class_name = self.name,
                             base_class_module = base_class_module,
                             base_class_name = base_class_name,
                             decorators = self.decorators,
                             body = self.body,
                             in_pxd = False,
                             doc = self.doc)

    def create_scope(self, env):
        genv = env
        while genv.is_py_class_scope or genv.is_c_class_scope:
            genv = genv.outer_scope
        cenv = self.scope = PyClassScope(name = self.name, outer_scope = genv)
        return cenv

    def analyse_declarations(self, env):
        class_result = self.classobj
        if self.decorators:
            from ExprNodes import SimpleCallNode
            for decorator in self.decorators[::-1]:
                class_result = SimpleCallNode(
                    decorator.pos,
                    function = decorator.decorator,
                    args = [class_result])
        self.class_result = class_result
        self.class_result.analyse_declarations(env)
        self.target.analyse_target_declaration(env)
        cenv = self.create_scope(env)
        cenv.directives = env.directives
        cenv.class_obj_cname = self.target.entry.cname
        self.body.analyse_declarations(cenv)

    def analyse_expressions(self, env):
        if self.py3_style_class:
            self.bases.analyse_expressions(env)
            self.metaclass.analyse_expressions(env)
            self.mkw.analyse_expressions(env)
        self.dict.analyse_expressions(env)
        self.class_result.analyse_expressions(env)
        genv = env.global_scope()
        cenv = self.scope
        self.body.analyse_expressions(cenv)
        self.target.analyse_target_expression(env, self.classobj)
        self.class_cell.analyse_expressions(cenv)

    def generate_function_definitions(self, env, code):
        self.generate_lambda_definitions(self.scope, code)
        self.body.generate_function_definitions(self.scope, code)

    def generate_execution_code(self, code):
        code.pyclass_stack.append(self)
        cenv = self.scope
        if self.py3_style_class:
            self.bases.generate_evaluation_code(code)
            self.mkw.generate_evaluation_code(code)
            self.metaclass.generate_evaluation_code(code)
        self.dict.generate_evaluation_code(code)
        cenv.namespace_cname = cenv.class_obj_cname = self.dict.result()
        self.class_cell.generate_evaluation_code(code)
        self.body.generate_execution_code(code)
        self.class_result.generate_evaluation_code(code)
        self.class_cell.generate_injection_code(
            code, self.class_result.result())
        self.class_cell.generate_disposal_code(code)
        cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result()
        self.target.generate_assignment_code(self.class_result, code)
        self.dict.generate_disposal_code(code)
        self.dict.free_temps(code)
        if self.py3_style_class:
            self.mkw.generate_disposal_code(code)
            self.mkw.free_temps(code)
            self.metaclass.generate_disposal_code(code)
            self.metaclass.free_temps(code)
            self.bases.generate_disposal_code(code)
            self.bases.free_temps(code)
        code.pyclass_stack.pop() class StatListNode(Node):
    # stats     a list of StatNode

    child_attrs = ["stats"]

    def create_analysed(pos, env, *args, **kw):
        node = StatListNode(pos, *args, **kw)
        return node # No node-specific analysis necesarry
    create_analysed = staticmethod(create_analysed)

    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)

    def annotate(self, code):
        for stat in self.stats:
            stat.annotate(code) class PassStatNode(StatNode):
    #  pass statement

    child_attrs = []

    def analyse_expressions(self, env):
        pass

    def generate_execution_code(self, code):
        pass class CPtrDeclaratorNode(CDeclaratorNode):
    # base     CDeclaratorNode

    child_attrs = ["base"]

    def analyse(self, base_type, env, nonempty = 0):
        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, nonempty = nonempty) class DecoratorNode(Node):
    # A decorator
    #
    # decorator    NameNode or CallNode or AttributeNode
    child_attrs = ['decorator'] class FuncDefNode(StatNode, BlockNode):
    #  Base class for function definition nodes.
    #
    #  return_type     PyrexType
    #  #filename        string        C name of filename string const
    #  entry           Symtab.Entry
    #  needs_closure   boolean        Whether or not this function has inner functions/classes/yield
    #  needs_outer_scope boolean      Whether or not this function requires outer scope
    #  pymethdef_required boolean     Force Python method struct generation
    #  directive_locals { string : ExprNode } locals defined by cython.locals(...)
    #  directive_returns [ExprNode] type defined by cython.returns(...)
    # star_arg      PyArgDeclNode or None  * argument
    # starstar_arg  PyArgDeclNode or None  ** argument

    #  has_fused_arguments  boolean
    #       Whether this cdef function has fused parameters. This is needed
    #       by AnalyseDeclarationsTransform, so it can replace CFuncDefNodes
    #       with fused argument types with a FusedCFuncDefNode

    py_func = None
    needs_closure = False
    needs_outer_scope = False
    pymethdef_required = False
    is_generator = False
    is_generator_body = False
    modifiers = []
    has_fused_arguments = False
    star_arg = None
    starstar_arg = None
    is_cyfunction = False

    def analyse_default_values(self, env):
        genv = env.global_scope()
        default_seen = 0
        for arg in self.args:
            if arg.default:
                default_seen = 1
                if arg.is_generic:
                    arg.default.analyse_types(env)
                    arg.default = arg.default.coerce_to(arg.type, genv)
                else:
                    error(arg.pos,
                        "This argument cannot have a default value")
                    arg.default = None
            elif arg.kw_only:
                default_seen = 1
            elif default_seen:
                error(arg.pos, "Non-default argument following default argument")

    def align_argument_type(self, env, arg):
        directive_locals = self.directive_locals
        type = arg.type
        if arg.name in directive_locals:
            type_node = directive_locals[arg.name]
            other_type = type_node.analyse_as_type(env)
            if other_type is None:
                error(type_node.pos, "Not a type")
            elif (type is not PyrexTypes.py_object_type
                    and not type.same_as(other_type)):
                error(arg.base_type.pos, "Signature does not agree with previous declaration")
                error(type_node.pos, "Previous declaration here")
            else:
                arg.type = other_type
        return arg

    def need_gil_acquisition(self, lenv):
        return 0

    def create_local_scope(self, env):
        genv = env
        while genv.is_py_class_scope or genv.is_c_class_scope:
            genv = genv.outer_scope
        if self.needs_closure:
            lenv = ClosureScope(name=self.entry.name,
                                outer_scope = genv,
                                parent_scope = env,
                                scope_name=self.entry.cname)
        else:
            lenv = LocalScope(name=self.entry.name,
                              outer_scope=genv,
                              parent_scope=env)
        lenv.return_type = self.return_type
        type = self.entry.type
        if type.is_cfunction:
            lenv.nogil = type.nogil and not type.with_gil
        self.local_scope = lenv
        lenv.directives = env.directives
        return lenv

    def generate_function_body(self, env, code):
        self.body.generate_execution_code(code)

    def generate_function_definitions(self, env, code):
        import Buffer
        if self.return_type.is_memoryviewslice:
            import MemoryView

        lenv = self.local_scope
        if lenv.is_closure_scope and not lenv.is_passthrough:
            outer_scope_cname = "%s->%s" % (Naming.cur_scope_cname,
                                            Naming.outer_scope_cname)
        else:
            outer_scope_cname = Naming.outer_scope_cname
        lenv.mangle_closure_cnames(outer_scope_cname)
        # Generate closure function definitions
        self.body.generate_function_definitions(lenv, code)
        # generate lambda function definitions
        self.generate_lambda_definitions(lenv, code)

        is_getbuffer_slot = (self.entry.name == "__getbuffer__" and
                             self.entry.scope.is_c_class_scope)
        is_releasebuffer_slot = (self.entry.name == "__releasebuffer__" and
                                 self.entry.scope.is_c_class_scope)
        is_buffer_slot = is_getbuffer_slot or is_releasebuffer_slot
        if is_buffer_slot:
            if 'cython_unused' not in self.modifiers:
                self.modifiers = self.modifiers + ['cython_unused']

        preprocessor_guard = self.get_preprocessor_guard()

        profile = code.globalstate.directives['profile']
        if profile and lenv.nogil:
            warning(self.pos, "Cannot profile nogil function.", 1)
            profile = False
        if profile:
            code.globalstate.use_utility_code(profile_utility_code)

        # Generate C code for header and body of function
        code.enter_cfunc_scope()
        code.return_from_error_cleanup_label = code.new_label()

        # ----- Top-level constants used by this function
        code.mark_pos(self.pos)
        self.generate_cached_builtins_decls(lenv, code)
        # ----- Function header
        code.putln("")

        if preprocessor_guard:
            code.putln(preprocessor_guard)

        with_pymethdef = (self.needs_assignment_synthesis(env, code) or
                          self.pymethdef_required)
        if self.py_func:
            self.py_func.generate_function_header(code,
                with_pymethdef = with_pymethdef,
                proto_only=True)
        self.generate_function_header(code,
            with_pymethdef = with_pymethdef)
        # ----- Local variable declarations
        # Find function scope
        cenv = env
        while cenv.is_py_class_scope or cenv.is_c_class_scope:
            cenv = cenv.outer_scope
        if self.needs_closure:
            code.put(lenv.scope_class.type.declaration_code(Naming.cur_scope_cname))
            code.putln(";")
        elif self.needs_outer_scope:
            if lenv.is_passthrough:
                code.put(lenv.scope_class.type.declaration_code(Naming.cur_scope_cname))
                code.putln(";")
            code.put(cenv.scope_class.type.declaration_code(Naming.outer_scope_cname))
            code.putln(";")
        self.generate_argument_declarations(lenv, code)

        for entry in lenv.var_entries:
            if not (entry.in_closure or entry.is_arg):
                code.put_var_declaration(entry)

        # Initialize the return variable __pyx_r
        init = ""
        if not self.return_type.is_void:
            if self.return_type.is_pyobject:
                init = " = NULL"
            elif self.return_type.is_memoryviewslice:
                init = ' = ' + MemoryView.memslice_entry_init

            code.putln(
                "%s%s;" %
                    (self.return_type.declaration_code(Naming.retval_cname),
                     init))

        tempvardecl_code = code.insertion_point()
        self.generate_keyword_list(code)

        if profile:
            code.put_trace_declarations()

        # ----- Extern library function declarations
        lenv.generate_library_function_declarations(code)

        # ----- GIL acquisition
        acquire_gil = self.acquire_gil

        # See if we need to acquire the GIL for variable declarations, or for
        # refnanny only

        # Profiling or closures are not currently possible for cdef nogil
        # functions, but check them anyway
        have_object_args = (self.needs_closure or self.needs_outer_scope or
                            profile)
        for arg in lenv.arg_entries:
            if arg.type.is_pyobject:
                have_object_args = True
                break

        acquire_gil_for_var_decls_only = (
                lenv.nogil and lenv.has_with_gil_block and
                (have_object_args or lenv.buffer_entries))

        acquire_gil_for_refnanny_only = (
                lenv.nogil and lenv.has_with_gil_block and not
                acquire_gil_for_var_decls_only)

        use_refnanny = not lenv.nogil or lenv.has_with_gil_block

        if acquire_gil or acquire_gil_for_var_decls_only:
            code.put_ensure_gil()
        elif lenv.nogil and lenv.has_with_gil_block:
            code.declare_gilstate()

        # ----- set up refnanny
        if use_refnanny:
            tempvardecl_code.put_declare_refcount_context()
            code.put_setup_refcount_context(
                self.entry.name, acquire_gil=acquire_gil_for_refnanny_only)

        # ----- Automatic lead-ins for certain special functions
        if is_getbuffer_slot:
            self.getbuffer_init(code)
        # ----- Create closure scope object
        if self.needs_closure:
            code.putln("%s = (%s)%s->tp_new(%s, %s, NULL);" % (
                Naming.cur_scope_cname,
                lenv.scope_class.type.declaration_code(''),
                lenv.scope_class.type.typeptr_cname,
                lenv.scope_class.type.typeptr_cname,
                Naming.empty_tuple))
            code.putln("if (unlikely(!%s)) {" % Naming.cur_scope_cname)
            if is_getbuffer_slot:
                self.getbuffer_error_cleanup(code)

            if use_refnanny:
                code.put_finish_refcount_context()
                if acquire_gil or acquire_gil_for_var_decls_only:
                    code.put_release_ensured_gil()

            # FIXME: what if the error return value is a Python value?
            code.putln("return %s;" % self.error_value())
            code.putln("}")
            code.put_gotref(Naming.cur_scope_cname)
            # Note that it is unsafe to decref the scope at this point.
        if self.needs_outer_scope:
            if self.is_cyfunction:
                code.putln("%s = (%s) __Pyx_CyFunction_GetClosure(%s);" % (
                    outer_scope_cname,
                    cenv.scope_class.type.declaration_code(''),
                    Naming.self_cname))
            else:
                code.putln("%s = (%s) %s;" % (
                    outer_scope_cname,
                    cenv.scope_class.type.declaration_code(''),
                    Naming.self_cname))
            if lenv.is_passthrough:
                code.putln("%s = %s;" % (Naming.cur_scope_cname, outer_scope_cname));
            elif self.needs_closure:
                # inner closures own a reference to their outer parent
                code.put_incref(outer_scope_cname, cenv.scope_class.type)
                code.put_giveref(outer_scope_cname)
        # ----- Trace function call
        if profile:
            # this looks a bit late, but if we don't get here due to a
            # fatal error before hand, it's not really worth tracing
            code.put_trace_call(self.entry.name, self.pos)
        # ----- Fetch arguments
        self.generate_argument_parsing_code(env, code)
        # If an argument is assigned to in the body, we must
        # incref it to properly keep track of refcounts.
        is_cdef = isinstance(self, CFuncDefNode)
        for entry in lenv.arg_entries:
            if entry.type.is_pyobject:
                if ((acquire_gil or len(entry.cf_assignments) > 1) and
                    not entry.in_closure):
                    code.put_var_incref(entry)

            # Note: defaults are always incref-ed. For def functions, we
            #       we aquire arguments from object converstion, so we have
            #       new references. If we are a cdef function, we need to
            #       incref our arguments
            elif (is_cdef and entry.type.is_memoryviewslice and
                  len(entry.cf_assignments) > 1):
                code.put_incref_memoryviewslice(entry.cname,
                                                have_gil=not lenv.nogil)
        for entry in lenv.var_entries:
            if entry.is_arg and len(entry.cf_assignments) > 1:
                code.put_var_incref(entry)

        # ----- Initialise local buffer auxiliary variables
        for entry in lenv.var_entries + lenv.arg_entries:
            if entry.type.is_buffer and entry.buffer_aux.buflocal_nd_var.used:
                Buffer.put_init_vars(entry, code)

        # ----- Check and convert arguments
        self.generate_argument_type_tests(code)
        # ----- Acquire buffer arguments
        for entry in lenv.arg_entries:
            if entry.type.is_buffer:
                Buffer.put_acquire_arg_buffer(entry, code, self.pos)

        if acquire_gil_for_var_decls_only:
            code.put_release_ensured_gil()

        # -------------------------
        # ----- Function body -----
        # -------------------------
        self.generate_function_body(env, 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))
        # ----- Error cleanup
        if code.error_label in code.labels_used:
            code.put_goto(code.return_label)
            code.put_label(code.error_label)
            for cname, type in code.funcstate.all_managed_temps():
                code.put_xdecref(cname, type, have_gil=not lenv.nogil)

            # Clean up buffers -- this calls a Python function
            # so need to save and restore error state
            buffers_present = len(lenv.buffer_entries) > 0
            memslice_entries = [e for e in lenv.entries.itervalues()
                                      if e.type.is_memoryviewslice]
            if buffers_present:
                code.globalstate.use_utility_code(restore_exception_utility_code)
                code.putln("{ PyObject *__pyx_type, *__pyx_value, *__pyx_tb;")
                code.putln("__Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);")
                for entry in lenv.buffer_entries:
                    Buffer.put_release_buffer_code(code, entry)
                    #code.putln("%s = 0;" % entry.cname)
                code.putln("__Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}")

            if self.return_type.is_memoryviewslice:
                MemoryView.put_init_entry(Naming.retval_cname, code)
                err_val = Naming.retval_cname
            else:
                err_val = self.error_value()

            exc_check = self.caller_will_check_exceptions()
            if err_val is not None or exc_check:
                # TODO: Fix exception tracing (though currently unused by cProfile).
                # code.globalstate.use_utility_code(get_exception_tuple_utility_code)
                # code.put_trace_exception()

                if lenv.nogil and not lenv.has_with_gil_block:
                    code.putln("{")
                    code.put_ensure_gil()

                code.put_add_traceback(self.entry.qualified_name)

                if lenv.nogil and not lenv.has_with_gil_block:
                    code.put_release_ensured_gil()
                    code.putln("}")
            else:
                warning(self.entry.pos, "Unraisable exception in function '%s'." \
                            % self.entry.qualified_name, 0)
                format_tuple = (
                    self.entry.qualified_name,
                    Naming.clineno_cname,
                    Naming.lineno_cname,
                    Naming.filename_cname,
                    )
                code.putln(
                    '__Pyx_WriteUnraisable("%s", %s, %s, %s);' % format_tuple)
                env.use_utility_code(unraisable_exception_utility_code)
                env.use_utility_code(restore_exception_utility_code)
            default_retval = self.return_type.default_value
            if err_val is None and default_retval:
                err_val = default_retval
            if err_val is not None:
                code.putln("%s = %s;" % (Naming.retval_cname, err_val))

            if is_getbuffer_slot:
                self.getbuffer_error_cleanup(code)

            # If we are using the non-error cleanup section we should
            # jump past it if we have an error. The if-test below determine
            # whether this section is used.
            if buffers_present or is_getbuffer_slot:
                code.put_goto(code.return_from_error_cleanup_label)

        # ----- Non-error return cleanup
        code.put_label(code.return_label)
        for entry in lenv.buffer_entries:
            if entry.used:
                Buffer.put_release_buffer_code(code, entry)
        if is_getbuffer_slot:
            self.getbuffer_normal_cleanup(code)

        if self.return_type.is_memoryviewslice:
            # See if our return value is uninitialized on non-error return
            # import MemoryView
            # MemoryView.err_if_nogil_initialized_check(self.pos, env)
            cond = code.unlikely(self.return_type.error_condition(
                                                    Naming.retval_cname))
            code.putln(
                'if (%s) {' % cond)
            if env.nogil:
                code.put_ensure_gil()
            code.putln(
                    'PyErr_SetString('
                        'PyExc_TypeError,'
                        '"Memoryview return value is not initialized");')
            if env.nogil:
                code.put_release_ensured_gil()
            code.putln(
                '}')

        # ----- Return cleanup for both error and no-error return
        code.put_label(code.return_from_error_cleanup_label)

        for entry in lenv.var_entries:
            if not entry.used or entry.in_closure:
                continue

            if entry.type.is_memoryviewslice:
                code.put_xdecref_memoryviewslice(entry.cname,
                                                 have_gil=not lenv.nogil)
            elif entry.type.is_pyobject:
                if not entry.is_arg or len(entry.cf_assignments) > 1:
                    code.put_var_decref(entry)

        # Decref any increfed args
        for entry in lenv.arg_entries:
            if entry.type.is_pyobject:
                if ((acquire_gil or len(entry.cf_assignments) > 1) and
                    not entry.in_closure):
                    code.put_var_decref(entry)
            elif (entry.type.is_memoryviewslice and
                  (not is_cdef or len(entry.cf_assignments) > 1)):
                # decref slices of def functions and acquired slices from cdef
                # functions, but not borrowed slices from cdef functions.
                code.put_xdecref_memoryviewslice(entry.cname,
                                                 have_gil=not lenv.nogil)
        if self.needs_closure:
            code.put_decref(Naming.cur_scope_cname, lenv.scope_class.type)

        # ----- Return
        # This code is duplicated in ModuleNode.generate_module_init_func
        if not lenv.nogil:
            default_retval = self.return_type.default_value
            err_val = self.error_value()
            if err_val is None and default_retval:
                err_val = default_retval
            if self.return_type.is_pyobject:
                code.put_xgiveref(self.return_type.as_pyobject(Naming.retval_cname))

        if self.entry.is_special and self.entry.name == "__hash__":
            # Returning -1 for __hash__ is supposed to signal an error
            # We do as Python instances and coerce -1 into -2.
            code.putln("if (unlikely(%s == -1) && !PyErr_Occurred()) %s = -2;" % (
                    Naming.retval_cname, Naming.retval_cname))

        if profile:
            if self.return_type.is_pyobject:
                code.put_trace_return(Naming.retval_cname)
            else:
                code.put_trace_return("Py_None")

        if not lenv.nogil:
            # GIL holding funcion
            code.put_finish_refcount_context()

        if acquire_gil or (lenv.nogil and lenv.has_with_gil_block):
            # release the GIL (note that with-gil blocks acquire it on exit in their EnsureGILNode)
            code.put_release_ensured_gil()

        if not self.return_type.is_void:
            code.putln("return %s;" % Naming.retval_cname)

        code.putln("}")

        if preprocessor_guard:
            code.putln("#endif /*!(%s)*/" % preprocessor_guard)

        # ----- Go back and insert temp variable declarations
        tempvardecl_code.put_temp_declarations(code.funcstate)
        if code.funcstate.should_declare_error_indicator:
            # Initialize these variables to silence compiler warnings
            tempvardecl_code.putln("int %s = 0;" % Naming.lineno_cname)
            tempvardecl_code.putln("const char *%s = NULL;" %
                                                    Naming.filename_cname)
            if code.c_line_in_traceback:
                tempvardecl_code.putln("int %s = 0;" % Naming.clineno_cname)

        # ----- Python version
        code.exit_cfunc_scope()
        if self.py_func:
            self.py_func.generate_function_definitions(env, code)
        self.generate_wrapper_functions(code)

    def declare_argument(self, env, arg):
        if arg.type.is_void:
            error(arg.pos, "Invalid use of 'void'")
        elif not arg.type.is_complete() and not (arg.type.is_array or arg.type.is_memoryviewslice):
            error(arg.pos,
                "Argument type '%s' is incomplete" % arg.type)
        return env.declare_arg(arg.name, arg.type, arg.pos)

    def generate_arg_type_test(self, arg, code):
        # Generate type test for one argument.
        if arg.type.typeobj_is_available():
            code.globalstate.use_utility_code(
                UtilityCode.load_cached("ArgTypeTest", "FunctionArguments.c"))
            typeptr_cname = arg.type.typeptr_cname
            arg_code = "((PyObject *)%s)" % arg.entry.cname
            code.putln(
                'if (unlikely(!__Pyx_ArgTypeTest(%s, %s, %d, "%s", %s))) %s' % (
                    arg_code,
                    typeptr_cname,
                    arg.accept_none,
                    arg.name,
                    arg.type.is_builtin_type,
                    code.error_goto(arg.pos)))
        else:
            error(arg.pos, "Cannot test type of extern C class "
                "without type object name specification")

    def generate_arg_none_check(self, arg, code):
        # Generate None check for one argument.
        code.putln('if (unlikely(((PyObject *)%s) == Py_None)) {' % arg.entry.cname)
        code.putln('''PyErr_Format(PyExc_TypeError, "Argument '%s' must not be None"); %s''' % (
            arg.name,
            code.error_goto(arg.pos)))
        code.putln('}')

    def generate_wrapper_functions(self, code):
        pass

    def generate_execution_code(self, code):
        # Evaluate and store argument default values
        for arg in self.args:
            if not arg.is_dynamic:
                arg.generate_assignment_code(code)

    #
    # Special code for the __getbuffer__ function
    #
    def getbuffer_init(self, code):
        info = self.local_scope.arg_entries[1].cname
        # Python 3.0 betas have a bug in memoryview which makes it call
        # getbuffer with a NULL parameter. For now we work around this;
        # the following block should be removed when this bug is fixed.
        code.putln("if (%s != NULL) {" % info)
        code.putln("%s->obj = Py_None; __Pyx_INCREF(Py_None);" % info)
        code.put_giveref("%s->obj" % info) # Do not refnanny object within structs
        code.putln("}")

    def getbuffer_error_cleanup(self, code):
        info = self.local_scope.arg_entries[1].cname
        code.putln("if (%s != NULL && %s->obj != NULL) {"
                   % (info, info))
        code.put_gotref("%s->obj" % info)
        code.putln("__Pyx_DECREF(%s->obj); %s->obj = NULL;"
                   % (info, info))
        code.putln("}")

    def getbuffer_normal_cleanup(self, code):
        info = self.local_scope.arg_entries[1].cname
        code.putln("if (%s != NULL && %s->obj == Py_None) {" % (info, info))
        code.put_gotref("Py_None")
        code.putln("__Pyx_DECREF(Py_None); %s->obj = NULL;" % info)
        code.putln("}")

    def get_preprocessor_guard(self):
        if not self.entry.is_special:
            return None
        name = self.entry.name
        slot = TypeSlots.method_name_to_slot.get(name)
        if not slot:
            return None
        if name == '__long__' and not self.entry.scope.lookup_here('__int__'):
            return None
        if name in ("__getbuffer__", "__releasebuffer__") and self.entry.scope.is_c_class_scope:
            return None
        return slot.preprocessor_guard_code() class NameNode(AtomicExprNode):
    #  Reference to a local or global variable name.
    #
    #  name            string    Python name of the variable
    #  entry           Entry     Symbol table entry
    #  type_entry      Entry     For extension type names, the original type entry
    #  cf_is_null      boolean   Is uninitialized before this node
    #  cf_maybe_null   boolean   Maybe uninitialized before this node
    #  allow_null      boolean   Don't raise UnboundLocalError
    #  nogil           boolean   Whether it is used in a nogil context

    is_name = True
    is_cython_module = False
    cython_attribute = None
    lhs_of_first_assignment = False # TODO: remove me
    is_used_as_rvalue = 0
    entry = None
    type_entry = None
    cf_maybe_null = True
    cf_is_null = False
    allow_null = False
    nogil = False

    def as_cython_attribute(self):
        return self.cython_attribute

    def type_dependencies(self, env):
        if self.entry is None:
            self.entry = env.lookup(self.name)
        if self.entry is not None and self.entry.type.is_unspecified:
            return (self.entry,)
        else:
            return ()

    def infer_type(self, env):
        if self.entry is None:
            self.entry = env.lookup(self.name)
        if self.entry is None:
            return py_object_type
        elif (self.entry.type.is_extension_type or self.entry.type.is_builtin_type) and \
                self.name == self.entry.type.name:
            # Unfortunately the type attribute of type objects
            # is used for the pointer to the type they represent.
            return type_type
        elif self.entry.type.is_cfunction:
            if self.entry.scope.is_builtin_scope:
                # special case: optimised builtin functions must be treated as Python objects
                return py_object_type
            else:
                # special case: referring to a C function must return its pointer
                return PyrexTypes.CPtrType(self.entry.type)
        else:
            return self.entry.type

    def compile_time_value(self, denv):
        try:
            return denv.lookup(self.name)
        except KeyError:
            error(self.pos, "Compile-time name '%s' not defined" % self.name)

    def get_constant_c_result_code(self):
        if not self.entry or self.entry.type.is_pyobject:
            return None
        return self.entry.cname

    def coerce_to(self, dst_type, env):
        #  If coercing to a generic pyobject and this is a builtin
        #  C function with a Python equivalent, manufacture a NameNode
        #  referring to the Python builtin.
        #print "NameNode.coerce_to:", self.name, dst_type ###
        if dst_type is py_object_type:
            entry = self.entry
            if entry and entry.is_cfunction:
                var_entry = entry.as_variable
                if var_entry:
                    if var_entry.is_builtin and var_entry.is_const:
                        var_entry = env.declare_builtin(var_entry.name, self.pos)
                    node = NameNode(self.pos, name = self.name)
                    node.entry = var_entry
                    node.analyse_rvalue_entry(env)
                    return node

        return super(NameNode, self).coerce_to(dst_type, env)

    def analyse_as_module(self, env):
        # Try to interpret this as a reference to a cimported module.
        # Returns the module scope, or None.
        entry = self.entry
        if not entry:
            entry = env.lookup(self.name)
        if entry and entry.as_module:
            return entry.as_module
        return None

    def analyse_as_type(self, env):
        if self.cython_attribute:
            type = PyrexTypes.parse_basic_type(self.cython_attribute)
        else:
            type = PyrexTypes.parse_basic_type(self.name)
        if type:
            return type
        entry = self.entry
        if not entry:
            entry = env.lookup(self.name)
        if entry and entry.is_type:
            return entry.type
        else:
            return None

    def analyse_as_extension_type(self, env):
        # Try to interpret this as a reference to an extension type.
        # Returns the extension type, or None.
        entry = self.entry
        if not entry:
            entry = env.lookup(self.name)
        if entry and entry.is_type and entry.type.is_extension_type:
            return entry.type
        else:
            return None

    def analyse_target_declaration(self, env):
        if not self.entry:
            self.entry = env.lookup_here(self.name)
        if not self.entry:
            if env.directives['warn.undeclared']:
                warning(self.pos, "implicit declaration of '%s'" % self.name, 1)
            if env.directives['infer_types'] != False:
                type = unspecified_type
            else:
                type = py_object_type
            self.entry = env.declare_var(self.name, type, self.pos)
        if self.entry.is_declared_generic:
            self.result_ctype = py_object_type

    def analyse_types(self, env):
        self.initialized_check = env.directives['initializedcheck']
        if self.entry is None:
            self.entry = env.lookup(self.name)
        if not self.entry:
            self.entry = env.declare_builtin(self.name, self.pos)
        if not self.entry:
            self.type = PyrexTypes.error_type
            return
        entry = self.entry
        if entry:
            entry.used = 1
            if entry.type.is_buffer:
                import Buffer
                Buffer.used_buffer_aux_vars(entry)
            if entry.utility_code:
                env.use_utility_code(entry.utility_code)
        self.analyse_rvalue_entry(env)

    def analyse_target_types(self, env):
        self.analyse_entry(env)

        if (not self.is_lvalue() and self.entry.is_cfunction and
                self.entry.fused_cfunction and self.entry.as_variable):
            # We need this for the fused 'def' TreeFragment
            self.entry = self.entry.as_variable
            self.type = self.entry.type

        if not self.is_lvalue():
            error(self.pos, "Assignment to non-lvalue '%s'"
                % self.name)
            self.type = PyrexTypes.error_type
        self.entry.used = 1
        if self.entry.type.is_buffer:
            import Buffer
            Buffer.used_buffer_aux_vars(self.entry)

    def analyse_rvalue_entry(self, env):
        #print "NameNode.analyse_rvalue_entry:", self.name ###
        #print "Entry:", self.entry.__dict__ ###
        self.analyse_entry(env)
        entry = self.entry

        if entry.is_declared_generic:
            self.result_ctype = py_object_type

        if entry.is_pyglobal or entry.is_builtin:
            if entry.is_builtin and entry.is_const:
                self.is_temp = 0
            else:
                self.is_temp = 1
                env.use_utility_code(get_name_interned_utility_code)

            self.is_used_as_rvalue = 1
        elif entry.type.is_memoryviewslice:
            self.is_temp = False
            self.is_used_as_rvalue = True
            self.use_managed_ref = True

    def nogil_check(self, env):
        self.nogil = True
        if self.is_used_as_rvalue:
            entry = self.entry
            if entry.is_builtin:
                if not entry.is_const: # cached builtins are ok
                    self.gil_error()
            elif entry.is_pyglobal:
                self.gil_error()
            elif self.entry.type.is_memoryviewslice:
                if self.cf_is_null or self.cf_maybe_null:
                    import MemoryView
                    MemoryView.err_if_nogil_initialized_check(self.pos, env)

    gil_message = "Accessing Python global or builtin"

    def analyse_entry(self, env):
        #print "NameNode.analyse_entry:", self.name ###
        self.check_identifier_kind()
        entry = self.entry
        type = entry.type
        self.type = type

    def check_identifier_kind(self):
        # Check that this is an appropriate kind of name for use in an
        # expression.  Also finds the variable entry associated with
        # an extension type.
        entry = self.entry
        if entry.is_type and entry.type.is_extension_type:
            self.type_entry = entry
        if not (entry.is_const or entry.is_variable
            or entry.is_builtin or entry.is_cfunction
            or entry.is_cpp_class):
                if self.entry.as_variable:
                    self.entry = self.entry.as_variable
                else:
                    error(self.pos,
                          "'%s' is not a constant, variable or function identifier" % self.name)

    def is_simple(self):
        #  If it's not a C variable, it'll be in a temp.
        return 1

    def may_be_none(self):
        if self.cf_state and self.type and self.type.is_pyobject:
            # gard against infinite recursion on self-dependencies
            if getattr(self, '_none_checking', False):
                # self-dependency - either this node receives a None
                # value from *another* node, or it can not reference
                # None at this point => safe to assume "not None"
                return False
            self._none_checking = True
            # evaluate control flow state to see if there were any
            # potential None values assigned to the node so far
            may_be_none = False
            for assignment in self.cf_state:
                if assignment.rhs.may_be_none():
                    may_be_none = True
                    break
            del self._none_checking
            return may_be_none
        return super(NameNode, self).may_be_none()

    def nonlocally_immutable(self):
        if ExprNode.nonlocally_immutable(self):
            return True
        entry = self.entry
        return entry and (entry.is_local or entry.is_arg) and not entry.in_closure

    def calculate_target_results(self, env):
        pass

    def check_const(self):
        entry = self.entry
        if entry is not None and not (entry.is_const or entry.is_cfunction or entry.is_builtin):
            self.not_const()
            return False
        return True

    def check_const_addr(self):
        entry = self.entry
        if not (entry.is_cglobal or entry.is_cfunction or entry.is_builtin):
            self.addr_not_const()
            return False
        return True

    def is_lvalue(self):
        return self.entry.is_variable and \
            not self.entry.type.is_array and \
            not self.entry.is_readonly

    def is_addressable(self):
        return self.entry.is_variable

    def is_ephemeral(self):
        #  Name nodes are never ephemeral, even if the
        #  result is in a temporary.
        return 0

    def calculate_result_code(self):
        entry = self.entry
        if not entry:
            return "<error>" # There was an error earlier
        return entry.cname

    def generate_result_code(self, code):
        assert hasattr(self, 'entry')
        entry = self.entry
        if entry is None:
            return # There was an error earlier
        if entry.is_builtin and entry.is_const:
            return # Lookup already cached
        elif entry.is_pyclass_attr:
            assert entry.type.is_pyobject, "Python global or builtin not a Python object"
            interned_cname = code.intern_identifier(self.entry.name)
            if entry.is_builtin:
                namespace = Naming.builtins_cname
            else: # entry.is_pyglobal
                namespace = entry.scope.namespace_cname
            if not self.cf_is_null:
                code.putln(
                    '%s = PyObject_GetItem(%s, %s);' % (
                        self.result(),
                        namespace,
                        interned_cname))
            if self.cf_maybe_null:
                if not self.cf_is_null:
                    code.putln('if (unlikely(!%s)) {' % self.result())
                    code.putln('PyErr_Clear();')
                code.putln(
                    '%s = __Pyx_GetName(%s, %s);' % (
                    self.result(),
                    Naming.module_cname,
                    interned_cname))
                if not self.cf_is_null:
                    code.putln("}");
            code.putln(code.error_goto_if_null(self.result(), self.pos))
            code.put_gotref(self.py_result())

        elif entry.is_pyglobal or entry.is_builtin:
            assert entry.type.is_pyobject, "Python global or builtin not a Python object"
            interned_cname = code.intern_identifier(self.entry.name)
            if entry.is_builtin:
                namespace = Naming.builtins_cname
            else: # entry.is_pyglobal
                namespace = entry.scope.namespace_cname
            code.globalstate.use_utility_code(get_name_interned_utility_code)
            code.putln(
                '%s = __Pyx_GetName(%s, %s); %s' % (
                self.result(),
                namespace,
                interned_cname,
                code.error_goto_if_null(self.result(), self.pos)))
            code.put_gotref(self.py_result())

        elif entry.is_local or entry.in_closure or entry.from_closure or entry.type.is_memoryviewslice:
            # Raise UnboundLocalError for objects and memoryviewslices
            raise_unbound = (
                (self.cf_maybe_null or self.cf_is_null) and not self.allow_null)
            null_code = entry.type.check_for_null_code(entry.cname)

            memslice_check = entry.type.is_memoryviewslice and self.initialized_check

            if null_code and raise_unbound and (entry.type.is_pyobject or memslice_check):
                code.put_error_if_unbound(self.pos, entry, self.in_nogil_context)

    def generate_assignment_code(self, rhs, code):
        #print "NameNode.generate_assignment_code:", self.name ###
        entry = self.entry
        if entry is None:
            return # There was an error earlier

        if (self.entry.type.is_ptr and isinstance(rhs, ListNode)
            and not self.lhs_of_first_assignment):
            error(self.pos, "Literal list must be assigned to pointer at time of declaration")

        # is_pyglobal seems to be True for module level-globals only.
        # We use this to access class->tp_dict if necessary.
        if entry.is_pyglobal:
            assert entry.type.is_pyobject, "Python global or builtin not a Python object"
            interned_cname = code.intern_identifier(self.entry.name)
            namespace = self.entry.scope.namespace_cname
            if entry.is_member:
                # if the entry is a member we have to cheat: SetAttr does not work
                # on types, so we create a descriptor which is then added to tp_dict
                code.put_error_if_neg(self.pos,
                    'PyDict_SetItem(%s->tp_dict, %s, %s)' % (
                        namespace,
                        interned_cname,
                        rhs.py_result()))
                rhs.generate_disposal_code(code)
                rhs.free_temps(code)
                # in Py2.6+, we need to invalidate the method cache
                code.putln("PyType_Modified(%s);" %
                            entry.scope.parent_type.typeptr_cname)
            elif entry.is_pyclass_attr:
                code.put_error_if_neg(self.pos,
                    'PyObject_SetItem(%s, %s, %s)' % (
                        namespace,
                        interned_cname,
                        rhs.py_result()))
                rhs.generate_disposal_code(code)
                rhs.free_temps(code)
            else:
                code.put_error_if_neg(self.pos,
                    'PyObject_SetAttr(%s, %s, %s)' % (
                        namespace,
                        interned_cname,
                        rhs.py_result()))
                if debug_disposal_code:
                    print("NameNode.generate_assignment_code:")
                    print("...generating disposal code for %s" % rhs)
                rhs.generate_disposal_code(code)
                rhs.free_temps(code)
        else:
            if self.type.is_memoryviewslice:
                self.generate_acquire_memoryviewslice(rhs, code)

            elif self.type.is_buffer:
                # Generate code for doing the buffer release/acquisition.
                # This might raise an exception in which case the assignment (done
                # below) will not happen.
                #
                # The reason this is not in a typetest-like node is because the
                # variables that the acquired buffer info is stored to is allocated
                # per entry and coupled with it.
                self.generate_acquire_buffer(rhs, code)

            if self.type.is_pyobject:
                #print "NameNode.generate_assignment_code: to", self.name ###
                #print "...from", rhs ###
                #print "...LHS type", self.type, "ctype", self.ctype() ###
                #print "...RHS type", rhs.type, "ctype", rhs.ctype() ###
                if self.use_managed_ref:
                    rhs.make_owned_reference(code)
                    is_external_ref = entry.is_cglobal or self.entry.in_closure or self.entry.from_closure
                    if is_external_ref:
                        if not self.cf_is_null:
                            if self.cf_maybe_null:
                                code.put_xgotref(self.py_result())
                            else:
                                code.put_gotref(self.py_result())
                    if entry.is_cglobal:
                        code.put_decref(self.result(), self.ctype())
                    else:
                        if not self.cf_is_null:
                            if self.cf_maybe_null:
                                code.put_xdecref(self.result(), self.ctype())
                            else:
                                code.put_decref(self.result(), self.ctype())
                    if is_external_ref:
                        code.put_giveref(rhs.py_result())
            if not self.type.is_memoryviewslice:
                code.putln('%s = %s;' % (self.result(), rhs.result_as(self.ctype())))
                if debug_disposal_code:
                    print("NameNode.generate_assignment_code:")
                    print("...generating post-assignment code for %s" % rhs)
                rhs.generate_post_assignment_code(code)
            elif rhs.result_in_temp():
                rhs.generate_post_assignment_code(code)

            rhs.free_temps(code)

    def generate_acquire_memoryviewslice(self, rhs, code):
        """
        Slices, coercions from objects, return values etc are new references.
        We have a borrowed reference in case of dst = src
        """
        import MemoryView

        MemoryView.put_acquire_memoryviewslice(
            lhs_cname=self.result(),
            lhs_type=self.type,
            lhs_pos=self.pos,
            rhs=rhs,
            code=code,
            have_gil=not self.in_nogil_context,
            first_assignment=self.cf_is_null)

    def generate_acquire_buffer(self, rhs, code):
        # rhstmp is only used in case the rhs is a complicated expression leading to
        # the object, to avoid repeating the same C expression for every reference
        # to the rhs. It does NOT hold a reference.
        pretty_rhs = isinstance(rhs, NameNode) or rhs.is_temp
        if pretty_rhs:
            rhstmp = rhs.result_as(self.ctype())
        else:
            rhstmp = code.funcstate.allocate_temp(self.entry.type, manage_ref=False)
            code.putln('%s = %s;' % (rhstmp, rhs.result_as(self.ctype())))

        import Buffer
        Buffer.put_assign_to_buffer(self.result(), rhstmp, self.entry,
                                    is_initialized=not self.lhs_of_first_assignment,
                                    pos=self.pos, code=code)

        if not pretty_rhs:
            code.putln("%s = 0;" % rhstmp)
            code.funcstate.release_temp(rhstmp)

    def generate_deletion_code(self, code):
        if self.entry is None:
            return # There was an error earlier
        elif self.entry.is_pyclass_attr:
            namespace = self.entry.scope.namespace_cname
            interned_cname = code.intern_identifier(self.entry.name)
            code.put_error_if_neg(self.pos,
                'PyMapping_DelItem(%s, %s)' % (
                    namespace,
                    interned_cname))
        elif self.entry.is_pyglobal:
            code.put_error_if_neg(self.pos,
                '__Pyx_DelAttrString(%s, "%s")' % (
                    Naming.module_cname,
                    self.entry.name))
        elif self.entry.type.is_pyobject or self.entry.type.is_memoryviewslice:
            if not self.cf_is_null:
                if self.cf_maybe_null:
                    code.put_error_if_unbound(self.pos, self.entry)

                if self.entry.type.is_pyobject:
                    code.put_decref(self.result(), self.ctype())
                    code.putln('%s = NULL;' % self.result())
                else:
                    code.put_xdecref_memoryviewslice(self.entry.cname,
                                                     have_gil=not self.nogil)
        else:
            error(self.pos, "Deletion of C names not supported")

    def annotate(self, code):
        if hasattr(self, 'is_called') and self.is_called:
            pos = (self.pos[0], self.pos[1], self.pos[2] - len(self.name) - 1)
            if self.type.is_pyobject:
                code.annotate(pos, AnnotationItem('py_call', 'python function', size=len(self.name)))
            else:
                code.annotate(pos, AnnotationItem('c_call', 'c function', size=len(self.name))) class AttributeNode(ExprNode):
    #  obj.attribute
    #
    #  obj          ExprNode
    #  attribute    string
    #  needs_none_check boolean        Used if obj is an extension type.
    #                                  If set to True, it is known that the type is not None.
    #
    #  Used internally:
    #
    #  is_py_attr           boolean   Is a Python getattr operation
    #  member               string    C name of struct member
    #  is_called            boolean   Function call is being done on result
    #  entry                Entry     Symbol table entry of attribute

    is_attribute = 1
    subexprs = ['obj']

    type = PyrexTypes.error_type
    entry = None
    is_called = 0
    needs_none_check = True
    is_memslice_transpose = False

    def as_cython_attribute(self):
        if (isinstance(self.obj, NameNode) and
                self.obj.is_cython_module and not
                self.attribute == u"parallel"):
            return self.attribute

        cy = self.obj.as_cython_attribute()
        if cy:
            return "%s.%s" % (cy, self.attribute)
        return None

    def coerce_to(self, dst_type, env):
        #  If coercing to a generic pyobject and this is a cpdef function
        #  we can create the corresponding attribute
        if dst_type is py_object_type:
            entry = self.entry
            if entry and entry.is_cfunction and entry.as_variable:
                # must be a cpdef function
                self.is_temp = 1
                self.entry = entry.as_variable
                self.analyse_as_python_attribute(env)
                return self
        return ExprNode.coerce_to(self, dst_type, env)

    def calculate_constant_result(self):
        attr = self.attribute
        if attr.startswith("__") and attr.endswith("__"):
            return
        self.constant_result = getattr(self.obj.constant_result, attr)

    def compile_time_value(self, denv):
        attr = self.attribute
        if attr.startswith("__") and attr.endswith("__"):
            error(self.pos,
                  "Invalid attribute name '%s' in compile-time expression" % attr)
            return None
        obj = self.obj.compile_time_value(denv)
        try:
            return getattr(obj, attr)
        except Exception, e:
            self.compile_time_value_error(e)

    def type_dependencies(self, env):
        return self.obj.type_dependencies(env)

    def infer_type(self, env):
        if self.analyse_as_cimported_attribute(env, 0):
            return self.entry.type
        elif self.analyse_as_unbound_cmethod(env):
            return self.entry.type
        else:
            obj_type = self.obj.infer_type(env)
            self.analyse_attribute(env, obj_type = obj_type)
            if obj_type.is_builtin_type and self.type.is_cfunction:
                # special case: C-API replacements for C methods of
                # builtin types cannot be inferred as C functions as
                # that would prevent their use as bound methods
                self.type = py_object_type
                return py_object_type
            return self.type

    def analyse_target_declaration(self, env):
        pass

    def analyse_target_types(self, env):
        self.analyse_types(env, target = 1)
        if not self.is_lvalue():
            error(self.pos, "Assignment to non-lvalue of type '%s'" % self.type)

    def analyse_types(self, env, target = 0):
        self.initialized_check = env.directives['initializedcheck']
        if self.analyse_as_cimported_attribute(env, target):
            self.entry.used = True
        elif not target and self.analyse_as_unbound_cmethod(env):
            self.entry.used = True
        else:
            self.analyse_as_ordinary_attribute(env, target)
            if self.entry:
                self.entry.used = True

    def analyse_as_cimported_attribute(self, env, target):
        # Try to interpret this as a reference to an imported
        # C const, type, var or function. If successful, mutates
        # this node into a NameNode and returns 1, otherwise
        # returns 0.
        module_scope = self.obj.analyse_as_module(env)
        if module_scope:
            entry = module_scope.lookup_here(self.attribute)
            if entry and (
                entry.is_cglobal or entry.is_cfunction
                or entry.is_type or entry.is_const):
                    self.mutate_into_name_node(env, entry, target)
                    entry.used = 1
                    return 1
        return 0

    def analyse_as_unbound_cmethod(self, env):
        # Try to interpret this as a reference to an unbound
        # C method of an extension type. If successful, mutates
        # this node into a NameNode and returns 1, otherwise
        # returns 0.
        type = self.obj.analyse_as_extension_type(env)
        if type:
            entry = type.scope.lookup_here(self.attribute)
            if entry and entry.is_cmethod:
                # Create a temporary entry describing the C method
                # as an ordinary function.
                ubcm_entry = Symtab.Entry(entry.name,
                    "%s->%s" % (type.vtabptr_cname, entry.cname),
                    entry.type)
                ubcm_entry.is_cfunction = 1
                ubcm_entry.func_cname = entry.func_cname
                ubcm_entry.is_unbound_cmethod = 1
                self.mutate_into_name_node(env, ubcm_entry, None)
                return 1
        return 0

    def analyse_as_type(self, env):
        module_scope = self.obj.analyse_as_module(env)
        if module_scope:
            return module_scope.lookup_type(self.attribute)
        if not self.obj.is_string_literal:
            base_type = self.obj.analyse_as_type(env)
            if base_type and hasattr(base_type, 'scope') and base_type.scope is not None:
                return base_type.scope.lookup_type(self.attribute)
        return None

    def analyse_as_extension_type(self, env):
        # Try to interpret this as a reference to an extension type
        # in a cimported module. Returns the extension type, or None.
        module_scope = self.obj.analyse_as_module(env)
        if module_scope:
            entry = module_scope.lookup_here(self.attribute)
            if entry and entry.is_type and entry.type.is_extension_type:
                return entry.type
        return None

    def analyse_as_module(self, env):
        # Try to interpret this as a reference to a cimported module
        # in another cimported module. Returns the module scope, or None.
        module_scope = self.obj.analyse_as_module(env)
        if module_scope:
            entry = module_scope.lookup_here(self.attribute)
            if entry and entry.as_module:
                return entry.as_module
        return None

    def mutate_into_name_node(self, env, entry, target):
        # Mutate this node into a NameNode and complete the
        # analyse_types phase.
        self.__class__ = NameNode
        self.name = self.attribute
        self.entry = entry
        del self.obj
        del self.attribute
        if target:
            NameNode.analyse_target_types(self, env)
        else:
            NameNode.analyse_rvalue_entry(self, env)

    def analyse_as_ordinary_attribute(self, env, target):
        self.obj.analyse_types(env)
        self.analyse_attribute(env)
        if self.entry and self.entry.is_cmethod and not self.is_called:
#            error(self.pos, "C method can only be called")
            pass
        ## Reference to C array turns into pointer to first element.
        #while self.type.is_array:
        #    self.type = self.type.element_ptr_type()
        if self.is_py_attr:
            if not target:
                self.is_temp = 1
                self.result_ctype = py_object_type
        elif target and self.obj.type.is_builtin_type:
            error(self.pos, "Assignment to an immutable object field")
        #elif self.type.is_memoryviewslice and not target:
        #    self.is_temp = True

    def analyse_attribute(self, env, obj_type = None):
        # Look up attribute and set self.type and self.member.
        self.is_py_attr = 0
        self.member = self.attribute
        if obj_type is None:
            if self.obj.type.is_string:
                self.obj = self.obj.coerce_to_pyobject(env)
            obj_type = self.obj.type
        else:
            if obj_type.is_string:
                obj_type = py_object_type
        if obj_type.is_ptr or obj_type.is_array:
            obj_type = obj_type.base_type
            self.op = "->"
        elif obj_type.is_extension_type or obj_type.is_builtin_type:
            self.op = "->"
        else:
            self.op = "."
        if obj_type.has_attributes:
            entry = None
            if obj_type.attributes_known():
                if (obj_type.is_memoryviewslice and not
                        obj_type.scope.lookup_here(self.attribute)):
                    if self.attribute == 'T':
                        self.is_memslice_transpose = True
                        self.is_temp = True
                        self.use_managed_ref = True
                        self.type = self.obj.type
                        return
                    else:
                        obj_type.declare_attribute(self.attribute, env, self.pos)
                entry = obj_type.scope.lookup_here(self.attribute)
                if entry and entry.is_member:
                    entry = None
            else:
                error(self.pos,
                    "Cannot select attribute of incomplete type '%s'"
                    % obj_type)
                self.type = PyrexTypes.error_type
                return
            self.entry = entry
            if entry:
                if obj_type.is_extension_type and entry.name == "__weakref__":
                    error(self.pos, "Illegal use of special attribute __weakref__")
                # methods need the normal attribute lookup
                # because they do not have struct entries
                if entry.is_variable or entry.is_cmethod:
                    self.type = entry.type
                    self.member = entry.cname
                    return
                else:
                    # If it's not a variable or C method, it must be a Python
                    # method of an extension type, so we treat it like a Python
                    # attribute.
                    pass
        # NumPy hack
        if (getattr(self.obj, 'type', None) and
                obj_type.is_extension_type and
                obj_type.objstruct_cname == 'PyArrayObject'):
            from NumpySupport import numpy_transform_attribute_node
            replacement_node = numpy_transform_attribute_node(self)
            # Since we can't actually replace our node yet, we only grasp its
            # type, and then the replacement happens in
            # AnalyseExpresssionsTransform...
            self.type = replacement_node.type
            if replacement_node is not self:
                return
        
        # If we get here, the base object is not a struct/union/extension
        # type, or it is an extension type and the attribute is either not
        # declared or is declared as a Python method. Treat it as a Python
        # attribute reference.
        self.analyse_as_python_attribute(env, obj_type)

    def analyse_as_python_attribute(self, env, obj_type = None):
        if obj_type is None:
            obj_type = self.obj.type
        # mangle private '__*' Python attributes used inside of a class
        self.attribute = env.mangle_class_private_name(self.attribute)
        self.member = self.attribute
        self.type = py_object_type
        self.is_py_attr = 1
        if not obj_type.is_pyobject and not obj_type.is_error:
            if obj_type.can_coerce_to_pyobject(env):
                self.obj = self.obj.coerce_to_pyobject(env)
            else:
                error(self.pos,
                      "Object of type '%s' has no attribute '%s'" %
                      (obj_type, self.attribute))

    def nogil_check(self, env):
        if self.is_py_attr:
            self.gil_error()
        elif self.type.is_memoryviewslice:
            import MemoryView
            MemoryView.err_if_nogil_initialized_check(self.pos, env, 'attribute')

    gil_message = "Accessing Python attribute"

    def is_simple(self):
        if self.obj:
            return self.result_in_temp() or self.obj.is_simple()
        else:
            return NameNode.is_simple(self)

    def is_lvalue(self):
        if self.obj:
            return not self.type.is_array
        else:
            return NameNode.is_lvalue(self)

    def is_ephemeral(self):
        if self.obj:
            return self.obj.is_ephemeral()
        else:
            return NameNode.is_ephemeral(self)

    def calculate_result_code(self):
        #print "AttributeNode.calculate_result_code:", self.member ###
        #print "...obj node =", self.obj, "code", self.obj.result() ###
        #print "...obj type", self.obj.type, "ctype", self.obj.ctype() ###
        obj = self.obj
        obj_code = obj.result_as(obj.type)
        #print "...obj_code =", obj_code ###
        if self.entry and self.entry.is_cmethod:
            if obj.type.is_extension_type and not self.entry.is_builtin_cmethod:
                if self.entry.final_func_cname:
                    return self.entry.final_func_cname

                if self.type.from_fused:
                    # If the attribute was specialized through indexing, make
                    # sure to get the right fused name, as our entry was
                    # replaced by our parent index node
                    # (AnalyseExpressionsTransform)
                    self.member = self.entry.cname

                return "((struct %s *)%s%s%s)->%s" % (
                    obj.type.vtabstruct_cname, obj_code, self.op,
                    obj.type.vtabslot_cname, self.member)
            else:
                return self.member
        elif obj.type.is_complex:
            return "__Pyx_C%s(%s)" % (self.member.upper(), obj_code)
        else:
            if obj.type.is_builtin_type and self.entry and self.entry.is_variable:
                # accessing a field of a builtin type, need to cast better than result_as() does
                obj_code = obj.type.cast_code(obj.result(), to_object_struct = True)
            return "%s%s%s" % (obj_code, self.op, self.member)

    def generate_result_code(self, code):
        if self.is_py_attr:
            code.putln(
                '%s = PyObject_GetAttr(%s, %s); %s' % (
                    self.result(),
                    self.obj.py_result(),
                    code.intern_identifier(self.attribute),
                    code.error_goto_if_null(self.result(), self.pos)))
            code.put_gotref(self.py_result())
        elif self.type.is_memoryviewslice:
            if code.globalstate.directives['nonecheck']:
                self.put_nonecheck(code)

            if self.is_memslice_transpose:
                # transpose the slice
                for access, packing in self.type.axes:
                    if access == 'ptr':
                        error(self.pos, "Transposing not supported for slices "
                                        "with indirect dimensions")
                        return

                code.putln("%s = %s;" % (self.result(), self.obj.result()))
                if self.obj.is_name or (self.obj.is_attribute and
                                        self.obj.is_memslice_transpose):
                    code.put_incref_memoryviewslice(self.result(), have_gil=True)

                T = "__pyx_memslice_transpose(&%s) == 0"
                code.putln(code.error_goto_if(T % self.result(), self.pos))
            elif self.initialized_check:
                code.putln(
                    'if (unlikely(!%s.memview)) {'
                        'PyErr_SetString(PyExc_AttributeError,'
                                        '"Memoryview is not initialized");'
                        '%s'
                    '}' % (self.result(), code.error_goto(self.pos)))
        elif (self.obj.type.is_memoryviewslice and
                code.globalstate.directives['nonecheck']):
            self.put_nonecheck(code)
        else:
            # result_code contains what is needed, but we may need to insert
            # a check and raise an exception
            if self.obj.type.is_extension_type:
                if self.needs_none_check and code.globalstate.directives['nonecheck']:
                    self.put_nonecheck(code)
            elif self.entry and self.entry.is_cmethod and self.entry.utility_code:
                # C method implemented as function call with utility code
                code.globalstate.use_utility_code(self.entry.utility_code)

    def generate_assignment_code(self, rhs, code):
        self.obj.generate_evaluation_code(code)
        if self.is_py_attr:
            code.put_error_if_neg(self.pos,
                'PyObject_SetAttr(%s, %s, %s)' % (
                    self.obj.py_result(),
                    code.intern_identifier(self.attribute),
                    rhs.py_result()))
            rhs.generate_disposal_code(code)
            rhs.free_temps(code)
        elif self.obj.type.is_complex:
            code.putln("__Pyx_SET_C%s(%s, %s);" % (
                self.member.upper(),
                self.obj.result_as(self.obj.type),
                rhs.result_as(self.ctype())))
        else:
            if (self.obj.type.needs_nonecheck()
                  and self.needs_none_check
                  and code.globalstate.directives['nonecheck']):
                self.put_nonecheck(code)

            select_code = self.result()
            if self.type.is_pyobject and self.use_managed_ref:
                rhs.make_owned_reference(code)
                code.put_giveref(rhs.py_result())
                code.put_gotref(select_code)
                code.put_decref(select_code, self.ctype())
            elif self.type.is_memoryviewslice:
                import MemoryView
                MemoryView.put_assign_to_memviewslice(
                        select_code, rhs, rhs.result(), self.type, code)

            if not self.type.is_memoryviewslice:
                code.putln(
                    "%s = %s;" % (
                        select_code,
                        rhs.result_as(self.ctype())))
                        #rhs.result()))
            rhs.generate_post_assignment_code(code)
            rhs.free_temps(code)
        self.obj.generate_disposal_code(code)
        self.obj.free_temps(code)

    def generate_deletion_code(self, code):
        self.obj.generate_evaluation_code(code)
        if self.is_py_attr or (isinstance(self.entry.scope, Symtab.PropertyScope)
                               and u'__del__' in self.entry.scope.entries):
            code.put_error_if_neg(self.pos,
                'PyObject_DelAttr(%s, %s)' % (
                    self.obj.py_result(),
                    code.intern_identifier(self.attribute)))
        else:
            error(self.pos, "Cannot delete C attribute of extension type")
        self.obj.generate_disposal_code(code)
        self.obj.free_temps(code)

    def annotate(self, code):
        if self.is_py_attr:
            code.annotate(self.pos, AnnotationItem('py_attr', 'python attribute', size=len(self.attribute)))
        else:
            code.annotate(self.pos, AnnotationItem('c_attr', 'c attribute', size=len(self.attribute)))

    def put_nonecheck(self, code):
        code.globalstate.use_utility_code(raise_noneattr_error_utility_code)
        if self.obj.type.is_extension_type:
            test = "%s == Py_None" % self.obj.result_as(PyrexTypes.py_object_type)
        elif self.obj.type.is_memoryviewslice:
            test = "(PyObject *) %s.memview == Py_None" % self.obj.result()
        else:
            assert False
        code.putln("if (%s) {" % code.unlikely(test))
        code.putln("__Pyx_RaiseNoneAttributeError(\"%s\");" % self.attribute)
        code.putln(code.error_goto(self.pos))
        code.putln("}") class ListNode(SequenceNode):
    #  List constructor.

    # obj_conversion_errors    [PyrexError]   used internally
    # orignial_args            [ExprNode]     used internally

    obj_conversion_errors = []
    type = list_type

    gil_message = "Constructing Python list"

    def type_dependencies(self, env):
        return ()

    def infer_type(self, env):
        # TOOD: Infer non-object list arrays.
        return list_type

    def analyse_expressions(self, env):
        SequenceNode.analyse_expressions(self, env)
        self.coerce_to_pyobject(env)

    def analyse_types(self, env):
        hold_errors()
        self.original_args = list(self.args)
        SequenceNode.analyse_types(self, env)
        self.obj_conversion_errors = held_errors()
        release_errors(ignore=True)

    def coerce_to(self, dst_type, env):
        if dst_type.is_pyobject:
            for err in self.obj_conversion_errors:
                report_error(err)
            self.obj_conversion_errors = []
            if not self.type.subtype_of(dst_type):
                error(self.pos, "Cannot coerce list to type '%s'" % dst_type)
        elif self.mult_factor:
            error(self.pos, "Cannot coerce multiplied list to '%s'" % dst_type)
        elif dst_type.is_ptr and dst_type.base_type is not PyrexTypes.c_void_type:
            base_type = dst_type.base_type
            self.type = PyrexTypes.CArrayType(base_type, len(self.args))
            for i in range(len(self.original_args)):
                arg = self.args[i]
                if isinstance(arg, CoerceToPyTypeNode):
                    arg = arg.arg
                self.args[i] = arg.coerce_to(base_type, env)
        elif dst_type.is_struct:
            if len(self.args) > len(dst_type.scope.var_entries):
                error(self.pos, "Too may members for '%s'" % dst_type)
            else:
                if len(self.args) < len(dst_type.scope.var_entries):
                    warning(self.pos, "Too few members for '%s'" % dst_type, 1)
                for i, (arg, member) in enumerate(zip(self.original_args, dst_type.scope.var_entries)):
                    if isinstance(arg, CoerceToPyTypeNode):
                        arg = arg.arg
                    self.args[i] = arg.coerce_to(member.type, env)
            self.type = dst_type
        else:
            self.type = error_type
            error(self.pos, "Cannot coerce list to type '%s'" % dst_type)
        return self

    def release_temp(self, env):
        if self.type.is_array:
            # To be valid C++, we must allocate the memory on the stack
            # manually and be sure not to reuse it for something else.
            pass
        else:
            SequenceNode.release_temp(self, env)

    def calculate_constant_result(self):
        if self.mult_factor:
            raise ValueError() # may exceed the compile time memory
        self.constant_result = [
            arg.constant_result for arg in self.args]

    def compile_time_value(self, denv):
        l = self.compile_time_value_list(denv)
        if self.mult_factor:
            l *= self.mult_factor.compile_time_value(denv)
        return l

    def generate_operation_code(self, code):
        if self.type.is_pyobject:
            for err in self.obj_conversion_errors:
                report_error(err)
            self.generate_sequence_packing_code(code)
        elif self.type.is_array:
            for i, arg in enumerate(self.args):
                code.putln("%s[%s] = %s;" % (
                                self.result(),
                                i,
                                arg.result()))
        elif self.type.is_struct:
            for arg, member in zip(self.args, self.type.scope.var_entries):
                code.putln("%s.%s = %s;" % (
                        self.result(),
                        member.cname,
                        arg.result()))
        else:
            raise InternalError("List type never specified") class NoneNode(PyConstNode):
    #  The constant value None

    is_none = 1
    value = "Py_None"

    constant_result = None

    nogil_check = None

    def compile_time_value(self, denv):
        return None

    def may_be_none(self):
        return True class TupleNode(SequenceNode):
    #  Tuple constructor.

    type = tuple_type
    is_partly_literal = False

    gil_message = "Constructing Python tuple"

    def analyse_types(self, env, skip_children=False):
        if len(self.args) == 0:
            self.is_temp = False
            self.is_literal = True
        else:
            SequenceNode.analyse_types(self, env, skip_children)
            for child in self.args:
                if not child.is_literal:
                    break
            else:
                if not self.mult_factor or self.mult_factor.is_literal and \
                       isinstance(self.mult_factor.constant_result, (int, long)):
                    self.is_temp = False
                    self.is_literal = True
                else:
                    if not self.mult_factor.type.is_pyobject:
                        self.mult_factor = self.mult_factor.coerce_to_pyobject(env)
                    self.is_temp = True
                    self.is_partly_literal = True

    def is_simple(self):
        # either temp or constant => always simple
        return True

    def nonlocally_immutable(self):
        # either temp or constant => always safe
        return True

    def calculate_result_code(self):
        if len(self.args) > 0:
            return self.result_code
        else:
            return Naming.empty_tuple

    def calculate_constant_result(self):
        self.constant_result = tuple([
                arg.constant_result for arg in self.args])

    def compile_time_value(self, denv):
        values = self.compile_time_value_list(denv)
        try:
            return tuple(values)
        except Exception, e:
            self.compile_time_value_error(e)

    def generate_operation_code(self, code):
        if len(self.args) == 0:
            # result_code is Naming.empty_tuple
            return
        if self.is_partly_literal:
            # underlying tuple is const, but factor is not
            tuple_target = code.get_py_const(py_object_type, 'tuple_', cleanup_level=2)
            const_code = code.get_cached_constants_writer()
            const_code.mark_pos(self.pos)
            self.generate_sequence_packing_code(const_code, tuple_target, plain=True)
            const_code.put_giveref(tuple_target)
            code.putln('%s = PyNumber_Multiply(%s, %s); %s' % (
                self.result(), tuple_target, self.mult_factor.py_result(),
                code.error_goto_if_null(self.result(), self.pos)
                ))
            code.put_gotref(self.py_result())
        elif self.is_literal:
            # non-empty cached tuple => result is global constant,
            # creation code goes into separate code writer
            self.result_code = code.get_py_const(py_object_type, 'tuple_', cleanup_level=2)
            code = code.get_cached_constants_writer()
            code.mark_pos(self.pos)
            self.generate_sequence_packing_code(code)
            code.put_giveref(self.py_result())
        else:
            self.generate_sequence_packing_code(code) class StringNode(PyConstNode):
    # A Python str object, i.e. a byte string in Python 2.x and a
    # unicode string in Python 3.x
    #
    # value          BytesLiteral (or EncodedString with ASCII content)
    # unicode_value  EncodedString or None
    # is_identifier  boolean

    type = str_type
    is_string_literal = True
    is_identifier = None
    unicode_value = None

    def coerce_to(self, dst_type, env):
        if dst_type is not py_object_type and not str_type.subtype_of(dst_type):
#            if dst_type is Builtin.bytes_type:
#                # special case: bytes = 'str literal'
#                return BytesNode(self.pos, value=self.value)
            if not dst_type.is_pyobject:
                return BytesNode(self.pos, value=self.value).coerce_to(dst_type, env)
            self.check_for_coercion_error(dst_type, fail=True)
        return self

    def can_coerce_to_char_literal(self):
        return not self.is_identifier and len(self.value) == 1

    def generate_evaluation_code(self, code):
        self.result_code = code.get_py_string_const(
            self.value, identifier=self.is_identifier, is_str=True,
            unicode_value=self.unicode_value)

    def get_constant_c_result_code(self):
        return None

    def calculate_result_code(self):
        return self.result_code

    def compile_time_value(self, env):
        return self.value class SimpleCallNode(CallNode):
    #  Function call without keyword, * or ** args.
    #
    #  function       ExprNode
    #  args           [ExprNode]
    #  arg_tuple      ExprNode or None     used internally
    #  self           ExprNode or None     used internally
    #  coerced_self   ExprNode or None     used internally
    #  wrapper_call   bool                 used internally
    #  has_optional_args   bool            used internally
    #  nogil          bool                 used internally

    subexprs = ['self', 'coerced_self', 'function', 'args', 'arg_tuple']

    self = None
    coerced_self = None
    arg_tuple = None
    wrapper_call = False
    has_optional_args = False
    nogil = False
    analysed = False

    def compile_time_value(self, denv):
        function = self.function.compile_time_value(denv)
        args = [arg.compile_time_value(denv) for arg in self.args]
        try:
            return function(*args)
        except Exception, e:
            self.compile_time_value_error(e)

    def analyse_as_type(self, env):
        attr = self.function.as_cython_attribute()
        if attr == 'pointer':
            if len(self.args) != 1:
                error(self.args.pos, "only one type allowed.")
            else:
                type = self.args[0].analyse_as_type(env)
                if not type:
                    error(self.args[0].pos, "Unknown type")
                else:
                    return PyrexTypes.CPtrType(type)

    def explicit_args_kwds(self):
        return self.args, None

    def analyse_types(self, env):
        if self.analyse_as_type_constructor(env):
            return
        if self.analysed:
            return
        self.analysed = True
        function = self.function
        function.is_called = 1
        self.function.analyse_types(env)

        if function.is_attribute and function.entry and function.entry.is_cmethod:
            # Take ownership of the object from which the attribute
            # was obtained, because we need to pass it as 'self'.
            self.self = function.obj
            function.obj = CloneNode(self.self)

        func_type = self.function_type()
        if func_type.is_pyobject:
            self.arg_tuple = TupleNode(self.pos, args = self.args)
            self.arg_tuple.analyse_types(env)
            self.args = None
            if func_type is Builtin.type_type and function.is_name and \
                   function.entry and \
                   function.entry.is_builtin and \
                   function.entry.name in Builtin.types_that_construct_their_instance:
                # calling a builtin type that returns a specific object type
                if function.entry.name == 'float':
                    # the following will come true later on in a transform
                    self.type = PyrexTypes.c_double_type
                    self.result_ctype = PyrexTypes.c_double_type
                else:
                    self.type = Builtin.builtin_types[function.entry.name]
                    self.result_ctype = py_object_type
                self.may_return_none = False
            elif function.is_name and function.type_entry:
                # We are calling an extension type constructor.  As
                # long as we do not support __new__(), the result type
                # is clear
                self.type = function.type_entry.type
                self.result_ctype = py_object_type
                self.may_return_none = False
            else:
                self.type = py_object_type
            self.is_temp = 1
        else:
            for arg in self.args:
                arg.analyse_types(env)

            if self.self and func_type.args:
                # Coerce 'self' to the type expected by the method.
                self_arg = func_type.args[0]
                if self_arg.not_none: # C methods must do the None test for self at *call* time
                    self.self = self.self.as_none_safe_node(
                        "'NoneType' object has no attribute '%s'",
                        error = 'PyExc_AttributeError',
                        format_args = [self.function.entry.name])
                expected_type = self_arg.type
                if self_arg.accept_builtin_subtypes:
                    self.coerced_self = CMethodSelfCloneNode(self.self)
                else:
                    self.coerced_self = CloneNode(self.self)
                self.coerced_self = self.coerced_self.coerce_to(expected_type, env)
                # Insert coerced 'self' argument into argument list.
                self.args.insert(0, self.coerced_self)
            self.analyse_c_function_call(env)

    def function_type(self):
        # Return the type of the function being called, coercing a function
        # pointer to a function if necessary. If the function has fused
        # arguments, return the specific type.
        func_type = self.function.type

        if func_type.is_ptr:
            func_type = func_type.base_type

        return func_type

    def is_simple(self):
        # C function calls could be considered simple, but they may
        # have side-effects that may hit when multiple operations must
        # be effected in order, e.g. when constructing the argument
        # sequence for a function call or comparing values.
        return False

    def analyse_c_function_call(self, env):
        if self.function.type is error_type:
            self.type = error_type
            return

        if self.function.type.is_cpp_class:
            overloaded_entry = self.function.type.scope.lookup("operator()")
            if overloaded_entry is None:
                self.type = PyrexTypes.error_type
                self.result_code = "<error>"
                return
        elif hasattr(self.function, 'entry'):
            overloaded_entry = self.function.entry
        elif (isinstance(self.function, IndexNode) and
              self.function.is_fused_index):
            overloaded_entry = self.function.type.entry
        else:
            overloaded_entry = None

        if overloaded_entry:
            if self.function.type.is_fused:
                functypes = self.function.type.get_all_specialized_function_types()
                alternatives = [f.entry for f in functypes]
            else:
                alternatives = overloaded_entry.all_alternatives()

            entry = PyrexTypes.best_match(self.args, alternatives, self.pos, env)

            if not entry:
                self.type = PyrexTypes.error_type
                self.result_code = "<error>"
                return

            entry.used = True
            self.function.entry = entry
            self.function.type = entry.type
            func_type = self.function_type()
        else:
            func_type = self.function_type()
            if not func_type.is_cfunction:
                error(self.pos, "Calling non-function type '%s'" % func_type)
                self.type = PyrexTypes.error_type
                self.result_code = "<error>"
                return
        # Check no. of args
        max_nargs = len(func_type.args)
        expected_nargs = max_nargs - func_type.optional_arg_count
        actual_nargs = len(self.args)
        if func_type.optional_arg_count and expected_nargs != actual_nargs:
            self.has_optional_args = 1
            self.is_temp = 1
        # Coerce arguments
        some_args_in_temps = False
        for i in xrange(min(max_nargs, actual_nargs)):
            formal_type = func_type.args[i].type
            arg = self.args[i].coerce_to(formal_type, env)
            if arg.is_temp:
                if i > 0:
                    # first argument in temp doesn't impact subsequent arguments
                    some_args_in_temps = True
            elif arg.type.is_pyobject and not env.nogil:
                if i == 0 and self.self is not None:
                    # a method's cloned "self" argument is ok
                    pass
                elif arg.nonlocally_immutable():
                    # plain local variables are ok
                    pass
                else:
                    # we do not safely own the argument's reference,
                    # but we must make sure it cannot be collected
                    # before we return from the function, so we create
                    # an owned temp reference to it
                    if i > 0: # first argument doesn't matter
                        some_args_in_temps = True
                    arg = arg.coerce_to_temp(env)
            self.args[i] = arg
        # handle additional varargs parameters
        for i in xrange(max_nargs, actual_nargs):
            arg = self.args[i]
            if arg.type.is_pyobject:
                arg_ctype = arg.type.default_coerced_ctype()
                if arg_ctype is None:
                    error(self.args[i].pos,
                          "Python object cannot be passed as a varargs parameter")
                else:
                    self.args[i] = arg = arg.coerce_to(arg_ctype, env)
            if arg.is_temp and i > 0:
                some_args_in_temps = True
        if some_args_in_temps:
            # if some args are temps and others are not, they may get
            # constructed in the wrong order (temps first) => make
            # sure they are either all temps or all not temps (except
            # for the last argument, which is evaluated last in any
            # case)
            for i in xrange(actual_nargs-1):
                if i == 0 and self.self is not None:
                    continue # self is ok
                arg = self.args[i]
                if arg.nonlocally_immutable():
                    # locals, C functions, unassignable types are safe.
                    pass
                elif arg.type.is_cpp_class:
                    # Assignment has side effects, avoid.
                    pass
                elif env.nogil and arg.type.is_pyobject:
                    # can't copy a Python reference into a temp in nogil
                    # env (this is safe: a construction would fail in
                    # nogil anyway)
                    pass
                else:
                    #self.args[i] = arg.coerce_to_temp(env)
                    # instead: issue a warning
                    if i > 0 or i == 1 and self.self is not None: # skip first arg
                        warning(arg.pos, "Argument evaluation order in C function call is undefined and may not be as expected", 0)
                        break

        # Calc result type and code fragment
        if isinstance(self.function, NewExprNode):
            self.type = PyrexTypes.CPtrType(self.function.class_type)
        else:
            self.type = func_type.return_type

        if self.function.is_name or self.function.is_attribute:
            if self.function.entry and self.function.entry.utility_code:
                self.is_temp = 1 # currently doesn't work for self.calculate_result_code()

        if self.type.is_pyobject:
            self.result_ctype = py_object_type
            self.is_temp = 1
        elif func_type.exception_value is not None \
                 or func_type.exception_check:
            self.is_temp = 1
        elif self.type.is_memoryviewslice:
            self.is_temp = 1
            # func_type.exception_check = True

        # Called in 'nogil' context?
        self.nogil = env.nogil
        if (self.nogil and
            func_type.exception_check and
            func_type.exception_check != '+'):
            env.use_utility_code(pyerr_occurred_withgil_utility_code)
        # C++ exception handler
        if func_type.exception_check == '+':
            if func_type.exception_value is None:
                env.use_utility_code(cpp_exception_utility_code)

    def calculate_result_code(self):
        return self.c_call_code()

    def c_call_code(self):
        func_type = self.function_type()
        if self.type is PyrexTypes.error_type or not func_type.is_cfunction:
            return "<error>"
        formal_args = func_type.args
        arg_list_code = []
        args = list(zip(formal_args, self.args))
        max_nargs = len(func_type.args)
        expected_nargs = max_nargs - func_type.optional_arg_count
        actual_nargs = len(self.args)
        for formal_arg, actual_arg in args[:expected_nargs]:
                arg_code = actual_arg.result_as(formal_arg.type)
                arg_list_code.append(arg_code)

        if func_type.is_overridable:
            arg_list_code.append(str(int(self.wrapper_call or self.function.entry.is_unbound_cmethod)))

        if func_type.optional_arg_count:
            if expected_nargs == actual_nargs:
                optional_args = 'NULL'
            else:
                optional_args = "&%s" % self.opt_arg_struct
            arg_list_code.append(optional_args)

        for actual_arg in self.args[len(formal_args):]:
            arg_list_code.append(actual_arg.result())

        result = "%s(%s)" % (self.function.result(), ', '.join(arg_list_code))
        return result

    def generate_result_code(self, code):
        func_type = self.function_type()
        if self.function.is_name or self.function.is_attribute:
            if self.function.entry and self.function.entry.utility_code:
                code.globalstate.use_utility_code(self.function.entry.utility_code)
        if func_type.is_pyobject:
            arg_code = self.arg_tuple.py_result()
            code.putln(
                "%s = PyObject_Call(%s, %s, NULL); %s" % (
                    self.result(),
                    self.function.py_result(),
                    arg_code,
                    code.error_goto_if_null(self.result(), self.pos)))
            code.put_gotref(self.py_result())
        elif func_type.is_cfunction:
            if self.has_optional_args:
                actual_nargs = len(self.args)
                expected_nargs = len(func_type.args) - func_type.optional_arg_count
                self.opt_arg_struct = code.funcstate.allocate_temp(
                    func_type.op_arg_struct.base_type, manage_ref=True)
                code.putln("%s.%s = %s;" % (
                        self.opt_arg_struct,
                        Naming.pyrex_prefix + "n",
                        len(self.args) - expected_nargs))
                args = list(zip(func_type.args, self.args))
                for formal_arg, actual_arg in args[expected_nargs:actual_nargs]:
                    code.putln("%s.%s = %s;" % (
                            self.opt_arg_struct,
                            func_type.opt_arg_cname(formal_arg.name),
                            actual_arg.result_as(formal_arg.type)))
            exc_checks = []
            if self.type.is_pyobject and self.is_temp:
                exc_checks.append("!%s" % self.result())
            elif self.type.is_memoryviewslice:
                assert self.is_temp
                exc_checks.append(self.type.error_condition(self.result()))
            else:
                exc_val = func_type.exception_value
                exc_check = func_type.exception_check
                if exc_val is not None:
                    exc_checks.append("%s == %s" % (self.result(), exc_val))
                if exc_check:
                    if self.nogil:
                        exc_checks.append("__Pyx_ErrOccurredWithGIL()")
                    else:
                        exc_checks.append("PyErr_Occurred()")
            if self.is_temp or exc_checks:
                rhs = self.c_call_code()
                if self.result():
                    lhs = "%s = " % self.result()
                    if self.is_temp and self.type.is_pyobject:
                        #return_type = self.type # func_type.return_type
                        #print "SimpleCallNode.generate_result_code: casting", rhs, \
                        #    "from", return_type, "to pyobject" ###
                        rhs = typecast(py_object_type, self.type, rhs)
                else:
                    lhs = ""
                if func_type.exception_check == '+':
                    if func_type.exception_value is None:
                        raise_py_exception = "__Pyx_CppExn2PyErr()"
                    elif func_type.exception_value.type.is_pyobject:
                        raise_py_exception = ' try { throw; } catch(const std::exception& exn) { PyErr_SetString(%s, exn.what()); } catch(...) { PyErr_SetNone(%s); }' % (
                            func_type.exception_value.entry.cname,
                            func_type.exception_value.entry.cname)
                    else:
                        raise_py_exception = '%s(); if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError , "Error converting c++ exception.")' % func_type.exception_value.entry.cname
                    if self.nogil:
                        raise_py_exception = 'Py_BLOCK_THREADS; %s; Py_UNBLOCK_THREADS' % raise_py_exception
                    code.putln(
                    "try {%s%s;} catch(...) {%s; %s}" % (
                        lhs,
                        rhs,
                        raise_py_exception,
                        code.error_goto(self.pos)))
                else:
                    if exc_checks:
                        goto_error = code.error_goto_if(" && ".join(exc_checks), self.pos)
                    else:
                        goto_error = ""
                    code.putln("%s%s; %s" % (lhs, rhs, goto_error))
                if self.type.is_pyobject and self.result():
                    code.put_gotref(self.py_result())
            if self.has_optional_args:
                code.funcstate.release_temp(self.opt_arg_struct) class ImportNode(ExprNode):
    #  Used as part of import statement implementation.
    #  Implements result =
    #    __import__(module_name, globals(), None, name_list, level)
    #
    #  module_name   StringNode            dotted name of module. Empty module
    #                       name means importing the parent package accourding
    #                       to level
    #  name_list     ListNode or None      list of names to be imported
    #  level         int                   relative import level:
    #                       -1: attempt both relative import and absolute import;
    #                        0: absolute import;
    #                       >0: the number of parent directories to search
    #                           relative to the current module.
    #                     None: decide the level according to language level and
    #                           directives

    type = py_object_type

    subexprs = ['module_name', 'name_list']

    def analyse_types(self, env):
        if self.level is None:
            if env.directives['language_level'] < 3 or env.directives['py2_import']:
                self.level = -1
            else:
                self.level = 0
        self.module_name.analyse_types(env)
        self.module_name = self.module_name.coerce_to_pyobject(env)
        if self.name_list:
            self.name_list.analyse_types(env)
            self.name_list.coerce_to_pyobject(env)
        self.is_temp = 1
        env.use_utility_code(import_utility_code)

    gil_message = "Python import"

    def generate_result_code(self, code):
        if self.name_list:
            name_list_code = self.name_list.py_result()
        else:
            name_list_code = "0"
        code.putln(
            "%s = __Pyx_Import(%s, %s, %d); %s" % (
                self.result(),
                self.module_name.py_result(),
                name_list_code,
                self.level,
                code.error_goto_if_null(self.result(), self.pos)))
        code.put_gotref(self.py_result()) class CallNode(ExprNode):

    # allow overriding the default 'may_be_none' behaviour
    may_return_none = None

    def infer_type(self, env):
        function = self.function
        func_type = function.infer_type(env)
        if isinstance(self.function, NewExprNode):
            return PyrexTypes.CPtrType(self.function.class_type)
        if func_type.is_ptr:
            func_type = func_type.base_type
        if func_type.is_cfunction:
            return func_type.return_type
        elif func_type is type_type:
            if function.is_name and function.entry and function.entry.type:
                result_type = function.entry.type
                if result_type.is_extension_type:
                    return result_type
                elif result_type.is_builtin_type:
                    if function.entry.name == 'float':
                        return PyrexTypes.c_double_type
                    elif function.entry.name in Builtin.types_that_construct_their_instance:
                        return result_type
        return py_object_type

    def type_dependencies(self, env):
        # TODO: Update when Danilo's C++ code merged in to handle the
        # the case of function overloading.
        return self.function.type_dependencies(env)

    def may_be_none(self):
        if self.may_return_none is not None:
            return self.may_return_none
        return ExprNode.may_be_none(self)

    def analyse_as_type_constructor(self, env):
        type = self.function.analyse_as_type(env)
        if type and type.is_struct_or_union:
            args, kwds = self.explicit_args_kwds()
            items = []
            for arg, member in zip(args, type.scope.var_entries):
                items.append(DictItemNode(pos=arg.pos, key=StringNode(pos=arg.pos, value=member.name), value=arg))
            if kwds:
                items += kwds.key_value_pairs
            self.key_value_pairs = items
            self.__class__ = DictNode
            self.analyse_types(env)
            self.coerce_to(type, env)
            return True
        elif type and type.is_cpp_class:
            for arg in self.args:
                arg.analyse_types(env)
            constructor = type.scope.lookup("<init>")
            self.function = RawCNameExprNode(self.function.pos, constructor.type)
            self.function.entry = constructor
            self.function.set_cname(type.declaration_code(""))
            self.analyse_c_function_call(env)
            return True

    def is_lvalue(self):
        return self.type.is_reference

    def nogil_check(self, env):
        func_type = self.function_type()
        if func_type.is_pyobject:
            self.gil_error()
        elif not getattr(func_type, 'nogil', False):
            self.gil_error()

    gil_message = "Calling gil-requiring function" class TreeFragment(object):
    def __init__(self, code, name="(tree fragment)", pxds={}, temps=[], pipeline=[], level=None, initial_pos=None):
        if isinstance(code, unicode):
            def fmt(x): return u"\n".join(strip_common_indent(x.split(u"\n")))

            fmt_code = fmt(code)
            fmt_pxds = {}
            for key, value in pxds.iteritems():
                fmt_pxds[key] = fmt(value)
            mod = t = parse_from_strings(name, fmt_code, fmt_pxds, level=level, initial_pos=initial_pos)
            if level is None:
                t = t.body # Make sure a StatListNode is at the top
            if not isinstance(t, StatListNode):
                t = StatListNode(pos=mod.pos, stats=[t])
            for transform in pipeline:
                if transform is None:
                    continue
                t = transform(t)
            self.root = t
        elif isinstance(code, Node):
            if pxds != {}: raise NotImplementedError()
            self.root = code
        else:
            raise ValueError("Unrecognized code format (accepts unicode and Node)")
        self.temps = temps

    def copy(self):
        return copy_code_tree(self.root)

    def substitute(self, nodes={}, temps=[], pos = None):
        return TemplateTransform()(self.root,
                                   substitutions = nodes,
                                   temps = self.temps + temps, pos = pos) def _empty_decorator(x):
def locals(**arg_types):
def test_assert_path_exists(path):
def test_fail_if_path_exists(path):
    def __call__(self, x):
    def __enter__(self):
    def __exit__(self, exc_type, exc_value, traceback):
def inline(f, *args, **kwds):
def compile(f):
def cdiv(a, b):
def cmod(a, b):
def cast(type, *args):
def sizeof(arg):
def typeof(arg):
def address(arg):
def declare(type=None, value=_Unspecified, **kwds):
    def __enter__(self):
    def __exit__(self, exc_class, exc, tb):
    def __getitem__(type, ix):
    def _pointer(self, n=1):
    def __init__(self, value=None):
    def __getitem__(self, ix):
    def __setitem__(self, ix, value):
    def __eq__(self, value):
    def __repr__(self):
    def __init__(self):
    def __init__(self, cast_from=_Unspecified, **data):
    def __setattr__(self, key, value):
    def __init__(self, cast_from=_Unspecified, **data):
    def __setattr__(self, key, value):
def pointer(basetype):
def array(basetype, n):
def struct(**members):
def union(**members):
    def __init__(self, type, name=None):
    def __call__(self, *arg):
    def __repr__(self):
def fused_type(*args):
def _specialized_from_args(signatures, args, kwargs):
    def parallel(self, num_threads=None):
    def prange(self, start=0, stop=None, step=1, schedule=None, nogil=False):
    def threadid(self):
def _ctype_find_func(lib_list, func_name):
def ctypes_func(func_name, libs, restype, *argtypes):
def ctypes_struct(fields):
def ctypes_declare(ctypes_t):        
    def __init__(self, include_file):
    def __enter__(self, *args):
    def __exit__(self, *args):
def ctypes_union(fields, size=None):
class _EmptyDecoratorAndManager(object):
class _nogil(object):
class CythonMetaType(type):
class CythonType(CythonTypeObject):
class PointerType(CythonType):
class ArrayType(PointerType):
class StructType(CythonType):
class UnionType(CythonType):
    class PointerInstance(PointerType):
    class ArrayInstance(ArrayType):
    class StructInstance(StructType):
    class UnionInstance(UnionType):
class typedef(CythonType):
class _FusedType(CythonType):
class CythonDotParallel(object):
    class struct(ctypes.Structure):
class ctypes_extern(object):        
    class union(ctypes.Union):
NULL = p_void(0)
import ctypes
import ctypes.util
import ctypes
from ctypes_configure import configure
from itertools import chain
from Cython.Compiler.Visitor import VisitorTransform
from Cython.Compiler.Nodes import CFuncDeclaratorNode, CVarDefNode, SingleAssignmentNode, CStructOrUnionDefNode, PyClassDefNode, StatListNode, PassStatNode, CPtrDeclaratorNode, DecoratorNode, FuncDefNode
from Cython.Compiler.ExprNodes import NameNode, AttributeNode, ListNode, NoneNode, TupleNode, StringNode, SimpleCallNode, ImportNode, CallNode
from Cython.Compiler.TreeFragment import TreeFragment
from ctypes import *
from Cython import Shadow

cythonTypetoCtypes = {'char': ctypes.c_char,
 'double': ctypes.c_double,
 'float': ctypes.c_float,
 'int': ctypes.c_int,
 'long': ctypes.c_long,
 'longdouble': ctypes.c_longdouble,
 'longlong': ctypes.c_long,
 'short': ctypes.c_short,
 'size_t': ctypes.c_size_t,
 'uint': ctypes.c_uint,
 'ulong': ctypes.c_ulong,
 'ulonglong': ctypes.c_ulonglong,
 'ushort': ctypes.c_ushort,
 'void': None}

class ExternDefTransform(VisitorTransform):
    visit_Node = VisitorTransform.recurse_to_children

    def __init__(self, context):
        super(ExternDefTransform, self).__init__()
        self.context = context
        self.ctypes_struct_union_dict = {}
        self.isInExternScope = False
        self.include_file = None
    def _ctypeToStr(self, ctype_t):
        if ctype_t is None:
            return 'None'
        return 'ctypes.' + ctype_t.__name__       
    def _cythonTypeToCtypes(self, cython_t, decl):
        base_type = cython_t.base_type
            
        if base_type.is_basic_c_type:
            field_type = cythonTypetoCtypes[base_type.name]
            field_type_str = self._ctypeToStr(cythonTypetoCtypes[base_type.name])
        else:
            field_type = self.ctypes_struct_union_dict[base_type.name]
            field_type_str = base_type.name
            
        if isinstance(decl, CPtrDeclaratorNode):
            field_name = getattr(decl.base, 'name', None)
        else:
            field_name = getattr(decl, 'name', None)
            
        while isinstance(decl, CPtrDeclaratorNode):
            field_type = POINTER(field_type)
            field_type_str = 'ctypes.POINTER(%s)' % field_type_str
            decl = decl.base
            
        return (field_name, field_type, field_type_str)
    
    def _get_actual_ctype(self, base_name, initial_type):
        class CConfigure(object):
            _compilation_info_ = configure.ExternalCompilationInfo(
                    pre_include_lines = [],
                    includes = [self.include_file],
                    include_dirs = self.context.options.include_path,
                    post_include_lines = [],
                    libraries = [],
                    library_dirs = [],
                    separate_module_sources = [],
                    separate_module_files = [],
                )
            
            c_type = configure.SimpleType(base_name, initial_type)
            
            
        info = configure.configure(CConfigure)
        return info['c_type']
    def _ctype_to_node(self, type_name):
        return NameNode(0, name=type_name)
    
    def _cython_type_to_ctypes_node(self, cython_t):
        ctype_name = self._cythonTypeToCtypes(cython_t, getattr(cython_t, 'declarator', None))[2]
#        ctype_t = getattr(ctypes, ctype_name)
#        
#        final_ctype_t = self._get_actual_ctype(cython_t.base_type.name, ctype_t)
#        ctype_final_name = ctypeToStr[final_ctype_t]
        ctype_final_name = ctype_name
        return self._ctype_to_node(ctype_final_name)
    
    def _find_libname(self, func_name):
        func_lib = None
        func_libname = None
        for lib_name in self.context.options.libraries:
            lib = ctypes.CDLL(ctypes.util.find_library(lib_name))
            try:
                getattr(lib, func_name)
            except AttributeError:
                pass
            finally:
                func_lib = lib
                func_libname = lib_name
                break

        if not func_lib:
            raise NameError("Function %s cannot be found" % func_name)
        
        return func_libname
    
    def _CFuncToFunc(self, declarator, restype):
        libname = self._find_libname(declarator.base.name)
        
        rhs=SimpleCallNode(0,
                         child_attrs=[],
                         function=AttributeNode(0, obj=NameNode(0, name=u"cython"), attribute=u"ctypes_func"),
                         args=[NameNode(0, name="'%s'" % declarator.base.name), 
                               NameNode(0, name="'%s'" % libname), 
                               self._cython_type_to_ctypes_node(restype)] + [self._cython_type_to_ctypes_node(arg) for arg in declarator.args])

        return SingleAssignmentNode(0,