Beispiel #1
0
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
Beispiel #2
0
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
Beispiel #3
0
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)
Beispiel #4
0
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
Beispiel #5
0
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!'
Beispiel #6
0
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.')
Beispiel #7
0
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.')
Beispiel #8
0
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
Beispiel #9
0
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)
Beispiel #10
0
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
Beispiel #11
0
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
Beispiel #12
0
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
Beispiel #13
0
    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)
Beispiel #14
0
    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}")
Beispiel #15
0
    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)
Beispiel #16
0
 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))
Beispiel #17
0
 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
Beispiel #18
0
    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))
Beispiel #19
0
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`"
    )
Beispiel #20
0
    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,
            )
Beispiel #21
0
    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)
Beispiel #22
0
    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)