def cleanupSlices(a):
"""Remove any slice shenanigans, because Python lets you include unneccessary values"""
if not isinstance(a, ast.AST):
return a
if type(a) == ast.Subscript:
if type(a.slice) == ast.Slice:
# Lower defaults to 0
if a.slice.lower != None and type(a.slice.lower) == ast.Num and a.slice.lower.n == 0:
a.slice.lower = None
# Upper defaults to len(value)
if a.slice.upper != None and type(a.slice.upper) == ast.Call and \
type(a.slice.upper.func) == ast.Name and a.slice.upper.func.id == "len":
if compareASTs(a.value, a.slice.upper.args[0], checkEquality=True) == 0:
a.slice.upper = None
# Step defaults to 1
if a.slice.step != None and type(a.slice.step) == ast.Num and a.slice.step.n == 1:
a.slice.step = None
return applyToChildren(a, cleanupSlices)
python类Slice()的实例源码
def visit_Slice(self, node):
"""
Slice(expr? lower, expr? upper, expr? step)
"""
if node.lower and node.upper and node.step:
""" <Python> [8, 9, 10, 11, 12, 13, 14][1:6:2]
<Ruby> [8, 9, 10, 11, 12, 13, 14][1...6].each_slice(2).map(&:first) """
return "%s...%s,each_slice(%s).map(&:first)" % (self.visit(node.lower),
self.visit(node.upper), self.visit(node.step))
if node.lower and node.upper:
return "%s...%s" % (self.visit(node.lower),
self.visit(node.upper))
if node.upper and not node.step:
return "0...%s" % (self.visit(node.upper))
if node.lower and not node.step:
return "%s..-1" % (self.visit(node.lower))
if not node.lower and not node.upper and not node.step:
return "0..-1"
raise NotImplementedError("Slice")
def visit_Subscript(self, node):
self._is_string_symbol = False
name = self.visit(node.value)
if isinstance(node.slice, (ast.Index)):
for arg in self._function_args:
if arg == ("**%s" % name):
self._is_string_symbol = True
index = self.visit(node.slice)
self._is_string_symbol = False
return "%s[%s]" % (name, index)
#return "%s%s" % (name, index)
else:
# ast.Slice
index = self.visit(node.slice)
if ',' in index:
""" [See visit_Slice]
<Python> [8, 9, 10, 11, 12, 13, 14][1:6:2]
<Ruby> [8, 9, 10, 11, 12, 13, 14][1...6].each_slice(2).map(&:first)
"""
indexs = index.split(',')
return "%s[%s].%s" % (name, indexs[0], indexs[1])
else:
return "%s[%s]" % (name, index)
def slicev(self, node):
if isinstance(node, ast.Slice):
if node.lower:
self.visit(node.lower)
if node.upper:
self.visit(node.upper)
if node.step:
self.visit(node.step)
elif isinstance(node, ast.ExtSlice):
if node.dims:
for d in node.dims:
self.visit(d)
else:
self.visit(node.value)
# operator = Add | Sub | Mult | MatMult | Div | Mod | Pow | LShift | RShift | BitOr | BitXor | BitAnd | FloorDiv
def test_subscript(self):
sub = ast.Subscript(ast.Name("x", ast.Store()), ast.Index(ast.Num(3)),
ast.Load())
self.expr(sub, "must have Load context")
x = ast.Name("x", ast.Load())
sub = ast.Subscript(x, ast.Index(ast.Name("y", ast.Store())),
ast.Load())
self.expr(sub, "must have Load context")
s = ast.Name("x", ast.Store())
for args in (s, None, None), (None, s, None), (None, None, s):
sl = ast.Slice(*args)
self.expr(ast.Subscript(x, sl, ast.Load()),
"must have Load context")
sl = ast.ExtSlice([])
self.expr(ast.Subscript(x, sl, ast.Load()), "empty dims on ExtSlice")
sl = ast.ExtSlice([ast.Index(s)])
self.expr(ast.Subscript(x, sl, ast.Load()), "must have Load context")
def parse_array_slice_py_ast(array_node):
if hasattr(array_node.slice, 'value'):
getitem_tuple = array_node.slice.value
elif hasattr(array_node.slice, 'dims'):
getitem_tuple = array_node.slice.dims
elif isinstance(array_node.slice, ast.Slice):
getitem_tuple = array_node.slice
if hasattr(getitem_tuple, 'elts'):
getitem_tuple = getitem_tuple.elts
if isinstance(getitem_tuple, ast.Name) or isinstance(getitem_tuple, ast.Slice) or isinstance(getitem_tuple, ast.Num):
getitem_tuple = [getitem_tuple]
try:
getitem_strs = [py_ast.dump_ast(x) for x in getitem_tuple]
except:
getitem_strs = [py_ast.dump_ast(x) for x in getitem_tuple.elts]
return (getitem_tuple, getitem_strs)
def test_subscript(self):
sub = ast.Subscript(ast.Name("x", ast.Store()), ast.Index(ast.Num(3)),
ast.Load())
self.expr(sub, "must have Load context")
x = ast.Name("x", ast.Load())
sub = ast.Subscript(x, ast.Index(ast.Name("y", ast.Store())),
ast.Load())
self.expr(sub, "must have Load context")
s = ast.Name("x", ast.Store())
for args in (s, None, None), (None, s, None), (None, None, s):
sl = ast.Slice(*args)
self.expr(ast.Subscript(x, sl, ast.Load()),
"must have Load context")
sl = ast.ExtSlice([])
self.expr(ast.Subscript(x, sl, ast.Load()), "empty dims on ExtSlice")
sl = ast.ExtSlice([ast.Index(s)])
self.expr(ast.Subscript(x, sl, ast.Load()), "must have Load context")
def test_subscript(self):
sub = ast.Subscript(ast.Name("x", ast.Store()), ast.Index(ast.Num(3)),
ast.Load())
self.expr(sub, "must have Load context")
x = ast.Name("x", ast.Load())
sub = ast.Subscript(x, ast.Index(ast.Name("y", ast.Store())),
ast.Load())
self.expr(sub, "must have Load context")
s = ast.Name("x", ast.Store())
for args in (s, None, None), (None, s, None), (None, None, s):
sl = ast.Slice(*args)
self.expr(ast.Subscript(x, sl, ast.Load()),
"must have Load context")
sl = ast.ExtSlice([])
self.expr(ast.Subscript(x, sl, ast.Load()), "empty dims on ExtSlice")
sl = ast.ExtSlice([ast.Index(s)])
self.expr(ast.Subscript(x, sl, ast.Load()), "must have Load context")
def syn_Subscript(self, ctx, e):
slice_ = e.slice
if isinstance(slice_, ast.Ellipsis):
raise _errors.TyError("stringing slice cannot be an Ellipsis.", e)
elif isinstance(slice_, ast.ExtSlice):
raise _errors.TyError("stringing slice can only have one dimension.", e)
elif isinstance(slice_, ast.Index):
ctx.ana(slice_.value, _numeric.num)
else: # if isinstance(slice_, ast.Slice):
lower, upper, step = slice_.lower, slice_.upper, slice_.step
if lower is not None:
ctx.ana(lower, _numeric.num)
if upper is not None:
ctx.ana(upper, _numeric.num)
if not _is_None(step):
ctx.ana(step, _numeric.num)
return self
def _get_pat_and_asc(ctx, binding):
if isinstance(binding, ast.Subscript):
value = binding.value
if isinstance(value, ast.Name) and value.id == 'let':
slice = binding.slice
if isinstance(slice, ast.Index):
return (slice.value, None)
elif isinstance(slice, ast.Slice):
lower, upper, step = slice.lower, slice.upper, slice.step
if lower is not None and upper is not None and step is None:
asc = typy._process_asc_ast(ctx, upper)
return lower, asc
else:
raise _errors.TyError("Invalid ascription format.", slice)
else:
raise _errors.TyError("Invalid ascription format.", slice)
else:
raise _errors.TyError("Invalid with format.", value)
else:
raise _errors.TyError("Invalid with format.", binding)
def _is_ascribed_match_head(cls, e):
if isinstance(e, ast.Subscript):
value = e.value
if cls._is_unascribed_match_head(value):
slice = e.slice
if isinstance(slice, ast.Slice):
lower, upper, step = slice.lower, slice.upper, slice.step
if lower is None and upper is not None and step is None:
e.is_match_head = True
e.scrutinee = value.scrutinee
e.asc_ast = upper
return True
else:
raise _errors.TyError("Invalid ascription format.", slice)
else:
raise _errors.TyError("Invalid ascription format.", slice)
return False
def visit_Subscript(self, node, types=None, typ=None):
pp = ProgramPoint(node.lineno, node.col_offset)
if isinstance(node.slice, ast.Index):
target = self.visit(node.value, types, typ)
key = self.visit(node.slice.value, types, typ)
return SubscriptionAccess(pp, target, key)
elif isinstance(node.slice, ast.Slice):
return SliceStmt(pp, self._ensure_stmt_visit(node.value, pp, *args, **kwargs),
self._ensure_stmt_visit(node.slice.lower, pp, *args, **kwargs),
self._ensure_stmt_visit(node.slice.step, pp, *args, **kwargs) if node.slice.step else None,
self._ensure_stmt_visit(node.slice.upper, pp, *args, **kwargs))
else:
raise NotImplementedError(f"The statement {str(type(node.slice))} is not yet translatable to CFG!")
def noneSpecialFunction(cv):
"""If the old type is 'None' (which won't show up in the original), move up in the AST to get the metadata"""
if (not isinstance(cv, AddVector)) and cv.oldSubtree == None:
cvCopy = cv.deepcopy()
if cv.path[0] == ('value', 'Return'):
cv.oldSubtree = deepcopy(cvCopy.traverseTree(cv.start))
cv.newSubtree = ast.Return(cv.newSubtree)
cv.path = cv.path[1:]
elif cv.path[0] == ('value', 'Name Constant'):
cv.oldSubtree = deepcopy(cvCopy.traverseTree(cv.start))
cv.newSubtree = ast.NameConstant(cv.newSubtree)
cv.path = cv.path[1:]
elif cv.path[0] in [('lower', 'Slice'), ('upper', 'Slice'), ('step', 'Slice')]:
tmpNew = cv.newSubtree
cvCopy = cv.deepcopy()
cv.oldSubtree = deepcopy(cvCopy.traverseTree(cv.start))
cv.newSubtree = deepcopy(cv.oldSubtree) # use the same slice
if cv.path[0][0] == 'lower':
cv.newSubtree.lower = tmpNew
elif cv.path[0][0] == 'upper':
cv.newSubtree.upper = tmpNew
else:
cv.newSubtree.step = tmpNew
cv.path = cv.path[1:] # get rid of None and the val
else:
log("Individualize\tmapEdit\tMissing option in None special case 1: " + str(cv.path[0]), "bug")
elif cv.oldSubtree == "None":
cv.path = cv.path[1:] # get rid of None and the id
cvCopy = cv.deepcopy()
cv.oldSubtree = deepcopy(cvCopy.traverseTree(cv.start))
if cv.path[0] == ('value', 'Return'):
cv.newSubtree = ast.Return(ast.Name(cv.newSubtree, ast.Load()))
else:
log("Individualize\tmapEdit\tMissing option in None special case 2: " + str(cv.path[0]), "bug")
cv.path = cv.path[1:]
return cv
def astFormat(x, gid=None):
"""Given a value, turn it into an AST if it's a constant; otherwise, leave it alone."""
if type(x) in [int, float, complex]:
return ast.Num(x)
elif type(x) == bool or x == None:
return ast.NameConstant(x)
elif type(x) == type:
types = { bool : "bool", int : "int", float : "float",
complex : "complex", str : "str", bytes : "bytes", unicode : "unicode",
list : "list", tuple : "tuple", dict : "dict" }
return ast.Name(types[x], ast.Load())
elif type(x) == str: # str or unicode
return ast.Str(x)
elif type(x) == bytes:
return ast.Bytes(x)
elif type(x) == list:
elts = [astFormat(val) for val in x]
return ast.List(elts, ast.Load())
elif type(x) == dict:
keys = []
vals = []
for key in x:
keys.append(astFormat(key))
vals.append(astFormat(x[key]))
return ast.Dict(keys, vals)
elif type(x) == tuple:
elts = [astFormat(val) for val in x]
return ast.Tuple(elts, ast.Load())
elif type(x) == set:
elts = [astFormat(val) for val in x]
if len(elts) == 0: # needs to be a call instead
return ast.Call(ast.Name("set", ast.Load()), [], [])
else:
return ast.Set(elts)
elif type(x) == slice:
return ast.Slice(astFormat(x.start), astFormat(x.stop), astFormat(x.step))
elif isinstance(x, ast.AST):
return x # Do not change if it's not constant!
else:
log("astTools\tastFormat\t" + str(type(x)) + "," + str(x),"bug")
return None
def slicev(self, node):
if isinstance(node, ast.Slice):
if node.lower:
self.visit(node.lower)
if node.upper:
self.visit(node.upper)
if node.step:
self.visit(node.step)
elif isinstance(node, ast.ExtSlice):
if node.dims:
for d in node.dims:
self.visit(d)
else:
self.visit(node.value)
def visit_Subscript(self, node):
if not self.config.constant_folding:
return
if isinstance(node.slice, ast.Slice):
new_node = self.subscript_slice(node)
if new_node is not None:
return new_node
elif isinstance(node.slice, ast.Index):
new_node = self.subscript_index(node)
if new_node is not None:
return new_node
def make_unconcat_slice(axis, lower, upper):
dims = []
for i in range(axis):
dims.append(ast.Slice(lower=None, upper=None, step=None))
dims.append(ast.Slice(lower=lower, upper=upper, step=None))
dims.append(ast.Ellipsis())
ext_slice = ast.ExtSlice(dims=dims)
return ext_slice
def __init__(self, operators=None, functions=None, names=None):
"""
Create the evaluator instance. Set up valid operators (+,-, etc)
functions (add, random, get_val, whatever) and names. """
if not operators:
operators = DEFAULT_OPERATORS
if not functions:
functions = DEFAULT_FUNCTIONS
if not names:
names = DEFAULT_NAMES
self.operators = operators
self.functions = functions
self.names = names
self.nodes = {
ast.Num: self._eval_num,
ast.Str: self._eval_str,
ast.Name: self._eval_name,
ast.UnaryOp: self._eval_unaryop,
ast.BinOp: self._eval_binop,
ast.BoolOp: self._eval_boolop,
ast.Compare: self._eval_compare,
ast.IfExp: self._eval_ifexp,
ast.Call: self._eval_call,
ast.keyword: self._eval_keyword,
ast.Subscript: self._eval_subscript,
ast.Attribute: self._eval_attribute,
ast.Index: self._eval_index,
ast.Slice: self._eval_slice,
}
# py3k stuff:
if hasattr(ast, 'NameConstant'):
self.nodes[ast.NameConstant] = self._eval_nameconstant
elif isinstance(self.names, dict) and "None" not in self.names:
self.names["None"] = None
def visit_Subscript(self, node):
pp = ProgramPoint(node.lineno, node.col_offset)
if isinstance(node.slice, ast.Index):
return IndexStmt(pp, self._ensure_stmt_visit(node.value, pp), self._ensure_stmt_visit(node.slice.value, pp))
elif isinstance(node.slice, ast.Slice):
return SliceStmt(pp, self._ensure_stmt_visit(node.value, pp),
self._ensure_stmt_visit(node.slice.lower, pp),
self._ensure_stmt_visit(node.slice.step, pp) if node.slice.step else None,
self._ensure_stmt_visit(node.slice.upper, pp))
else:
raise NotImplementedError(f"The statement {str(type(node.slice))} is not yet translatable to CFG!")
def mutate_Slice_remove_lower(self, node):
if not node.lower:
raise MutationResign()
return ast.Slice(lower=None, upper=node.upper, step=node.step)
def mutate_Slice_remove_upper(self, node):
if not node.upper:
raise MutationResign()
return ast.Slice(lower=node.lower, upper=None, step=node.step)
def mutate_Slice_remove_step(self, node):
if not node.step:
raise MutationResign()
return ast.Slice(lower=node.lower, upper=node.upper, step=None)
def Subscript_slice(t, x):
if isinstance(x.slice, ast.Slice):
slice = x.slice
t.unsupported(x, slice.step and slice.step != 1, "Slice step is unsupported")
args = []
if slice.lower:
args.append(slice.lower)
else:
args.append(JSNum(0))
if slice.upper:
args.append(slice.upper)
return JSCall(JSAttribute(x.value, 'slice'), args)
def handle_Subscript(state, node, ctx):
state, value_result = _peval_expression(state, node.value, ctx)
state, slice_result = _peval_expression(state, node.slice, ctx)
if is_known_value(value_result) and is_known_value(slice_result):
success, elem = try_call_method(
value_result.value, '__getitem__', args=(slice_result.value,))
if success:
return state, KnownValue(value=elem)
state, new_value = map_reify(state, value_result)
state, new_slice = map_reify(state, slice_result)
if type(new_slice) not in (ast.Index, ast.Slice, ast.ExtSlice):
new_slice = ast.Index(value=new_slice)
return state, replace_fields(node, value=new_value, slice=new_slice)
def _is_None(node):
#
# for some reason,
#
# > ast.dump(ast.parse(x[0:1:]))
# Module(body=[Expr(value=Subscript(value=Name(id='x', ctx=Load()),
# slice=Slice(lower=Num(n=0), upper=None,
# step=Name(id='None', ctx=Load())), ctx=Load()))])
#
# notice that the step value is not 'None' but the Name that contains 'None'.
# Need to special case this.
#
return node is None or (isinstance(node, ast.Name) and node.id == 'None')
def visit_Delete(self, node):
"""
Delete(expr* targets)
"""
id = ''
num = ''
key = ''
slice = ''
attr = ''
for stmt in node.targets:
if isinstance(stmt, (ast.Name)):
id = self.visit(stmt)
elif isinstance(stmt, (ast.Subscript)):
if isinstance(stmt.value, (ast.Name)):
id = self.visit(stmt.value)
if isinstance(stmt.slice, (ast.Index)):
if isinstance(stmt.slice.value, (ast.Str)):
key = self.visit(stmt.slice)
if isinstance(stmt.slice.value, (ast.Num)):
num = self.visit(stmt.slice)
if isinstance(stmt.slice, (ast.Slice)):
slice = self.visit(stmt.slice)
elif isinstance(stmt, (ast.Attribute)):
if isinstance(stmt.value, (ast.Name)):
id = self.visit(stmt.value)
attr = stmt.attr
if num != '':
""" <Python> del foo[0]
<Ruby> foo.delete_at[0] """
self.write("%s.delete_at(%s)" % (id, num))
elif key != '':
""" <Python> del foo['hoge']
<Ruby> foo.delete['hoge'] """
self.write("%s.delete(%s)" % (id, key))
elif slice != '':
""" <Python> del foo[1:3]
<Ruby> foo.slise!(1...3) """
self.write("%s.slice!(%s)" % (id, slice))
elif attr != '':
""" <Python> del foo.bar
<Ruby> foo.instance_eval { remove_instance_variable(:@bar) } """
self.write("%s.instance_eval { remove_instance_variable(:@%s) }" % (id, attr))
else:
""" <Python> del foo
<Ruby> foo = nil """
self.write("%s = nil" % (id))
def visit_Assign(self, node):
"""
Assign(expr* targets, expr value)
"""
assert len(node.targets) == 1
target = node.targets[0]
#~ if self._class_name:
#~ target = self._class_name + '.' + target
# ast.Tuple, ast.List, ast.*
value = self.visit(node.value)
#if isinstance(node.value, (ast.Tuple, ast.List)):
# value = "[%s]" % self.visit(node.value)
#else:
# value = self.visit(node.value)
if isinstance(target, (ast.Tuple, ast.List)):
# multiassign.py
""" x, y, z = [1, 2, 3] """
x = [self.visit(t) for t in target.elts]
self.write("%s = %s" % (','.join(x), value))
elif isinstance(target, ast.Subscript) and isinstance(target.slice, ast.Index):
# found index assignment # a[0] = xx
#self.write("%s%s = %s" % (self.visit(target.value), # a[0] = xx
name = self.visit(target.value)
for arg in self._function_args:
if arg == ("**%s" % name):
self._is_string_symbol = True
self.write("%s[%s] = %s" % (name, self.visit(target.slice), value))
self._is_string_symbol = False
elif isinstance(target, ast.Subscript) and isinstance(target.slice, ast.Slice):
# found slice assignmnet
self.write("%s[%s...%s] = %s" % (self.visit(target.value),
self.visit(target.slice.lower), self.visit(target.slice.upper),
value))
else:
if isinstance(target, ast.Name):
var = self.visit(target)
if not (var in self._scope):
self._scope.append(var)
if isinstance(node.value, ast.Call):
if isinstance(node.value.func, ast.Name):
if node.value.func.id in self._class_names:
self._classes_self_functions_args[var] = self._classes_self_functions_args[node.value.func.id]
# set lambda functions
if isinstance(node.value, ast.Lambda):
self._lambda_functions.append(var)
self.write("%s = %s" % (var, value))
elif isinstance(target, ast.Attribute):
var = self.visit(target)
""" [instance variable] :
<Python> self.foo = hoge
<Ruby> @foo = hoge
"""
if var == 'self':
self.write("@%s = %s" % (str(target.attr), value))
self._class_self_variables.append(str(target.attr))
else:
self.write("%s = %s" % (var, value))
else:
raise RubyError("Unsupported assignment type")