예제 #1
0
def base_type_conversion(orig, frm, to, pos=None):
    orig = unwrap_location(orig)
    if not isinstance(frm,
                      (BaseType, NullType)) or not isinstance(to, BaseType):
        raise TypeMismatchException(
            "Base type conversion from or to non-base type: %r %r" % (frm, to),
            pos)
    elif is_base_type(frm, to.typ) and are_units_compatible(frm, to):
        return LLLnode(orig.value,
                       orig.args,
                       typ=to,
                       add_gas_estimate=orig.add_gas_estimate)
    elif is_base_type(frm, 'num') and is_base_type(
            to, 'decimal') and are_units_compatible(frm, to):
        return LLLnode.from_list(['mul', orig, DECIMAL_DIVISOR],
                                 typ=BaseType('decimal', to.unit,
                                              to.positional))
    elif is_base_type(frm, 'num256') and is_base_type(
            to, 'num') and are_units_compatible(frm, to):
        return LLLnode.from_list(
            ['uclample', orig, ['mload', MemoryPositions.MAXNUM]],
            typ=BaseType("num"))
    elif isinstance(frm, NullType):
        if to.typ not in ('num', 'bool', 'num256', 'address', 'bytes32',
                          'decimal'):
            raise TypeMismatchException(
                "Cannot convert null-type object to type %r" % to, pos)
        return LLLnode.from_list(0, typ=to)
    else:
        raise TypeMismatchException(
            "Typecasting from base type %r to %r unavailable" % (frm, to), pos)
