Adds a separte typing system #3
@ -72,8 +72,6 @@ U8_OPERATOR_MAP = {
|
|||||||
# Under the hood, this is an i32
|
# Under the hood, this is an i32
|
||||||
# Implementing Right Shift XOR, OR, AND is fine since the 3 remaining
|
# Implementing Right Shift XOR, OR, AND is fine since the 3 remaining
|
||||||
# bytes stay zero after this operation
|
# bytes stay zero after this operation
|
||||||
# Since it's unsigned an unsigned value, Logical or Arithmetic shift right
|
|
||||||
# are the same operation
|
|
||||||
'>>': 'shr_u',
|
'>>': 'shr_u',
|
||||||
'^': 'xor',
|
'^': 'xor',
|
||||||
'|': 'or',
|
'|': 'or',
|
||||||
|
|||||||
@ -77,18 +77,30 @@ def expression(ctx: Context, inp: ourlang.Expression) -> 'TypeVar':
|
|||||||
return right
|
return right
|
||||||
|
|
||||||
if isinstance(inp, ourlang.BinaryOp):
|
if isinstance(inp, ourlang.BinaryOp):
|
||||||
# TODO: Simplified version
|
if inp.operator in ('+', '-', '*', '|', '&', '^'):
|
||||||
if inp.operator not in ('+', '-', '*', '|', '&', '^'):
|
|
||||||
raise NotImplementedError(expression, inp, inp.operator)
|
|
||||||
|
|
||||||
left = expression(ctx, inp.left)
|
left = expression(ctx, inp.left)
|
||||||
right = expression(ctx, inp.right)
|
right = expression(ctx, inp.right)
|
||||||
ctx.unify(left, right)
|
ctx.unify(left, right)
|
||||||
|
|
||||||
inp.type_var = left
|
inp.type_var = left
|
||||||
|
return left
|
||||||
|
|
||||||
|
if inp.operator in ('<<', '>>', ):
|
||||||
|
inp.type_var = ctx.new_var()
|
||||||
|
inp.type_var.add_constraint(TypeConstraintPrimitive(TypeConstraintPrimitive.Primitive.INT))
|
||||||
|
inp.type_var.add_constraint(TypeConstraintBitWidth(oneof=(32, 64, )))
|
||||||
|
inp.type_var.add_constraint(TypeConstraintSigned(False))
|
||||||
|
|
||||||
|
left = expression(ctx, inp.left)
|
||||||
|
right = expression(ctx, inp.right)
|
||||||
|
ctx.unify(left, right)
|
||||||
|
|
||||||
|
ctx.unify(inp.type_var, left)
|
||||||
|
|
||||||
return left
|
return left
|
||||||
|
|
||||||
|
raise NotImplementedError(expression, inp, inp.operator)
|
||||||
|
|
||||||
if isinstance(inp, ourlang.FunctionCall):
|
if isinstance(inp, ourlang.FunctionCall):
|
||||||
assert inp.function.returns_type_var is not None
|
assert inp.function.returns_type_var is not None
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
The phasm type system
|
The phasm type system
|
||||||
"""
|
"""
|
||||||
from typing import Dict, Optional, List, Type
|
from typing import Dict, Iterable, Optional, List, Set, Type
|
||||||
|
|
||||||
import enum
|
import enum
|
||||||
|
|
||||||
@ -217,35 +217,41 @@ class TypeConstraintBitWidth(TypeConstraintBase):
|
|||||||
"""
|
"""
|
||||||
Contraint on how many bits an expression has or can possibly have
|
Contraint on how many bits an expression has or can possibly have
|
||||||
"""
|
"""
|
||||||
__slots__ = ('minb', 'maxb', )
|
__slots__ = ('oneof', )
|
||||||
|
|
||||||
minb: int
|
oneof: Set[int]
|
||||||
maxb: int
|
|
||||||
|
|
||||||
def __init__(self, *, minb: int = 1, maxb: int = 64) -> None:
|
def __init__(self, *, oneof: Optional[Iterable[int]] = None, minb: Optional[int] = None, maxb: Optional[int] = None) -> None:
|
||||||
assert minb is not None or maxb is not None
|
# For now, support up to 64 bits values
|
||||||
assert maxb <= 64 # For now, support up to 64 bits values
|
self.oneof = set(oneof) if oneof is not None else set(range(1, 65))
|
||||||
|
|
||||||
self.minb = minb
|
if minb is not None:
|
||||||
self.maxb = maxb
|
self.oneof = {
|
||||||
|
x
|
||||||
|
for x in self.oneof
|
||||||
|
if minb <= x
|
||||||
|
}
|
||||||
|
|
||||||
|
if maxb is not None:
|
||||||
|
self.oneof = {
|
||||||
|
x
|
||||||
|
for x in self.oneof
|
||||||
|
if x <= maxb
|
||||||
|
}
|
||||||
|
|
||||||
def narrow(self, other: 'TypeConstraintBase') -> 'TypeConstraintBitWidth':
|
def narrow(self, other: 'TypeConstraintBase') -> 'TypeConstraintBitWidth':
|
||||||
if not isinstance(other, TypeConstraintBitWidth):
|
if not isinstance(other, TypeConstraintBitWidth):
|
||||||
raise Exception('Invalid comparison')
|
raise Exception('Invalid comparison')
|
||||||
|
|
||||||
if self.minb > other.maxb:
|
new_oneof = self.oneof & other.oneof
|
||||||
raise TypingNarrowProtoError('Min bitwidth exceeds other max bitwidth')
|
|
||||||
|
|
||||||
if other.minb > self.maxb:
|
if not new_oneof:
|
||||||
raise TypingNarrowProtoError('Other min bitwidth exceeds max bitwidth')
|
raise TypingNarrowProtoError('Memory width cannot be resolved')
|
||||||
|
|
||||||
return TypeConstraintBitWidth(
|
return TypeConstraintBitWidth(oneof=new_oneof)
|
||||||
minb=max(self.minb, other.minb),
|
|
||||||
maxb=min(self.maxb, other.maxb),
|
|
||||||
)
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f'BitWidth={self.minb}..{self.maxb}'
|
return 'BitWidth=oneof(' + ','.join(map(str, sorted(self.oneof))) + ')'
|
||||||
|
|
||||||
class TypeVar:
|
class TypeVar:
|
||||||
"""
|
"""
|
||||||
@ -380,11 +386,15 @@ def simplify(inp: TypeVar) -> Optional[str]:
|
|||||||
assert isinstance(tc_bits, TypeConstraintBitWidth) # type hint
|
assert isinstance(tc_bits, TypeConstraintBitWidth) # type hint
|
||||||
assert isinstance(tc_sign, TypeConstraintSigned) # type hint
|
assert isinstance(tc_sign, TypeConstraintSigned) # type hint
|
||||||
|
|
||||||
if tc_sign.signed is None or tc_bits.minb != tc_bits.maxb or tc_bits.minb not in (8, 32, 64):
|
if tc_sign.signed is None or len(tc_bits.oneof) != 1:
|
||||||
|
return None
|
||||||
|
|
||||||
|
bitwidth = next(iter(tc_bits.oneof))
|
||||||
|
if bitwidth not in (8, 32, 64):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
base = 'i' if tc_sign.signed else 'u'
|
base = 'i' if tc_sign.signed else 'u'
|
||||||
return f'{base}{tc_bits.minb}'
|
return f'{base}{bitwidth}'
|
||||||
|
|
||||||
if primitive is TypeConstraintPrimitive.Primitive.FLOAT:
|
if primitive is TypeConstraintPrimitive.Primitive.FLOAT:
|
||||||
if tc_bits is None or tc_sign is not None: # Floats should not hava sign contraint
|
if tc_bits is None or tc_sign is not None: # Floats should not hava sign contraint
|
||||||
@ -392,10 +402,14 @@ def simplify(inp: TypeVar) -> Optional[str]:
|
|||||||
|
|
||||||
assert isinstance(tc_bits, TypeConstraintBitWidth) # type hint
|
assert isinstance(tc_bits, TypeConstraintBitWidth) # type hint
|
||||||
|
|
||||||
if tc_bits.minb != tc_bits.maxb or tc_bits.minb not in (32, 64):
|
if len(tc_bits.oneof) != 1:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return f'f{tc_bits.minb}'
|
bitwidth = next(iter(tc_bits.oneof))
|
||||||
|
if bitwidth not in (32, 64):
|
||||||
|
return None
|
||||||
|
|
||||||
|
return f'f{bitwidth}'
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@ -76,8 +76,8 @@ def testEntry() -> {type_}:
|
|||||||
assert TYPE_MAP[type_] == type(result.returned_value)
|
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
@pytest.mark.parametrize('type_', ['u8', 'u32', 'u64'])
|
@pytest.mark.parametrize('type_', ['u32', 'u64'])
|
||||||
def test_logical_right_shift(type_):
|
def test_logical_right_shift_left_bit_zero(type_):
|
||||||
code_py = f"""
|
code_py = f"""
|
||||||
@exported
|
@exported
|
||||||
def testEntry() -> {type_}:
|
def testEntry() -> {type_}:
|
||||||
@ -89,6 +89,18 @@ def testEntry() -> {type_}:
|
|||||||
assert 1 == result.returned_value
|
assert 1 == result.returned_value
|
||||||
assert TYPE_MAP[type_] == type(result.returned_value)
|
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_logical_right_shift_left_bit_one():
|
||||||
|
code_py = """
|
||||||
|
@exported
|
||||||
|
def testEntry() -> u32:
|
||||||
|
return 4294967295 >> 16
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
|
assert 0xFFFF == result.returned_value
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
@pytest.mark.parametrize('type_', ['u8', 'u32', 'u64'])
|
@pytest.mark.parametrize('type_', ['u8', 'u32', 'u64'])
|
||||||
def test_bitwise_or(type_):
|
def test_bitwise_or(type_):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user