def convertFunctionCallToOutline(provider, function_body, values, call_source_ref): # This has got to have pretty man details, pylint: disable=too-many-locals function_source_ref = function_body.getSourceReference() outline_body = ExpressionOutlineBody(provider=provider, name="inline", source_ref=function_source_ref) # Make a clone first, so we do not harm other references. clone = function_body.subnode_body.makeClone() locals_scope_clone, variable_translation = function_body.locals_scope.makeClone( clone) # TODO: Lets update all at once maybe, it would take less visits. updateLocalsScope( clone, locals_scope=locals_scope_clone, variable_translation=variable_translation, ) argument_names = function_body.getParameters().getParameterNames() assert len(argument_names) == len(values), (argument_names, values) statements = [] for argument_name, value in zip(argument_names, values): statements.append( StatementAssignmentVariable( variable=variable_translation[argument_name], source=value, source_ref=call_source_ref, )) body = makeStatementsSequence(statements=(statements, clone), allow_none=False, source_ref=function_source_ref) auto_releases = function_body.getFunctionVariablesWithAutoReleases() # TODO: Not possible to auto release with outline bodies too? if auto_releases: releases = [ StatementReleaseVariable(variable=variable, source_ref=function_source_ref) for variable in auto_releases ] body = makeTryFinallyStatement( provider=outline_body, tried=body, final=releases, source_ref=function_source_ref, ) outline_body.setChild("body", body) return outline_body
def buildNamedExprNode(provider, node, source_ref): """Assignment expressions, Python3.8 or higher only.""" outline_body = ExpressionOutlineBody(provider=provider, name="assignment_expr", source_ref=source_ref) tmp_value = outline_body.allocateTempVariable(temp_scope=None, name="value") value = buildNode(provider=provider, node=node.value, source_ref=source_ref) locals_owner = provider while locals_owner.isExpressionOutlineFunction(): locals_owner = locals_owner.getParentVariableProvider() variable_name = node.target.id if (locals_owner.isExpressionGeneratorObjectBody() and locals_owner.name == "<genexpr>"): locals_owner.addNonlocalsDeclaration((variable_name, ), user_provided=False, source_ref=source_ref) statements = ( StatementAssignmentVariable(variable=tmp_value, source=value, source_ref=source_ref), StatementAssignmentVariableName( provider=locals_owner, variable_name=variable_name, source=ExpressionTempVariableRef(variable=tmp_value, source_ref=source_ref), source_ref=source_ref, ), StatementReturn( expression=ExpressionTempVariableRef(variable=tmp_value, source_ref=source_ref), source_ref=source_ref, ), ) outline_body.setChild( "body", makeStatementsSequenceFromStatement(statement=makeTryFinallyStatement( provider=provider, tried=statements, final=StatementReleaseVariable(variable=tmp_value, source_ref=source_ref), source_ref=source_ref, )), ) return outline_body
def _buildPython2ListContraction(provider, node, 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. function_body = ExpressionOutlineBody( provider=provider, name="list_contraction", source_ref=source_ref ) iter_tmp = function_body.allocateTempVariable(temp_scope=None, name=".0") container_tmp = function_body.allocateTempVariable( temp_scope=None, name="contraction_result" ) statements, release_statements = _buildContractionBodyNode( provider=provider, node=node, emit_class=StatementListOperationAppend, iter_tmp=iter_tmp, temp_scope=None, start_value=[], container_tmp=container_tmp, function_body=function_body, assign_provider=True, for_asyncgen=False, source_ref=source_ref, ) statements.append( StatementReturn( expression=ExpressionTempVariableRef( variable=container_tmp, source_ref=source_ref ), source_ref=source_ref, ) ) statement = makeTryFinallyStatement( provider=function_body, tried=statements, final=release_statements, source_ref=source_ref.atInternal(), ) function_body.setChild( "body", makeStatementsSequenceFromStatement(statement=statement) ) return function_body
def buildCallNode(provider, node, source_ref): called = buildNode(provider, node.func, source_ref) if python_version >= 0x350: list_star_arg = None dict_star_arg = None positional_args = [] # For Python3.5 compatibility, the error handling with star argument last # is the old one, only with a starred argument before that, things use the # new unpacking code. for node_arg in node.args[:-1]: if getKind(node_arg) == "Starred": assert python_version >= 0x350 list_star_arg = buildListUnpacking(provider, node.args, source_ref) positional_args = [] break else: if node.args and getKind(node.args[-1]) == "Starred": assert python_version >= 0x350 list_star_arg = buildNode(provider, node.args[-1].value, source_ref) positional_args = buildNodeList(provider, node.args[:-1], source_ref) else: positional_args = buildNodeList(provider, node.args, source_ref) # Only the values of keyword pairs have a real source ref, and those only # really matter, so that makes sense. keys = [] values = [] for keyword in node.keywords[:-1]: if keyword.arg is None: assert python_version >= 0x350 outline_body = ExpressionOutlineBody( provider=provider, name="dict_unpacking_call", source_ref=source_ref ) tmp_called = outline_body.allocateTempVariable( temp_scope=None, name="called" ) helper_args = [ ExpressionTempVariableRef(variable=tmp_called, source_ref=source_ref), makeExpressionMakeTuple( elements=buildDictionaryUnpackingArgs( provider=provider, keys=(keyword.arg for keyword in node.keywords), values=(keyword.value for keyword in node.keywords), source_ref=source_ref, ), source_ref=source_ref, ), ] dict_star_arg = ExpressionFunctionCall( function=ExpressionFunctionCreation( function_ref=ExpressionFunctionRef( function_body=getFunctionCallHelperDictionaryUnpacking(), source_ref=source_ref, ), defaults=(), kw_defaults=None, annotations=None, source_ref=source_ref, ), values=helper_args, source_ref=source_ref, ) outline_body.setChild( "body", makeStatementsSequenceFromStatements( StatementAssignmentVariable( variable=tmp_called, source=called, source_ref=source_ref ), StatementReturn( expression=_makeCallNode( called=ExpressionTempVariableRef( variable=tmp_called, source_ref=source_ref ), positional_args=positional_args, keys=keys, values=values, list_star_arg=list_star_arg, dict_star_arg=dict_star_arg, source_ref=source_ref, ), source_ref=source_ref, ), ), ) return outline_body # For Python3.5 compatibility, the error handling with star argument last # is the old one, only with a starred argument before that, things use the # new unpacking code. if node.keywords and node.keywords[-1].arg is None: assert python_version >= 0x350 dict_star_arg = buildNode(provider, node.keywords[-1].value, source_ref) keywords = node.keywords[:-1] else: keywords = node.keywords for keyword in keywords: keys.append( makeConstantRefNode( constant=keyword.arg, source_ref=source_ref, user_provided=True ) ) values.append(buildNode(provider, keyword.value, source_ref)) if python_version < 0x350: list_star_arg = buildNode(provider, node.starargs, source_ref, True) dict_star_arg = buildNode(provider, node.kwargs, source_ref, True) return _makeCallNode( called=called, positional_args=positional_args, keys=keys, values=values, list_star_arg=list_star_arg, dict_star_arg=dict_star_arg, source_ref=source_ref, )
def buildComplexComparisonNode(provider, left, rights, comparators, source_ref): # This is a bit complex, due to the many details, pylint: disable=too-many-locals outline_body = ExpressionOutlineBody( provider=provider, name="comparison_chain", source_ref=source_ref ) variables = [ outline_body.allocateTempVariable(temp_scope=None, name="operand_%d" % count) for count in range(2, len(rights) + 2) ] tmp_variable = outline_body.allocateTempVariable( temp_scope=None, name="comparison_result" ) def makeTempAssignment(count, value): return StatementAssignmentVariable( variable=variables[count], source=value, source_ref=source_ref ) def makeReleaseStatement(count): return StatementReleaseVariable( variable=variables[count], source_ref=source_ref ) def makeValueComparisonReturn(left, right, comparator): yield StatementAssignmentVariable( variable=tmp_variable, source=_makeComparisonNode( left=left, right=right, comparator=comparator, source_ref=source_ref ), source_ref=source_ref, ) yield makeStatementConditional( condition=ExpressionOperationNot( operand=ExpressionTempVariableRef( variable=tmp_variable, source_ref=source_ref ), source_ref=source_ref, ), yes_branch=StatementReturn( expression=ExpressionTempVariableRef( variable=tmp_variable, source_ref=source_ref ), source_ref=source_ref, ), no_branch=None, source_ref=source_ref, ) statements = [] final = [] for count, value in enumerate(rights): if value is not rights[-1]: statements.append(makeTempAssignment(count, value)) final.append(makeReleaseStatement(count)) right = ExpressionTempVariableRef( variable=variables[count], source_ref=source_ref ) else: right = value if count != 0: left = ExpressionTempVariableRef( variable=variables[count - 1], source_ref=source_ref ) comparator = comparators[count] if value is not rights[-1]: statements.extend(makeValueComparisonReturn(left, right, comparator)) else: statements.append( StatementReturn( expression=_makeComparisonNode( left=left, right=right, comparator=comparator, source_ref=source_ref, ), source_ref=source_ref, ) ) final.append( StatementReleaseVariable(variable=tmp_variable, source_ref=source_ref) ) outline_body.setChild( "body", makeStatementsSequenceFromStatement( statement=makeTryFinallyStatement( provider=outline_body, tried=statements, final=final, source_ref=source_ref, ) ), ) return outline_body
def buildClassNode2(provider, node, source_ref): # This function is the Python2 special case with special re-formulation as # according to Developer Manual, and it's very detailed, pylint: disable=too-many-locals class_statement_nodes, class_doc = extractDocFromBody(node) function_body = ExpressionClassBody(provider=provider, name=node.name, doc=class_doc, source_ref=source_ref) parent_module = provider.getParentModule() code_object = CodeObjectSpec( co_name=node.name, co_kind="Class", co_varnames=(), co_freevars=(), co_argcount=0, 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 = buildFrameNode( provider=function_body, nodes=class_statement_nodes, code_object=code_object, source_ref=source_ref, ) if body is not None: # The frame guard has nothing to tell its line number to. body.source_ref = source_ref.atInternal() locals_scope = function_body.getLocalsScope() # The class body is basically a function that implicitly, at the end # returns its locals and cannot have other return statements contained, and # starts out with a variables "__module__" and potentially "__doc__" set. statements = [ StatementSetLocalsDictionary(locals_scope=locals_scope, source_ref=source_ref), StatementAssignmentVariableName( provider=function_body, variable_name="__module__", source=ExpressionModuleAttributeNameRef( variable=provider.getParentModule().getVariableForReference( "__name__"), source_ref=source_ref, ), source_ref=source_ref.atInternal(), ), ] if class_doc is not None: statements.append( StatementAssignmentVariableName( provider=function_body, variable_name="__doc__", source=makeConstantRefNode(constant=class_doc, source_ref=source_ref, user_provided=True), source_ref=source_ref.atInternal(), )) statements += ( body, StatementReturn( expression=ExpressionBuiltinLocalsRef(locals_scope=locals_scope, source_ref=source_ref), source_ref=source_ref, ), ) body = makeStatementsSequenceFromStatement( statement=makeTryFinallyStatement( provider=function_body, tried=mergeStatements(statements, True), final=StatementReleaseLocals(locals_scope=locals_scope, source_ref=source_ref), source_ref=source_ref, )) # The class body is basically a function that implicitly, at the end # returns its locals and cannot have other return statements contained. function_body.setChild("body", body) temp_scope = provider.allocateTempScope("class_creation") tmp_bases = provider.allocateTempVariable(temp_scope, "bases") tmp_class_dict = provider.allocateTempVariable(temp_scope, "class_dict") tmp_metaclass = provider.allocateTempVariable(temp_scope, "metaclass") tmp_class = provider.allocateTempVariable(temp_scope, "class") select_metaclass = ExpressionOutlineBody(provider=provider, name="select_metaclass", body=None, source_ref=source_ref) if node.bases: tmp_base = select_metaclass.allocateTempVariable(temp_scope=None, name="base") statements = ( StatementAssignmentVariable( variable=tmp_base, source=ExpressionSubscriptLookup( expression=ExpressionTempVariableRef( variable=tmp_bases, source_ref=source_ref), subscript=makeConstantRefNode(constant=0, source_ref=source_ref, user_provided=True), source_ref=source_ref, ), source_ref=source_ref, ), makeTryFinallyStatement( provider, tried=StatementTry( tried=makeStatementsSequenceFromStatement( statement=StatementReturn( expression=makeExpressionAttributeLookup( expression=ExpressionTempVariableRef( variable=tmp_base, source_ref=source_ref), attribute_name="__class__", source_ref=source_ref, ), source_ref=source_ref, )), except_handler=makeStatementsSequenceFromStatement( statement=StatementReturn( expression=ExpressionBuiltinType1( value=ExpressionTempVariableRef( variable=tmp_base, source_ref=source_ref), source_ref=source_ref, ), source_ref=source_ref, )), break_handler=None, continue_handler=None, return_handler=None, source_ref=source_ref, ), final=StatementReleaseVariable(variable=tmp_base, source_ref=source_ref), source_ref=source_ref, public_exc=False, ), ) else: statements = ( StatementTry( tried=makeStatementsSequenceFromStatement( statement=StatementReturn( # TODO: Should avoid checking __builtins__ for this. expression=ExpressionVariableNameRef( variable_name="__metaclass__", provider=parent_module, source_ref=source_ref, ), source_ref=source_ref, )), except_handler=makeStatementsSequenceFromStatement( statement=StatementReturn( expression=ExpressionBuiltinAnonymousRef( builtin_name="classobj", source_ref=source_ref), source_ref=source_ref, )), break_handler=None, continue_handler=None, return_handler=None, source_ref=source_ref, ), ) select_metaclass.setChild( "body", makeStatementsSequence(statements=statements, allow_none=False, source_ref=source_ref), ) statements = [ StatementAssignmentVariable( variable=tmp_bases, source=makeExpressionMakeTupleOrConstant( elements=buildNodeList(provider=provider, nodes=node.bases, source_ref=source_ref), user_provided=True, source_ref=source_ref, ), source_ref=source_ref, ), StatementAssignmentVariable(variable=tmp_class_dict, source=function_body, source_ref=source_ref), StatementAssignmentVariable( variable=tmp_metaclass, source=ExpressionConditional( condition=ExpressionDictOperationIn( key=makeConstantRefNode( constant="__metaclass__", source_ref=source_ref, user_provided=True, ), dict_arg=ExpressionTempVariableRef(variable=tmp_class_dict, source_ref=source_ref), source_ref=source_ref, ), expression_yes=ExpressionDictOperationGet2( dict_arg=ExpressionTempVariableRef(variable=tmp_class_dict, source_ref=source_ref), key=makeConstantRefNode( constant="__metaclass__", source_ref=source_ref, user_provided=True, ), source_ref=source_ref, ), expression_no=select_metaclass, source_ref=source_ref, ), source_ref=source_ref, ), StatementAssignmentVariable( variable=tmp_class, source=makeExpressionCall( called=ExpressionTempVariableRef(variable=tmp_metaclass, source_ref=source_ref), args=makeExpressionMakeTuple( elements=( makeConstantRefNode( constant=node.name, source_ref=source_ref, user_provided=True, ), ExpressionTempVariableRef(variable=tmp_bases, source_ref=source_ref), ExpressionTempVariableRef(variable=tmp_class_dict, source_ref=source_ref), ), source_ref=source_ref, ), kw=None, source_ref=source_ref, ), source_ref=source_ref, ), ] for decorator in buildNodeList(provider, reversed(node.decorator_list), source_ref): statements.append( StatementAssignmentVariable( variable=tmp_class, source=makeExpressionCall( called=decorator, args=makeExpressionMakeTuple( elements=(ExpressionTempVariableRef( variable=tmp_class, source_ref=source_ref), ), source_ref=source_ref, ), kw=None, source_ref=decorator.getSourceReference(), ), source_ref=decorator.getSourceReference(), )) statements.append( StatementAssignmentVariableName( provider=provider, variable_name=mangleName(node.name, provider), source=ExpressionTempVariableRef(variable=tmp_class, source_ref=source_ref), source_ref=source_ref, )) final = ( StatementReleaseVariable(variable=tmp_class, source_ref=source_ref), StatementReleaseVariable(variable=tmp_bases, source_ref=source_ref), StatementReleaseVariable(variable=tmp_class_dict, source_ref=source_ref), StatementReleaseVariable(variable=tmp_metaclass, source_ref=source_ref), ) return makeTryFinallyStatement(provider=function_body, tried=statements, final=final, source_ref=source_ref)
def buildGeneratorExpressionNode(provider, node, source_ref): # Generator expressions are dealt with by general code. assert getKind(node) == "GeneratorExp" function_body = ExpressionOutlineBody( provider=provider, name="genexpr", source_ref=source_ref ) iter_tmp = function_body.allocateTempVariable(temp_scope=None, name=".0") parent_module = provider.getParentModule() code_object = CodeObjectSpec( co_name="<genexpr>", co_kind="Generator", co_varnames=(".0",), 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(), ) is_async = any(getattr(qual, "is_async", 0) for qual in node.generators) # Some of the newly allowed stuff in 3.7 fails to set the async flag. if not is_async and python_version >= 0x370: is_async = detectFunctionBodyKind(nodes=node.generators)[0] in ( "Asyncgen", "Coroutine", ) if is_async: code_body = ExpressionAsyncgenObjectBody( provider=provider, name="<genexpr>", code_object=code_object, flags=None, auto_release=None, source_ref=source_ref, ) maker_class = ExpressionMakeAsyncgenObject else: code_body = ExpressionGeneratorObjectBody( provider=provider, name="<genexpr>", code_object=code_object, flags=None, auto_release=None, source_ref=source_ref.atColumnNumber(node.col_offset + 1), ) maker_class = ExpressionMakeGeneratorObject function_body.setChild( "body", makeStatementsSequenceFromStatements( StatementAssignmentVariable( variable=iter_tmp, source=_makeIteratorCreation( provider=provider, qual=node.generators[0], for_asyncgen=is_async, source_ref=source_ref, ), source_ref=source_ref, ), makeTryFinallyStatement( provider=function_body, tried=StatementReturn( expression=maker_class( ExpressionFunctionRef( function_body=code_body, source_ref=source_ref ), source_ref=source_ref, ), source_ref=source_ref, ), final=StatementReleaseVariable( variable=iter_tmp, source_ref=source_ref ), source_ref=source_ref, ), ), ) statements, release_statements = _buildContractionBodyNode( provider=provider, node=node, emit_class=ExpressionYield, iter_tmp=iter_tmp, temp_scope=None, start_value=None, container_tmp=None, function_body=code_body, assign_provider=False, for_asyncgen=is_async, source_ref=source_ref, ) if is_async: statements.append(StatementGeneratorReturnNone(source_ref=source_ref)) statements = ( makeTryFinallyStatement( provider=function_body, tried=statements, final=release_statements, source_ref=source_ref.atInternal(), ), ) code_body.setChild( "body", makeStatementsSequenceFromStatement( statement=StatementsFrameGenerator( statements=mergeStatements(statements, False), code_object=code_object, source_ref=source_ref, ) ), ) return function_body