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