def buildFunctionNode(provider, node, source_ref): # Functions have way too many details, pylint: disable=R0912,R0914 assert getKind(node) == "FunctionDef" function_statement_nodes, function_doc = extractDocFromBody(node) function_kind, flags, _written_variables, _non_local_declarations, _global_declarations = \ detectFunctionBodyKind( nodes = function_statement_nodes ) outer_body, function_body, code_object = buildFunctionWithParsing( provider = provider, function_kind = function_kind, name = node.name, function_doc = function_doc, flags = flags, node = node, source_ref = source_ref ) if function_kind == "Function": code_body = function_body elif function_kind == "Generator": code_body = ExpressionGeneratorObjectBody( provider = function_body, name = node.name, flags = flags, source_ref = source_ref ) for variable in function_body.getVariables(): code_body.getVariableForReference(variable.getName()) else: assert False, function_kind if function_kind == "Generator": 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 ) ) ) decorators = buildNodeList( provider = provider, nodes = reversed(node.decorator_list), source_ref = source_ref ) defaults = buildNodeList( provider = provider, nodes = node.args.defaults, source_ref = source_ref ) kw_defaults = buildParameterKwDefaults( provider = provider, node = node, function_body = function_body, source_ref = source_ref ) function_statements_body = buildFrameNode( provider = code_body, nodes = function_statement_nodes, code_object = code_object, source_ref = source_ref ) if function_kind == "Function": # TODO: Generators might have to raise GeneratorExit instead. function_statements_body = _insertFinalReturnStatement( function_statements_body = function_statements_body, return_class = StatementReturn, source_ref = source_ref ) if function_statements_body.isStatementsFrame(): function_statements_body = makeStatementsSequenceFromStatement( statement = function_statements_body ) code_body.setBody( function_statements_body ) annotations = buildParameterAnnotations(provider, node, source_ref) function_creation = ExpressionFunctionCreation( function_ref = ExpressionFunctionRef( function_body = outer_body, source_ref = source_ref ), code_object = code_object, defaults = defaults, kw_defaults = kw_defaults, annotations = annotations, source_ref = source_ref ) # Add the "staticmethod" decorator to __new__ methods if not provided. # CPython made these optional, but secretly applies them when it does # "class __new__". We add them earlier, so our optimization will see it. if node.name == "__new__" and \ provider.isExpressionClassBody(): for decorator in decorators: if decorator.isExpressionVariableRef() and \ decorator.getVariableName() == "staticmethod": break else: decorators.append( ExpressionBuiltinRef( builtin_name = "staticmethod", source_ref = source_ref ) ) if python_version >= 360 and \ node.name == "__init_subclass__" and \ provider.isExpressionClassBody(): for decorator in decorators: if decorator.isExpressionVariableRef() and \ decorator.getVariableName() == "classmethod": break else: decorators.append( ExpressionBuiltinRef( builtin_name = "classmethod", source_ref = source_ref ) ) decorated_function = function_creation for decorator in decorators: decorated_function = ExpressionCallNoKeywords( called = decorator, args = ExpressionMakeTuple( elements = (decorated_function,), source_ref = source_ref ), source_ref = decorator.getSourceReference() ) result = StatementAssignmentVariable( variable_ref = ExpressionTargetVariableRef( variable_name = mangleName(node.name, provider), source_ref = source_ref ), source = decorated_function, source_ref = source_ref ) if python_version >= 340: function_body.qualname_setup = result.getTargetVariableRef() return result
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. # 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=function_body.getParameters().getParameterNames(), co_argcount=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, provider=provider, node=node, emit_class=emit_class, iter_tmp=iter_tmp, temp_scope=None, start_value=start_value, container_tmp=container_tmp, assign_provider=False, 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()), ) if emit_class is ExpressionYield: guard_mode = "generator" else: guard_mode = "full" code_body.setBody( makeStatementsSequenceFromStatement(statement=StatementsFrame( statements=mergeStatements(statements, False), guard_mode=guard_mode, code_object=code_object, source_ref=source_ref))) 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)
def buildFunctionNode(provider, node, source_ref): # Functions have way too many details, pylint: disable=R0912,R0914 assert getKind(node) == "FunctionDef" function_statement_nodes, function_doc = extractDocFromBody(node) function_kind, flags, _written_variables, _non_local_declarations, _global_declarations = \ detectFunctionBodyKind( nodes = function_statement_nodes ) outer_body, function_body, code_object = buildFunctionWithParsing( provider=provider, function_kind=function_kind, name=node.name, function_doc=function_doc, flags=flags, node=node, source_ref=source_ref) if function_kind == "Function": code_body = function_body elif function_kind == "Generator": code_body = ExpressionGeneratorObjectBody(provider=function_body, name=node.name, flags=flags, source_ref=source_ref) for variable in function_body.getVariables(): code_body.getVariableForReference(variable.getName()) else: assert False, function_kind if function_kind == "Generator": 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))) decorators = buildNodeList(provider=provider, nodes=reversed(node.decorator_list), source_ref=source_ref) defaults = buildNodeList(provider=provider, nodes=node.args.defaults, source_ref=source_ref) kw_defaults = buildParameterKwDefaults(provider=provider, node=node, function_body=function_body, source_ref=source_ref) function_statements_body = buildFrameNode(provider=code_body, nodes=function_statement_nodes, code_object=code_object, source_ref=source_ref) if function_kind == "Function": # TODO: Generators might have to raise GeneratorExit instead. function_statements_body = _insertFinalReturnStatement( function_statements_body=function_statements_body, return_class=StatementReturn, source_ref=source_ref) if function_statements_body.isStatementsFrame(): function_statements_body = makeStatementsSequenceFromStatement( statement=function_statements_body) code_body.setBody(function_statements_body) annotations = buildParameterAnnotations(provider, node, source_ref) function_creation = ExpressionFunctionCreation( function_ref=ExpressionFunctionRef(function_body=outer_body, source_ref=source_ref), code_object=code_object, defaults=defaults, kw_defaults=kw_defaults, annotations=annotations, source_ref=source_ref) # Add the "staticmethod" decorator to __new__ methods if not provided. # CPython made these optional, but secretly applies them when it does # "class __new__". We add them earlier, so our optimization will see it. if node.name == "__new__" and \ provider.isExpressionClassBody(): for decorator in decorators: if decorator.isExpressionVariableRef() and \ decorator.getVariableName() == "staticmethod": break else: decorators.append( ExpressionBuiltinRef(builtin_name="staticmethod", source_ref=source_ref)) if python_version >= 360 and \ node.name == "__init_subclass__" and \ provider.isExpressionClassBody(): for decorator in decorators: if decorator.isExpressionVariableRef() and \ decorator.getVariableName() == "classmethod": break else: decorators.append( ExpressionBuiltinRef(builtin_name="classmethod", source_ref=source_ref)) decorated_function = function_creation for decorator in decorators: decorated_function = ExpressionCallNoKeywords( called=decorator, args=ExpressionMakeTuple(elements=(decorated_function, ), source_ref=source_ref), source_ref=decorator.getSourceReference()) result = StatementAssignmentVariable( variable_ref=ExpressionTargetVariableRef(variable_name=mangleName( node.name, provider), source_ref=source_ref), source=decorated_function, source_ref=source_ref) if python_version >= 340: function_body.qualname_setup = result.getTargetVariableRef() return result
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