def buildExtSliceNode(provider, node, source_ref): elements = [] for dim in node.slice.dims: dim_kind = getKind(dim) if dim_kind == "Slice": lower = buildNode(provider, dim.lower, source_ref, True) upper = buildNode(provider, dim.upper, source_ref, True) step = buildNode(provider, dim.step, source_ref, True) element = makeExpressionBuiltinSlice(start=lower, stop=upper, step=step, source_ref=source_ref) elif dim_kind == "Ellipsis": element = ExpressionConstantEllipsisRef(source_ref=source_ref) elif dim_kind == "Index": element = buildNode(provider=provider, node=dim.value, source_ref=source_ref) else: assert False, dim elements.append(element) return makeExpressionMakeTupleOrConstant(elements=elements, user_provided=True, source_ref=source_ref)
def buildSliceNode(provider, node, source_ref): """Python3.9 or higher, slice notations.""" return makeExpressionBuiltinSlice( start=buildNode(provider, node.lower, source_ref, allow_none=True), stop=buildNode(provider, node.upper, source_ref, allow_none=True), step=buildNode(provider, node.step, source_ref, allow_none=True), source_ref=source_ref, )
def _buildInplaceAssignSliceNode( provider, lookup_source, lower, upper, tmp_variable1, tmp_variable2, tmp_variable3, tmp_variable4, operator, expression, source_ref, ): # Due to the 3 inputs, which we need to also put into temporary variables, # there are too many variables here, but they are needed. # pylint: disable=too-many-locals # First assign the target value, lower and upper to temporary variables. copy_to_tmp = StatementAssignmentVariable(variable=tmp_variable1, source=lookup_source, source_ref=source_ref) final_statements = [ StatementReleaseVariable(variable=tmp_variable1, source_ref=source_ref) ] statements = [] if lower is not None: statements.append( StatementAssignmentVariable(variable=tmp_variable2, source=lower, source_ref=source_ref)) final_statements.append( StatementReleaseVariable(variable=tmp_variable2, source_ref=source_ref)) lower_ref1 = ExpressionTempVariableRef(variable=tmp_variable2, source_ref=source_ref) lower_ref2 = ExpressionTempVariableRef(variable=tmp_variable2, source_ref=source_ref) else: assert tmp_variable2 is None lower_ref1 = lower_ref2 = None if upper is not None: statements.append( StatementAssignmentVariable(variable=tmp_variable3, source=upper, source_ref=source_ref)) final_statements.append( StatementReleaseVariable(variable=tmp_variable3, source_ref=source_ref)) upper_ref1 = ExpressionTempVariableRef(variable=tmp_variable3, source_ref=source_ref) upper_ref2 = ExpressionTempVariableRef(variable=tmp_variable3, source_ref=source_ref) else: assert tmp_variable3 is None upper_ref1 = upper_ref2 = None use_sliceobj = python_version >= 300 # Second assign the in-place result over the original value. if use_sliceobj: statements += ( StatementAssignmentVariable( variable=tmp_variable4, source=ExpressionSubscriptLookup( expression=ExpressionTempVariableRef( variable=tmp_variable1, source_ref=source_ref), subscript=makeExpressionBuiltinSlice( start=lower_ref2, stop=upper_ref2, step=None, source_ref=source_ref, ), source_ref=source_ref, ), source_ref=source_ref, ), StatementAssignmentVariable( variable=tmp_variable4, source=makeExpressionOperationBinaryInplace( operator=operator, left=ExpressionTempVariableRef(variable=tmp_variable4, source_ref=source_ref), right=expression, source_ref=source_ref, ), source_ref=source_ref, ), StatementAssignmentSubscript( expression=ExpressionTempVariableRef(variable=tmp_variable1, source_ref=source_ref), subscript=makeExpressionBuiltinSlice(start=lower_ref1, stop=upper_ref1, step=None, source_ref=source_ref), source=ExpressionTempVariableRef(variable=tmp_variable4, source_ref=source_ref), source_ref=source_ref, ), ) else: statements += ( StatementAssignmentVariable( variable=tmp_variable4, source=ExpressionSliceLookup( expression=ExpressionTempVariableRef( variable=tmp_variable1, source_ref=source_ref), lower=lower_ref2, upper=upper_ref2, source_ref=source_ref, ), source_ref=source_ref, ), StatementAssignmentVariable( variable=tmp_variable4, source=makeExpressionOperationBinaryInplace( operator=operator, left=ExpressionTempVariableRef(variable=tmp_variable4, source_ref=source_ref), right=expression, source_ref=source_ref, ), source_ref=source_ref, ), StatementAssignmentSlice( expression=ExpressionTempVariableRef(variable=tmp_variable1, source_ref=source_ref), lower=lower_ref1, upper=upper_ref1, source=ExpressionTempVariableRef(variable=tmp_variable4, source_ref=source_ref), source_ref=source_ref, ), ) final_statements.append( StatementReleaseVariable(variable=tmp_variable4, source_ref=source_ref)) return ( copy_to_tmp, makeTryFinallyStatement( provider=provider, tried=statements, final=final_statements, source_ref=source_ref, ), )
def buildDeleteStatementFromDecoded(provider, kind, detail, source_ref): if kind in ("Name", "Name_Exception"): # Note: Name_Exception is a "del" for exception handlers that doesn't # insist on the variable being defined, user code may do it too, and # that will be fine, so make that tolerant. return StatementDelVariableName( provider=provider, variable_name=detail, tolerant=kind == "Name_Exception", source_ref=source_ref, ) elif kind == "Attribute": lookup_source, attribute_name = detail return StatementDelAttribute( expression=lookup_source, attribute_name=mangleName(attribute_name, provider), source_ref=source_ref, ) elif kind == "Subscript": subscribed, subscript = detail return StatementDelSubscript(expression=subscribed, subscript=subscript, source_ref=source_ref) elif kind == "Slice": lookup_source, lower, upper = detail use_sliceobj = python_version >= 300 if use_sliceobj: return StatementDelSubscript( expression=lookup_source, subscript=makeExpressionBuiltinSlice(start=lower, stop=upper, step=None, source_ref=source_ref), source_ref=source_ref, ) else: return StatementDelSlice( expression=lookup_source, lower=lower, upper=upper, source_ref=source_ref, ) elif kind == "Tuple": result = [] for sub_node in detail: result.append( buildDeleteStatementFromDecoded( provider=provider, kind=sub_node[0], detail=sub_node[1], source_ref=source_ref, )) return makeStatementsSequenceOrStatement(statements=result, source_ref=source_ref) else: assert False, (kind, detail, source_ref)
def decodeAssignTarget(provider, node, source_ref, allow_none=False): # Many cases to deal with, because of the different assign targets, # pylint: disable=too-many-branches,too-many-return-statements if node is None and allow_none: return None if type(node) is str: return "Name", mangleName(node, provider) kind = getKind(node) if hasattr(node, "ctx"): assert getKind(node.ctx) in ("Store", "Del") if kind == "Name": return kind, mangleName(node.id, provider) elif kind == "Attribute": return kind, (buildNode(provider, node.value, source_ref), node.attr) elif kind == "Subscript": slice_kind = getKind(node.slice) if slice_kind == "Index": return ( "Subscript", ( buildNode(provider, node.value, source_ref), buildNode(provider, node.slice.value, source_ref), ), ) elif slice_kind == "Slice": lower = buildNode(provider, node.slice.lower, source_ref, True) upper = buildNode(provider, node.slice.upper, source_ref, True) if node.slice.step is not None: step = buildNode(provider, node.slice.step, source_ref) return ( "Subscript", ( buildNode(provider, node.value, source_ref), makeExpressionBuiltinSlice(start=lower, stop=upper, step=step, source_ref=source_ref), ), ) else: return ( "Slice", (buildNode(provider, node.value, source_ref), lower, upper), ) elif slice_kind == "ExtSlice": return ( "Subscript", ( buildNode(provider, node.value, source_ref), buildExtSliceNode(provider, node, source_ref), ), ) elif slice_kind == "Ellipsis": return ( "Subscript", ( buildNode(provider, node.value, source_ref), ExpressionConstantEllipsisRef(source_ref=source_ref), ), ) elif python_version >= 390: return ( "Subscript", ( buildNode(provider, node.value, source_ref), buildNode(provider, node.slice, source_ref), ), ) else: assert False, slice_kind elif kind in ("Tuple", "List"): return ( "Tuple", tuple( decodeAssignTarget( provider=provider, node=sub_node, source_ref=source_ref, allow_none=False, ) for sub_node in node.elts), ) elif kind == "Starred": return ( "Starred", decodeAssignTarget( provider=provider, node=node.value, source_ref=source_ref, allow_none=False, ), ) else: assert False, (source_ref, kind)
def buildAssignmentStatementsFromDecoded(provider, kind, detail, source, source_ref): # This is using many variable names on purpose, so as to give names to the # unpacked detail values, and has many branches due to the many cases # dealt with, pylint: disable=too-many-branches,too-many-locals,too-many-statements if kind == "Name": return StatementAssignmentVariableName( provider=provider, variable_name=detail, source=source, source_ref=source_ref, ) elif kind == "Attribute": lookup_source, attribute_name = detail return StatementAssignmentAttribute( expression=lookup_source, attribute_name=mangleName(attribute_name, provider), source=source, source_ref=source_ref, ) elif kind == "Subscript": subscribed, subscript = detail return StatementAssignmentSubscript( expression=subscribed, subscript=subscript, source=source, source_ref=source_ref, ) elif kind == "Slice": lookup_source, lower, upper = detail # For Python3 there is no slicing operation, this is always done # with subscript using a slice object. For Python2, it is only done # if no "step" is provided. use_sliceobj = python_version >= 300 if use_sliceobj: return StatementAssignmentSubscript( expression=lookup_source, source=source, subscript=makeExpressionBuiltinSlice(start=lower, stop=upper, step=None, source_ref=source_ref), source_ref=source_ref, ) else: return StatementAssignmentSlice( expression=lookup_source, lower=lower, upper=upper, source=source, source_ref=source_ref, ) elif kind == "Tuple": temp_scope = provider.allocateTempScope("tuple_unpack") source_iter_var = provider.allocateTempVariable(temp_scope=temp_scope, name="source_iter") element_vars = [ provider.allocateTempVariable(temp_scope=temp_scope, name="element_%d" % (element_index + 1)) for element_index in range(len(detail)) ] starred_list_var = None starred_index = None statements = [] for element_index, element in enumerate(detail): if element[0] == "Starred": if starred_index is not None: raiseSyntaxError( "two starred expressions in assignment" if python_version < 390 else "multiple starred expressions in assignment", source_ref.atColumnNumber(0), ) starred_index = element_index for element_index, element in enumerate(detail): element_var = element_vars[element_index] if starred_list_var is not None: statements.insert( starred_index + 1, StatementAssignmentVariable( variable=element_var, source=ExpressionListOperationPop( list_arg=ExpressionTempVariableRef( variable=starred_list_var, source_ref=source_ref), source_ref=source_ref, ), source_ref=source_ref, ), ) elif element[0] != "Starred": statements.append( StatementAssignmentVariable( variable=element_var, source=ExpressionSpecialUnpack( value=ExpressionTempVariableRef( variable=source_iter_var, source_ref=source_ref), count=element_index + 1, expected=starred_index or len(detail), starred=starred_index is not None, source_ref=source_ref, ), source_ref=source_ref, )) else: assert starred_index == element_index starred_list_var = element_var statements.append( StatementAssignmentVariable( variable=element_var, source=ExpressionBuiltinList( value=ExpressionTempVariableRef( variable=source_iter_var, source_ref=source_ref), source_ref=source_ref, ), source_ref=source_ref, )) if starred_list_var is None: statements.append( StatementSpecialUnpackCheck( iterator=ExpressionTempVariableRef( variable=source_iter_var, source_ref=source_ref), count=len(detail), source_ref=source_ref, )) else: statements.insert( starred_index + 1, makeStatementConditional( condition=makeComparisonExpression( comparator="Lt", left=ExpressionBuiltinLen( value=ExpressionTempVariableRef( variable=starred_list_var, source_ref=source_ref), source_ref=source_ref, ), right=makeConstantRefNode( constant=len(statements) - starred_index - 1, source_ref=source_ref, ), source_ref=source_ref, ), yes_branch=makeRaiseExceptionExpressionFromTemplate( exception_type="ValueError", template="""\ not enough values to unpack (expected at least %d, got %%d)""" % (len(statements) - 1), template_args=makeBinaryOperationNode( operator="Add", left=ExpressionBuiltinLen( value=ExpressionTempVariableRef( variable=starred_list_var, source_ref=source_ref), source_ref=source_ref, ), right=makeConstantRefNode(constant=starred_index, source_ref=source_ref), source_ref=source_ref, ), source_ref=source_ref, ).asStatement(), no_branch=None, source_ref=source_ref, ), ) if python_version >= 370: iter_creation_class = ExpressionBuiltinIterForUnpack else: iter_creation_class = ExpressionBuiltinIter1 statements = [ StatementAssignmentVariable( variable=source_iter_var, source=iter_creation_class(value=source, source_ref=source_ref), source_ref=source_ref, ), makeTryFinallyStatement( provider=provider, tried=statements, final=(StatementReleaseVariable(variable=source_iter_var, source_ref=source_ref), ), source_ref=source_ref, ), ] # When all is done, copy over to the actual assignment targets, starred # or not makes no difference here anymore. for element_index, element in enumerate(detail): if element[0] == "Starred": element = element[1] element_var = element_vars[element_index] statements.append( buildAssignmentStatementsFromDecoded( provider=provider, kind=element[0], detail=element[1], source=ExpressionTempVariableRef(variable=element_var, source_ref=source_ref), source_ref=source_ref, )) # Need to release temporary variables right after successful # usage. statements.append( StatementDelVariable(variable=element_var, tolerant=True, source_ref=source_ref)) final_statements = [] for element_var in element_vars: final_statements.append( StatementReleaseVariable(variable=element_var, source_ref=source_ref)) return makeTryFinallyStatement( provider=provider, tried=statements, final=final_statements, source_ref=source_ref, ) elif kind == "Starred": raiseSyntaxError( "starred assignment target must be in a list or tuple", source_ref.atColumnNumber(0), ) else: assert False, (kind, source_ref, detail)
def buildSubscriptNode(provider, node, source_ref): # Subscript expression nodes, various types are dispatched here. assert getKind(node.ctx) == "Load", source_ref # The subscript "[]" operator is one of many different things. This is # expressed by this kind, there are "slice" lookups (two values, even if one # is using default), and then "index" lookups. The form with three argument # is really an "index" lookup, with a slice object. And the "..." lookup is # also an index loop-up, with it as the argument. So this splits things into # two different operations, "subscript" with a single "subscript" object. Or # a slice lookup with a lower and higher boundary. These things should # behave similar, but they are different slots. kind = getKind(node.slice) if kind == "Index": return ExpressionSubscriptLookup( expression=buildNode(provider, node.value, source_ref), subscript=buildNode(provider, node.slice.value, source_ref), source_ref=source_ref, ) elif kind == "Slice": lower = buildNode( provider=provider, node=node.slice.lower, source_ref=source_ref, allow_none=True, ) upper = buildNode( provider=provider, node=node.slice.upper, source_ref=source_ref, allow_none=True, ) step = buildNode( provider=provider, node=node.slice.step, source_ref=source_ref, allow_none=True, ) # For Python3 there is no slicing operation, this is always done # with subscript using a slice object. For Python2, it is only done # if no "step" is provided. use_sliceobj = step is not None or python_version >= 300 if use_sliceobj: return ExpressionSubscriptLookup( expression=buildNode(provider, node.value, source_ref), subscript=makeExpressionBuiltinSlice(start=lower, stop=upper, step=step, source_ref=source_ref), source_ref=source_ref, ) else: return ExpressionSliceLookup( expression=buildNode(provider, node.value, source_ref), lower=lower, upper=upper, source_ref=source_ref, ) elif kind == "ExtSlice": return ExpressionSubscriptLookup( expression=buildNode(provider, node.value, source_ref), subscript=buildExtSliceNode(provider, node, source_ref), source_ref=source_ref, ) elif kind == "Ellipsis": return ExpressionSubscriptLookup( expression=buildNode(provider, node.value, source_ref), subscript=ExpressionConstantEllipsisRef(source_ref=source_ref), source_ref=source_ref, ) elif python_version >= 390: return ExpressionSubscriptLookup( expression=buildNode(provider, node.value, source_ref), subscript=buildNode(provider, node.slice, source_ref), source_ref=source_ref, ) else: assert False, kind