示例#1
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(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")
     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)
     ltyp, rtyp = left.typ.typ, right.typ.typ
     if ltyp == rtyp:
         return LLLnode.from_list([op, left, right],
                                  typ='bool',
                                  pos=getpos(self.expr))
     elif ltyp == 'decimal' and rtyp == 'num':
         return LLLnode.from_list(
             [op, left, ['mul', right, DECIMAL_DIVISOR]],
             typ='bool',
             pos=getpos(self.expr))
     elif ltyp == 'num' and rtyp == 'decimal':
         return LLLnode.from_list(
             [op, ['mul', left, DECIMAL_DIVISOR], right],
             typ='bool',
             pos=getpos(self.expr))
     else:
         raise TypeMismatchException(
             "Unsupported types for comparison: %r %r" % (ltyp, rtyp),
             self.expr)
示例#2
0
文件: expr.py 项目: sdtsui/viper
 def unary_operations(self):
     operand = Expr.parse_value_expr(self.expr.operand, self.context)
     if isinstance(self.expr.op, ast.Not):
         # Note that in the case of bool, num, address, decimal, num256 AND bytes32,
         # a zero entry represents false, all others represent true
         return LLLnode.from_list(["iszero", operand], typ='bool', pos=getpos(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)
         return LLLnode.from_list(["sub", 0, operand], typ=operand.typ, pos=getpos(self.expr))
     else:
         raise StructureException("Only the 'not' unary operator is supported")
示例#3
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)
     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 == rtyp:
             o = LLLnode.from_list([op, left, right],
                                   typ=BaseType(ltyp, new_unit,
                                                new_positional),
                                   pos=getpos(self.expr))
         elif ltyp == 'num' and rtyp == 'decimal':
             o = LLLnode.from_list(
                 [op, ['mul', left, DECIMAL_DIVISOR], right],
                 typ=BaseType('decimal', new_unit, new_positional),
                 pos=getpos(self.expr))
         elif ltyp == 'decimal' and rtyp == 'num':
             o = LLLnode.from_list(
                 [op, left, ['mul', right, DECIMAL_DIVISOR]],
                 typ=BaseType('decimal', new_unit, new_positional),
                 pos=getpos(self.expr))
         else:
             raise Exception("How did I get here? %r %r" % (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 == 'num':
             o = LLLnode.from_list(['mul', left, right],
                                   typ=BaseType('num', 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'
                                     ], ['not', 'l']
                                 ]
                             ], ['sdiv', 'ans', DECIMAL_DIVISOR]
                         ]
                     ]
                 ]
             ],
                                   typ=BaseType('decimal', new_unit),
                                   pos=getpos(self.expr))
         elif (ltyp == 'num' and rtyp == 'decimal') or (ltyp == 'decimal'
                                                        and rtyp == 'num'):
             o = LLLnode.from_list([
                 'with', 'r', right,
                 [
                     'with', 'l', left,
                     [
                         'with', 'ans', ['mul', 'l', 'r'],
                         [
                             'seq',
                             [
                                 'assert',
                                 [
                                     'or', [
                                         'eq', ['sdiv', 'ans', 'l'], 'r'
                                     ], ['not', 'l']
                                 ]
                             ], 'ans'
                         ]
                     ]
                 ]
             ],
                                   typ=BaseType('decimal', new_unit),
                                   pos=getpos(self.expr))
     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 rtyp == 'num':
             o = LLLnode.from_list(['sdiv', left, ['clamp_nonzero', right]],
                                   typ=BaseType(ltyp, 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))
         elif ltyp == 'num' and rtyp == 'decimal':
             o = LLLnode.from_list([
                 'sdiv', ['mul', left, DECIMAL_DIVISOR**2],
                 ['clamp_nonzero', right]
             ],
                                   typ=BaseType('decimal', new_unit),
                                   pos=getpos(self.expr))
     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:
             o = LLLnode.from_list(['smod', left, ['clamp_nonzero', right]],
                                   typ=BaseType(ltyp, new_unit),
                                   pos=getpos(self.expr))
         elif ltyp == 'decimal' and rtyp == 'num':
             o = LLLnode.from_list([
                 'smod', left,
                 ['mul', ['clamp_nonzero', right], DECIMAL_DIVISOR]
             ],
                                   typ=BaseType('decimal', new_unit),
                                   pos=getpos(self.expr))
         elif ltyp == 'num' and rtyp == 'decimal':
             o = LLLnode.from_list([
                 'smod', ['mul', left, DECIMAL_DIVISOR],
                 ['clamp_nonzero', right]
             ],
                                   typ=BaseType('decimal', new_unit),
                                   pos=getpos(self.expr))
     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 != 'num' and isinstance(self.expr.right, ast.Name):
             raise TypeMismatchException(
                 "Cannot use dynamic values as exponents, for unit base types",
                 self.expr)
         if ltyp == rtyp == 'num':
             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('num', 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 == 'num':
         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))
     else:
         raise Exception("%r %r" % (o, o.typ))