예제 #1
0
    def unary_operations(self):
        operand = Expr.parse_value_expr(self.expr.operand, self.context)
        if isinstance(self.expr.op, ast.Not):
            if isinstance(operand.typ, BaseType) and operand.typ.typ == 'bool':
                return LLLnode.from_list(["iszero", operand],
                                         typ='bool',
                                         pos=getpos(self.expr))
            else:
                raise TypeMismatchException(
                    "Only bool is supported for not operation, %r supplied." %
                    operand.typ,
                    self.expr,
                )
        elif isinstance(self.expr.op, ast.USub):
            if not is_numeric_type(operand.typ):
                raise TypeMismatchException(
                    "Unsupported type for negation: %r" % operand.typ,
                    operand,
                )

            if operand.typ.is_literal and 'int' in operand.typ.typ:
                num = ast.Num(n=0 - operand.value)
                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)

            return LLLnode.from_list(["sub", 0, operand],
                                     typ=operand.typ,
                                     pos=getpos(self.expr))
        else:
            raise StructureException(
                "Only the 'not' unary operator is supported")
예제 #2
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.')
예제 #3
0
파일: expr.py 프로젝트: cottonhat00/vyper
    def unary_operations(self):
        operand = Expr.parse_value_expr(self.expr.operand, self.context)
        if isinstance(self.expr.op, ast.Not):
            if isinstance(operand.typ, BaseType) and operand.typ.typ == 'bool':
                return LLLnode.from_list(["iszero", operand],
                                         typ='bool',
                                         pos=getpos(self.expr))
            else:
                raise TypeMismatchException(
                    f"Only bool is supported for not operation, {operand.typ} supplied.",
                    self.expr,
                )
        elif isinstance(self.expr.op, ast.USub):
            # Must be a signed integer
            if not is_numeric_type(
                    operand.typ) or operand.typ.typ.lower().startswith('u'):
                raise TypeMismatchException(
                    f"Unsupported type for negation: {operand.typ}",
                    operand,
                )

            if operand.typ.is_literal and 'int' in operand.typ.typ:
                num = ast.Num(n=0 - operand.value)
                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)

            # Clamp on minimum integer value as we cannot negate that value
            # (all other integer values are fine)
            min_int_val = get_min_val_for_type(operand.typ.typ)
            return LLLnode.from_list(
                ["sub", 0, ["clampgt", operand, min_int_val]],
                typ=operand.typ,
                pos=getpos(self.expr))
        else:
            raise StructureException(
                "Only the 'not' or 'neg' unary operators are supported")
예제 #4
0
파일: expr.py 프로젝트: kiok46/vyper
    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, 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)

        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,
                )

        # 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

            new_typ = BaseType(ltyp, new_unit, new_positional)

            op = 'add' if isinstance(self.expr.op, ast.Add) else 'sub'

            if ltyp == 'uint256' and isinstance(self.expr.op, ast.Add):
                # safeadd
                arith = ['seq',
                         ['assert', ['ge', ['add', 'l', 'r'], 'l']],
                         ['add', 'l', 'r']]

            elif ltyp == 'uint256' and isinstance(self.expr.op, 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, 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, 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)
            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, 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
            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, 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,
                )
            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}
            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)
예제 #5
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(
                "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) 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(
                    'Unsupported literal operator: %s' %
                    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

            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(
                "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 != {} and right.typ.unit != {}:
                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

            # 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("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([
                    '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("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 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("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 ParserException(
                "Unsupported binary operator: %r" % 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("%r %r" % (o, o.typ))