예제 #2
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)
예제 #3
0
    def parse_return(self):
        from .parser import (make_setter)
        if self.context.return_type is None:
            if self.stmt.value:
                raise TypeMismatchException("Not expecting to return a value",
                                            self.stmt)
            return LLLnode.from_list(['return', 0, 0],
                                     typ=None,
                                     pos=getpos(self.stmt))
        if not self.stmt.value:
            raise TypeMismatchException("Expecting to return a value",
                                        self.stmt)
        sub = Expr(self.stmt.value, self.context).lll_node
        self.context.increment_return_counter()
        # Returning a value (most common case)
        if isinstance(sub.typ, BaseType):
            if not isinstance(self.context.return_type, BaseType):
                raise TypeMismatchException(
                    "Trying to return base type %r, output expecting %r" %
                    (sub.typ, self.context.return_type), self.stmt.value)
            sub = unwrap_location(sub)
            if not are_units_compatible(sub.typ, self.context.return_type):
                raise TypeMismatchException(
                    "Return type units mismatch %r %r" %
                    (sub.typ, self.context.return_type), self.stmt.value)
            elif is_base_type(sub.typ, self.context.return_type.typ) or \
                    (is_base_type(sub.typ, 'num') and is_base_type(self.context.return_type, 'signed256')):
                return LLLnode.from_list(
                    ['seq', ['mstore', 0, sub], ['return', 0, 32]],
                    typ=None,
                    pos=getpos(self.stmt))
            else:
                raise TypeMismatchException(
                    "Unsupported type conversion: %r to %r" %
                    (sub.typ, self.context.return_type), self.stmt.value)
        # Returning a byte array
        elif isinstance(sub.typ, ByteArrayType):
            if not isinstance(self.context.return_type, ByteArrayType):
                raise TypeMismatchException(
                    "Trying to return base type %r, output expecting %r" %
                    (sub.typ, self.context.return_type), self.stmt.value)
            if sub.typ.maxlen > self.context.return_type.maxlen:
                raise TypeMismatchException(
                    "Cannot cast from greater max-length %d to shorter max-length %d"
                    % (sub.typ.maxlen, self.context.return_type.maxlen),
                    self.stmt.value)
            # Returning something already in memory
            if sub.location == 'memory':
                return LLLnode.from_list([
                    'with', '_loc', sub,
                    [
                        'seq', ['mstore', ['sub', '_loc', 32], 32],
                        [
                            'return', ['sub', '_loc', 32],
                            ['ceil32', ['add', ['mload', '_loc'], 64]]
                        ]
                    ]
                ],
                                         typ=None,
                                         pos=getpos(self.stmt))
            # Copying from storage
            elif sub.location == 'storage':
                # Instantiate a byte array at some index
                fake_byte_array = LLLnode(self.context.get_next_mem() + 32,
                                          typ=sub.typ,
                                          location='memory',
                                          pos=getpos(self.stmt))
                o = [
                    'seq',
                    # Copy the data to this byte array
                    make_byte_array_copier(fake_byte_array, sub),
                    # Store the number 32 before it for ABI formatting purposes
                    ['mstore', self.context.get_next_mem(), 32],
                    # Return it
                    [
                        'return',
                        self.context.get_next_mem(),
                        [
                            'add',
                            [
                                'ceil32',
                                ['mload',
                                 self.context.get_next_mem() + 32]
                            ], 64
                        ]
                    ]
                ]
                return LLLnode.from_list(o, typ=None, pos=getpos(self.stmt))
            else:
                raise Exception("Invalid location: %s" % sub.location)

        elif isinstance(sub.typ, ListType):
            sub_base_type = re.split(r'\(|\[', str(sub.typ.subtype))[0]
            ret_base_type = re.split(r'\(|\[',
                                     str(self.context.return_type.subtype))[0]
            if sub_base_type != ret_base_type and sub.value != 'multi':
                raise TypeMismatchException(
                    "List return type %r does not match specified return type, expecting %r"
                    % (sub_base_type, ret_base_type), self.stmt)
            if sub.location == "memory" and sub.value != "multi":
                return LLLnode.from_list([
                    'return', sub,
                    get_size_of_type(self.context.return_type) * 32
                ],
                                         typ=None,
                                         pos=getpos(self.stmt))
            else:
                new_sub = LLLnode.from_list(self.context.new_placeholder(
                    self.context.return_type),
                                            typ=self.context.return_type,
                                            location='memory')
                setter = make_setter(new_sub,
                                     sub,
                                     'memory',
                                     pos=getpos(self.stmt))
                return LLLnode.from_list([
                    'seq', setter,
                    [
                        'return', new_sub,
                        get_size_of_type(self.context.return_type) * 32
                    ]
                ],
                                         typ=None,
                                         pos=getpos(self.stmt))

        # Returning a tuple.
        elif isinstance(sub.typ, TupleType):
            if len(self.context.return_type.members) != len(sub.typ.members):
                raise StructureException("Tuple lengths don't match!")
            subs = []
            dynamic_offset_counter = LLLnode(
                self.context.get_next_mem(),
                typ=None,
                annotation="dynamic_offset_counter"
            )  # dynamic offset position counter.
            new_sub = LLLnode.from_list(self.context.get_next_mem() + 32,
                                        typ=self.context.return_type,
                                        location='memory',
                                        annotation='new_sub')
            keyz = list(range(len(sub.typ.members)))
            dynamic_offset_start = 32 * len(
                sub.args)  # The static list of args end.
            left_token = LLLnode.from_list('_loc',
                                           typ=new_sub.typ,
                                           location="memory")

            def get_dynamic_offset_value():
                # Get value of dynamic offset counter.
                return ['mload', dynamic_offset_counter]

            def increment_dynamic_offset(dynamic_spot):
                # Increment dyanmic offset counter in memory.
                return [
                    'mstore', dynamic_offset_counter,
                    [
                        'add',
                        ['add', ['ceil32', ['mload', dynamic_spot]], 32],
                        ['mload', dynamic_offset_counter]
                    ]
                ]

            for i, typ in enumerate(keyz):
                arg = sub.args[i]
                variable_offset = LLLnode.from_list(
                    ['add', 32 * i, left_token],
                    typ=arg.typ,
                    annotation='variable_offset')
                if isinstance(arg.typ, ByteArrayType):
                    # Store offset pointer value.
                    subs.append([
                        'mstore', variable_offset,
                        get_dynamic_offset_value()
                    ])

                    # Store dynamic data, from offset pointer onwards.
                    dynamic_spot = LLLnode.from_list(
                        ['add', left_token,
                         get_dynamic_offset_value()],
                        location="memory",
                        typ=arg.typ,
                        annotation='dynamic_spot')
                    subs.append(
                        make_setter(dynamic_spot,
                                    arg,
                                    location="memory",
                                    pos=getpos(self.stmt)))
                    subs.append(increment_dynamic_offset(dynamic_spot))

                elif isinstance(arg.typ, BaseType):
                    subs.append(
                        make_setter(variable_offset,
                                    arg,
                                    "memory",
                                    pos=getpos(self.stmt)))
                else:
                    raise Exception("Can't return type %s as part of tuple",
                                    type(arg.typ))

            setter = LLLnode.from_list([
                'seq', [
                    'mstore', dynamic_offset_counter, dynamic_offset_start
                ], ['with', '_loc', new_sub, ['seq'] + subs]
            ],
                                       typ=None)

            return LLLnode.from_list([
                'seq', setter, ['return', new_sub,
                                get_dynamic_offset_value()]
            ],
                                     typ=None,
                                     pos=getpos(self.stmt))
        else:
            raise TypeMismatchException("Can only return base type!",
                                        self.stmt)
