def _buildContractionNode(provider, node, name, emit_class, start_value,
                          source_ref):
    # The contraction nodes are reformulated to function bodies, with loops as
    # described in the developer manual. They use a lot of temporary names,
    # nested blocks, etc. and so a lot of variable names.

    function_body = ExpressionOutlineFunction(provider=provider,
                                              name=intern(name[1:-1]),
                                              source_ref=source_ref)

    iter_tmp = function_body.allocateTempVariable(temp_scope=None, name=".0")

    container_tmp = function_body.allocateTempVariable(temp_scope=None,
                                                       name="contraction")

    statements, release_statements = _buildContractionBodyNode(
        provider=provider,
        node=node,
        emit_class=emit_class,
        iter_tmp=iter_tmp,
        temp_scope=None,
        start_value=start_value,
        container_tmp=container_tmp,
        function_body=function_body,
        assign_provider=False,
        for_asyncgen=False,
        source_ref=source_ref,
    )

    assign_iter_statement = StatementAssignmentVariable(
        source=_makeIteratorCreation(
            provider=provider,
            qual=node.generators[0],
            for_asyncgen=False,
            source_ref=source_ref,
        ),
        variable=iter_tmp,
        source_ref=source_ref,
    )

    statements.append(
        StatementReturn(
            expression=ExpressionTempVariableRef(variable=container_tmp,
                                                 source_ref=source_ref),
            source_ref=source_ref,
        ))

    statements = (makeTryFinallyStatement(
        provider=function_body,
        tried=statements,
        final=release_statements,
        source_ref=source_ref.atInternal(),
    ), )

    if python_version < 300:
        body = makeStatementsSequenceFromStatements(assign_iter_statement,
                                                    statements)
    else:
        parent_module = provider.getParentModule()

        code_object = CodeObjectSpec(
            co_name=name,
            co_kind="Function",
            co_varnames=(),
            co_freevars=(),
            co_argcount=1,
            co_posonlyargcount=0,
            co_kwonlyargcount=0,
            co_has_starlist=False,
            co_has_stardict=False,
            co_filename=parent_module.getRunTimeFilename(),
            co_lineno=source_ref.getLineNumber(),
            future_spec=parent_module.getFutureSpec(),
        )

        body = makeStatementsSequenceFromStatements(
            assign_iter_statement,
            StatementsFrameFunction(
                statements=mergeStatements(statements, False),
                code_object=code_object,
                source_ref=source_ref,
            ),
        )

    function_body.setBody(body)

    return function_body
def _wrapFunctionWithSpecialNestedArgs(
    name, outer_body, parameters, special_args, source_ref
):
    inner_name = name.strip("<>") + "$inner"
    iter_vars = []

    values = []

    statements = []

    def unpackFrom(source, arg_names):
        accesses = []

        sub_special_index = 0

        iter_var = outer_body.allocateTempVariable(None, "arg_iter_%d" % len(iter_vars))
        iter_vars.append(iter_var)

        statements.append(
            StatementAssignmentVariable(
                variable=iter_var,
                source=ExpressionBuiltinIter1(value=source, source_ref=source_ref),
                source_ref=source_ref,
            )
        )

        for element_index, arg_name in enumerate(arg_names):
            if getKind(arg_name) == "Name":
                arg_var = outer_body.createProvidedVariable(arg_name.id)
                outer_body.getLocalsScope().registerProvidedVariable(arg_var)

                statements.append(
                    StatementAssignmentVariable(
                        variable=arg_var,
                        source=ExpressionSpecialUnpack(
                            value=ExpressionTempVariableRef(
                                variable=iter_var, source_ref=source_ref
                            ),
                            count=element_index + 1,
                            expected=len(arg_names),
                            starred=False,
                            source_ref=source_ref,
                        ),
                        source_ref=source_ref,
                    )
                )

                accesses.append(
                    ExpressionVariableRef(variable=arg_var, source_ref=source_ref)
                )
            elif getKind(arg_name) == "Tuple":
                accesses.extend(
                    unpackFrom(
                        source=ExpressionSpecialUnpack(
                            value=ExpressionTempVariableRef(
                                variable=iter_var, source_ref=source_ref
                            ),
                            count=element_index + 1,
                            expected=len(arg_names),
                            starred=False,
                            source_ref=source_ref,
                        ),
                        arg_names=arg_name.elts,
                    )
                )

                sub_special_index += 1
            else:
                assert False, arg_name

        statements.append(
            StatementSpecialUnpackCheck(
                iterator=ExpressionTempVariableRef(
                    variable=iter_var, source_ref=source_ref
                ),
                count=len(arg_names),
                source_ref=source_ref,
            )
        )

        return accesses

    for arg_name in parameters.getParameterNames():
        if arg_name.startswith("."):
            source = ExpressionVariableNameRef(
                provider=outer_body, variable_name=arg_name, source_ref=source_ref
            )

            values.extend(unpackFrom(source, special_args[arg_name]))
        else:
            values.append(
                ExpressionVariableNameRef(
                    provider=outer_body, variable_name=arg_name, source_ref=source_ref
                )
            )

    code_body = ExpressionOutlineFunction(
        provider=outer_body, name=inner_name, source_ref=source_ref
    )

    statements.append(StatementReturn(expression=code_body, source_ref=source_ref))

    outer_body.setChild(
        "body",
        makeStatementsSequenceFromStatement(
            statement=makeTryFinallyStatement(
                provider=outer_body,
                tried=statements,
                final=[
                    StatementReleaseVariable(variable=variable, source_ref=source_ref)
                    for variable in sorted(
                        outer_body.getTempVariables(),
                        key=lambda variable: variable.getName(),
                    )
                ],
                source_ref=source_ref,
                public_exc=False,
            )
        ),
    )

    return code_body
