def parse_to_ast(source_code: str, source_id: int = 0, contract_name: Optional[str] = None) -> vy_ast.Module: """ Parses a Vyper source string and generates basic Vyper AST nodes. Parameters ---------- source_code : str The Vyper source code to parse. source_id : int, optional Source id to use in the `src` member of each node. Returns ------- list Untyped, unoptimized Vyper AST nodes. """ if "\x00" in source_code: raise ParserException( "No null bytes (\\x00) allowed in the source code.") class_types, reformatted_code = pre_parse(source_code) try: py_ast = python_ast.parse(reformatted_code) except SyntaxError as e: # TODO: Ensure 1-to-1 match of source_code:reformatted_code SyntaxErrors raise SyntaxException(str(e), source_code, e.lineno, e.offset) from e annotate_python_ast(py_ast, source_code, class_types, source_id, contract_name) # Convert to Vyper AST. return vy_ast.get_node(py_ast) # type: ignore
def parse_to_ast(source_code: str, source_id: int = 0) -> vy_ast.Module: """ Parses a vyper source string and generates basic vyper AST nodes. Parameters ---------- source_code : str The vyper source code to parse. source_id : int, optional Source id to use in the .src member of each node. Returns ------- list Untyped, unoptimized vyper AST nodes. """ if '\x00' in source_code: raise ParserException( 'No null bytes (\\x00) allowed in the source code.') class_types, reformatted_code = pre_parse(source_code) try: py_ast = python_ast.parse(reformatted_code) except SyntaxError as e: # TODO: Ensure 1-to-1 match of source_code:reformatted_code SyntaxErrors raise PythonSyntaxException(e, source_code) from e annotate_python_ast(py_ast, source_code, class_types, source_id) # Convert to Vyper AST. return vy_ast.get_node(py_ast) # type: ignore
def convert(expr, context): if isinstance(expr.args[1], ast.Str): warnings.warn( "String parameter has been removed (see VIP1026). " "Use a vyper type instead.", DeprecationWarning) if isinstance(expr.args[1], ast.Name): output_type = expr.args[1].id else: raise ParserException("Invalid conversion type, use valid Vyper type.", expr) if output_type in conversion_table: return conversion_table[output_type](expr, context) else: raise ParserException( "Conversion to {} is invalid.".format(output_type), expr)
def parse_to_ast(code): class_names, code = pre_parse(code) if '\x00' in code: raise ParserException( 'No null bytes (\\x00) allowed in the source code.') o = ast.parse(code) # python ast decorate_ast(o, code, class_names) # decorated python ast o = resolve_negative_literals(o) return o.body
def test_type_exception_pos(): pos = (1, 2) with raises(ParserException) as e: raise ParserException('Fail!', pos) assert e.value.lineno == 1 assert e.value.col_offset == 2 assert str(e.value) == 'line 1:2 Fail!'
def abi_type_to_ast(atype, expected_size): if atype in ('int128', 'uint256', 'bool', 'address', 'bytes32'): return ast.Name(id=atype) elif atype == 'fixed168x10': return ast.Name(id='decimal') elif atype in ('bytes', 'string'): # expected_size is the maximum length for inputs, minimum length for outputs return ast.Subscript(value=ast.Name(id=atype), slice=ast.Index(value=ast.Num(n=expected_size))) else: raise ParserException(f'Type {atype} not supported by vyper.')
def abi_type_to_ast(atype): if atype in ('int128', 'uint256', 'bool', 'address', 'bytes32'): return ast.Name(id=atype) elif atype == 'decimal': return ast.Name(id='int128') elif atype == 'bytes': return ast.Subscript(value=ast.Name(id='bytes'), slice=ast.Index(256)) elif atype == 'string': return ast.Subscript(value=ast.Name(id='string'), slice=ast.Index(256)) else: raise ParserException(f'Type {atype} not supported by vyper.')
def parse_to_ast(source_code: str) -> list: if '\x00' in source_code: raise ParserException('No null bytes (\\x00) allowed in the source code.') class_types, reformatted_code = pre_parse(source_code) py_ast = python_ast.parse(reformatted_code) annotate_ast(py_ast, source_code, class_types) # Convert to Vyper AST. vyper_ast = parse_python_ast( source_code=source_code, node=py_ast, ) return vyper_ast.body # type: ignore
def convert(expr, context): if len(expr.args) != 2: raise ParserException('The convert function expects two parameters.', expr) if isinstance(expr.args[1], ast.Str): warnings.warn( "String parameter has been removed (see VIP1026). " "Use a vyper type instead.", DeprecationWarning ) if isinstance(expr.args[1], ast.Name): output_type = expr.args[1].id elif isinstance(expr.args[1], (ast.Subscript)) and isinstance(expr.args[1].value, (ast.Name)): output_type = expr.args[1].value.id else: raise ParserException("Invalid conversion type, use valid Vyper type.", expr) if output_type in conversion_table: return conversion_table[output_type](expr, context) else: raise ParserException("Conversion to {} is invalid.".format(output_type), expr)
def parse_to_ast( source_code: str, source_id: int = 0, contract_name: Optional[str] = None, add_fn_node: Optional[str] = None, ) -> vy_ast.Module: """ Parses a Vyper source string and generates basic Vyper AST nodes. Parameters ---------- source_code : str The Vyper source code to parse. source_id : int, optional Source id to use in the `src` member of each node. contract_name: str, optional Name of contract. add_fn_node: str, optional If not None, adds a dummy Python AST FunctionDef wrapper node. Returns ------- list Untyped, unoptimized Vyper AST nodes. """ if "\x00" in source_code: raise ParserException( "No null bytes (\\x00) allowed in the source code.") class_types, reformatted_code = pre_parse(source_code) try: py_ast = python_ast.parse(reformatted_code) except SyntaxError as e: # TODO: Ensure 1-to-1 match of source_code:reformatted_code SyntaxErrors raise SyntaxException(str(e), source_code, e.lineno, e.offset) from e # Add dummy function node to ensure local variables are treated as `AnnAssign` # instead of state variables (`VariableDecl`) if add_fn_node: fn_node = python_ast.FunctionDef(add_fn_node, py_ast.body, [], []) fn_node.body = py_ast.body fn_node.args = python_ast.arguments(defaults=[]) py_ast.body = [fn_node] annotate_python_ast(py_ast, source_code, class_types, source_id, contract_name) # Convert to Vyper AST. return vy_ast.get_node(py_ast) # type: ignore
def parse_to_ast(source_code: str, source_id: int = 0) -> list: if '\x00' in source_code: raise ParserException( 'No null bytes (\\x00) allowed in the source code.') class_types, reformatted_code = pre_parse(source_code) try: py_ast = python_ast.parse(reformatted_code) except SyntaxError as e: # TODO: Ensure 1-to-1 match of source_code:reformatted_code SyntaxErrors raise PythonSyntaxException(e, source_code) from e annotate_ast(py_ast, source_code, class_types) asttokens.ASTTokens(source_code, tree=py_ast) # Convert to Vyper AST. vyper_ast = parse_python_ast( source_code=source_code, node=py_ast, source_id=source_id, ) return vyper_ast.body # type: ignore
def parse_to_ast(source_code: str) -> List[ast.stmt]: """ Parses the given vyper source code and returns a list of python AST objects for all statements in the source. Performs pre-processing of source code before parsing as well as post-processing of the resulting AST. :param source_code: The vyper source code to be parsed. :return: The post-processed list of python AST objects for each statement in ``source_code``. """ class_types, reformatted_code = pre_parse(source_code) if '\x00' in reformatted_code: raise ParserException( 'No null bytes (\\x00) allowed in the source code.') parsed_ast = ast.parse(reformatted_code) annotate_and_optimize_ast(parsed_ast, reformatted_code, class_types) return parsed_ast.body
def arithmetic(self): left = Expr.parse_value_expr(self.expr.left, self.context) right = Expr.parse_value_expr(self.expr.right, self.context) if not is_numeric_type(left.typ) or not is_numeric_type(right.typ): raise TypeMismatchException( f"Unsupported types for arithmetic op: {left.typ} {right.typ}", self.expr, ) arithmetic_pair = {left.typ.typ, right.typ.typ} # Special Case: Simplify any literal to literal arithmetic at compile time. if left.typ.is_literal and right.typ.is_literal and \ isinstance(right.value, int) and isinstance(left.value, int) and \ arithmetic_pair.issubset({'uint256', 'int128'}): if isinstance(self.expr.op, vy_ast.Add): val = left.value + right.value elif isinstance(self.expr.op, vy_ast.Sub): val = left.value - right.value elif isinstance(self.expr.op, vy_ast.Mult): val = left.value * right.value elif isinstance(self.expr.op, vy_ast.Pow): val = left.value ** right.value elif isinstance(self.expr.op, (vy_ast.Div, vy_ast.Mod)): if right.value == 0: raise ZeroDivisionException( "integer division or modulo by zero", self.expr, ) if isinstance(self.expr.op, vy_ast.Div): val = left.value // right.value elif isinstance(self.expr.op, vy_ast.Mod): # modified modulo logic to remain consistent with EVM behaviour val = abs(left.value) % abs(right.value) if left.value < 0: val = -val else: raise ParserException( f'Unsupported literal operator: {type(self.expr.op)}', self.expr, ) num = vy_ast.Int(n=val) num.full_source_code = self.expr.full_source_code num.node_source_code = self.expr.node_source_code num.lineno = self.expr.lineno num.col_offset = self.expr.col_offset num.end_lineno = self.expr.end_lineno num.end_col_offset = self.expr.end_col_offset return Expr.parse_value_expr(num, self.context) pos = getpos(self.expr) # Special case with uint256 were int literal may be casted. if arithmetic_pair == {'uint256', 'int128'}: # Check right side literal. if right.typ.is_literal and SizeLimits.in_bounds('uint256', right.value): right = LLLnode.from_list( right.value, typ=BaseType('uint256', None, is_literal=True), pos=pos, ) # Check left side literal. elif left.typ.is_literal and SizeLimits.in_bounds('uint256', left.value): left = LLLnode.from_list( left.value, typ=BaseType('uint256', None, is_literal=True), pos=pos, ) if left.typ.typ == "decimal" and isinstance(self.expr.op, vy_ast.Pow): raise TypeMismatchException( "Cannot perform exponentiation on decimal values.", self.expr, ) # Only allow explicit conversions to occur. if left.typ.typ != right.typ.typ: raise TypeMismatchException( f"Cannot implicitly convert {left.typ.typ} to {right.typ.typ}.", self.expr, ) ltyp, rtyp = left.typ.typ, right.typ.typ if isinstance(self.expr.op, (vy_ast.Add, vy_ast.Sub)): if left.typ.unit != right.typ.unit and left.typ.unit != {} and right.typ.unit != {}: raise TypeMismatchException( f"Unit mismatch: {left.typ.unit} {right.typ.unit}", self.expr, ) if ( left.typ.positional and right.typ.positional and isinstance(self.expr.op, vy_ast.Add) ): raise TypeMismatchException( "Cannot add two positional units!", self.expr, ) new_unit = left.typ.unit or right.typ.unit # xor, as subtracting two positionals gives a delta new_positional = left.typ.positional ^ right.typ.positional new_typ = BaseType(ltyp, new_unit, new_positional) op = 'add' if isinstance(self.expr.op, vy_ast.Add) else 'sub' if ltyp == 'uint256' and isinstance(self.expr.op, vy_ast.Add): # safeadd arith = ['seq', ['assert', ['ge', ['add', 'l', 'r'], 'l']], ['add', 'l', 'r']] elif ltyp == 'uint256' and isinstance(self.expr.op, vy_ast.Sub): # safesub arith = ['seq', ['assert', ['ge', 'l', 'r']], ['sub', 'l', 'r']] elif ltyp == rtyp: arith = [op, 'l', 'r'] else: raise Exception(f"Unsupported Operation '{op}({ltyp}, {rtyp})'") elif isinstance(self.expr.op, vy_ast.Mult): if left.typ.positional or right.typ.positional: raise TypeMismatchException("Cannot multiply positional values!", self.expr) new_unit = combine_units(left.typ.unit, right.typ.unit) new_typ = BaseType(ltyp, new_unit) if ltyp == rtyp == 'uint256': arith = ['with', 'ans', ['mul', 'l', 'r'], ['seq', ['assert', ['or', ['eq', ['div', 'ans', 'l'], 'r'], ['iszero', 'l']]], 'ans']] elif ltyp == rtyp == 'int128': # TODO should this be 'smul' (note edge cases in YP for smul) arith = ['mul', 'l', 'r'] elif ltyp == rtyp == 'decimal': # TODO should this be smul arith = ['with', 'ans', ['mul', 'l', 'r'], ['seq', ['assert', ['or', ['eq', ['sdiv', 'ans', 'l'], 'r'], ['iszero', 'l']]], ['sdiv', 'ans', DECIMAL_DIVISOR]]] else: raise Exception(f"Unsupported Operation 'mul({ltyp}, {rtyp})'") elif isinstance(self.expr.op, vy_ast.Div): if right.typ.is_literal and right.value == 0: raise ZeroDivisionException("Cannot divide by 0.", self.expr) if left.typ.positional or right.typ.positional: raise TypeMismatchException("Cannot divide positional values!", self.expr) new_unit = combine_units(left.typ.unit, right.typ.unit, div=True) new_typ = BaseType(ltyp, new_unit) if ltyp == rtyp == 'uint256': arith = ['div', 'l', ['clamp_nonzero', 'r']] elif ltyp == rtyp == 'int128': arith = ['sdiv', 'l', ['clamp_nonzero', 'r']] elif ltyp == rtyp == 'decimal': arith = ['sdiv', # TODO check overflow cases, also should it be smul ['mul', 'l', DECIMAL_DIVISOR], ['clamp_nonzero', 'r']] else: raise Exception(f"Unsupported Operation 'div({ltyp}, {rtyp})'") elif isinstance(self.expr.op, vy_ast.Mod): if right.typ.is_literal and right.value == 0: raise ZeroDivisionException("Cannot calculate modulus of 0.", self.expr) if left.typ.positional or right.typ.positional: raise TypeMismatchException( "Cannot use positional values as modulus arguments!", self.expr, ) if not are_units_compatible(left.typ, right.typ) and not (left.typ.unit or right.typ.unit): # noqa: E501 raise TypeMismatchException("Modulus arguments must have same unit", self.expr) new_unit = left.typ.unit or right.typ.unit new_typ = BaseType(ltyp, new_unit) if ltyp == rtyp == 'uint256': arith = ['mod', 'l', ['clamp_nonzero', 'r']] elif ltyp == rtyp: # TODO should this be regular mod arith = ['smod', 'l', ['clamp_nonzero', 'r']] else: raise Exception(f"Unsupported Operation 'mod({ltyp}, {rtyp})'") elif isinstance(self.expr.op, vy_ast.Pow): if left.typ.positional or right.typ.positional: raise TypeMismatchException( "Cannot use positional values as exponential arguments!", self.expr, ) if right.typ.unit: raise TypeMismatchException( "Cannot use unit values as exponents", self.expr, ) if ltyp != 'int128' and ltyp != 'uint256' and isinstance(self.expr.right, vy_ast.Name): raise TypeMismatchException( "Cannot use dynamic values as exponents, for unit base types", self.expr, ) new_unit = left.typ.unit if left.typ.unit and not isinstance(self.expr.right, vy_ast.Name): new_unit = {left.typ.unit.copy().popitem()[0]: self.expr.right.n} new_typ = BaseType(ltyp, new_unit) if ltyp == rtyp == 'uint256': arith = ['seq', ['assert', ['or', # r == 1 | iszero(r) # could be simplified to ~(r & 1) ['or', ['eq', 'r', 1], ['iszero', 'r']], ['lt', 'l', ['exp', 'l', 'r']]]], ['exp', 'l', 'r']] elif ltyp == rtyp == 'int128': arith = ['exp', 'l', 'r'] else: raise TypeMismatchException('Only whole number exponents are supported', self.expr) else: raise ParserException(f"Unsupported binary operator: {self.expr.op}", self.expr) p = ['seq'] if new_typ.typ == 'int128': p.append([ 'clamp', ['mload', MemoryPositions.MINNUM], arith, ['mload', MemoryPositions.MAXNUM], ]) elif new_typ.typ == 'decimal': p.append([ 'clamp', ['mload', MemoryPositions.MINDECIMAL], arith, ['mload', MemoryPositions.MAXDECIMAL], ]) elif new_typ.typ == 'uint256': p.append(arith) else: raise Exception(f"{arith} {new_typ}") p = ['with', 'l', left, ['with', 'r', right, p]] return LLLnode.from_list(p, typ=new_typ, pos=pos)
def arithmetic(self): pre_alloc_left, left = self.arithmetic_get_reference(self.expr.left) pre_alloc_right, right = self.arithmetic_get_reference(self.expr.right) if not is_numeric_type(left.typ) or not is_numeric_type(right.typ): raise TypeMismatchException( f"Unsupported types for arithmetic op: {left.typ} {right.typ}", self.expr, ) arithmetic_pair = {left.typ.typ, right.typ.typ} # Special Case: Simplify any literal to literal arithmetic at compile time. if left.typ.is_literal and right.typ.is_literal and \ isinstance(right.value, int) and isinstance(left.value, int) and \ arithmetic_pair.issubset({'uint256', 'int128'}): if isinstance(self.expr.op, ast.Add): val = left.value + right.value elif isinstance(self.expr.op, ast.Sub): val = left.value - right.value elif isinstance(self.expr.op, ast.Mult): val = left.value * right.value elif isinstance(self.expr.op, ast.Div): val = left.value // right.value elif isinstance(self.expr.op, ast.Mod): val = left.value % right.value elif isinstance(self.expr.op, ast.Pow): val = left.value ** right.value else: raise ParserException( f'Unsupported literal operator: {str(type(self.expr.op))}', self.expr, ) num = ast.Num(n=val) num.source_code = self.expr.source_code num.lineno = self.expr.lineno num.col_offset = self.expr.col_offset num.end_lineno = self.expr.end_lineno num.end_col_offset = self.expr.end_col_offset return Expr.parse_value_expr(num, self.context) # Special case with uint256 were int literal may be casted. if arithmetic_pair == {'uint256', 'int128'}: # Check right side literal. if right.typ.is_literal and SizeLimits.in_bounds('uint256', right.value): right = LLLnode.from_list( right.value, typ=BaseType('uint256', None, is_literal=True), pos=getpos(self.expr), ) # Check left side literal. elif left.typ.is_literal and SizeLimits.in_bounds('uint256', left.value): left = LLLnode.from_list( left.value, typ=BaseType('uint256', None, is_literal=True), pos=getpos(self.expr), ) # Only allow explicit conversions to occur. if left.typ.typ != right.typ.typ: raise TypeMismatchException( f"Cannot implicitly convert {left.typ.typ} to {right.typ.typ}.", self.expr, ) ltyp, rtyp = left.typ.typ, right.typ.typ if isinstance(self.expr.op, (ast.Add, ast.Sub)): if left.typ.unit != right.typ.unit and left.typ.unit != {} and right.typ.unit != {}: raise TypeMismatchException( f"Unit mismatch: {left.typ.unit} {right.typ.unit}", self.expr, ) if left.typ.positional and right.typ.positional and isinstance(self.expr.op, ast.Add): raise TypeMismatchException( "Cannot add two positional units!", self.expr, ) new_unit = left.typ.unit or right.typ.unit # xor, as subtracting two positionals gives a delta new_positional = left.typ.positional ^ right.typ.positional op = 'add' if isinstance(self.expr.op, ast.Add) else 'sub' if ltyp == 'uint256' and isinstance(self.expr.op, ast.Add): o = LLLnode.from_list([ 'seq', # Checks that: a + b >= a ['assert', ['ge', ['add', left, right], left]], ['add', left, right], ], typ=BaseType('uint256', new_unit, new_positional), pos=getpos(self.expr)) elif ltyp == 'uint256' and isinstance(self.expr.op, ast.Sub): o = LLLnode.from_list([ 'seq', # Checks that: a >= b ['assert', ['ge', left, right]], ['sub', left, right] ], typ=BaseType('uint256', new_unit, new_positional), pos=getpos(self.expr)) elif ltyp == rtyp: o = LLLnode.from_list( [op, left, right], typ=BaseType(ltyp, new_unit, new_positional), pos=getpos(self.expr), ) else: raise Exception(f"Unsupported Operation '{op}({ltyp}, {rtyp})'") elif isinstance(self.expr.op, ast.Mult): if left.typ.positional or right.typ.positional: raise TypeMismatchException("Cannot multiply positional values!", self.expr) new_unit = combine_units(left.typ.unit, right.typ.unit) if ltyp == rtyp == 'uint256': o = LLLnode.from_list([ 'if', ['eq', left, 0], [0], [ 'seq', ['assert', ['eq', ['div', ['mul', left, right], left], right]], ['mul', left, right] ], ], typ=BaseType('uint256', new_unit), pos=getpos(self.expr)) elif ltyp == rtyp == 'int128': o = LLLnode.from_list( ['mul', left, right], typ=BaseType('int128', new_unit), pos=getpos(self.expr), ) elif ltyp == rtyp == 'decimal': o = LLLnode.from_list([ 'with', 'r', right, [ 'with', 'l', left, [ 'with', 'ans', ['mul', 'l', 'r'], [ 'seq', [ 'assert', ['or', ['eq', ['sdiv', 'ans', 'l'], 'r'], ['iszero', 'l']] ], ['sdiv', 'ans', DECIMAL_DIVISOR], ], ], ], ], typ=BaseType('decimal', new_unit), pos=getpos(self.expr)) else: raise Exception(f"Unsupported Operation 'mul({ltyp}, {rtyp})'") elif isinstance(self.expr.op, ast.Div): if left.typ.positional or right.typ.positional: raise TypeMismatchException("Cannot divide positional values!", self.expr) new_unit = combine_units(left.typ.unit, right.typ.unit, div=True) if ltyp == rtyp == 'uint256': o = LLLnode.from_list([ 'seq', # Checks that: b != 0 ['assert', right], ['div', left, right], ], typ=BaseType('uint256', new_unit), pos=getpos(self.expr)) elif ltyp == rtyp == 'int128': o = LLLnode.from_list( ['sdiv', left, ['clamp_nonzero', right]], typ=BaseType('int128', new_unit), pos=getpos(self.expr), ) elif ltyp == rtyp == 'decimal': o = LLLnode.from_list([ 'with', 'l', left, [ 'with', 'r', ['clamp_nonzero', right], [ 'sdiv', ['mul', 'l', DECIMAL_DIVISOR], 'r', ], ] ], typ=BaseType('decimal', new_unit), pos=getpos(self.expr)) else: raise Exception(f"Unsupported Operation 'div({ltyp}, {rtyp})'") elif isinstance(self.expr.op, ast.Mod): if left.typ.positional or right.typ.positional: raise TypeMismatchException( "Cannot use positional values as modulus arguments!", self.expr, ) if not are_units_compatible(left.typ, right.typ) and not (left.typ.unit or right.typ.unit): # noqa: E501 raise TypeMismatchException("Modulus arguments must have same unit", self.expr) new_unit = left.typ.unit or right.typ.unit if ltyp == rtyp == 'uint256': o = LLLnode.from_list([ 'seq', ['assert', right], ['mod', left, right] ], typ=BaseType('uint256', new_unit), pos=getpos(self.expr)) elif ltyp == rtyp: o = LLLnode.from_list( ['smod', left, ['clamp_nonzero', right]], typ=BaseType(ltyp, new_unit), pos=getpos(self.expr), ) else: raise Exception(f"Unsupported Operation 'mod({ltyp}, {rtyp})'") elif isinstance(self.expr.op, ast.Pow): if left.typ.positional or right.typ.positional: raise TypeMismatchException( "Cannot use positional values as exponential arguments!", self.expr, ) if right.typ.unit: raise TypeMismatchException( "Cannot use unit values as exponents", self.expr, ) if ltyp != 'int128' and ltyp != 'uint256' and isinstance(self.expr.right, ast.Name): raise TypeMismatchException( "Cannot use dynamic values as exponents, for unit base types", self.expr, ) if ltyp == rtyp == 'uint256': o = LLLnode.from_list([ 'seq', [ 'assert', [ 'or', ['or', ['eq', right, 1], ['iszero', right]], ['lt', left, ['exp', left, right]] ], ], ['exp', left, right], ], typ=BaseType('uint256'), pos=getpos(self.expr)) elif ltyp == rtyp == 'int128': new_unit = left.typ.unit if left.typ.unit and not isinstance(self.expr.right, ast.Name): new_unit = {left.typ.unit.copy().popitem()[0]: self.expr.right.n} o = LLLnode.from_list( ['exp', left, right], typ=BaseType('int128', new_unit), pos=getpos(self.expr), ) else: raise TypeMismatchException('Only whole number exponents are supported', self.expr) else: raise ParserException(f"Unsupported binary operator: {self.expr.op}", self.expr) p = ['seq'] if pre_alloc_left: p.append(pre_alloc_left) if pre_alloc_right: p.append(pre_alloc_right) if o.typ.typ == 'int128': p.append([ 'clamp', ['mload', MemoryPositions.MINNUM], o, ['mload', MemoryPositions.MAXNUM], ]) return LLLnode.from_list(p, typ=o.typ, pos=getpos(self.expr)) elif o.typ.typ == 'decimal': p.append([ 'clamp', ['mload', MemoryPositions.MINDECIMAL], o, ['mload', MemoryPositions.MAXDECIMAL], ]) return LLLnode.from_list(p, typ=o.typ, pos=getpos(self.expr)) if o.typ.typ == 'uint256': p.append(o) return LLLnode.from_list(p, typ=o.typ, pos=getpos(self.expr)) else: raise Exception(f"{o} {o.typ}")
def add_globals_and_events(self, item): item_attributes = {"public": False} if len(self._globals) > NONRENTRANT_STORAGE_OFFSET: raise ParserException( f"Too many globals defined, only {NONRENTRANT_STORAGE_OFFSET} globals are allowed", item, ) # Make sure we have a valid variable name. if not isinstance(item.target, ast.Name): raise StructureException('Invalid global variable name', item.target) # Handle constants. if self.get_call_func_name(item) == "constant": self._constants.add_constant(item, global_ctx=self) return # Handle events. if not (self.get_call_func_name(item) == "event"): item_name, item_attributes = self.get_item_name_and_attributes( item, item_attributes) if not all([ attr in VALID_GLOBAL_KEYWORDS for attr in item_attributes.keys() ]): raise StructureException( f'Invalid global keyword used: {item_attributes}', item) if item.value is not None: raise StructureException( 'May not assign value whilst defining type', item) elif self.get_call_func_name(item) == "event": if self._globals or len(self._defs): raise EventDeclarationException( "Events must all come before global declarations and function definitions", item) self._events.append(item) elif not isinstance(item.target, ast.Name): raise StructureException( "Can only assign type to variable in top-level statement", item) # Is this a custom unit definition. elif item.target.id == 'units': if not self._custom_units: if not isinstance(item.annotation, ast.Dict): raise VariableDeclarationException( "Define custom units using units: { }.", item.target) for key, value in zip(item.annotation.keys, item.annotation.values): if not isinstance(value, ast.Str): raise VariableDeclarationException( "Custom unit description must be a valid string", value) if not isinstance(key, ast.Name): raise VariableDeclarationException( "Custom unit name must be a valid string", key) check_valid_varname(key.id, self._custom_units, self._structs, self._constants, key, "Custom unit invalid.") self._custom_units.add(key.id) self._custom_units_descriptions[key.id] = value.s else: raise VariableDeclarationException( "Custom units can only be defined once", item.target) # Check if variable name is valid. # Don't move this check higher, as unit parsing has to happen first. elif not self.is_valid_varname(item.target.id, item): pass elif len(self._defs): raise StructureException( "Global variables must all come before function definitions", item, ) elif item_name in self._contracts or item_name in self._interfaces: if self.get_call_func_name(item) == "address": raise StructureException( f"Persistent address({item_name}) style contract declarations " "are not support anymore." f" Use {item.target.id}: {item_name} instead") self._globals[item.target.id] = ContractRecord( item.target.id, len(self._globals), ContractType(item_name), True, ) if item_attributes["public"]: typ = ContractType(item_name) for getter in self.mk_getter(item.target.id, typ): self._getters.append( self.parse_line('\n' * (item.lineno - 1) + getter)) self._getters[-1].pos = getpos(item) elif self.get_call_func_name(item) == "public": if isinstance(item.annotation.args[0], ast.Name) and item_name in self._contracts: typ = ContractType(item_name) else: typ = parse_type( item.annotation.args[0], 'storage', custom_units=self._custom_units, custom_structs=self._structs, constants=self._constants, ) self._globals[item.target.id] = VariableRecord( item.target.id, len(self._globals), typ, True, ) # Adding getters here for getter in self.mk_getter(item.target.id, typ): self._getters.append( self.parse_line('\n' * (item.lineno - 1) + getter)) self._getters[-1].pos = getpos(item) elif isinstance(item.annotation, (ast.Name, ast.Call, ast.Subscript)): self._globals[item.target.id] = VariableRecord( item.target.id, len(self._globals), parse_type(item.annotation, 'storage', custom_units=self._custom_units, custom_structs=self._structs, constants=self._constants), True) else: raise InvalidTypeException('Invalid global type specified', item)
def attribute(self): # x.balance: balance of address x if self.expr.attr == 'balance': addr = Expr.parse_value_expr(self.expr.value, self.context) if not is_base_type(addr.typ, 'address'): raise TypeMismatchException( "Type mismatch: balance keyword expects an address as input", self.expr) return LLLnode.from_list( ['balance', addr], typ=BaseType('uint256', {'wei': 1}), location=None, pos=getpos(self.expr), ) # x.codesize: codesize of address x elif self.expr.attr == 'codesize' or self.expr.attr == 'is_contract': addr = Expr.parse_value_expr(self.expr.value, self.context) if not is_base_type(addr.typ, 'address'): raise TypeMismatchException( "Type mismatch: codesize keyword expects an address as input", self.expr, ) if self.expr.attr == 'codesize': eval_code = ['extcodesize', addr] output_type = 'int128' else: eval_code = ['gt', ['extcodesize', addr], 0] output_type = 'bool' return LLLnode.from_list( eval_code, typ=BaseType(output_type), location=None, pos=getpos(self.expr), ) # self.x: global attribute elif isinstance(self.expr.value, ast.Name) and self.expr.value.id == "self": if self.expr.attr not in self.context.globals: raise VariableDeclarationException( "Persistent variable undeclared: " + self.expr.attr, self.expr, ) var = self.context.globals[self.expr.attr] return LLLnode.from_list( var.pos, typ=var.typ, location='storage', pos=getpos(self.expr), annotation='self.' + self.expr.attr, ) # Reserved keywords elif isinstance( self.expr.value, ast.Name) and self.expr.value.id in ("msg", "block", "tx"): key = self.expr.value.id + "." + self.expr.attr if key == "msg.sender": if self.context.is_private: raise ParserException( "msg.sender not allowed in private functions.", self.expr) return LLLnode.from_list(['caller'], typ='address', pos=getpos(self.expr)) elif key == "msg.value": if not self.context.is_payable: raise NonPayableViolationException( "Cannot use msg.value in a non-payable function", self.expr, ) return LLLnode.from_list( ['callvalue'], typ=BaseType('uint256', {'wei': 1}), pos=getpos(self.expr), ) elif key == "msg.gas": return LLLnode.from_list( ['gas'], typ='uint256', pos=getpos(self.expr), ) elif key == "block.difficulty": return LLLnode.from_list( ['difficulty'], typ='uint256', pos=getpos(self.expr), ) elif key == "block.timestamp": return LLLnode.from_list( ['timestamp'], typ=BaseType('uint256', {'sec': 1}, True), pos=getpos(self.expr), ) elif key == "block.coinbase": return LLLnode.from_list(['coinbase'], typ='address', pos=getpos(self.expr)) elif key == "block.number": return LLLnode.from_list(['number'], typ='uint256', pos=getpos(self.expr)) elif key == "block.prevhash": return LLLnode.from_list( ['blockhash', ['sub', 'number', 1]], typ='bytes32', pos=getpos(self.expr), ) elif key == "tx.origin": return LLLnode.from_list(['origin'], typ='address', pos=getpos(self.expr)) else: raise ParserException("Unsupported keyword: " + key, self.expr) # Other variables else: sub = Expr.parse_variable_location(self.expr.value, self.context) # contract type if isinstance(sub.typ, ContractType): return sub if not isinstance(sub.typ, StructType): raise TypeMismatchException( "Type mismatch: member variable access not expected", self.expr.value, ) attrs = list(sub.typ.members.keys()) if self.expr.attr not in attrs: raise TypeMismatchException( "Member %s not found. Only the following available: %s" % (self.expr.attr, " ".join(attrs)), self.expr, ) return add_variable_offset(sub, self.expr.attr, pos=getpos(self.expr))
def parse_variable_location(expr, context): o = Expr(expr, context).lll_node if not o.location: raise ParserException( "Looking for a variable location, instead got a value", expr) return o
def arithmetic(self): left = Expr.parse_value_expr(self.expr.left, self.context) right = Expr.parse_value_expr(self.expr.right, self.context) if not is_numeric_type(left.typ) or not is_numeric_type(right.typ): raise TypeMismatchException( "Unsupported types for arithmetic op: %r %r" % (left.typ, right.typ), self.expr) arithmetic_pair = {left.typ.typ, right.typ.typ} # Special Case: Simplify any literal to literal arithmetic at compile time. if left.typ.is_literal and right.typ.is_literal and \ isinstance(right.value, int) and isinstance(left.value, int): if isinstance(self.expr.op, ast.Add): val = left.value + right.value elif isinstance(self.expr.op, ast.Sub): val = left.value - right.value elif isinstance(self.expr.op, ast.Mult): val = left.value * right.value elif isinstance(self.expr.op, ast.Div): val = left.value // right.value elif isinstance(self.expr.op, ast.Mod): val = left.value % right.value elif isinstance(self.expr.op, ast.Pow): val = left.value**right.value else: raise ParserException( 'Unsupported literal operator: %s' % str(type(self.expr.op)), self.expr) num = ast.Num(val) num.source_code = self.expr.source_code num.lineno = self.expr.lineno num.col_offset = self.expr.col_offset return Expr.parse_value_expr(num, self.context) # Special case with uint256 were int literal may be casted. if arithmetic_pair == {'uint256', 'int128'}: # Check right side literal. if right.typ.is_literal and SizeLimits.in_bounds( 'uint256', right.value): right = LLLnode.from_list(right.value, typ=BaseType('uint256', None, is_literal=True), pos=getpos(self.expr)) arithmetic_pair = {left.typ.typ, right.typ.typ} # Check left side literal. elif left.typ.is_literal and SizeLimits.in_bounds( 'uint256', left.value): left = LLLnode.from_list(left.value, typ=BaseType('uint256', None, is_literal=True), pos=getpos(self.expr)) arithmetic_pair = {left.typ.typ, right.typ.typ} # Only allow explicit conversions to occur. if left.typ.typ != right.typ.typ: raise TypeMismatchException( "Cannot implicitly convert {} to {}.".format( left.typ.typ, right.typ.typ), self.expr) ltyp, rtyp = left.typ.typ, right.typ.typ if isinstance(self.expr.op, (ast.Add, ast.Sub)): if left.typ.unit != right.typ.unit and left.typ.unit is not None and right.typ.unit is not None: raise TypeMismatchException( "Unit mismatch: %r %r" % (left.typ.unit, right.typ.unit), self.expr) if left.typ.positional and right.typ.positional and isinstance( self.expr.op, ast.Add): raise TypeMismatchException("Cannot add two positional units!", self.expr) new_unit = left.typ.unit or right.typ.unit new_positional = left.typ.positional ^ right.typ.positional # xor, as subtracting two positionals gives a delta op = 'add' if isinstance(self.expr.op, ast.Add) else 'sub' if ltyp == 'uint256' and isinstance(self.expr.op, ast.Add): o = LLLnode.from_list( [ 'seq', # Checks that: a + b >= a ['assert', ['ge', ['add', left, right], left]], ['add', left, right] ], typ=BaseType('uint256', new_unit, new_positional), pos=getpos(self.expr)) elif ltyp == 'uint256' and isinstance(self.expr.op, ast.Sub): o = LLLnode.from_list( [ 'seq', # Checks that: a >= b ['assert', ['ge', left, right]], ['sub', left, right] ], typ=BaseType('uint256', new_unit, new_positional), pos=getpos(self.expr)) elif ltyp == rtyp: o = LLLnode.from_list([op, left, right], typ=BaseType(ltyp, new_unit, new_positional), pos=getpos(self.expr)) else: raise Exception("Unsupported Operation '%r(%r, %r)'" % (op, ltyp, rtyp)) elif isinstance(self.expr.op, ast.Mult): if left.typ.positional or right.typ.positional: raise TypeMismatchException( "Cannot multiply positional values!", self.expr) new_unit = combine_units(left.typ.unit, right.typ.unit) if ltyp == rtyp == 'uint256': o = LLLnode.from_list( [ 'seq', # Checks that: a == 0 || a / b == b [ 'assert', [ 'or', ['iszero', left], [ 'eq', ['div', ['mul', left, right], left], right ] ] ], ['mul', left, right] ], typ=BaseType('uint256', new_unit), pos=getpos(self.expr)) elif ltyp == rtyp == 'int128': o = LLLnode.from_list(['mul', left, right], typ=BaseType('int128', new_unit), pos=getpos(self.expr)) elif ltyp == rtyp == 'decimal': o = LLLnode.from_list([ 'with', 'r', right, [ 'with', 'l', left, [ 'with', 'ans', ['mul', 'l', 'r'], [ 'seq', [ 'assert', [ 'or', [ 'eq', ['sdiv', 'ans', 'l'], 'r' ], ['iszero', 'l'] ] ], ['sdiv', 'ans', DECIMAL_DIVISOR] ] ] ] ], typ=BaseType('decimal', new_unit), pos=getpos(self.expr)) else: raise Exception("Unsupported Operation 'mul(%r, %r)'" % (ltyp, rtyp)) elif isinstance(self.expr.op, ast.Div): if left.typ.positional or right.typ.positional: raise TypeMismatchException("Cannot divide positional values!", self.expr) new_unit = combine_units(left.typ.unit, right.typ.unit, div=True) if ltyp == rtyp == 'uint256': o = LLLnode.from_list( [ 'seq', # Checks that: b != 0 ['assert', right], ['div', left, right] ], typ=BaseType('uint256', new_unit), pos=getpos(self.expr)) elif ltyp == rtyp == 'int128': o = LLLnode.from_list(['sdiv', left, ['clamp_nonzero', right]], typ=BaseType('int128', new_unit), pos=getpos(self.expr)) elif ltyp == rtyp == 'decimal': o = LLLnode.from_list([ 'with', 'l', left, [ 'with', 'r', ['clamp_nonzero', right], ['sdiv', ['mul', 'l', DECIMAL_DIVISOR], 'r'] ] ], typ=BaseType('decimal', new_unit), pos=getpos(self.expr)) else: raise Exception("Unsupported Operation 'div(%r, %r)'" % (ltyp, rtyp)) elif isinstance(self.expr.op, ast.Mod): if left.typ.positional or right.typ.positional: raise TypeMismatchException( "Cannot use positional values as modulus arguments!", self.expr) if left.typ.unit != right.typ.unit and left.typ.unit is not None and right.typ.unit is not None: raise TypeMismatchException( "Modulus arguments must have same unit", self.expr) new_unit = left.typ.unit or right.typ.unit if ltyp == rtyp == 'uint256': o = LLLnode.from_list( ['seq', ['assert', right], ['mod', left, right]], typ=BaseType('uint256', new_unit), pos=getpos(self.expr)) elif ltyp == rtyp: o = LLLnode.from_list(['smod', left, ['clamp_nonzero', right]], typ=BaseType(ltyp, new_unit), pos=getpos(self.expr)) else: raise Exception("Unsupported Operation 'mod(%r, %r)'" % (ltyp, rtyp)) elif isinstance(self.expr.op, ast.Pow): if left.typ.positional or right.typ.positional: raise TypeMismatchException( "Cannot use positional values as exponential arguments!", self.expr) if right.typ.unit: raise TypeMismatchException( "Cannot use unit values as exponents", self.expr) if ltyp != 'int128' and ltyp != 'uint256' and isinstance( self.expr.right, ast.Name): raise TypeMismatchException( "Cannot use dynamic values as exponents, for unit base types", self.expr) if ltyp == rtyp == 'uint256': o = LLLnode.from_list([ 'seq', [ 'assert', [ 'or', ['or', ['eq', right, 1], ['iszero', right]], ['lt', left, ['exp', left, right]] ] ], ['exp', left, right] ], typ=BaseType('uint256'), pos=getpos(self.expr)) elif ltyp == rtyp == 'int128': new_unit = left.typ.unit if left.typ.unit and not isinstance(self.expr.right, ast.Name): new_unit = { left.typ.unit.copy().popitem()[0]: self.expr.right.n } o = LLLnode.from_list(['exp', left, right], typ=BaseType('int128', new_unit), pos=getpos(self.expr)) else: raise TypeMismatchException( 'Only whole number exponents are supported', self.expr) else: raise Exception("Unsupported binop: %r" % self.expr.op) if o.typ.typ == 'int128': return LLLnode.from_list([ 'clamp', ['mload', MemoryPositions.MINNUM], o, ['mload', MemoryPositions.MAXNUM] ], typ=o.typ, pos=getpos(self.expr)) elif o.typ.typ == 'decimal': return LLLnode.from_list([ 'clamp', ['mload', MemoryPositions.MINDECIMAL], o, ['mload', MemoryPositions.MAXDECIMAL] ], typ=o.typ, pos=getpos(self.expr)) if o.typ.typ == 'uint256': return o else: raise Exception("%r %r" % (o, o.typ))
def _clear(): raise ParserException( "This function should never be called! `clear()` is currently handled " "differently than other functions as it self modifies its input argument " "statement. Please see `_clear()` in `stmt.py`" )
def compare(self): left = Expr.parse_value_expr(self.expr.left, self.context) right = Expr.parse_value_expr(self.expr.comparators[0], self.context) if isinstance(right.typ, NullType): raise InvalidLiteralException( 'Comparison to None is not allowed, compare against a default value.', self.expr, ) if isinstance(left.typ, ByteArrayLike) and isinstance(right.typ, ByteArrayLike): # TODO: Can this if branch be removed ^ pass elif isinstance(self.expr.ops[0], vy_ast.In) and isinstance(right.typ, ListType): if left.typ != right.typ.subtype: raise TypeMismatchException( "Can't use IN comparison with different types!", self.expr, ) return self.build_in_comparator() else: if not are_units_compatible(left.typ, right.typ) and not are_units_compatible(right.typ, left.typ): # noqa: E501 raise TypeMismatchException("Can't compare values with different units!", self.expr) if len(self.expr.ops) != 1: raise StructureException( "Cannot have a comparison with more than two elements", self.expr, ) if isinstance(self.expr.ops[0], vy_ast.Gt): op = 'sgt' elif isinstance(self.expr.ops[0], vy_ast.GtE): op = 'sge' elif isinstance(self.expr.ops[0], vy_ast.LtE): op = 'sle' elif isinstance(self.expr.ops[0], vy_ast.Lt): op = 'slt' elif isinstance(self.expr.ops[0], vy_ast.Eq): op = 'eq' elif isinstance(self.expr.ops[0], vy_ast.NotEq): op = 'ne' else: raise Exception("Unsupported comparison operator") # Compare (limited to 32) byte arrays. if isinstance(left.typ, ByteArrayLike) and isinstance(right.typ, ByteArrayLike): left = Expr(self.expr.left, self.context).lll_node right = Expr(self.expr.comparators[0], self.context).lll_node length_mismatch = (left.typ.maxlen != right.typ.maxlen) left_over_32 = left.typ.maxlen > 32 right_over_32 = right.typ.maxlen > 32 if length_mismatch or left_over_32 or right_over_32: left_keccak = keccak256_helper(self.expr, [left], None, self.context) right_keccak = keccak256_helper(self.expr, [right], None, self.context) if op == 'eq' or op == 'ne': return LLLnode.from_list( [op, left_keccak, right_keccak], typ='bool', pos=getpos(self.expr), ) else: raise ParserException( "Can only compare strings/bytes of length shorter", " than 32 bytes other than equality comparisons", self.expr, ) else: def load_bytearray(side): if side.location == 'memory': return ['mload', ['add', 32, side]] elif side.location == 'storage': return ['sload', ['add', 1, ['sha3_32', side]]] return LLLnode.from_list( [op, load_bytearray(left), load_bytearray(right)], typ='bool', pos=getpos(self.expr), ) # Compare other types. if not is_numeric_type(left.typ) or not is_numeric_type(right.typ): if op not in ('eq', 'ne'): raise TypeMismatchException("Invalid type for comparison op", self.expr) left_type, right_type = left.typ.typ, right.typ.typ # Special Case: comparison of a literal integer. If in valid range allow it to be compared. if {left_type, right_type} == {'int128', 'uint256'} and {left.typ.is_literal, right.typ.is_literal} == {True, False}: # noqa: E501 comparison_allowed = False if left.typ.is_literal and SizeLimits.in_bounds(right_type, left.value): comparison_allowed = True elif right.typ.is_literal and SizeLimits.in_bounds(left_type, right.value): comparison_allowed = True op = self._signed_to_unsigned_comparision_op(op) if comparison_allowed: return LLLnode.from_list([op, left, right], typ='bool', pos=getpos(self.expr)) elif {left_type, right_type} == {'uint256', 'uint256'}: op = self._signed_to_unsigned_comparision_op(op) elif (left_type in ('decimal', 'int128') or right_type in ('decimal', 'int128')) and left_type != right_type: # noqa: E501 raise TypeMismatchException( f'Implicit conversion from {left_type} to {right_type} disallowed, please convert.', self.expr, ) if left_type == right_type: return LLLnode.from_list([op, left, right], typ='bool', pos=getpos(self.expr)) else: raise TypeMismatchException( f"Unsupported types for comparison: {left_type} {right_type}", self.expr, )
def compare(self): left = Expr.parse_value_expr(self.expr.left, self.context) right = Expr.parse_value_expr(self.expr.comparators[0], self.context) if isinstance(left.typ, ByteArrayType) and isinstance( right.typ, ByteArrayType): if left.typ.maxlen != right.typ.maxlen: raise TypeMismatchException( 'Can only compare bytes of the same length', self.expr) if left.typ.maxlen > 32 or right.typ.maxlen > 32: raise ParserException( 'Can only compare bytes of length shorter than 32 bytes', self.expr) elif isinstance(self.expr.ops[0], ast.In) and \ isinstance(right.typ, ListType): if not are_units_compatible( left.typ, right.typ.subtype) and not are_units_compatible( right.typ.subtype, left.typ): raise TypeMismatchException( "Can't use IN comparison with different types!", self.expr) return self.build_in_comparator() else: if not are_units_compatible( left.typ, right.typ) and not are_units_compatible( right.typ, left.typ): raise TypeMismatchException( "Can't compare values with different units!", self.expr) if len(self.expr.ops) != 1: raise StructureException( "Cannot have a comparison with more than two elements", self.expr) if isinstance(self.expr.ops[0], ast.Gt): op = 'sgt' elif isinstance(self.expr.ops[0], ast.GtE): op = 'sge' elif isinstance(self.expr.ops[0], ast.LtE): op = 'sle' elif isinstance(self.expr.ops[0], ast.Lt): op = 'slt' elif isinstance(self.expr.ops[0], ast.Eq): op = 'eq' elif isinstance(self.expr.ops[0], ast.NotEq): op = 'ne' else: raise Exception("Unsupported comparison operator") # Compare (limited to 32) byte arrays. if isinstance(left.typ, ByteArrayType) and isinstance( left.typ, ByteArrayType): left = Expr(self.expr.left, self.context).lll_node right = Expr(self.expr.comparators[0], self.context).lll_node def load_bytearray(side): if side.location == 'memory': return ['mload', ['add', 32, side]] elif side.location == 'storage': return ['sload', ['add', 1, ['sha3_32', side]]] return LLLnode.from_list( [op, load_bytearray(left), load_bytearray(right)], typ='bool', pos=getpos(self.expr)) # Compare other types. if not is_numeric_type(left.typ) or not is_numeric_type(right.typ): if op not in ('eq', 'ne'): raise TypeMismatchException("Invalid type for comparison op", self.expr) left_type, right_type = left.typ.typ, right.typ.typ # Special Case: comparison of a literal integer. If in valid range allow it to be compared. if {left_type, right_type} == {'int128', 'uint256'} and { left.typ.is_literal, right.typ.is_literal } == {True, False}: comparison_allowed = False if left.typ.is_literal and SizeLimits.in_bounds( right_type, left.value): comparison_allowed = True elif right.typ.is_literal and SizeLimits.in_bounds( left_type, right.value): comparison_allowed = True op = self._signed_to_unsigned_comparision_op(op) if comparison_allowed: return LLLnode.from_list([op, left, right], typ='bool', pos=getpos(self.expr)) elif {left_type, right_type} == {'uint256', 'uint256'}: op = self._signed_to_unsigned_comparision_op(op) elif (left_type in ('decimal', 'int128') or right_type in ('decimal', 'int128')) and left_type != right_type: raise TypeMismatchException( 'Implicit conversion from {} to {} disallowed, please convert.' .format(left_type, right_type), self.expr) if left_type == right_type: return LLLnode.from_list([op, left, right], typ='bool', pos=getpos(self.expr)) else: raise TypeMismatchException( "Unsupported types for comparison: %r %r" % (left_type, right_type), self.expr)
def add_globals_and_events(self, item): item_attributes = {"public": False} if len(self._globals) > NONRENTRANT_STORAGE_OFFSET: raise ParserException( "Too many globals defined, only {} globals are allowed".format( NONRENTRANT_STORAGE_OFFSET), item) # Make sure we have a valid variable name. if not isinstance(item.target, ast.Name): raise StructureException('Invalid global variable name', item.target) # Handle constants. if self.get_call_func_name(item) == "constant": self._constants.add_constant(item, global_ctx=self) return # Handle events. if not (self.get_call_func_name(item) == "event"): item_name, item_attributes = self.get_item_name_and_attributes( item, item_attributes) if not all([ attr in valid_global_keywords for attr in item_attributes.keys() ]): raise StructureException( 'Invalid global keyword used: %s' % item_attributes, item) if item.value is not None: raise StructureException( 'May not assign value whilst defining type', item) elif self.get_call_func_name(item) == "event": if self._globals or len(self._defs): raise EventDeclarationException( "Events must all come before global declarations and function definitions", item) self._events.append(item) elif not isinstance(item.target, ast.Name): raise StructureException( "Can only assign type to variable in top-level statement", item) # Is this a custom unit definition. elif item.target.id == 'units': if not self._custom_units: if not isinstance(item.annotation, ast.Dict): raise VariableDeclarationException( "Define custom units using units: { }.", item.target) for key, value in zip(item.annotation.keys, item.annotation.values): if not isinstance(value, ast.Str): raise VariableDeclarationException( "Custom unit description must be a valid string", value) if not isinstance(key, ast.Name): raise VariableDeclarationException( "Custom unit name must be a valid string", key) check_valid_varname(key.id, self._custom_units, self._structs, self._constants, key, "Custom unit invalid.") self._custom_units.add(key.id) self._custom_units_descriptions[key.id] = value.s else: raise VariableDeclarationException( "Custom units can only be defined once", item.target) # Check if variable name is valid. # Don't move this check higher, as unit parsing has to happen first. elif not self.is_valid_varname(item.target.id, item): pass elif len(self._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 self.get_call_func_name(item) == "address": 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] self._contracts[item.target.id] = self.make_contract( premade_contract.body) self._globals[item.target.id] = VariableRecord( item.target.id, len(self._globals), BaseType('address'), True) elif item_name in self._contracts: self._globals[item.target.id] = ContractRecord( item.target.id, len(self._globals), ContractType(item_name), True) if item_attributes["public"]: typ = ContractType(item_name) for getter in self.mk_getter(item.target.id, typ): self._getters.append( self.parse_line('\n' * (item.lineno - 1) + getter)) self._getters[-1].pos = getpos(item) elif self.get_call_func_name(item) == "public": if isinstance(item.annotation.args[0], ast.Name) and item_name in self._contracts: typ = ContractType(item_name) else: typ = parse_type(item.annotation.args[0], 'storage', custom_units=self._custom_units, custom_structs=self._structs, constants=self._constants) self._globals[item.target.id] = VariableRecord( item.target.id, len(self._globals), typ, True) # Adding getters here for getter in self.mk_getter(item.target.id, typ): self._getters.append( self.parse_line('\n' * (item.lineno - 1) + getter)) self._getters[-1].pos = getpos(item) elif isinstance(item.annotation, (ast.Name, ast.Call, ast.Subscript)): self._globals[item.target.id] = VariableRecord( item.target.id, len(self._globals), parse_type(item.annotation, 'storage', custom_units=self._custom_units, custom_structs=self._structs, constants=self._constants), True) else: raise InvalidTypeException('Invalid global type specified', item)