예제 #4
0
파일: stmt.py 프로젝트: edwardh5/viper
 def parse_return(self):
     from .parser import (parse_expr, make_setter)
     if self.context.return_type is None:
         if self.stmt.value:
             raise TypeMismatchException("Not expecting to return a value",
                                         self.stmt)
         return LLLnode.from_list(['return', 0, 0],
                                  typ=None,
                                  pos=getpos(self.stmt))
     if not self.stmt.value:
         raise TypeMismatchException("Expecting to return a value",
                                     self.stmt)
     sub = parse_expr(self.stmt.value, self.context)
     # Returning a value (most common case)
     if isinstance(sub.typ, BaseType):
         if not isinstance(self.context.return_type, BaseType):
             raise TypeMismatchException(
                 "Trying to return base type %r, output expecting %r" %
                 (sub.typ, self.context.return_type), self.stmt.value)
         sub = unwrap_location(sub)
         if not are_units_compatible(sub.typ, self.context.return_type):
             raise TypeMismatchException(
                 "Return type units mismatch %r %r" %
                 (sub.typ, self.context.return_type), self.stmt.value)
         elif is_base_type(sub.typ, self.context.return_type.typ) or \
                 (is_base_type(sub.typ, 'num') and is_base_type(self.context.return_type, 'signed256')):
             return LLLnode.from_list(
                 ['seq', ['mstore', 0, sub], ['return', 0, 32]],
                 typ=None,
                 pos=getpos(self.stmt))
         else:
             raise TypeMismatchException(
                 "Unsupported type conversion: %r to %r" %
                 (sub.typ, self.context.return_type), self.stmt.value)
     # Returning a byte array
     elif isinstance(sub.typ, ByteArrayType):
         if not isinstance(self.context.return_type, ByteArrayType):
             raise TypeMismatchException(
                 "Trying to return base type %r, output expecting %r" %
                 (sub.typ, self.context.return_type), self.stmt.value)
         if sub.typ.maxlen > self.context.return_type.maxlen:
             raise TypeMismatchException(
                 "Cannot cast from greater max-length %d to shorter max-length %d"
                 % (sub.typ.maxlen, self.context.return_type.maxlen),
                 self.stmt.value)
         # Returning something already in memory
         if sub.location == 'memory':
             return LLLnode.from_list([
                 'with', '_loc', sub,
                 [
                     'seq', ['mstore', ['sub', '_loc', 32], 32],
                     [
                         'return', ['sub', '_loc', 32],
                         ['ceil32', ['add', ['mload', '_loc'], 64]]
                     ]
                 ]
             ],
                                      typ=None,
                                      pos=getpos(self.stmt))
         # Copying from storage
         elif sub.location == 'storage':
             # Instantiate a byte array at some index
             fake_byte_array = LLLnode(self.context.get_next_mem() + 32,
                                       typ=sub.typ,
                                       location='memory',
                                       pos=getpos(self.stmt))
             o = [
                 'seq',
                 # Copy the data to this byte array
                 make_byte_array_copier(fake_byte_array, sub),
                 # Store the number 32 before it for ABI formatting purposes
                 ['mstore', self.context.get_next_mem(), 32],
                 # Return it
                 [
                     'return',
                     self.context.get_next_mem(),
                     [
                         'add',
                         [
                             'ceil32',
                             ['mload',
                              self.context.get_next_mem() + 32]
                         ], 64
                     ]
                 ]
             ]
             return LLLnode.from_list(o, typ=None, pos=getpos(self.stmt))
         else:
             raise Exception("Invalid location: %s" % sub.location)
     # Returning a list
     elif isinstance(sub.typ, ListType):
         if sub.location == "memory" and sub.value != "multi":
             return LLLnode.from_list([
                 'return', sub,
                 get_size_of_type(self.context.return_type) * 32
             ],
                                      typ=None,
                                      pos=getpos(self.stmt))
         else:
             new_sub = LLLnode.from_list(self.context.new_placeholder(
                 self.context.return_type),
                                         typ=self.context.return_type,
                                         location='memory')
             setter = make_setter(new_sub, sub, 'memory')
             return LLLnode.from_list([
                 'seq', setter,
                 [
                     'return', new_sub,
                     get_size_of_type(self.context.return_type) * 32
                 ]
             ],
                                      typ=None,
                                      pos=getpos(self.stmt))
     else:
         raise TypeMismatchException("Can only return base type!",
                                     self.stmt)