def buildFunctionWithParsing(provider, function_kind, name, function_doc,
                             flags, node, source_ref):
    # This contains a complex re-formulation for nested parameter functions.
    # pylint: disable=too-many-locals

    kind = getKind(node)
    assert kind in ("FunctionDef", "Lambda",
                    "AsyncFunctionDef"), "unsupported for kind " + kind

    def extractArg(arg):
        if arg is None:
            return None
        elif type(arg) is str:
            return mangleName(arg, provider)
        elif getKind(arg) == "Name":
            return mangleName(arg.id, provider)
        elif getKind(arg) == "arg":
            return mangleName(arg.arg, provider)
        elif getKind(arg) == "Tuple":
            # These are to be re-formulated on the outside.
            assert False
        else:
            assert False, getKind(arg)

    special_args = {}

    def extractNormalArgs(args):
        normal_args = []

        for arg in args:
            if type(arg) is not str and getKind(arg) == "Tuple":
                special_arg_name = ".%d" % (len(special_args) + 1)

                special_args[special_arg_name] = arg.elts
                normal_args.append(special_arg_name)
            else:
                normal_args.append(extractArg(arg))

        return normal_args

    normal_args = extractNormalArgs(node.args.args)

    parameters = ParameterSpec(
        ps_name=name,
        ps_normal_args=normal_args,
        ps_kw_only_args=[extractArg(arg) for arg in node.args.kwonlyargs]
        if python_version >= 300 else [],
        ps_list_star_arg=extractArg(node.args.vararg),
        ps_dict_star_arg=extractArg(node.args.kwarg),
        ps_default_count=len(node.args.defaults))

    message = parameters.checkParametersValid()

    if message is not None:
        raiseSyntaxError(
            message,
            source_ref.atColumnNumber(node.col_offset),
        )

    parent_module = provider.getParentModule()

    code_object = CodeObjectSpec(
        co_name=name,
        co_kind=function_kind,
        co_varnames=parameters.getParameterNames(),
        co_argcount=parameters.getArgumentCount(),
        co_kwonlyargcount=parameters.getKwOnlyParameterCount(),
        co_has_starlist=parameters.getStarListArgumentName() is not None,
        co_has_stardict=parameters.getStarDictArgumentName() is not None,
        co_filename=parent_module.getRunTimeFilename(),
        co_lineno=source_ref.getLineNumber(),
        future_spec=parent_module.getFutureSpec())

    outer_body = ExpressionFunctionBody(provider=provider,
                                        name=name,
                                        flags=flags,
                                        doc=function_doc,
                                        parameters=parameters,
                                        source_ref=source_ref)

    if special_args:
        inner_name = name.strip("<>") + "$inner"
        iter_vars = []

        values = []

        statements = []

        def unpackFrom(source, arg_names):
            accesses = []

            sub_special_index = 0

            iter_var = outer_body.allocateTempVariable(
                None, "arg_iter_%d" % len(iter_vars))
            iter_vars.append(iter_var)

            statements.append(
                StatementAssignmentVariable(variable=iter_var,
                                            source=ExpressionBuiltinIter1(
                                                value=source,
                                                source_ref=source_ref),
                                            source_ref=source_ref))

            for element_index, arg_name in enumerate(arg_names):
                if getKind(arg_name) == "Name":
                    arg_var = outer_body.createProvidedVariable(arg_name.id)
                    outer_body.registerProvidedVariable(arg_var)

                    statements.append(
                        StatementAssignmentVariable(
                            variable=arg_var,
                            source=ExpressionSpecialUnpack(
                                value=ExpressionTempVariableRef(
                                    variable=iter_var, source_ref=source_ref),
                                count=element_index + 1,
                                expected=len(arg_names),
                                source_ref=source_ref),
                            source_ref=source_ref))

                    accesses.append(
                        ExpressionVariableRef(variable=arg_var,
                                              source_ref=source_ref))
                elif getKind(arg_name) == "Tuple":
                    accesses.extend(
                        unpackFrom(source=ExpressionSpecialUnpack(
                            value=ExpressionTempVariableRef(
                                variable=iter_var, source_ref=source_ref),
                            count=element_index + 1,
                            expected=len(arg_names),
                            source_ref=source_ref),
                                   arg_names=arg_name.elts))

                    sub_special_index += 1
                else:
                    assert False, arg_name

            statements.append(
                StatementSpecialUnpackCheck(iterator=ExpressionTempVariableRef(
                    variable=iter_var, source_ref=source_ref),
                                            count=len(arg_names),
                                            source_ref=source_ref))

            return accesses

        for arg_name in parameters.getParameterNames():
            if arg_name.startswith('.'):
                source = ExpressionVariableNameRef(provider=outer_body,
                                                   variable_name=arg_name,
                                                   source_ref=source_ref)

                values.extend(unpackFrom(source, special_args[arg_name]))
            else:
                values.append(
                    ExpressionVariableNameRef(provider=outer_body,
                                              variable_name=arg_name,
                                              source_ref=source_ref))

        code_body = ExpressionOutlineFunction(provider=outer_body,
                                              name=inner_name,
                                              source_ref=source_ref)

        statements.append(
            StatementReturn(expression=code_body, source_ref=source_ref))

        outer_body.setBody(
            makeStatementsSequenceFromStatement(
                statement=makeTryFinallyStatement(
                    provider=outer_body,
                    tried=statements,
                    final=[
                        StatementReleaseVariable(variable=variable,
                                                 source_ref=source_ref)
                        for variable in sorted(
                            outer_body.getTempVariables(),
                            key=lambda variable: variable.getName())
                    ],
                    source_ref=source_ref,
                    public_exc=False)))
    else:
        code_body = outer_body

    return outer_body, code_body, code_object