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))
python类BinOp()的实例源码
def pop_format_context(self, expl_expr):
"""Format the %-formatted string with current format context.
The expl_expr should be an ast.Str instance constructed from
the %-placeholders created by .explanation_param(). This will
add the required code to format said string to .on_failure and
return the ast.Name instance of the formatted string.
"""
current = self.stack.pop()
if self.stack:
self.explanation_specifiers = self.stack[-1]
keys = [ast.Str(key) for key in current.keys()]
format_dict = ast.Dict(keys, list(current.values()))
form = ast.BinOp(expl_expr, ast.Mod(), format_dict)
name = "@py_format" + str(next(self.variable_counter))
self.on_failure.append(ast.Assign([ast.Name(name, ast.Store())], form))
return ast.Name(name, ast.Load())
def visit_BinOp(self, node: ast.BinOp) -> ast.BinOp:
node = self.generic_visit(node)
if self._is_numeric_mult(node):
if isinstance(node.right, ast.Num):
if node.right.n == 0:
node = ast.copy_location(ast.Num(n = 0), node)
elif node.right.n == 1:
node = node.left
elif node.right.n == 2:
node.op = ast.copy_location(ast.Add(), node.op)
node.right = copy(node.left)
elif isinstance(node.left , ast.Num):
if node.left.n == 0:
node = ast.copy_location(ast.Num(n = 0), node)
elif node.left.n == 1:
node = node.right
elif node.left.n == 2:
node.op = ast.copy_location(ast.Add(), node.op)
node.left = copy(node.right)
return node
def _is_numeric_pow(self, node: ast.BinOp) -> bool:
if isinstance(node.op, ast.Pow):
left, right = node.left, node.right
if isinstance(left, (ast.Name, ast.Num)):
if isinstance(right, ast.Num):
degree = right.n
elif isinstance(right, ast.UnaryOp)\
and isinstance(right.op, (ast.USub, ast.UAdd))\
and isinstance(right.operand, ast.Num):
degree = right.operand.n
else:
return False
if isinstance(degree, float):
degree = int(degree) if degree.is_integer() else degree
return isinstance(degree, int)
return False
def eval_expr(expr):
""" Eval and expression inside a #define using a suppart of python grammar """
def _eval(node):
if isinstance(node, ast.Num):
return node.n
elif isinstance(node, ast.BinOp):
return OPERATORS[type(node.op)](_eval(node.left), _eval(node.right))
elif isinstance(node, ast.UnaryOp):
return OPERATORS[type(node.op)](_eval(node.operand))
elif isinstance(node, ast.BoolOp):
values = [_eval(x) for x in node.values]
return OPERATORS[type(node.op)](**values)
else:
raise TypeError(node)
return _eval(ast.parse(expr, mode='eval').body)
def test_increment_lineno(self):
src = ast.parse('1 + 1', mode='eval')
self.assertEqual(ast.increment_lineno(src, n=3), src)
self.assertEqual(ast.dump(src, include_attributes=True),
'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
'col_offset=0))'
)
# issue10869: do not increment lineno of root twice
src = ast.parse('1 + 1', mode='eval')
self.assertEqual(ast.increment_lineno(src.body, n=3), src.body)
self.assertEqual(ast.dump(src, include_attributes=True),
'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
'col_offset=0))'
)
def get_type(self, node):
if isinstance(node, ast.Num):
return Type.NUMBER
elif isinstance(node, ast.Str):
return Type.STRING
elif isinstance(node, ast.Name):
if self.variables[node.id] is not None:
return self.variables[node.id].var_type
else:
return Type.VOID
elif isinstance(node, ast.BinOp):
if self.get_type(node.left).is_number and self.get_type(node.right).is_number:
return Type.NUMBER
elif self.get_type(node.left).is_string or self.get_type(node.right).is_string:
return Type.STRING
elif isinstance(node, ast.Call):
return self.functions[node.func.id].return_type
else:
return Type.VOID
def test_increment_lineno(self):
src = ast.parse('1 + 1', mode='eval')
self.assertEqual(ast.increment_lineno(src, n=3), src)
self.assertEqual(ast.dump(src, include_attributes=True),
'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
'col_offset=0))'
)
# issue10869: do not increment lineno of root twice
src = ast.parse('1 + 1', mode='eval')
self.assertEqual(ast.increment_lineno(src.body, n=3), src.body)
self.assertEqual(ast.dump(src, include_attributes=True),
'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
'col_offset=0))'
)
def test_increment_lineno(self):
src = ast.parse('1 + 1', mode='eval')
self.assertEqual(ast.increment_lineno(src, n=3), src)
self.assertEqual(ast.dump(src, include_attributes=True),
'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
'col_offset=0))'
)
# issue10869: do not increment lineno of root twice
src = ast.parse('1 + 1', mode='eval')
self.assertEqual(ast.increment_lineno(src.body, n=3), src.body)
self.assertEqual(ast.dump(src, include_attributes=True),
'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
'col_offset=0))'
)
def pop_format_context(self, expl_expr):
"""Format the %-formatted string with current format context.
The expl_expr should be an ast.Str instance constructed from
the %-placeholders created by .explanation_param(). This will
add the required code to format said string to .on_failure and
return the ast.Name instance of the formatted string.
"""
current = self.stack.pop()
if self.stack:
self.explanation_specifiers = self.stack[-1]
keys = [ast.Str(key) for key in current.keys()]
format_dict = ast.Dict(keys, list(current.values()))
form = ast.BinOp(expl_expr, ast.Mod(), format_dict)
name = "@py_format" + str(next(self.variable_counter))
self.on_failure.append(ast.Assign([ast.Name(name, ast.Store())], form))
return ast.Name(name, ast.Load())
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 _evaluate_ast(node):
wrapper = None
statement = ''
if isinstance(node.parent, ast.BinOp):
out = utils.concat_string(node, node.parent)
wrapper = out[0].parent
statement = out[1]
elif (isinstance(node.parent, ast.Attribute)
and node.parent.attr == 'format'):
statement = node.s
# Hierarchy for "".format() is Wrapper -> Call -> Attribute -> Str
wrapper = node.parent.parent.parent
if isinstance(wrapper, ast.Call): # wrapped in "execute" call?
names = ['execute', 'executemany']
name = utils.get_called_name(wrapper)
return (name in names, statement)
else:
return (False, statement)
def test_increment_lineno(self):
src = ast.parse('1 + 1', mode='eval')
self.assertEqual(ast.increment_lineno(src, n=3), src)
self.assertEqual(ast.dump(src, include_attributes=True),
'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
'col_offset=0))'
)
# issue10869: do not increment lineno of root twice
src = ast.parse('1 + 1', mode='eval')
self.assertEqual(ast.increment_lineno(src.body, n=3), src.body)
self.assertEqual(ast.dump(src, include_attributes=True),
'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
'col_offset=0))'
)
def pop_format_context(self, expl_expr):
"""Format the %-formatted string with current format context.
The expl_expr should be an ast.Str instance constructed from
the %-placeholders created by .explanation_param(). This will
add the required code to format said string to .on_failure and
return the ast.Name instance of the formatted string.
"""
current = self.stack.pop()
if self.stack:
self.explanation_specifiers = self.stack[-1]
keys = [ast.Str(key) for key in current.keys()]
format_dict = ast.Dict(keys, list(current.values()))
form = ast.BinOp(expl_expr, ast.Mod(), format_dict)
name = "@py_format" + str(next(self.variable_counter))
self.on_failure.append(ast.Assign([ast.Name(name, ast.Store())], form))
return ast.Name(name, ast.Load())
def pop_format_context(self, expl_expr):
"""Format the %-formatted string with current format context.
The expl_expr should be an ast.Str instance constructed from
the %-placeholders created by .explanation_param(). This will
add the required code to format said string to .on_failure and
return the ast.Name instance of the formatted string.
"""
current = self.stack.pop()
if self.stack:
self.explanation_specifiers = self.stack[-1]
keys = [ast.Str(key) for key in current.keys()]
format_dict = ast.Dict(keys, list(current.values()))
form = ast.BinOp(expl_expr, ast.Mod(), format_dict)
name = "@py_format" + str(next(self.variable_counter))
self.on_failure.append(ast.Assign([ast.Name(name, ast.Store())], form))
return ast.Name(name, ast.Load())
def check_call_visitor(self, visitor):
tree = ast.parse("1+1")
with self.assertRaises(Exception) as cm:
visitor.visit(tree)
binop = tree.body[0].value
what = ast.dump(binop)
self.assertEqual(str(cm.exception),
'error at <string>:1 on visiting %s: bug' % what)
# Test truncature of the AST dump
with mock.patch('fatoptimizer.tools.COMPACT_DUMP_MAXLEN', 5):
with self.assertRaises(Exception) as cm:
visitor.visit(tree)
what = 'BinOp(...)'
self.assertEqual(str(cm.exception),
'error at <string>:1 on visiting %s: bug' % what)
expr.py 文件源码
项目:PyDataLondon29-EmbarrassinglyParallelDAWithAWSLambda
作者: SignalMedia
项目源码
文件源码
阅读 27
收藏 0
点赞 0
评论 0
def visit_Compare(self, node, **kwargs):
ops = node.ops
comps = node.comparators
# base case: we have something like a CMP b
if len(comps) == 1:
op = self.translate_In(ops[0])
binop = ast.BinOp(op=op, left=node.left, right=comps[0])
return self.visit(binop)
# recursive case: we have a chained comparison, a CMP b CMP c, etc.
left = node.left
values = []
for op, comp in zip(ops, comps):
new_node = self.visit(ast.Compare(comparators=[comp], left=left,
ops=[self.translate_In(op)]))
left = comp
values.append(new_node)
return self.visit(ast.BoolOp(op=ast.And(), values=values))
def eval_numeric_constexpr(node: ast.AST) -> int:
if isinstance(node, ast.Num):
return node.n
if isinstance(node, ast.UnaryOp):
if isinstance(node.op, ast.UAdd):
return +eval_numeric_constexpr(node.operand)
elif isinstance(node.op, ast.USub):
return -eval_numeric_constexpr(node.operand)
else:
return None
if isinstance(node, ast.BinOp):
if isinstance(node.op, ast.Add):
return eval_numeric_constexpr(node.left) + eval_numeric_constexpr(node.right)
if isinstance(node.op, ast.Sub):
return eval_numeric_constexpr(node.left) - eval_numeric_constexpr(node.right)
if isinstance(node.op, ast.Mult):
return eval_numeric_constexpr(node.left) * eval_numeric_constexpr(node.right)
if isinstance(node.op, ast.Div):
return eval_numeric_constexpr(node.left) / eval_numeric_constexpr(node.right)
return None
def test_increment_lineno(self):
src = ast.parse('1 + 1', mode='eval')
self.assertEqual(ast.increment_lineno(src, n=3), src)
self.assertEqual(ast.dump(src, include_attributes=True),
'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
'col_offset=0))'
)
# issue10869: do not increment lineno of root twice
src = ast.parse('1 + 1', mode='eval')
self.assertEqual(ast.increment_lineno(src.body, n=3), src.body)
self.assertEqual(ast.dump(src, include_attributes=True),
'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
'col_offset=0))'
)
def visit_ExceptHandler(self, node):
node_name = None
if isinstance(node.name, ast.Name):
# Python 2
node_name = node.name.id
elif isinstance(node.name, str):
# Python 3
node_name = node.name
if node_name in builtin_exception_types:
yield self.tag(node, 'except-shadows-builtin', node_name)
if node.type is None:
ex_types = []
elif isinstance(node.type, ast.Tuple):
ex_types = list(node.type.elts)
else:
ex_types = [node.type]
for ex_type in ex_types:
while isinstance(ex_type, ast.BinOp):
ex_type = ex_type.left
if isinstance(ex_type, ast.Str):
yield self.tag(node, 'string-exception')
break
for t in self.generic_visit(node):
yield t
def test_increment_lineno(self):
src = ast.parse('1 + 1', mode='eval')
self.assertEqual(ast.increment_lineno(src, n=3), src)
self.assertEqual(ast.dump(src, include_attributes=True),
'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
'col_offset=0))'
)
# issue10869: do not increment lineno of root twice
src = ast.parse('1 + 1', mode='eval')
self.assertEqual(ast.increment_lineno(src.body, n=3), src.body)
self.assertEqual(ast.dump(src, include_attributes=True),
'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
'col_offset=0))'
)
def test_increment_lineno(self):
src = ast.parse('1 + 1', mode='eval')
self.assertEqual(ast.increment_lineno(src, n=3), src)
self.assertEqual(ast.dump(src, include_attributes=True),
'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
'col_offset=0))'
)
# issue10869: do not increment lineno of root twice
src = ast.parse('1 + 1', mode='eval')
self.assertEqual(ast.increment_lineno(src.body, n=3), src.body)
self.assertEqual(ast.dump(src, include_attributes=True),
'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
'col_offset=0))'
)
def eval_expr(expr):
import ast
import operator as op
op = {
ast.Add: op.add,
ast.Sub: op.sub,
ast.Mult: op.mul,
ast.Div: op.truediv,
ast.Pow: op.pow,
ast.BitXor: op.xor,
ast.USub: op.neg,
}
def eval_(node):
if isinstance(node, ast.Num):
return fractions.Fraction(node.n)
elif isinstance(node, ast.BinOp):
return op[type(node.op)](eval_(node.left), eval_(node.right))
elif isinstance(node, ast.UnaryOp):
return op[type(node.op)](eval_(node.operand))
raise TypeError(node)
return eval_(ast.parse(str(expr), mode='eval').body)
def test_increment_lineno(self):
src = ast.parse('1 + 1', mode='eval')
self.assertEqual(ast.increment_lineno(src, n=3), src)
self.assertEqual(ast.dump(src, include_attributes=True),
'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
'col_offset=0))'
)
# issue10869: do not increment lineno of root twice
src = ast.parse('1 + 1', mode='eval')
self.assertEqual(ast.increment_lineno(src.body, n=3), src.body)
self.assertEqual(ast.dump(src, include_attributes=True),
'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), '
'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, '
'col_offset=0))'
)
def pop_format_context(self, expl_expr):
"""Format the %-formatted string with current format context.
The expl_expr should be an ast.Str instance constructed from
the %-placeholders created by .explanation_param(). This will
add the required code to format said string to .on_failure and
return the ast.Name instance of the formatted string.
"""
current = self.stack.pop()
if self.stack:
self.explanation_specifiers = self.stack[-1]
keys = [ast.Str(key) for key in current.keys()]
format_dict = ast.Dict(keys, list(current.values()))
form = ast.BinOp(expl_expr, ast.Mod(), format_dict)
name = "@py_format" + str(next(self.variable_counter))
self.on_failure.append(ast.Assign([ast.Name(name, ast.Store())], form))
return ast.Name(name, ast.Load())
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 parse_unit(item):
if isinstance(item, ast.Name):
if item.id not in valid_units:
raise InvalidTypeException("Invalid base unit", item)
return {item.id: 1}
elif isinstance(item, ast.Num) and item.n == 1:
return {}
elif not isinstance(item, ast.BinOp):
raise InvalidTypeException("Invalid unit expression", item)
elif isinstance(item.op, ast.Mult):
left, right = parse_unit(item.left), parse_unit(item.right)
return combine_units(left, right)
elif isinstance(item.op, ast.Div):
left, right = parse_unit(item.left), parse_unit(item.right)
return combine_units(left, right, div=True)
elif isinstance(item.op, ast.Pow):
if not isinstance(item.left, ast.Name):
raise InvalidTypeException("Can only raise a base type to an exponent", item)
if not isinstance(item.right, ast.Num) or not isinstance(item.right.n, int) or item.right.n <= 0:
raise InvalidTypeException("Exponent must be positive integer", item)
return {item.left.id: item.right.n}
else:
raise InvalidTypeException("Invalid unit expression", item)
# Parses an expression representing a type. Annotation refers to whether
# the type is to be located in memory or storage
def aug_assign(self):
target = self.get_target(self.stmt.target)
sub = Expr.parse_value_expr(self.stmt.value, self.context)
if not isinstance(self.stmt.op, (ast.Add, ast.Sub, ast.Mult, ast.Div, ast.Mod)):
raise Exception("Unsupported operator for augassign")
if not isinstance(target.typ, BaseType):
raise TypeMismatchException("Can only use aug-assign operators with simple types!", self.stmt.target)
if target.location == 'storage':
o = Expr.parse_value_expr(ast.BinOp(left=LLLnode.from_list(['sload', '_stloc'], typ=target.typ, pos=target.pos),
right=sub, op=self.stmt.op, lineno=self.stmt.lineno, col_offset=self.stmt.col_offset), self.context)
return LLLnode.from_list(['with', '_stloc', target, ['sstore', '_stloc', base_type_conversion(o, o.typ, target.typ)]], typ=None, pos=getpos(self.stmt))
elif target.location == 'memory':
o = Expr.parse_value_expr(ast.BinOp(left=LLLnode.from_list(['mload', '_mloc'], typ=target.typ, pos=target.pos),
right=sub, op=self.stmt.op, lineno=self.stmt.lineno, col_offset=self.stmt.col_offset), self.context)
return LLLnode.from_list(['with', '_mloc', target, ['mstore', '_mloc', base_type_conversion(o, o.typ, target.typ)]], typ=None, pos=getpos(self.stmt))
def visit_BinOp(self, binop):
symbol = binop_map[binop.op.__class__]
left_expr, left_expl = self.visit(binop.left)
right_expr, right_expl = self.visit(binop.right)
explanation = "(%s %s %s)" % (left_expl, symbol, right_expl)
res = self.assign(ast.BinOp(left_expr, binop.op, right_expr))
return res, explanation
def _is_numeric_mult(self, node: ast.BinOp) -> bool:
if isinstance(node.op, ast.Mult):
if isinstance(node.left , (ast.Name, ast.Num)) \
and isinstance(node.right, ast.Num):
return True
if isinstance(node.right, (ast.Name, ast.Num)) \
and isinstance(node.left , ast.Num):
return True
return False