Adds u32 and u64
Also, adds some range checks to constants.
This commit is contained in:
parent
89ad648f34
commit
a83858aca7
@ -29,6 +29,12 @@ def type_(inp: typing.TypeBase) -> str:
|
||||
if isinstance(inp, typing.TypeUInt8):
|
||||
return 'u8'
|
||||
|
||||
if isinstance(inp, typing.TypeUInt32):
|
||||
return 'u32'
|
||||
|
||||
if isinstance(inp, typing.TypeUInt64):
|
||||
return 'u64'
|
||||
|
||||
if isinstance(inp, typing.TypeInt32):
|
||||
return 'i32'
|
||||
|
||||
@ -71,7 +77,10 @@ def expression(inp: ourlang.Expression) -> str:
|
||||
"""
|
||||
Render: A Phasm expression
|
||||
"""
|
||||
if isinstance(inp, (ourlang.ConstantUInt8, ourlang.ConstantInt32, ourlang.ConstantInt64, )):
|
||||
if isinstance(inp, (
|
||||
ourlang.ConstantUInt8, ourlang.ConstantUInt32, ourlang.ConstantUInt64,
|
||||
ourlang.ConstantInt32, ourlang.ConstantInt64,
|
||||
)):
|
||||
return str(inp.value)
|
||||
|
||||
if isinstance(inp, (ourlang.ConstantFloat32, ourlang.ConstantFloat64, )):
|
||||
|
||||
@ -11,6 +11,8 @@ Statements = Generator[wasm.Statement, None, None]
|
||||
|
||||
LOAD_STORE_TYPE_MAP = {
|
||||
typing.TypeUInt8: 'i32',
|
||||
typing.TypeUInt32: 'i32',
|
||||
typing.TypeUInt64: 'i64',
|
||||
typing.TypeInt32: 'i32',
|
||||
typing.TypeInt64: 'i64',
|
||||
typing.TypeFloat32: 'f32',
|
||||
@ -39,6 +41,12 @@ def type_(inp: typing.TypeBase) -> wasm.WasmType:
|
||||
# So we need to store more memory per byte
|
||||
return wasm.WasmTypeInt32()
|
||||
|
||||
if isinstance(inp, typing.TypeUInt32):
|
||||
return wasm.WasmTypeInt32()
|
||||
|
||||
if isinstance(inp, typing.TypeUInt64):
|
||||
return wasm.WasmTypeInt64()
|
||||
|
||||
if isinstance(inp, typing.TypeInt32):
|
||||
return wasm.WasmTypeInt32()
|
||||
|
||||
@ -66,14 +74,28 @@ OPERATOR_MAP = {
|
||||
'==': 'eq',
|
||||
}
|
||||
|
||||
I32_OPERATOR_MAP = { # TODO: Introduce UInt32 type
|
||||
U32_OPERATOR_MAP = {
|
||||
'<': 'lt_u',
|
||||
'>': 'gt_u',
|
||||
'<=': 'le_u',
|
||||
'>=': 'ge_u',
|
||||
}
|
||||
|
||||
U64_OPERATOR_MAP = {
|
||||
'<': 'lt_u',
|
||||
'>': 'gt_u',
|
||||
'<=': 'le_u',
|
||||
'>=': 'ge_u',
|
||||
}
|
||||
|
||||
I32_OPERATOR_MAP = {
|
||||
'<': 'lt_s',
|
||||
'>': 'gt_s',
|
||||
'<=': 'le_s',
|
||||
'>=': 'ge_s',
|
||||
}
|
||||
|
||||
I64_OPERATOR_MAP = { # TODO: Introduce UInt32 type
|
||||
I64_OPERATOR_MAP = {
|
||||
'<': 'lt_s',
|
||||
'>': 'gt_s',
|
||||
'<=': 'le_s',
|
||||
@ -88,6 +110,14 @@ def expression(inp: ourlang.Expression) -> Statements:
|
||||
yield wasm.Statement('i32.const', str(inp.value))
|
||||
return
|
||||
|
||||
if isinstance(inp, ourlang.ConstantUInt32):
|
||||
yield wasm.Statement('i32.const', str(inp.value))
|
||||
return
|
||||
|
||||
if isinstance(inp, ourlang.ConstantUInt64):
|
||||
yield wasm.Statement('i64.const', str(inp.value))
|
||||
return
|
||||
|
||||
if isinstance(inp, ourlang.ConstantInt32):
|
||||
yield wasm.Statement('i32.const', str(inp.value))
|
||||
return
|
||||
@ -112,6 +142,20 @@ def expression(inp: ourlang.Expression) -> Statements:
|
||||
yield from expression(inp.left)
|
||||
yield from expression(inp.right)
|
||||
|
||||
if isinstance(inp.type, typing.TypeUInt32):
|
||||
if operator := OPERATOR_MAP.get(inp.operator, None):
|
||||
yield wasm.Statement(f'i32.{operator}')
|
||||
return
|
||||
if operator := U32_OPERATOR_MAP.get(inp.operator, None):
|
||||
yield wasm.Statement(f'i32.{operator}')
|
||||
return
|
||||
if isinstance(inp.type, typing.TypeUInt64):
|
||||
if operator := OPERATOR_MAP.get(inp.operator, None):
|
||||
yield wasm.Statement(f'i64.{operator}')
|
||||
return
|
||||
if operator := U64_OPERATOR_MAP.get(inp.operator, None):
|
||||
yield wasm.Statement(f'i64.{operator}')
|
||||
return
|
||||
if isinstance(inp.type, typing.TypeInt32):
|
||||
if operator := OPERATOR_MAP.get(inp.operator, None):
|
||||
yield wasm.Statement(f'i32.{operator}')
|
||||
@ -288,7 +332,7 @@ def function(inp: ourlang.Function) -> wasm.Function:
|
||||
for y in inp.statements
|
||||
for x in statement(y)
|
||||
]
|
||||
locals_ = [] # TODO
|
||||
locals_ = [] # FIXME: Implement function locals, if required
|
||||
|
||||
return wasm.Function(
|
||||
inp.name,
|
||||
|
||||
@ -12,7 +12,7 @@ from .typing import (
|
||||
TypeBase,
|
||||
TypeNone,
|
||||
TypeBool,
|
||||
TypeUInt8,
|
||||
TypeUInt8, TypeUInt32, TypeUInt64,
|
||||
TypeInt32, TypeInt64,
|
||||
TypeFloat32, TypeFloat64,
|
||||
TypeBytes,
|
||||
@ -49,6 +49,30 @@ class ConstantUInt8(Constant):
|
||||
super().__init__(type_)
|
||||
self.value = value
|
||||
|
||||
class ConstantUInt32(Constant):
|
||||
"""
|
||||
An UInt32 constant value expression within a statement
|
||||
"""
|
||||
__slots__ = ('value', )
|
||||
|
||||
value: int
|
||||
|
||||
def __init__(self, type_: TypeUInt32, value: int) -> None:
|
||||
super().__init__(type_)
|
||||
self.value = value
|
||||
|
||||
class ConstantUInt64(Constant):
|
||||
"""
|
||||
An UInt64 constant value expression within a statement
|
||||
"""
|
||||
__slots__ = ('value', )
|
||||
|
||||
value: int
|
||||
|
||||
def __init__(self, type_: TypeUInt64, value: int) -> None:
|
||||
super().__init__(type_)
|
||||
self.value = value
|
||||
|
||||
class ConstantInt32(Constant):
|
||||
"""
|
||||
An Int32 constant value expression within a statement
|
||||
@ -317,6 +341,8 @@ class Module:
|
||||
self.types = {
|
||||
'None': TypeNone(),
|
||||
'u8': TypeUInt8(),
|
||||
'u32': TypeUInt32(),
|
||||
'u64': TypeUInt64(),
|
||||
'i32': TypeInt32(),
|
||||
'i64': TypeInt64(),
|
||||
'f32': TypeFloat32(),
|
||||
|
||||
@ -8,6 +8,8 @@ import ast
|
||||
from .typing import (
|
||||
TypeBase,
|
||||
TypeUInt8,
|
||||
TypeUInt32,
|
||||
TypeUInt64,
|
||||
TypeInt32,
|
||||
TypeInt64,
|
||||
TypeFloat32,
|
||||
@ -30,7 +32,8 @@ from .ourlang import (
|
||||
Expression,
|
||||
AccessBytesIndex, AccessStructMember, AccessTupleMember,
|
||||
BinaryOp,
|
||||
ConstantFloat32, ConstantFloat64, ConstantInt32, ConstantInt64, ConstantUInt8,
|
||||
ConstantFloat32, ConstantFloat64, ConstantInt32, ConstantInt64,
|
||||
ConstantUInt8, ConstantUInt32, ConstantUInt64,
|
||||
FunctionCall,
|
||||
StructConstructor, TupleConstructor,
|
||||
UnaryOp, VariableReference,
|
||||
@ -485,15 +488,35 @@ class OurVisitor:
|
||||
if not isinstance(node.value, int):
|
||||
_raise_static_error(node, 'Expected integer value')
|
||||
|
||||
# FIXME: Range check
|
||||
if node.value < 0 or node.value > 255:
|
||||
_raise_static_error(node, 'Integer value out of range')
|
||||
|
||||
return ConstantUInt8(exp_type, node.value)
|
||||
|
||||
if isinstance(exp_type, TypeUInt32):
|
||||
if not isinstance(node.value, int):
|
||||
_raise_static_error(node, 'Expected integer value')
|
||||
|
||||
if node.value < 0 or node.value > 4294967295:
|
||||
_raise_static_error(node, 'Integer value out of range')
|
||||
|
||||
return ConstantUInt32(exp_type, node.value)
|
||||
|
||||
if isinstance(exp_type, TypeUInt64):
|
||||
if not isinstance(node.value, int):
|
||||
_raise_static_error(node, 'Expected integer value')
|
||||
|
||||
if node.value < 0 or node.value > 18446744073709551615:
|
||||
_raise_static_error(node, 'Integer value out of range')
|
||||
|
||||
return ConstantUInt64(exp_type, node.value)
|
||||
|
||||
if isinstance(exp_type, TypeInt32):
|
||||
if not isinstance(node.value, int):
|
||||
_raise_static_error(node, 'Expected integer value')
|
||||
|
||||
# FIXME: Range check
|
||||
if node.value < -2147483648 or node.value > 2147483647:
|
||||
_raise_static_error(node, 'Integer value out of range')
|
||||
|
||||
return ConstantInt32(exp_type, node.value)
|
||||
|
||||
@ -501,7 +524,8 @@ class OurVisitor:
|
||||
if not isinstance(node.value, int):
|
||||
_raise_static_error(node, 'Expected integer value')
|
||||
|
||||
# FIXME: Range check
|
||||
if node.value < -9223372036854775808 or node.value > 9223372036854775807:
|
||||
_raise_static_error(node, 'Integer value out of range')
|
||||
|
||||
return ConstantInt64(exp_type, node.value)
|
||||
|
||||
|
||||
@ -30,12 +30,37 @@ class TypeBool(TypeBase):
|
||||
class TypeUInt8(TypeBase):
|
||||
"""
|
||||
The Integer type, unsigned and 8 bits wide
|
||||
|
||||
Note that under the hood we need to use i32 to represent
|
||||
these values in expressions. So we need to add some operations
|
||||
to make sure the math checks out.
|
||||
|
||||
So while this does save bytes in memory, it may not actually
|
||||
speed up or improve your code.
|
||||
"""
|
||||
__slots__ = ()
|
||||
|
||||
def alloc_size(self) -> int:
|
||||
return 4 # Int32 under the hood
|
||||
|
||||
class TypeUInt32(TypeBase):
|
||||
"""
|
||||
The Integer type, unsigned and 32 bits wide
|
||||
"""
|
||||
__slots__ = ()
|
||||
|
||||
def alloc_size(self) -> int:
|
||||
return 4
|
||||
|
||||
class TypeUInt64(TypeBase):
|
||||
"""
|
||||
The Integer type, unsigned and 64 bits wide
|
||||
"""
|
||||
__slots__ = ()
|
||||
|
||||
def alloc_size(self) -> int:
|
||||
return 8
|
||||
|
||||
class TypeInt32(TypeBase):
|
||||
"""
|
||||
The Integer type, signed and 32 bits wide
|
||||
|
||||
@ -4,14 +4,22 @@ from .helpers import Suite
|
||||
|
||||
TYPE_MAP = {
|
||||
'u8': int,
|
||||
'u32': int,
|
||||
'u64': int,
|
||||
'i32': int,
|
||||
'i64': int,
|
||||
'f32': float,
|
||||
'f64': float,
|
||||
}
|
||||
|
||||
COMPLETE_SIMPLE_TYPES = [
|
||||
'u32', 'u64',
|
||||
'i32', 'i64',
|
||||
'f32', 'f64',
|
||||
]
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@pytest.mark.parametrize('type_', ['i32', 'i64', 'f32', 'f64', 'u8'])
|
||||
@pytest.mark.parametrize('type_', TYPE_MAP.keys())
|
||||
def test_return(type_):
|
||||
code_py = f"""
|
||||
@exported
|
||||
@ -25,7 +33,7 @@ def testEntry() -> {type_}:
|
||||
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@pytest.mark.parametrize('type_', ['i32', 'i64', 'f32', 'f64'])
|
||||
@pytest.mark.parametrize('type_', COMPLETE_SIMPLE_TYPES)
|
||||
def test_addition(type_):
|
||||
code_py = f"""
|
||||
@exported
|
||||
@ -39,7 +47,7 @@ def testEntry() -> {type_}:
|
||||
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@pytest.mark.parametrize('type_', ['i32', 'i64', 'f32', 'f64'])
|
||||
@pytest.mark.parametrize('type_', COMPLETE_SIMPLE_TYPES)
|
||||
def test_subtraction(type_):
|
||||
code_py = f"""
|
||||
@exported
|
||||
@ -67,7 +75,7 @@ def testEntry() -> {type_}:
|
||||
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@pytest.mark.parametrize('type_', ['i32', 'i64', 'f32', 'f64', 'u8'])
|
||||
@pytest.mark.parametrize('type_', TYPE_MAP.keys())
|
||||
def test_arg(type_):
|
||||
code_py = f"""
|
||||
@exported
|
||||
@ -265,7 +273,7 @@ def helper(left: i32, right: i32) -> i32:
|
||||
assert [] == result.log_int32_list
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@pytest.mark.parametrize('type_', ['i32', 'i64', 'f32', 'f64'])
|
||||
@pytest.mark.parametrize('type_', COMPLETE_SIMPLE_TYPES)
|
||||
def test_call_with_expression(type_):
|
||||
code_py = f"""
|
||||
@exported
|
||||
@ -298,7 +306,7 @@ def testEntry() -> i32:
|
||||
assert [] == result.log_int32_list
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@pytest.mark.parametrize('type_', ['i32', 'i64', 'f32', 'f64', 'u8'])
|
||||
@pytest.mark.parametrize('type_', TYPE_MAP.keys())
|
||||
def test_struct_0(type_):
|
||||
code_py = f"""
|
||||
class CheckedValue:
|
||||
@ -360,7 +368,7 @@ def helper(shape1: Rectangle, shape2: Rectangle) -> i32:
|
||||
assert [] == result.log_int32_list
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@pytest.mark.parametrize('type_', ['i32', 'i64', 'f32', 'f64'])
|
||||
@pytest.mark.parametrize('type_', COMPLETE_SIMPLE_TYPES)
|
||||
def test_tuple_simple(type_):
|
||||
code_py = f"""
|
||||
@exported
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user