def compare_contains(self, node):
seq_ast = node.comparators[0]
if not isinstance(seq_ast, (ast.Set, ast.List)):
return
# elements must be hashable
seq = get_literal(seq_ast, constant_items=True)
if seq is UNSET:
return
if isinstance(seq_ast, ast.Set):
seq = frozenset(seq)
else:
seq = tuple(seq)
new_seq_ast = self.new_constant(seq_ast, seq)
if new_seq_ast is None:
return
new_node = copy_node(node)
new_node.comparators[0] = new_seq_ast
return new_node
python类Set()的实例源码
def Call_issubclass(t, x):
"""Translate ``issubclass(Foo, Bar)`` to ``Foo.prototype instanceof Bar``.
"""
with switch(x):
if ast.Call(func=ast.Name(id='issubclass'), args=[target, classes]):
tproto = q[ast_literal[target].prototype]
if isinstance(classes, (ast.Tuple, ast.List, ast.Set)):
classes = classes.elts
else:
classes = [classes]
prev = None
for c in classes:
cur = q[ast_literal[c].prototype.isPrototypeOf(
ast_literal[tproto])]
if prev is not None:
cur = q[ast_literal[prev] or ast_literal[cur]]
prev = cur
return JSExpressionStatement(cur)
def _process_function_signature(stmt, arg_names, static_env):
return_type = Ellipsis
if isinstance(stmt, ast.Expr):
value = stmt.value
if isinstance(value, ast.BinOp):
left, op, right = value.left, value.op, value.right
if isinstance(op, ast.RShift):
arg_types = fn._process_argument_signature(left, arg_names,
static_env)
return_type = static_env.eval_expr_ast(right)
else:
return None
elif isinstance(value, ast.Dict) or isinstance(value, ast.Set):
arg_types = fn._process_argument_signature(value, arg_names,
static_env)
else:
return None
else:
return None
if arg_types is None:
return None
return (arg_types, return_type)
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 test_set(self):
self.expr(ast.Set([None]), "None disallowed")
s = ast.Set([ast.Name("x", ast.Store())])
self.expr(s, "must have Load context")
def _new_constant(node, value):
if isinstance(value, ast.AST):
# convenient shortcut: return the AST object unchanged
return value
# FIXME: test the config directly here?
if value is None:
new_node = ast.Constant(value=None)
elif isinstance(value, (bool, int, float, complex, str, bytes)):
new_node = ast.Constant(value=value)
elif isinstance(value, (tuple, frozenset)):
if not _is_constant(value):
raise TypeError("container items are not constant: %r" % (value,))
new_node = ast.Constant(value=value)
elif isinstance(value, list):
elts = [_new_constant(node, elt) for elt in value]
new_node = ast.List(elts=elts, ctx=ast.Load())
elif isinstance(value, dict):
keys = []
values = []
for key, value in value.items():
keys.append(_new_constant(node, key))
values.append(_new_constant(node, value))
new_node = ast.Dict(keys=keys, values=values, ctx=ast.Load())
elif isinstance(value, set):
elts = [_new_constant(node, elt) for elt in value]
new_node = ast.Set(elts=elts, ctx=ast.Load())
else:
raise TypeError("unknown type: %s" % type(value).__name__)
copy_lineno(node, new_node)
return new_node
# FIXME: use functools.singledispatch?
def test_set(self):
self.expr(ast.Set([None]), "None disallowed")
s = ast.Set([ast.Name("x", ast.Store())])
self.expr(s, "must have Load context")
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 __init__(self, operators=None, functions=None, names=None):
super(EvalWithCompoundTypes, self).__init__(operators, functions, names)
self.functions.update(
list=list,
tuple=tuple,
dict=dict,
set=set)
self.nodes.update({
ast.Dict: self._eval_dict,
ast.Tuple: self._eval_tuple,
ast.List: self._eval_list,
ast.Set: self._eval_set
})
def resolve_attr_id(node):
if isinstance(node, (ast.Attribute, ast.Subscript)):
value_id = None
if isinstance(node.value, (ast.Name, ast.Attribute, ast.Subscript)):
value_id = resolve_attr_id(node.value)
elif isinstance(node.value, ast.Call):
value_id = resolve_attr_id(node.value)
elif isinstance(node.value, ast.Str):
value_id = 'str'
elif isinstance(node.value, ast.Bytes):
value_id = 'bytes'
elif isinstance(node.value, (ast.List, ast.ListComp)):
value_id = 'list'
elif isinstance(node.value, ast.Tuple):
value_id = 'tuple'
elif isinstance(node.value, (ast.Set, ast.SetComp)):
value_id = 'set'
elif isinstance(node.value, (ast.Dict, ast.DictComp)):
value_id = 'dict'
else:
raise SyntaxError(
'unsupport type: {}'.format(ast.dump(node.value))
)
if isinstance(node, ast.Attribute):
return '{}.{}'.format(value_id, node.attr)
elif isinstance(node, ast.Subscript):
slice = None
if isinstance(node.slice.value, ast.Str):
slice = node.slice.value.s
elif isinstance(node.slice.value, ast.Num):
slice = node.slice.value.n
elif isinstance(node.slice.value, ast.Name):
slice = resolve_attr_id(node.slice.value)
return '{}[{}]'.format(value_id, slice)
elif isinstance(node, ast.Call):
return '{}()'.format(resolve_attr_id(node.func))
return node.id
def test_set(self):
self.expr(ast.Set([None]), "None disallowed")
s = ast.Set([ast.Name("x", ast.Store())])
self.expr(s, "must have Load context")
def _build_call_isinstance(tgt, cls_or_seq):
"""Helper to build the translate the equivalence of ``isinstance(foo, Bar)``
to ``foo instanceof Bar`` and ``isinstance(Foo, (Bar, Zoo))`` to
``foo instanceof Bar || foo instanceof Zoo``.
"""
if isinstance(cls_or_seq, (ast.Tuple, ast.List, ast.Set)):
classes = cls_or_seq.elts
args = tuple((tgt, c) for c in classes)
return JSMultipleArgsOp(JSOpInstanceof(), JSOpOr(), *args)
else:
cls = cls_or_seq
if isinstance(cls, ast.Name) and cls.id == 'str':
return JSMultipleArgsOp(
(JSOpStrongEq(), JSOpInstanceof()),
JSOpOr(),
(JSUnaryOp(JSOpTypeof(), tgt), JSStr('string')),
(tgt, JSName('String'))
)
elif isinstance(cls, ast.Name) and cls.id in ['int', 'float']:
return JSMultipleArgsOp(
(JSOpStrongEq(), JSOpInstanceof()),
JSOpOr(),
(JSUnaryOp(JSOpTypeof(), tgt), JSStr('number')),
(tgt, JSName('Number'))
)
else:
return JSBinOp(tgt, JSOpInstanceof(), cls)
def _process_argument_signature(value, arg_names, static_env):
arg_types = []
if isinstance(value, ast.Dict):
keys, values = value.keys, value.values
n_keys = len(keys)
n_args = len(arg_names)
if n_keys != n_args:
raise _errors.TyError(
"Function specifies {0} arguments, "
"but function signature specifies {1} arguments."
.format(n_args, n_keys), value)
for key, value, arg_name in zip(keys, values, arg_names):
if not isinstance(key, ast.Name):
raise _errors.TyError(
"Argument name must be an identiifer.", key)
sig_arg_name = key.id
if sig_arg_name != arg_name:
raise _errors.TyError(
"Function specifies argument name {0}, but function "
"signature specifies argument name {1}."
.format(arg_name, key), key)
arg_types.append(static_env.eval_expr_ast(value))
elif isinstance(value, ast.Set):
elts = value.elts
n_elts = len(elts)
n_args = len(arg_names)
if n_elts != n_args:
raise _errors.TyError(
"Function specifies {0} arguments, but function"
"signature specifies {1} arguments."
.format(n_args, n_elts), value)
for elt in elts:
arg_types.append(static_env.eval_expr_ast(elt))
else:
raise _errors.TyError(
"Argument signature must have the form of either a set "
"or dict literal.", value)
return tuple(arg_types)
def iter_expr_values(parent, node, child=None):
"""
Yield each value for *node* which can be tracked. Literals are returned as
their evaluated value where as nodes which fail to evaluate to literals are
returned as is.
:param node parent: The parent node used to mark the start of the search path.
:param node node: The target ast.Name node to find literal values for.
:param node child: An optional child node to mark the end of the search path.
"""
child = child or node
success, value = eval_ast.literal_expr(node)
if success:
yield value
return
if not isinstance(node, ast.Name):
return
test_nodes = collections.deque()
def_nodes = get_definition_nodes(parent, node.id, child)
for def_node_idx, def_node in enumerate(def_nodes):
each = False
next_node = (def_nodes[def_node_idx + 1] if len(def_nodes) > def_node_idx + 1 else child)
src_node = None
test_nodes.clear()
if isinstance(def_node, ast.Assign):
test_node = get_expr_value_src_dst(def_node.value, def_node.targets[0], node)
if test_node:
test_nodes.append(test_node)
elif isinstance(def_node, ast.For):
src_node = get_expr_value_src_dst(def_node.iter, def_node.target, node)
each = node_is_child_of_parent(def_node.body, next_node)
elif isinstance(def_node, ast.ListComp):
for generator in def_node.generators:
src_node = get_expr_value_src_dst(generator.iter, generator.target, node)
if src_node:
break
if isinstance(src_node, (ast.List, ast.Tuple, ast.Set)):
test_nodes.extend(src_node.elts if each else src_node.elts[-1:])
for test_node in test_nodes:
success, value = eval_ast.literal_expr(test_node)
if success:
yield value
continue
for value in iter_expr_values(parent, test_node):
success = True
yield value
if success:
continue
for def_node in get_definition_nodes(parent, test_node):
for value in iter_expr_values(parent, def_node):
success = True
yield value
yield test_node
def test__get_literal_value(self):
new_context = context.Context()
value = ast.Num(42)
expected = value.n
self.assertEqual(expected, new_context._get_literal_value(value))
value = ast.Str('spam')
expected = value.s
self.assertEqual(expected, new_context._get_literal_value(value))
value = ast.List([ast.Str('spam'), ast.Num(42)], ast.Load())
expected = [ast.Str('spam').s, ast.Num(42).n]
self.assertListEqual(expected, new_context._get_literal_value(value))
value = ast.Tuple([ast.Str('spam'), ast.Num(42)], ast.Load())
expected = (ast.Str('spam').s, ast.Num(42).n)
self.assertTupleEqual(expected, new_context._get_literal_value(value))
value = ast.Set([ast.Str('spam'), ast.Num(42)])
expected = set([ast.Str('spam').s, ast.Num(42).n])
self.assertSetEqual(expected, new_context._get_literal_value(value))
value = ast.Dict(['spam', 'eggs'], [42, 'foo'])
expected = dict(spam=42, eggs='foo')
self.assertDictEqual(expected, new_context._get_literal_value(value))
value = ast.Ellipsis()
self.assertIsNone(new_context._get_literal_value(value))
value = ast.Name('spam', ast.Load())
expected = value.id
self.assertEqual(expected, new_context._get_literal_value(value))
if six.PY3:
value = ast.NameConstant(True)
expected = str(value.value)
self.assertEqual(expected, new_context._get_literal_value(value))
if six.PY3:
value = ast.Bytes(b'spam')
expected = value.s
self.assertEqual(expected, new_context._get_literal_value(value))
self.assertIsNone(new_context._get_literal_value(None))
def _get_literal(node, constant_items=False):
use_literal = (not constant_items)
value = get_constant(node)
if value is not UNSET:
return value
if isinstance(node, ast.Tuple) and use_literal:
elts = _get_node_list(node.elts, literal=True)
if elts is UNSET:
return UNSET
return list(elts)
if isinstance(node, ast.List):
elts = _get_node_list(node.elts, literal=use_literal)
if elts is UNSET:
return UNSET
return list(elts)
if isinstance(node, ast.Set):
# elements must be hashable
elts = _get_node_list(node.elts)
if elts is UNSET:
return UNSET
return set(elts)
if isinstance(node, ast.Dict):
# FIXME: this code is slow, only do it when get_literal() is
# called with types==dict (or dict in types)
# keys musts be hashable
keys = _get_node_list(node.keys)
if keys is UNSET:
return UNSET
values = _get_node_list(node.values, literal=use_literal)
if values is UNSET:
return UNSET
return dict(zip(keys, values))
return UNSET
def infer(node, context, solver, from_call=False):
"""Infer the type of a given AST node"""
if isinstance(node, ast.Num):
return infer_numeric(node, solver)
elif isinstance(node, ast.Str):
return solver.z3_types.string
elif (sys.version_info[0] >= 3 and sys.version_info[1] >= 6 and
(isinstance(node, ast.FormattedValue) or isinstance(node, ast.JoinedStr))):
# Formatted strings were introduced in Python 3.6
return solver.z3_types.string
elif isinstance(node, ast.Bytes):
return solver.z3_types.bytes
elif isinstance(node, ast.List):
return infer_list(node, context, solver)
elif isinstance(node, ast.Dict):
return infer_dict(node, context, solver)
elif isinstance(node, ast.Tuple):
return infer_tuple(node, context, solver)
elif isinstance(node, ast.NameConstant):
return infer_name_constant(node, solver)
elif isinstance(node, ast.Set):
return infer_set(node, context, solver)
elif isinstance(node, ast.BinOp):
return infer_binary_operation(node, context, solver)
elif isinstance(node, ast.BoolOp):
return infer_boolean_operation(node, context, solver)
elif isinstance(node, ast.UnaryOp):
return infer_unary_operation(node, context, solver)
elif isinstance(node, ast.IfExp):
return infer_if_expression(node, context, solver)
elif isinstance(node, ast.Subscript):
return infer_subscript(node, context, solver)
elif sys.version_info[0] >= 3 and sys.version_info[1] >= 5 and isinstance(node, ast.Await):
# Await and Async were introduced in Python 3.5
return infer(node.value, context, solver)
elif isinstance(node, ast.Yield):
return infer(node.value, context, solver)
elif isinstance(node, ast.Compare):
return infer_compare(node, context, solver)
elif isinstance(node, ast.Name):
return infer_name(node, context)
elif isinstance(node, ast.ListComp):
return infer_sequence_comprehension(node, solver.z3_types.list, context, solver)
elif isinstance(node, ast.SetComp):
return infer_sequence_comprehension(node, solver.z3_types.set, context, solver)
elif isinstance(node, ast.DictComp):
return infer_dict_comprehension(node, context, solver)
elif isinstance(node, ast.Call):
return infer_func_call(node, context, solver)
elif isinstance(node, ast.Attribute):
return infer_attribute(node, context, from_call, solver)
elif isinstance(node, ast.Lambda):
return _infer_lambda(node, context, solver)
raise NotImplementedError("Inference for expression {} is not implemented yet.".format(type(node).__name__))