def syn_UnaryOp(self, ctx, e):
if not isinstance(e.op, ast.Not):
return self
else:
raise _errors.TyError(
"Invalid unary operator 'not' for operand of type num.", e)
python类Not()的实例源码
def syn_UnaryOp(self, ctx, e):
if isinstance(e.op, (ast.Not, ast.Invert)):
raise _errors.TyError("Invalid unary operator for operand of type ieee.", e)
else:
return self
def syn_UnaryOp(self, ctx, e):
if not isinstance(e.op, (ast.Not, ast.Invert)):
return self
else:
raise _errors.TyError("Invalid unary operator for operand of type cplx.", e)
def visit_Assert(self, assert_):
"""Return the AST statements to replace the ast.Assert instance.
This re-writes the test of an assertion to provide
intermediate values and replace it with an if statement which
raises an assertion error with a detailed explanation in case
the expression is false.
"""
if isinstance(assert_.test, ast.Tuple) and self.config is not None:
fslocation = (self.module_path, assert_.lineno)
self.config.warn('R1', 'assertion is always true, perhaps '
'remove parentheses?', fslocation=fslocation)
self.statements = []
self.variables = []
self.variable_counter = itertools.count()
self.stack = []
self.on_failure = []
self.push_format_context()
# Rewrite assert into a bunch of statements.
top_condition, explanation = self.visit(assert_.test)
# Create failure message.
body = self.on_failure
negation = ast.UnaryOp(ast.Not(), top_condition)
self.statements.append(ast.If(negation, body, []))
if assert_.msg:
assertmsg = self.helper('format_assertmsg', assert_.msg)
explanation = "\n>assert " + explanation
else:
assertmsg = ast.Str("")
explanation = "assert " + explanation
template = ast.BinOp(assertmsg, ast.Add(), ast.Str(explanation))
msg = self.pop_format_context(template)
fmt = self.helper("format_explanation", msg)
err_name = ast.Name("AssertionError", ast.Load())
exc = ast_Call(err_name, [fmt], [])
if sys.version_info[0] >= 3:
raise_ = ast.Raise(exc, None)
else:
raise_ = ast.Raise(exc, None, None)
body.append(raise_)
# Clear temporary variables by setting them to None.
if self.variables:
variables = [ast.Name(name, ast.Store())
for name in self.variables]
clear = ast.Assign(variables, _NameConstant(None))
self.statements.append(clear)
# Fix line numbers.
for stmt in self.statements:
set_location(stmt, assert_.lineno, assert_.col_offset)
return self.statements
def specialFunctions(cv, old, new):
if type(old) == type(new) == list:
log("individualize\tspecialFunctions\tWhy are we comparing lists?: " + str(cv) + ";" + printFunction(old) + ";" + printFunction(new), "bug")
return cv
rev = neg = False
if (hasattr(old, "reversed") and old.reversed and (not hasattr(old, "multCompFixed"))):
rev = True
if (hasattr(old, "negated") and old.negated):
neg = True
if rev and neg:
(old, new) = (negate(undoReverse(old)), negate(undoReverse(new)))
elif rev:
(old, new) = (undoReverse(old), undoReverse(new))
elif neg:
(old, new) = (negate(old), negate(new))
if type(old) == ast.UnaryOp and type(old.op) == ast.Not and \
type(new) == ast.UnaryOp and type(new.op) == ast.Not:
# Just get rid of them
old = old.operand
new = new.operand
if hasattr(old, "num_negated") and old.num_negated:
origNew = deepcopy(new)
(old, new) = (num_negate(old), num_negate(new))
if new == None: # couldn't reverse the new operator
# To get here, we must have a binary operator. Go up a level and negate the right side
cvCopy = cv.deepcopy()
parentSpot = deepcopy(cvCopy.traverseTree(cvCopy.start))
if type(parentSpot) == ast.BinOp:
cvCopy.path = cvCopy.path[1:]
cvCopy.oldSubtree = parentSpot
cvCopy.newSubtree = deepcopy(parentSpot)
cvCopy.newSubtree.op = origNew
cvCopy.newSubtree.right = num_negate(cvCopy.newSubtree.right)
cvCopy = orderedBinOpSpecialFunction(cvCopy) # just in case
return cvCopy
else:
log("individualize\tspecialFunctions\tWhere are we? " + str(type(parentSpot)), "bug")
#if (hasattr(old, "inverted") and old.inverted):
# (old, new) = (invert(old), invert(new))
cv.oldSubtree = old
cv.newSubtree = new
return cv
def areDisjoint(a, b):
"""Are the sets of values that satisfy these two boolean constraints disjoint?"""
# The easiest way to be disjoint is to have comparisons that cover different areas
if type(a) == type(b) == ast.Compare:
aop = a.ops[0]
bop = b.ops[0]
aLeft = a.left
aRight = a.comparators[0]
bLeft = b.left
bRight = b.comparators[0]
alblComp = compareASTs(aLeft, bLeft, checkEquality=True)
albrComp = compareASTs(aLeft, bRight, checkEquality=True)
arblComp = compareASTs(aRight, bLeft, checkEquality=True)
arbrComp = compareASTs(aRight, bRight, checkEquality=True)
altype = type(aLeft) in [ast.Num, ast.Str]
artype = type(aRight) in [ast.Num, ast.Str]
bltype = type(bLeft) in [ast.Num, ast.Str]
brtype = type(bRight) in [ast.Num, ast.Str]
if (type(aop) == ast.Eq and type(bop) == ast.NotEq) or \
(type(bop) == ast.Eq and type(aop) == ast.NotEq):
# x == y, x != y
if (alblComp == 0 and arbrComp == 0) or (albrComp == 0 and arblComp == 0):
return True
elif type(aop) == type(bop) == ast.Eq:
if (alblComp == 0 and arbrComp == 0) or (albrComp == 0 and arblComp == 0):
return False
# x = num1, x = num2
elif alblComp == 0 and artype and brtype:
return True
elif albrComp == 0 and artype and bltype:
return True
elif arblComp == 0 and altype and brtype:
return True
elif arbrComp == 0 and altype and bltype:
return True
elif (type(aop) == ast.Lt and type(bop) == ast.GtE) or \
(type(aop) == ast.Gt and type(bop) == ast.LtE) or \
(type(aop) == ast.LtE and type(bop) == ast.Gt) or \
(type(aop) == ast.GtE and type(bop) == ast.Lt) or \
(type(aop) == ast.Is and type(bop) == ast.IsNot) or \
(type(aop) == ast.IsNot and type(bop) == ast.Is) or \
(type(aop) == ast.In and type(bop) == ast.NotIn) or \
(type(aop) == ast.NotIn and type(bop) == ast.In):
if alblComp == 0 and arbrComp == 0:
return True
elif (type(aop) == ast.Lt and type(bop) == ast.LtE) or \
(type(aop) == ast.Gt and type(bop) == ast.GtE) or \
(type(aop) == ast.LtE and type(bop) == ast.Lt) or \
(type(aop) == ast.GtE and type(bop) == ast.Gt):
if albrComp == 0 and arblComp == 0:
return True
elif type(a) == type(b) == ast.BoolOp:
return False # for now- TODO: when is this not true?
elif type(a) == ast.UnaryOp and type(a.op) == ast.Not:
if compareASTs(a.operand, b, checkEquality=True) == 0:
return True
elif type(b) == ast.UnaryOp and type(b.op) == ast.Not:
if compareASTs(b.operand, a, checkEquality=True) == 0:
return True
return False
def deMorganize(a):
"""Apply De Morgan's law throughout the code in order to canonicalize"""
if not isinstance(a, ast.AST):
return a
# We only care about statements beginning with not
if type(a) == ast.UnaryOp and type(a.op) == ast.Not:
oper = a.operand
top = type(oper)
# not (blah and gah) == (not blah or not gah)
if top == ast.BoolOp:
oper.op = negate(oper.op)
for i in range(len(oper.values)):
oper.values[i] = deMorganize(negate(oper.values[i]))
oper.negated = not oper.negated if hasattr(oper, "negated") else True
transferMetaData(a, oper)
return oper
# not a < b == a >= b
elif top == ast.Compare:
oper.left = deMorganize(oper.left)
oper.ops = [negate(oper.ops[0])]
oper.comparators = [deMorganize(oper.comparators[0])]
oper.negated = not oper.negated if hasattr(oper, "negated") else True
transferMetaData(a, oper)
return oper
# not not blah == blah
elif top == ast.UnaryOp and type(oper.op) == ast.Not:
oper.operand = deMorganize(oper.operand)
if eventualType(oper.operand) != bool:
return a
oper.operand.negated = not oper.operand.negated if hasattr(oper.operand, "negated") else True
return oper.operand
elif top == ast.NameConstant:
if oper.value in [True, False]:
oper = negate(oper)
transferMetaData(a, oper)
return oper
elif oper.value == None:
tmp = ast.NameConstant(True)
transferMetaData(a, tmp)
tmp.negated = True
return tmp
else:
log("Unknown NameConstant: " + str(oper.value), "bug")
return applyToChildren(a, deMorganize)
##### CLEANUP FUNCTIONS #####
def negate(op):
"""Return the negation of the provided operator"""
if op == None:
return None
top = type(op)
neg = not op.negated if hasattr(op, "negated") else True
if top == ast.And:
newOp = ast.Or()
elif top == ast.Or:
newOp = ast.And()
elif top == ast.Eq:
newOp = ast.NotEq()
elif top == ast.NotEq:
newOp = ast.Eq()
elif top == ast.Lt:
newOp = ast.GtE()
elif top == ast.GtE:
newOp = ast.Lt()
elif top == ast.Gt:
newOp = ast.LtE()
elif top == ast.LtE:
newOp = ast.Gt()
elif top == ast.Is:
newOp = ast.IsNot()
elif top == ast.IsNot:
newOp = ast.Is()
elif top == ast.In:
newOp = ast.NotIn()
elif top == ast.NotIn:
newOp = ast.In()
elif top == ast.NameConstant and op.value in [True, False]:
op.value = not op.value
op.negated = neg
return op
elif top == ast.Compare:
if len(op.ops) == 1:
op.ops[0] = negate(op.ops[0])
op.negated = neg
return op
else:
values = []
allOperands = [op.left] + op.comparators
for i in range(len(op.ops)):
values.append(ast.Compare(allOperands[i], [negate(op.ops[i])],
[allOperands[i+1]], multiCompPart=True))
newOp = ast.BoolOp(ast.Or(multiCompOp=True), values, multiComp=True)
elif top == ast.UnaryOp and type(op.op) == ast.Not and \
eventualType(op.operand) == bool: # this can mess things up type-wise
return op.operand
else:
# this is a normal value, so put a not around it
newOp = ast.UnaryOp(ast.Not(addedNot=True), op)
transferMetaData(op, newOp)
newOp.negated = neg
return newOp
def visit_Assert(self, assert_):
"""Return the AST statements to replace the ast.Assert instance.
This re-writes the test of an assertion to provide
intermediate values and replace it with an if statement which
raises an assertion error with a detailed explanation in case
the expression is false.
"""
if isinstance(assert_.test, ast.Tuple) and self.config is not None:
fslocation = (self.module_path, assert_.lineno)
self.config.warn('R1', 'assertion is always true, perhaps '
'remove parentheses?', fslocation=fslocation)
self.statements = []
self.variables = []
self.variable_counter = itertools.count()
self.stack = []
self.on_failure = []
self.push_format_context()
# Rewrite assert into a bunch of statements.
top_condition, explanation = self.visit(assert_.test)
# Create failure message.
body = self.on_failure
negation = ast.UnaryOp(ast.Not(), top_condition)
self.statements.append(ast.If(negation, body, []))
if assert_.msg:
assertmsg = self.helper('format_assertmsg', assert_.msg)
explanation = "\n>assert " + explanation
else:
assertmsg = ast.Str("")
explanation = "assert " + explanation
template = ast.BinOp(assertmsg, ast.Add(), ast.Str(explanation))
msg = self.pop_format_context(template)
fmt = self.helper("format_explanation", msg)
err_name = ast.Name("AssertionError", ast.Load())
exc = ast_Call(err_name, [fmt], [])
if sys.version_info[0] >= 3:
raise_ = ast.Raise(exc, None)
else:
raise_ = ast.Raise(exc, None, None)
body.append(raise_)
# Clear temporary variables by setting them to None.
if self.variables:
variables = [ast.Name(name, ast.Store())
for name in self.variables]
clear = ast.Assign(variables, _NameConstant(None))
self.statements.append(clear)
# Fix line numbers.
for stmt in self.statements:
set_location(stmt, assert_.lineno, assert_.col_offset)
return self.statements
def visit_Assert(self, assert_):
"""Return the AST statements to replace the ast.Assert instance.
This re-writes the test of an assertion to provide
intermediate values and replace it with an if statement which
raises an assertion error with a detailed explanation in case
the expression is false.
"""
if isinstance(assert_.test, ast.Tuple) and self.config is not None:
fslocation = (self.module_path, assert_.lineno)
self.config.warn('R1', 'assertion is always true, perhaps '
'remove parentheses?', fslocation=fslocation)
self.statements = []
self.variables = []
self.variable_counter = itertools.count()
self.stack = []
self.on_failure = []
self.push_format_context()
# Rewrite assert into a bunch of statements.
top_condition, explanation = self.visit(assert_.test)
# Create failure message.
body = self.on_failure
negation = ast.UnaryOp(ast.Not(), top_condition)
self.statements.append(ast.If(negation, body, []))
if assert_.msg:
assertmsg = self.helper('format_assertmsg', assert_.msg)
explanation = "\n>assert " + explanation
else:
assertmsg = ast.Str("")
explanation = "assert " + explanation
template = ast.BinOp(assertmsg, ast.Add(), ast.Str(explanation))
msg = self.pop_format_context(template)
fmt = self.helper("format_explanation", msg)
err_name = ast.Name("AssertionError", ast.Load())
exc = ast_Call(err_name, [fmt], [])
if sys.version_info[0] >= 3:
raise_ = ast.Raise(exc, None)
else:
raise_ = ast.Raise(exc, None, None)
body.append(raise_)
# Clear temporary variables by setting them to None.
if self.variables:
variables = [ast.Name(name, ast.Store())
for name in self.variables]
clear = ast.Assign(variables, _NameConstant(None))
self.statements.append(clear)
# Fix line numbers.
for stmt in self.statements:
set_location(stmt, assert_.lineno, assert_.col_offset)
return self.statements
def visit_Assert(self, assert_):
"""Return the AST statements to replace the ast.Assert instance.
This re-writes the test of an assertion to provide
intermediate values and replace it with an if statement which
raises an assertion error with a detailed explanation in case
the expression is false.
"""
if isinstance(assert_.test, ast.Tuple) and self.config is not None:
fslocation = (self.module_path, assert_.lineno)
self.config.warn('R1', 'assertion is always true, perhaps '
'remove parentheses?', fslocation=fslocation)
self.statements = []
self.variables = []
self.variable_counter = itertools.count()
self.stack = []
self.on_failure = []
self.push_format_context()
# Rewrite assert into a bunch of statements.
top_condition, explanation = self.visit(assert_.test)
# Create failure message.
body = self.on_failure
negation = ast.UnaryOp(ast.Not(), top_condition)
self.statements.append(ast.If(negation, body, []))
if assert_.msg:
assertmsg = self.helper('format_assertmsg', assert_.msg)
explanation = "\n>assert " + explanation
else:
assertmsg = ast.Str("")
explanation = "assert " + explanation
template = ast.BinOp(assertmsg, ast.Add(), ast.Str(explanation))
msg = self.pop_format_context(template)
fmt = self.helper("format_explanation", msg)
err_name = ast.Name("AssertionError", ast.Load())
exc = ast_Call(err_name, [fmt], [])
if sys.version_info[0] >= 3:
raise_ = ast.Raise(exc, None)
else:
raise_ = ast.Raise(exc, None, None)
body.append(raise_)
# Clear temporary variables by setting them to None.
if self.variables:
variables = [ast.Name(name, ast.Store())
for name in self.variables]
clear = ast.Assign(variables, _NameConstant(None))
self.statements.append(clear)
# Fix line numbers.
for stmt in self.statements:
set_location(stmt, assert_.lineno, assert_.col_offset)
return self.statements
def rewrite_expr_z3_py_ast(r, is_py_ast=True):
if verbose and False:
print('rewrite_expr_z3_py_ast:', r)
# Rewrites py_ast expression to a str expression that could be used in z3
# Return (z3_expr_str, z3_varnames)
z3_expr_str = (py_ast.dump_ast(r) if is_py_ast else r).strip()
z3_expr_str = z3_expr_str.replace('.', '_').replace('[', '_').replace(']', '_')
rp = py_ast.get_ast(z3_expr_str).body[0].value
nodes = py_ast.find_all(rp, ast.UnaryOp)
while nodes != []:
node = nodes[0]
if isinstance(node.op, ast.Not):
if rp == node:
rp = py_ast.get_ast('z3.Not(' + py_ast.dump_ast(node.operand) + ')').body[0].value
else:
py_ast.replace_node(rp, node, py_ast.get_ast('z3.Not(' + py_ast.dump_ast(node.operand) + ')').body[0].value)
nodes = py_ast.find_all(rp, ast.UnaryOp)
else:
nodes = nodes[1:]
nodes = py_ast.find_all(rp, ast.BoolOp)
while nodes != []:
node = nodes[0]
if isinstance(node.op, ast.And):
rp_str = 'z3.And('
for value in node.values:
rp_str += py_ast.dump_ast(value) + ', '
rp_str = rp_str.rstrip(', ')
rp_str += ')'
if rp == node:
rp = py_ast.get_ast(rp_str).body[0].value
else:
py_ast.replace_node(rp, node, py_ast.get_ast(rp_str).body[0].value)
elif isinstance(node.op, ast.Or):
rp_str = 'z3.Or('
for value in node.values:
rp_str += py_ast.dump_ast(value) + ', '
rp_str = rp_str.rstrip(', ')
rp_str += ')'
if rp == node:
rp = py_ast.get_ast(rp_str).body[0].value
else:
py_ast.replace_node(rp, node, py_ast.get_ast(rp_str).body[0].value)
nodes = py_ast.find_all(rp, ast.BoolOp)
z3_expr_str = py_ast.dump_ast(rp)
z3_vars = set()
for node in py_ast.find_all(rp, ast.Name):
z3_vars.add(node.id)
if 'z3' in z3_vars:
z3_vars.remove('z3')
return (z3_expr_str, z3_vars)
def visit_Assert(self, assert_):
"""Return the AST statements to replace the ast.Assert instance.
This re-writes the test of an assertion to provide
intermediate values and replace it with an if statement which
raises an assertion error with a detailed explanation in case
the expression is false.
"""
self.statements = []
self.variables = []
self.variable_counter = itertools.count()
self.stack = []
self.on_failure = []
self.push_format_context()
# Rewrite assert into a bunch of statements.
top_condition, explanation = self.visit(assert_.test)
# Create failure message.
body = self.on_failure
negation = ast.UnaryOp(ast.Not(), top_condition)
self.statements.append(ast.If(negation, body, []))
if assert_.msg:
assertmsg = self.helper('format_assertmsg', assert_.msg)
explanation = "\n>assert " + explanation
else:
assertmsg = ast.Str("")
explanation = "assert " + explanation
template = ast.BinOp(assertmsg, ast.Add(), ast.Str(explanation))
msg = self.pop_format_context(template)
fmt = self.helper("format_explanation", msg)
err_name = ast.Name("AssertionError", ast.Load())
exc = ast_Call(err_name, [fmt], [])
if sys.version_info[0] >= 3:
raise_ = ast.Raise(exc, None)
else:
raise_ = ast.Raise(exc, None, None)
body.append(raise_)
# Clear temporary variables by setting them to None.
if self.variables:
variables = [ast.Name(name, ast.Store())
for name in self.variables]
clear = ast.Assign(variables, _NameConstant(None))
self.statements.append(clear)
# Fix line numbers.
for stmt in self.statements:
set_location(stmt, assert_.lineno, assert_.col_offset)
return self.statements