def _buildContractionNode(provider, node, name, emit_class, start_value,
                          assign_provider, 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.

    # Note: The assign_provider is only to cover Python2 list contractions,
    # assigning one of the loop variables to the outside scope.
    if assign_provider:
        function_body = ExpressionOutlineBody(
            provider   = provider,
            name       = name,
            source_ref = source_ref
        )

        iter_tmp = function_body.allocateTempVariable(
            temp_scope = None,
            name       = ".0"
        )
    else:
        # TODO: No function ought to be necessary.

        function_body = ExpressionFunctionBody(
            provider   = provider,
            name       = name,
            doc        = None,
            parameters = ParameterSpec(
                name          = name,
                normal_args   = (".0",),
                list_star_arg = None,
                dict_star_arg = None,
                default_count = 0,
                kw_only_args  = ()
            ),
            flags      = set(),
            source_ref = source_ref
        )

        iter_tmp = function_body.getVariableForAssignment(
            variable_name = ".0"
        )
        assert iter_tmp.isParameterVariable()

    code_object = CodeObjectSpec(
        code_name     = name,
        code_kind     = "Generator" if emit_class is ExpressionYield else "Function",
        arg_names     = () if assign_provider else function_body.getParameters().getParameterNames(),
        kw_only_count = 0,
        has_starlist  = False,
        has_stardict  = False,
    )

    if emit_class is ExpressionYield:
        code_body = ExpressionGeneratorObjectBody(
            provider   = function_body,
            name       = "<genexpr>",
            flags      = set(),
            source_ref = source_ref
        )

        iter_tmp = code_body.getVariableForReference(
            variable_name = ".0"
        )
        assert iter_tmp.isLocalVariable()

        function_body.setBody(
            makeStatementsSequenceFromStatement(
                statement = StatementReturn(
                    expression = ExpressionMakeGeneratorObject(
                        generator_ref = ExpressionFunctionRef(
                            function_body = code_body,
                            source_ref    = source_ref
                        ),
                        code_object   = code_object,
                        source_ref    = source_ref
                    ),
                    source_ref = source_ref
                )
            )
        )
    else:
        code_body = function_body

    if start_value is not None:
        container_tmp = code_body.allocateTempVariable(
            temp_scope = None,
            name       = "contraction_result"
        )
    else:
        container_tmp = None

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

    if start_value is not None:
        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()
        ),
    )

    code_body.setBody(
        makeStatementsSequenceFromStatement(
            statement = StatementsFrame(
                statements  = mergeStatements(statements, False),
                guard_mode  = "pass_through"
                                  if emit_class is not ExpressionYield else
                                "generator",
                code_object = code_object,
                source_ref  = source_ref
            )
        )
    )

    if not assign_provider:
        return ExpressionFunctionCall(
            function   = ExpressionFunctionCreation(
                function_ref = ExpressionFunctionRef(
                    function_body = function_body,
                    source_ref    = source_ref
                ),
                code_object  = code_object,
                defaults     = (),
                kw_defaults  = None,
                annotations  = None,
                source_ref   = source_ref
            ),
            values     = (
                ExpressionBuiltinIter1(
                    value      = buildNode(
                        provider   = provider,
                        node       = node.generators[0].iter,
                        source_ref = source_ref
                    ),
                    source_ref = source_ref
                ),
            ),
            source_ref = source_ref
        )
    else:
        return function_body
Exemplo n.º 2
0
def _buildContractionNode(provider, node, name, emit_class, start_value,
                          assign_provider, 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.

    # Note: The assign_provider is only to cover Python2 list contractions,
    # assigning one of the loop variables to the outside scope.
    if assign_provider:
        function_body = ExpressionOutlineBody(provider=provider,
                                              name=name,
                                              source_ref=source_ref)

        iter_tmp = function_body.allocateTempVariable(temp_scope=None,
                                                      name=".0")
    else:
        # TODO: No function ought to be necessary.

        function_body = ExpressionFunctionBody(provider=provider,
                                               name=name,
                                               doc=None,
                                               parameters=ParameterSpec(
                                                   ps_name=name,
                                                   ps_normal_args=(".0", ),
                                                   ps_list_star_arg=None,
                                                   ps_dict_star_arg=None,
                                                   ps_default_count=0,
                                                   ps_kw_only_args=()),
                                               flags=set(),
                                               source_ref=source_ref)

        iter_tmp = function_body.getVariableForAssignment(variable_name=".0")
        assert iter_tmp.isParameterVariable()

    code_object = CodeObjectSpec(
        co_name=name,
        co_kind="Generator" if emit_class is ExpressionYield else "Function",
        co_varnames=() if assign_provider else
        function_body.getParameters().getParameterNames(),
        co_argcount=0 if assign_provider else len(
            function_body.getParameters().getParameterNames()),
        co_kwonlyargcount=0,
        co_has_starlist=False,
        co_has_stardict=False,
    )

    if emit_class is ExpressionYield:
        code_body = ExpressionGeneratorObjectBody(provider=function_body,
                                                  name="<genexpr>",
                                                  flags=set(),
                                                  source_ref=source_ref)

        iter_tmp = code_body.getVariableForReference(variable_name=".0")
        assert iter_tmp.isLocalVariable()

        function_body.setBody(
            makeStatementsSequenceFromStatement(statement=StatementReturn(
                expression=ExpressionMakeGeneratorObject(
                    generator_ref=ExpressionFunctionRef(
                        function_body=code_body, source_ref=source_ref),
                    code_object=code_object,
                    source_ref=source_ref),
                source_ref=source_ref)))
    else:
        code_body = function_body

    if start_value is not None:
        container_tmp = code_body.allocateTempVariable(
            temp_scope=None, name="contraction_result")
    else:
        container_tmp = None

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

    if start_value is not None:
        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()), )

    code_body.setBody(
        makeStatementsSequenceFromStatement(statement=StatementsFrame(
            statements=mergeStatements(statements, False),
            guard_mode="pass_through"
            if emit_class is not ExpressionYield else "generator",
            code_object=code_object,
            source_ref=source_ref)))

    if not assign_provider:
        return ExpressionFunctionCall(function=ExpressionFunctionCreation(
            function_ref=ExpressionFunctionRef(function_body=function_body,
                                               source_ref=source_ref),
            code_object=code_object,
            defaults=(),
            kw_defaults=None,
            annotations=None,
            source_ref=source_ref),
                                      values=(ExpressionBuiltinIter1(
                                          value=buildNode(
                                              provider=provider,
                                              node=node.generators[0].iter,
                                              source_ref=source_ref),
                                          source_ref=source_ref), ),
                                      source_ref=source_ref)
    else:
        return function_body