def from_definition(cls, code, _sigs=None):
name = code.name
pos = 0
# Determine the arguments, expects something of the form def foo(arg1: num, arg2: num ...
args = []
for arg in code.args.args:
typ = arg.annotation
if not isinstance(arg.arg, str):
raise VariableDeclarationException("Argument name invalid", arg)
if not typ:
raise InvalidTypeException("Argument must have type", arg)
if not is_varname_valid(arg.arg):
raise VariableDeclarationException("Argument name invalid or reserved: " + arg.arg, arg)
if arg.arg in (x.name for x in args):
raise VariableDeclarationException("Duplicate function argument name: " + arg.arg, arg)
parsed_type = parse_type(typ, None, _sigs)
args.append(VariableRecord(arg.arg, pos, parsed_type, False))
if isinstance(parsed_type, ByteArrayType):
pos += 32
else:
pos += get_size_of_type(parsed_type) * 32
# Apply decorators
const, payable, private, public = False, False, False, False
for dec in code.decorator_list:
if isinstance(dec, ast.Name) and dec.id == "constant":
const = True
elif isinstance(dec, ast.Name) and dec.id == "payable":
payable = True
elif isinstance(dec, ast.Name) and dec.id == "private":
private = True
elif isinstance(dec, ast.Name) and dec.id == "public":
public = True
else:
raise StructureException("Bad decorator", dec)
if public and private:
raise StructureException("Cannot use public and private decorators on the same function", code)
if not public and not private and not isinstance(code.body[0], ast.Pass):
raise StructureException("Function visibility must be declared (@public or @private)", code)
# Determine the return type and whether or not it's constant. Expects something
# of the form:
# def foo(): ...
# def foo() -> num: ...
# If there is no return type, ie. it's of the form def foo(): ...
# and NOT def foo() -> type: ..., then it's null
if not code.returns:
output_type = None
elif isinstance(code.returns, (ast.Name, ast.Compare, ast.Subscript, ast.Call, ast.Tuple)):
output_type = parse_type(code.returns, None, _sigs)
else:
raise InvalidTypeException("Output type invalid or unsupported: %r" % parse_type(code.returns, None), code.returns)
# Output type must be canonicalizable
if output_type is not None:
assert isinstance(output_type, TupleType) or canonicalize_type(output_type)
# Get the canonical function signature
sig = name + '(' + ','.join([canonicalize_type(parse_type(arg.annotation, None, _sigs)) for arg in code.args.args]) + ')'
# Take the first 4 bytes of the hash of the sig to get the method ID
method_id = fourbytes_to_int(sha3(bytes(sig, 'utf-8'))[:4])
return cls(name, args, output_type, const, payable, private, sig, method_id)
评论列表
文章目录