Пример #1
0
 def op(data_type: DataType, *params) -> List[Optional[int]]:
     result = arith_op(*params)
     if result > data_type.max_value(
             is_signed) or result < data_type.min_value(is_signed):
         return [None]
     else:
         return [result]
Пример #2
0
 def _handle_load(self, load: Tree) -> List[Instruction]:
     target_name, source_name, offset_lit, type_name = load.children
     source_idx, _ = self._get_item(source_name, True)
     offset = int(offset_lit)
     type_match = self.REG_TYPE.match(type_name)
     is_signed = type_match.group(1) == 'i'
     bit_size = int(type_match.group(2))
     self._push(CompilerBeltItem(target_name, is_signed, False))
     return [InsLoad(DataType(bit_size), source_idx, offset)]
Пример #3
0
 def op(data_type: DataType, *params) -> List[Optional[int]]:
     result = arith_op(*params)
     num_bytes = data_type.num_bytes()
     wide_bytes = result.to_bytes(num_bytes,
                                  'little',
                                  signed=is_signed)
     return [
         int.from_bytes(wide_bytes[num_bytes:],
                        'little',
                        signed=is_signed),
         int.from_bytes(wide_bytes[:num_bytes],
                        'little',
                        signed=is_signed),
     ]
Пример #4
0
 def _handle_lit(self, names: List[str], lit: Tree) -> List[Instruction]:
     assigned_name, = names
     lit, = lit.children
     lit = lit.replace('_', '')
     if assigned_name.startswith('$'):
         raise ValueError('Cannot assign literals to locals (yet?)')
     m = self.REG_LIT.match(lit)
     num = int(m.group(1))
     is_signed = m.group(2) == 'i'
     bit_size = int(m.group(3))
     self._push(CompilerBeltItem(assigned_name, is_signed, False))
     return [
         InsConst(
             BeltNum.from_signed(Integer(num), DataType(bit_size),
                                 is_signed))
     ]
Пример #5
0
    def _handle_call(self, names: List[str], call: Tree) -> List[Instruction]:
        call_name, params = call.children
        params = params.children
        if call_name == 'is_err':
            if len(params) != 1:
                raise ValueError(f'{call_name} takes exactly 1 argument')
            item_name, = params
            result_name, = names
            item_idx, item = self._get_item(item_name, False)
            self._push(CompilerBeltItem(result_name, False, False))
            return [InsIsErr(item_idx)]
        elif call_name == 'length':
            if len(params) != 1:
                raise ValueError(f'{call_name} takes exactly 1 argument')
            slice_name, = params
            result_name, = names
            slice_idx, _ = self._get_item(slice_name, True)
            self._push(CompilerBeltItem(result_name, False, False))
            return [InsSliceLen(slice_idx)]
        elif call_name in {'trim_l', 'trim_r', 'shrink'}:
            if len(params) != 2:
                raise ValueError(f'{call_name} takes exactly 2 argument')
            slice_name, num_bytes_name = params
            result_name, = names
            slice_idx, _ = self._get_item(slice_name, True)
            num_bytes_idx, _ = self._get_item(num_bytes_name, False)
            self._push(CompilerBeltItem(result_name, None, True))
            return [
                InsSliceOp(
                    slice_idx, num_bytes_idx, {
                        'trim_l': BeltSlice.trim_l,
                        'trim_r': BeltSlice.trim_r,
                        'shrink': BeltSlice.shrink,
                    }[call_name])
            ]
        elif call_name == 'divmod':
            if len(params) != 2:
                raise ValueError(f'{call_name} takes exactly 2 argument')
            a_name, b_name = params
            div_name, mod_name = names
            a_idx, a = self._get_item(a_name, False)
            b_idx, b = self._get_item(b_name, False)
            if a.is_signed != b.is_signed:
                raise ValueError(
                    f'Incompatible operands, {a_name} {"is" if a.is_signed else "is not"} signed, '
                    f'but {b_name} {"is" if b.is_signed else "is not"}.')
            self._push(CompilerBeltItem(div_name, a.is_signed, False))
            self._push(CompilerBeltItem(mod_name, a.is_signed, False))
            return [
                InsNAryOp([a_idx, b_idx], a.is_signed,
                          lambda _, x, y: [None, None]
                          if y == 0 else divmod(x, y))
            ]
        elif call_name in {'rotl', 'rotr', 'clz', 'ctz', 'popcnt'}:
            raise NotImplemented
        else:
            match_cast = self.REG_CAST.match(call_name)
            if match_cast is not None:
                call_name = match_cast.group(1)
                bit_size = int(match_cast.group(2))
                data_type = DataType(bit_size)
                item_name, = params
                result, = names
                item_idx, item = self._get_item(item_name, False)
                self._push(CompilerBeltItem(result, item.is_signed, False))
                if call_name == 'cast_extend':
                    if bit_size == 8:
                        raise ValueError("Cannot use cast_extend8")
                    func = BeltNum.extend
                elif call_name == 'cast_wrap':

                    def func(num: BeltNum, _data_type: DataType,
                             _: bool) -> BeltNum:
                        return num.wrap(_data_type)

                    if bit_size == 64:
                        raise ValueError("Cannot use cast_wrap8")
                elif call_name == 'cast_sat':
                    if bit_size == 64:
                        raise ValueError("Cannot use cast_sat8")
                    func = BeltNum.cast_sat
                elif call_name == 'cast_checked':
                    if bit_size == 64:
                        raise ValueError("Cannot use cast_checked8")
                    func = BeltNum.cast_checked
                else:
                    raise ValueError('Unreachable')
                return [InsConvert(item_idx, data_type, item.is_signed, func)]
            else:
                raise ValueError(f"Unknown function {call_name}")
Пример #6
0
def test_data_type_min(data_type: DataType, is_signed: bool, expected: int):
    assert data_type.min_value(is_signed) == expected