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类Num()的实例源码
def visit_BinOp(self, node):
node = self.generic_visit(node)
left = node.left
right = node.right
if all(isinstance(value, ast.Num) for value in (left, right)):
if isinstance(node.op, tuple(self._operators.keys())):
val = self._operators[type(node.op)](left.n, right.n)
node = ast.copy_location(ast.Num(n = val), node)
return node
elif all(isinstance(value, ast.Str) for value in (left, right)):
if isinstance(node.op, ast.Add):
val = left.s + right.s
node = ast.copy_location(ast.Str(s = val), node)
return node
return self.fold(node)
#def visit_GeneratorExp(self, node):
# return self.comprehension(node)
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 visit_Module(self, node):
for expr in node.body:
if not isinstance(expr, ast.Assign):
continue
if not isinstance(expr.value, (ast.Num, ast.Str)):
continue
if len(expr.targets) != 1:
continue
name = expr.targets[0]
if not isinstance(name, ast.Name):
continue
name = name.id
if not self.is_const_name(name):
continue
if name in self._constants:
self._constants[name] = None
else:
self._constants[name] = expr.value
return self.generic_visit(node)
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 basicTypeSpecialFunction(cv):
"""If you're in a number or string (which has no metadata), move up to the AST to make the special functions work."""
if isinstance(cv, SwapVector) or isinstance(cv, MoveVector):
return cv
if (cv.path[0] in [('n', 'Number'), ('s', 'String'), ('id', 'Name'), ('arg', 'Argument'),
('value', 'Name Constant'), ('s', 'Bytes'), ('name', 'Alias')]):
cvCopy = cv.deepcopy()
cv.oldSubtree = deepcopy(cvCopy.traverseTree(cv.start))
if cv.path[0] == ('n', 'Number'):
cv.newSubtree = ast.Num(cv.newSubtree)
elif cv.path[0] == ('s', 'String'):
cv.newSubtree = ast.Str(cv.newSubtree)
elif cv.path[0] == ('id', 'Name'):
cv.newSubtree = ast.Name(cv.newSubtree, cv.oldSubtree.ctx)
elif cv.path[0] == ('arg', 'Argument'):
cv.newSubtree = ast.arg(cv.newSubtree, cv.oldSubtree.annotation)
elif cv.path[0] == ('value', 'Name Constant'):
cv.newSubtree = ast.NameConstant(cv.newSubtree)
elif cv.path[0] == ('s', 'Bytes'):
cv.newSubtree = ast.Bytes(cv.newSubtree)
elif cv.path[0] == ('name', 'Alias'):
cv.newSubtree = ast.alias(cv.newSubtree, cv.oldSubtree.asname)
cv.path = cv.path[1:]
return cv
def cleanupRanges(a):
"""Remove any range shenanigans, because Python lets you include unneccessary values"""
if not isinstance(a, ast.AST):
return a
if type(a) == ast.Call:
if type(a.func) == ast.Name:
if a.func.id in ["range"]:
if len(a.args) == 3:
# The step defaults to 1!
if type(a.args[2]) == ast.Num and a.args[2].n == 1:
a.args = a.args[:-1]
if len(a.args) == 2:
# The start defaults to 0!
if type(a.args[0]) == ast.Num and a.args[0].n == 0:
a.args = a.args[1:]
return applyToChildren(a, cleanupRanges)
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 num_negate(op):
top = type(op)
neg = not op.num_negated if hasattr(op, "num_negated") else True
if top == ast.Add:
newOp = ast.Sub()
elif top == ast.Sub:
newOp = ast.Add()
elif top in [ast.Mult, ast.Div, ast.Mod, ast.Pow, ast.LShift,
ast.RShift, ast.BitOr, ast.BitXor, ast.BitAnd, ast.FloorDiv]:
return None # can't negate this
elif top in [ast.Num, ast.Name]:
# this is a normal value, so put a - in front of it
newOp = ast.UnaryOp(ast.USub(addedNeg=True), op)
else:
log("astTools\tnum_negate\tUnusual type: " + str(top), "bug")
transferMetaData(op, newOp)
newOp.num_negated = neg
return newOp
def isDefault(a):
"""Our programs have a default setting of return 42, so we should detect that"""
if type(a) == ast.Module and len(a.body) == 1:
a = a.body[0]
else:
return False
if type(a) != ast.FunctionDef:
return False
if len(a.body) == 0:
return True
elif len(a.body) == 1:
if type(a.body[0]) == ast.Return:
if a.body[0].value == None or \
type(a.body[0].value) == ast.Num and a.body[0].value.n == 42:
return True
return False
def get_version():
with open(os.path.join('settei', 'version.py')) as f:
tree = ast.parse(f.read(), f.name)
for node in ast.walk(tree):
if not (isinstance(node, ast.Assign) and len(node.targets) == 1):
continue
target, = node.targets
value = node.value
if not (isinstance(target, ast.Name) and
target.id == 'VERSION_INFO' and
isinstance(value, ast.Tuple)):
continue
elts = value.elts
if any(not isinstance(elt, ast.Num) for elt in elts):
continue
return '.'.join(str(elt.n) for elt in elts)
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 parse_args(args):
arg_list = []
for arg in args:
if isinstance(arg, ast.Str):
arg_list.append("%s" % arg.s)
elif isinstance(arg, ast.Name):
value = arg.id
if value == "None":
arg_list.append(None)
else:
arg_list.append(value)
elif isinstance(arg, ast.Num):
arg_list.append(arg.n)
elif isinstance(arg, ast.List):
arg_list.append(parse_args(arg.elts))
elif isinstance(arg, ast.Tuple):
arg_list.append(tuple(parse_args(arg.elts)))
elif isinstance(arg, ast.Attribute):
arg_list.append(str(arg.value.id) + "." + str(arg.attr))
else:
print(arg, type(arg))
return arg_list
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 _UnaryOp(self, t):
self.write("(")
self.write(self.unop[t.op.__class__.__name__])
self.write(" ")
# If we're applying unary minus to a number, parenthesize the number.
# This is necessary: -2147483648 is different from -(2147483648) on
# a 32-bit machine (the first is an int, the second a long), and
# -7j is different from -(7j). (The first has real part 0.0, the second
# has real part -0.0.)
if isinstance(t.op, ast.USub) and isinstance(t.operand, ast.Num):
self.write("(")
self.dispatch(t.operand)
self.write(")")
else:
self.dispatch(t.operand)
self.write(")")
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_For(self, node):
"""
for i in 5: pass # range(5)
for i in 2^10: pass # range(2, 10)
for i in 1^100^5: pass # range(2, 10, 5)
"""
self.generic_visit(node)
it = node.iter
if isinstance(it, ast.Num):
node.iter = self.make_Call('range', [it])
elif self._is_range_op(it):
# two cases, 2^10 and 1^100^5
range_args = []
left = it.left
if self._is_range_op(left):
range_args.append(left.left)
range_args.append(left.right)
else:
range_args.append(left)
range_args.append(it.right)
node.iter = self.make_Call('range', range_args)
return node
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 specialize_constant(node, value):
if value is None or isinstance(value, bool):
new_node = ast.NameConstant(value=value)
elif isinstance(value, (int, float, complex)):
new_node = ast.Num(n=value)
elif isinstance(value, str):
new_node = ast.Str(s=value)
elif isinstance(value, bytes):
new_node = ast.Bytes(s=value)
elif isinstance(value, tuple):
elts = [specialize_constant(node, elt) for elt in value]
new_node = ast.Tuple(elts=elts, ctx=ast.Load())
else:
raise ValueError("unknown constant: %r" % value)
fatoptimizer.tools.copy_lineno(node, new_node)
return new_node
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 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 convert_to_value(item):
if isinstance(item, ast.Str):
return item.s
elif hasattr(ast, 'Bytes') and isinstance(item, ast.Bytes):
return item.s
elif isinstance(item, ast.Tuple):
return tuple(convert_to_value(i) for i in item.elts)
elif isinstance(item, ast.Num):
return item.n
elif isinstance(item, ast.Name):
result = VariableKey(item=item)
constants_lookup = {
'True': True,
'False': False,
'None': None,
}
return constants_lookup.get(
result.name,
result,
)
elif (not PY33) and isinstance(item, ast.NameConstant):
# None, True, False are nameconstants in python3, but names in 2
return item.value
else:
return UnhandledKeyType()
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 parse_decorator(node: ast.AST):
if isinstance(node, ast.Name):
ret = Decorator()
ret.name = node.id
return ret
elif isinstance(node, ast.Call):
ret = Decorator()
ret.name = node.func.id
for arg in node.args:
if isinstance(arg, ast.Num):
ret.args.append(str(arg.n))
elif isinstance(arg, ast.Str):
ret.args.append(str(arg.n))
elif isinstance(arg, ast.Name):
ret.args.append(arg.id)
else:
v = eval_numeric_constexpr(arg)
if v:
ret.args.append(str(v))
else:
error(loc(node), "Unsupported decorator type")
return ret
else:
error(loc(node), "Supported decorators are Name and Call")
return None
def PYSL_tl_decl(node: ast.AnnAssign):
"""Parses a specific top-level declaration"""
if not isinstance(node.annotation, ast.Call) or (node.annotation.func.id != 'register' or
len(node.annotation.args) != 2 or
not isinstance(node.annotation.args[0], ast.Name) or
not isinstance(node.annotation.args[1], ast.Num)):
error(loc(node), "Invalid top level resource declaration, see docs. <name> : register(<type>, <slot>) = (...)")
res_name = node.target.id
res_type = node.annotation.args[0].id
res_slot = node.annotation.args[1].n
if res_type in pysl.Language.Sampler.TYPES:
emitter.sampler(parse_sampler(node, res_name, res_type[7:], res_slot, node.value))
else:
error((node), "Unrecognized top-level resource declaration {0} : {1}".format(res_name, res_type))
def get_type(expr):
"""Find the type of an expression.
Args:
expr: The expression to check.
Returns:
The type of the expression.
"""
if isinstance(expr, ast.Num):
return build_pb2.Attribute.INTEGER
elif isinstance(expr, ast.Str):
return build_pb2.Attribute.STRING
elif isinstance(expr, ast.List):
return build_pb2.Attribute.STRING_LIST
elif isinstance(expr, ast.Name) and (expr.id == "True" or expr.id == "False"):
return build_pb2.Attribute.BOOLEAN
else:
return build_pb2.Attribute.UNKNOWN
def subs(root, **kwargs):
'''Substitute ast.Name nodes for numbers in root using the mapping in
kwargs. Returns a new copy of root.
'''
root = copy.deepcopy(root)
class Transformer(ast.NodeTransformer):
def visit_FunctionDef(self, node):
return node
def visit_Name(self, node):
if node.id in kwargs and not isinstance(node.ctx, ast.Store):
replacement = kwargs[node.id]
if isinstance(replacement, int):
return ast.copy_location(ast.Num(n=replacement), node)
else:
return copy.copy(replacement)
else:
return node
return Transformer().visit(root)
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 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 unfold_list(_list):
if any(isinstance(x, ast.Call) for x in _list):
new_list = list()
for e in _list:
if isinstance(e, ast.Call):
name = e.func.id
if name == 'r':
try:
lower = e.args[0].n
upper = e.args[1].n
r_list = r(lower, upper)
for elem in r_list:
new_list.append(ast.Num(elem))
except Exception:
raise AttributeError(
"function 'r' needs 2 integer arguments")
else:
return _list
else:
new_list.append(e)
return new_list
else:
return _list