def get_target(self, target):
if isinstance(target, ast.Subscript) and self.context.in_for_loop: # Check if we are doing assignment of an iteration loop.
raise_exception = False
if isinstance(target.value, ast.Attribute):
list_name = "%s.%s" % (target.value.value.id, target.value.attr)
if list_name in self.context.in_for_loop:
raise_exception = True
if isinstance(target.value, ast.Name) and \
target.value.id in self.context.in_for_loop:
list_name = target.value.id
raise_exception = True
if raise_exception:
raise StructureException("Altering list '%s' which is being iterated!" % list_name, self.stmt)
if isinstance(target, ast.Name) and target.id in self.context.forvars:
raise StructureException("Altering iterator '%s' which is in use!" % target.id, self.stmt)
target = Expr.parse_variable_location(target, self.context)
if target.location == 'storage' and self.context.is_constant:
raise ConstancyViolationException("Cannot modify storage inside a constant function: %s" % target.annotation)
if not target.mutable:
raise ConstancyViolationException("Cannot modify function argument: %s" % target.annotation)
return target
python类Subscript()的实例源码
def __init__(self, expr, context):
self.expr = expr
self.context = context
self.expr_table = {
LLLnode: self.get_expr,
ast.Num: self.number,
ast.Str: self.string,
ast.NameConstant: self.constants,
ast.Name: self.variables,
ast.Attribute: self.attribute,
ast.Subscript: self.subscript,
ast.BinOp: self.arithmetic,
ast.Compare: self.compare,
ast.BoolOp: self.boolean_operations,
ast.UnaryOp: self.unary_operations,
ast.Call: self.call,
ast.List: self.list_literals,
ast.Dict: self.struct_literals,
ast.Tuple: self.tuple_literals,
}
expr_type = self.expr.__class__
if expr_type in self.expr_table:
self.lll_node = self.expr_table[expr_type]()
else:
raise Exception("Unsupported operator: %r" % ast.dump(self.expr))
def resolve_type_annotation(annotation):
"""Type annotation resolution."""
if isinstance(annotation, ast.Name):
if annotation.id == 'bool':
return BooleanLyraType()
elif annotation.id == 'int':
return IntegerLyraType()
elif annotation.id == 'float':
return FloatLyraType()
elif annotation.id == 'str':
return StringLyraType()
if isinstance(annotation, ast.Subscript):
if annotation.value.id == 'List':
value = resolve_type_annotation(annotation.slice.value)
return ListLyraType(value)
raise NotImplementedError(f"Type annotation {annotation} is not yet supported!")
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)
def get_call_names_helper(node, result):
"""Recursively finds all function names."""
if isinstance(node, ast.Name):
if node.id not in BLACK_LISTED_CALL_NAMES:
result.append(node.id)
return result
elif isinstance(node, ast.Call):
return result
elif isinstance(node, ast.Subscript):
return get_call_names_helper(node.value, result)
elif isinstance(node, ast.Str):
result.append(node.s)
return result
else:
result.append(node.attr)
return get_call_names_helper(node.value, result)
def get_attribute_name(node, import_aliases=None):
import_aliases = import_aliases or {}
if not isinstance(node, ast.Attribute):
raise ValueError('node must be an instance of ast.Attribute')
base = node.attr
name = ''
node = node.value
while isinstance(node, ast.Attribute):
name = node.attr + '.' + name
node = node.value
if isinstance(node, (ast.Call, ast.Subscript)):
return None
if not isinstance(node, ast.Name):
raise ValueError('could not resolve node for attribute')
name = (node.id + '.' + name)[:-1]
return import_aliases.get(name, name) + '.' + base
def _solve(self):
import_aliases = (self.context._context['import_aliases'] if self.context else None)
cursor_node = self.tainted_node.parent
while cursor_node != self.target_node:
test_node = cursor_node
cursor_node = cursor_node.parent
if isinstance(test_node, ast.BinOp):
continue
elif isinstance(test_node, ast.Call):
if isinstance(test_node.func, ast.Attribute) and isinstance(test_node.func.value, ast.Str) and test_node.func.attr == 'format':
return True
function = s_utils.get_call_function(test_node, import_aliases=import_aliases)
if function in ('os.path.abspath', 'os.path.join', 'str'):
continue
elif function == 'os.path.relpath' and s_utils.node_is_child_of_parent(test_node.args[0], self.tainted_node):
continue
elif isinstance(test_node, ast.Subscript):
continue
return False
return True
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 _get_ast_name_node(node):
while True:
# only accept '*var'
if isinstance(node, ast.Starred):
# '*var = value' => 'var'
node = node.value
elif isinstance(node, ast.Subscript):
# 'obj[slice] = value' => 'obj'
node = node.value
elif isinstance(node, ast.Attribute):
# 'obj.attr = value' => 'obj'
node = node.value
elif (isinstance(node, ast.Call)
and isinstance(node.func, ast.Attribute)):
# 'obj.method().attr = value' => 'obj.method'
node = node.func
else:
return node
def make_subscript(varname, idx, ctx=None, lineno=0, col_offset=0):
ctx = ctx or ast.Load()
return ast.Subscript(
value = ast.Name(
id = varname,
ctx = ast.Load(),
lineno = lineno,
col_offset = col_offset,
),
slice = ast.Index(
value = ast.Num(
n = idx,
lineno = lineno,
col_offset = col_offset,
),
lineno = lineno,
col_offset = col_offset,
),
ctx = ctx,
lineno = lineno,
col_offset = col_offset,
)
def parse_factor_expression(call_or_name_node):
if isinstance(call_or_name_node, ast.Name): # a.set_to(b) is shorthand for a.set_to(Copy(b))
name_node = call_or_name_node
return None, [name_node.id]
elif isinstance(call_or_name_node, ast.Call): # a.set_to(f(b))
call_node = call_or_name_node
return call_node.func.id, [name_or_number(node) for node in call_node.args]
elif isinstance(call_or_name_node, ast.Num): # a.observe_value(0)
num_node = call_or_name_node
return None, [int(num_node.n)]
elif isinstance(call_or_name_node, ast.Subscript):
print ast.dump(call_or_name_node)
pdb.set_trace()
else:
assert False, "Can't parse factor " + ast.dump(call_or_name_node)
def var_to_dvar(var_node):
if isinstance(var_node, ast.Name):
name = var_node
new_name = ast.Name()
new_id = "d%s" % name.id
new_name.id = new_id
return new_name
elif isinstance(var_node, ast.Subscript):
subscript = var_node
name = subscript.value
new_name = ast.Name(id="d%s" % name.id)
new_subscript = ast.Subscript(value=new_name, slice=subscript.slice)
return new_subscript
else:
print "Error: don't know how to dvar a %s" % ast.dump(var_node)
print r.pretty(var_node)
assert False
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 _infer_assignment_target(target, context, value_type, solver):
"""Infer the type of a target in an assignment
Attributes:
target: the target whose type is to be inferred
context: the current context level
value_type: the type of the value assigned to the target
Target cases:
- Variable name. Ex: x = 1
- Tuple. Ex: a, b = 1, "string"
- List. Ex: [a, b] = [1, "string"]
- Subscript. Ex: x[0] = 1, x[1 : 2] = [2,3], x["key"] = value
- Compound: Ex: a, b[0], [c, d], e["key"] = 1, 2.0, [True, False], "value"
"""
target_type = _infer_one_target(target, context, solver)
solver.add(axioms.assignment(target_type, value_type, solver.z3_types),
fail_message="Assignment in line {}".format(target.lineno))
# Adding weight of 2 to give the assignment soft constraint a higher priority over others.
solver.optimize.add_soft(target_type == value_type, weight=2)
def _delete_element(target, context, lineno, solver):
"""Remove (if needed) a target from the context
Cases:
- del var_name: remove its type mapping from the context directly.
- del subscript:
* Tuple/String --> Immutable. Raise exception.
* List/Dict --> Do nothing to the context.
"""
if isinstance(target, (ast.Tuple, ast.List)): # Multiple deletions
for elem in target.elts:
_delete_element(elem, context, lineno, solver)
elif isinstance(target, ast.Name):
context.delete_type(target.id)
elif isinstance(target, ast.Subscript):
expr.infer(target, context, solver)
indexed_type = expr.infer(target.value, context, solver)
solver.add(axioms.delete_subscript(indexed_type, solver.z3_types),
fail_message="Deletion in line {}".format(lineno))
elif isinstance(target, ast.Attribute):
raise NotImplementedError("Attribute deletion is not supported.")
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 unpack_trailer(atom, power_star):
out = atom
for trailer in power_star:
if isinstance(trailer, FcnCall):
trailer.function = out
inherit_lineno(trailer, out)
out = trailer
elif isinstance(trailer, Attribute):
trailer.value = out
inherit_lineno(trailer, out, alt=False)
if hasattr(out, "alt"):
trailer.alt = out.alt
out = trailer
elif isinstance(trailer, Subscript):
trailer.value = out
inherit_lineno(trailer, out)
out = trailer
else:
assert False
return out
def Call_new(t, x):
"""Translate ``Foo(...)`` to ``new Foo(...)`` if function name starts
with a capital letter.
"""
def getNameString(x):
if isinstance(x, ast.Name):
return x.id
elif isinstance(x, ast.Attribute):
return str(x.attr)
elif isinstance(x, ast.Subscript):
if isinstance(x.slice, ast.Index):
return str(x.slice.value)
NAME_STRING = getNameString(x.func)
if (NAME_STRING and re.search(r'^[A-Z]', NAME_STRING)):
# TODO: generalize args mangling and apply here
# assert not any([x.keywords, x.starargs, x.kwargs])
subj = x
elif isinstance(x.func, ast.Name) and x.func.id == 'new':
subj = x.args[0]
else:
subj = None
if subj:
return Call_default(t, subj, operator='new ')
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 translate_pat_Call_constructor(self, ctx, pat, scrutinee_trans):
lbl = pat.func.id
tag_loc = ast.Subscript(
value=scrutinee_trans,
slice=ast.Index(value=ast.Num(n=0)))
lbl_condition = ast.Compare(
left=tag_loc,
ops=[ast.Eq()],
comparators=[ast.Str(s=lbl)])
arg = pat.args[0]
arg_scrutinee = ast.Subscript(
value=scrutinee_trans,
slice=ast.Index(value=ast.Num(n=1)))
arg_condition, binding_translations = ctx.translate_pat(arg, arg_scrutinee)
condition = ast.BoolOp(
op=ast.And(),
values=[lbl_condition, arg_condition])
return condition, binding_translations
def get_object_name(obj):
"""
Return the name of a given object
"""
name_dispatch = {
ast.Name: "id",
ast.Attribute: "attr",
ast.Call: "func",
ast.FunctionDef: "name",
ast.ClassDef: "name",
ast.Subscript: "value",
}
# This is a new ast type in Python 3
if hasattr(ast, "arg"):
name_dispatch[ast.arg] = "arg"
while not isinstance(obj, str):
assert type(obj) in name_dispatch
obj = getattr(obj, name_dispatch[type(obj)])
return obj
def get_names(self, node, result):
"""Recursively finds all names."""
if isinstance(node, ast.Name):
return node.id + result
elif isinstance(node, ast.Subscript):
return result
else:
return self.get_names(node.value, result + '.' + node.attr)
def get_call_names_helper(node, result):
"""Recursively finds all function names."""
if isinstance(node, ast.Name):
result.append(node.id)
return result
elif isinstance(node, ast.Call):
return result
elif isinstance(node, ast.Subscript):
return result
elif isinstance(node, ast.Str):
result.append(node.s)
return result
else:
result.append(node.attr)
return get_call_names_helper(node.value, result)
def gatherAssignedVars(targets):
"""Take a list of assigned variables and extract the names/subscripts/attributes"""
if type(targets) != list:
targets = [targets]
newTargets = []
for target in targets:
if type(target) in [ast.Tuple, ast.List]:
newTargets += gatherAssignedVars(target.elts)
elif type(target) in [ast.Name, ast.Subscript, ast.Attribute]:
newTargets.append(target)
else:
log("astTools\tgatherAssignedVars\tWeird Assign Type: " + str(type(target)),"bug")
return newTargets
def get_names(self, node, result):
"""Recursively finds all names."""
if isinstance(node, ast.Name):
return node.id + result
elif isinstance(node, ast.Subscript):
return result
else:
return self.get_names(node.value, result + '.' + node.attr)
def __getitem__(self, key):
keyname, key, constants = _normalize_arg(key, self._constants)
return __class__(
'%s[%s]' % (self._pname, keyname),
ast.Subscript(
value=self._tree,
slice=ast.Index(value=key),
ctx=ast.Load(),
),
constants,
)
def match_id(self, id_, node):
if isinstance(node, (ast.ClassDef, ast.FunctionDef)):
return node.name == id_
if isinstance(node, ast.Name):
return node.id == id_
if isinstance(node, ast.Attribute):
return node.attr == id_
if isinstance(node, ast.Assign):
for target in node.targets:
if hasattr(target, 'id'):
if target.id == id_:
return True
if hasattr(target, 'elts'):
if id_ in self._extract_names_from_tuple(target):
return True
elif isinstance(target, ast.Subscript):
if hasattr(target.value, 'id'):
if target.value.id == id_:
return True
if isinstance(node, ast.Call):
if isinstance(node.func, ast.Name) and node.func.id == id_:
return True
if id_ == 'print' \
and hasattr(ast, 'Print') and isinstance(node, ast.Print):
# Python 2.x compatibility
return True
def top_level_name(node):
if type(node) is ast.Name:
return node.id
elif type(node) is ast.Subscript or type(node) is ast.Attribute:
return SchedulerRewriter.top_level_name(node.value)
return None
def is_valid_assignment(self, node):
if not (type(node) is ast.Assign and self.is_concurrent_call(node.value)):
return False
if len(node.targets) != 1:
raise self.not_implemented_error(node, "Concurrent assignment does not support multiple assignment targets")
if not type(node.targets[0]) is ast.Subscript:
raise self.not_implemented_error(node, "Concurrent assignment only implemented for index based objects")
return True