def __init__(self, stmt, context):
self.stmt = stmt
self.context = context
self.stmt_table = {
ast.Expr: self.expr,
ast.Pass: self.parse_pass,
ast.AnnAssign: self.ann_assign,
ast.Assign: self.assign,
ast.If: self.parse_if,
ast.Call: self.call,
ast.Assert: self.parse_assert,
ast.For: self.parse_for,
ast.AugAssign: self.aug_assign,
ast.Break: self.parse_break,
ast.Return: self.parse_return,
}
stmt_type = self.stmt.__class__
if stmt_type in self.stmt_table:
self.lll_node = self.stmt_table[stmt_type]()
elif isinstance(stmt, ast.Name) and stmt.id == "throw":
self.lll_node = LLLnode.from_list(['assert', 0], typ=None, pos=getpos(stmt))
else:
raise StructureException("Unsupported statement type", stmt)
python类AnnAssign()的实例源码
def get_contracts_and_defs_and_globals(code):
_contracts = {}
_events = []
_globals = {}
_defs = []
_getters = []
for item in code:
# Contract references
if isinstance(item, ast.ClassDef):
if _events or _globals or _defs:
raise StructureException("External contract declarations must come before event declarations, global declarations, and function definitions", item)
_contracts[item.name] = add_contract(item.body)
# Statements of the form:
# variable_name: type
elif isinstance(item, ast.AnnAssign):
_contracts, _events, _globals, _getters = add_globals_and_events(_contracts, _defs, _events, _getters, _globals, item)
# Function definitions
elif isinstance(item, ast.FunctionDef):
_defs.append(item)
else:
raise StructureException("Invalid top-level statement", item)
return _contracts, _events, _defs + _getters, _globals
# Header code
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 add_annotation_to_assignments(self, model, solver):
"""Add a type comment for every assignment statement in the context"""
for node, z3_t in self.assignments:
if (len(node.targets) == 1 and isinstance(node.targets[0], ast.Name)
and sys.version_info[0] >= 3 and sys.version_info[1] >= 6):
# Replace the normal assignment node with annotated assignment
# Annotated assignment only supports single assignment (no tuples or lists)
# To unparse the assignment statement into the new syntax of the variable annotation,
# The class of the nodes needs to be AnnAssign, to be recognized by the unparser
node.__class__ = ast.AnnAssign
node.target = node.targets[0]
node.simple = 1
annotation_str = solver.annotation_resolver.unparse_annotation(
model[self.get_type(node.targets[0].id)])
node.annotation = ast.parse(annotation_str).body[0].value
# Add the type comment for assignments in children contexts
for child in self.children_contexts:
child.add_annotation_to_assignments(model, solver)
def _translate_body(self, body, types, allow_loose_in_edges=False, allow_loose_out_edges=False):
cfg_factory = CFGFactory(self._id_gen)
for child in body:
if isinstance(child, (ast.AnnAssign, ast.Expr)):
cfg_factory.add_stmts(self.visit(child, types))
elif isinstance(child, ast.If):
cfg_factory.complete_basic_block()
if_cfg = self.visit(child, types)
cfg_factory.append_cfg(if_cfg)
elif isinstance(child, ast.While):
cfg_factory.complete_basic_block()
while_cfg = self.visit(child, types)
cfg_factory.append_cfg(while_cfg)
elif isinstance(child, ast.Break):
cfg_factory.complete_basic_block()
break_cfg = self.visit(child, types)
cfg_factory.append_cfg(break_cfg)
elif isinstance(child, ast.Continue):
cfg_factory.complete_basic_block()
cont_cfg = self.visit(child, types)
cfg_factory.append_cfg(cont_cfg)
elif isinstance(child, ast.Pass):
if cfg_factory.incomplete_block():
pass
else:
cfg_factory.append_cfg(_dummy_cfg(self._id_gen))
else:
raise NotImplementedError(f"The statement {str(type(child))} is not yet translatable to CFG!")
cfg_factory.complete_basic_block()
if not allow_loose_in_edges and cfg_factory.cfg and cfg_factory.cfg.loose_in_edges:
cfg_factory.prepend_cfg(_dummy_cfg(self._id_gen))
if not allow_loose_out_edges and cfg_factory.cfg and cfg_factory.cfg.loose_out_edges:
cfg_factory.append_cfg(_dummy_cfg(self._id_gen))
return cfg_factory.cfg
def parse_assignment(node: ast.AST) -> pysl.Assignment:
"""Block level assignment, can either be a declaration or not"""
if not isinstance(node, ast.Assign) and not isinstance(node, ast.AnnAssign):
error(loc(node), "Expected Assignment")
return
ret = pysl.Assignment()
ret.set_location(node)
ret.qualifiers = []
if isinstance(node, ast.AnnAssign):
# Declaration
ret.name = node.target.id
if isinstance(node.annotation, ast.Name):
ret.type = node.annotation.id
elif (isinstance(node.annotation, ast.Attribute) and
isinstance(node.annotation.value, ast.Name)):
if node.annotation.value.id == pysl.Language.Qualifier.CONST:
ret.qualifiers.append(pysl.Language.Qualifier.CONST)
else:
error(loc(node.annotation), "Unsupported qualifier, only const is supported in a block assignment/declaration")
ret.type = node.annotation.attr
else:
error(loc(node.annotation), "Unsupported annotation, supported are <type> or const.<type>")
else:
# Assignment
if isinstance(node.targets[0], ast.Name):
ret.name = node.targets[0].id
elif isinstance(node.targets[0], ast.Attribute):
ret.name = parse_attribute_no_eval(node.targets[0])
else:
error(loc(node), "Unsupported assignment target")
if node.value and isinstance(node.value, ast.Name):
ret.value = node.value.id
elif node.value and isinstance(node.value, ast.Num):
ret.value = str(node.value.n)
else:
ret.value = None
return ret
def parse_struct(node: ast.ClassDef) -> pysl.Struct:
struct = pysl.Struct()
struct.set_location(node)
struct.name = node.name
struct.elements = []
struct.set_location(node)
for decl_node in node.body:
if isinstance(decl_node, ast.AnnAssign):
assignment = parse_assignment(decl_node)
struct.elements.append((str_to_pysl_type(loc(node), assignment.type), assignment.name))
else:
error(loc(decl_node), "Unrecognized node inside structure: {0}".format(struct.name))
return struct
def parse_stage_input(node: ast.ClassDef, stages: str) -> pysl.StageInput:
si = pysl.StageInput()
si.set_location(node)
si.name = node.name
si.elements = []
si.stages = stages
conditions = []
for decl_node in node.body:
if isinstance(decl_node, ast.AnnAssign):
assignment = parse_assignment(decl_node)
element = pysl.InputElement()
element.set_location(decl_node)
element.name = assignment.name
element.type = str_to_pysl_type(loc(decl_node), assignment.type)
element.semantic = assignment.value
element.conditions = list(conditions)
conditions[:] = [] # Copy
si.elements.append(element)
elif (isinstance(decl_node, ast.Expr) and
isinstance(decl_node.value, ast.Call)):
if decl_node.value.func.id is '_':
conditions.append(parse_preprocessor(decl_node.value))
else:
error(loc(decl_node), "Unsupported function call: {0} inside StageInput: {1}".format(decl_node.value.func.id, si.name))
else:
error(loc(decl_node), "Unrecognized node inside StageInput: {0}".format(si.name))
si.post_conditions = list(conditions)
return si
def parse_constant_buffer(node: ast.ClassDef) -> pysl.ConstantBuffer:
cbuffer = pysl.ConstantBuffer()
cbuffer.set_location(node)
cbuffer.name = node.name
cbuffer.constants = []
for decl_node in node.body:
if isinstance(decl_node, ast.AnnAssign):
assignment = parse_assignment(decl_node)
constant = pysl.Constant()
constant.set_location(decl_node)
constant.name = assignment.name
if assignment.value:
try:
constant.offset = int(assignment.value)
except ValueError:
error(loc(decl_node), "Expected numberic offset as argument")
assignment.value
constant.type = str_to_pysl_type(loc(decl_node), assignment.type)
cbuffer.constants.append(constant)
else:
error(loc(decl_node), "Unrecognized node inside ConstantBuffer: {0}".format(cbuffer.name))
for d in node.decorator_list:
decorator = parse_decorator(d)
if decorator.args:
try:
cbuffer.enforced_size = int(decorator.args[0])
except ValueError:
error(loc(d), "Expected integer argument to constructor indicating enforced size(in constants), but evaluated: {0}".format(decorator.args[0]))
return cbuffer
def add_globals_and_events(_contracts, _defs, _events, _getters, _globals, item):
if item.value is not None:
raise StructureException('May not assign value whilst defining type', item)
elif isinstance(item.annotation, ast.Call) and item.annotation.func.id == "__log__":
if _globals or len(_defs):
raise StructureException("Events must all come before global declarations and function definitions", item)
_events.append(item)
elif not isinstance(item.target, ast.Name):
raise StructureException("Can only assign type to variable in top-level statement", item)
# Check if variable name is reserved or invalid
elif not is_varname_valid(item.target.id):
raise VariableDeclarationException("Variable name invalid or reserved: ", item.target)
# Check if global already exists, if so error
elif item.target.id in _globals:
raise VariableDeclarationException("Cannot declare a persistent variable twice!", item.target)
elif len(_defs):
raise StructureException("Global variables must all come before function definitions", item)
# If the type declaration is of the form public(<type here>), then proceed with
# the underlying type but also add getters
elif isinstance(item.annotation, ast.Call) and item.annotation.func.id == "address":
if len(item.annotation.args) != 1:
raise StructureException("Address expects one arg (the type)")
if item.annotation.args[0].id not in premade_contracts:
raise VariableDeclarationException("Unsupported premade contract declaration", item.annotation.args[0])
premade_contract = premade_contracts[item.annotation.args[0].id]
_contracts[item.target.id] = add_contract(premade_contract.body)
_globals[item.target.id] = VariableRecord(item.target.id, len(_globals), BaseType('address'), True)
elif isinstance(item, ast.AnnAssign) and isinstance(item.annotation, ast.Name) and item.annotation.id in _contracts:
_globals[item.target.id] = VariableRecord(item.target.id, len(_globals), BaseType('address', item.annotation.id), True)
elif isinstance(item.annotation, ast.Call) and item.annotation.func.id == "public":
if len(item.annotation.args) != 1:
raise StructureException("Public expects one arg (the type)")
if isinstance(item.annotation.args[0], ast.Name) and item.annotation.args[0].id in _contracts:
typ = BaseType('address', item.annotation.args[0].id)
else:
typ = parse_type(item.annotation.args[0], 'storage')
_globals[item.target.id] = VariableRecord(item.target.id, len(_globals), typ, True)
# Adding getters here
for getter in mk_getter(item.target.id, typ):
_getters.append(parse_line('\n' * (item.lineno - 1) + getter))
_getters[-1].pos = getpos(item)
else:
_globals[item.target.id] = VariableRecord(item.target.id, len(_globals), parse_type(item.annotation, 'storage'), True)
return _contracts, _events, _globals, _getters
# Parse top-level functions and variables