Feature: Tuples with tuples in constants
This commit is contained in:
parent
de92504394
commit
16ec664cb6
@ -716,57 +716,65 @@ def module_data(inp: ourlang.ModuleData) -> bytes:
|
|||||||
for constant in block.data:
|
for constant in block.data:
|
||||||
assert isinstance(constant.type3, type3types.Type3), (id(constant), type3types.TYPE3_ASSERTION_ERROR)
|
assert isinstance(constant.type3, type3types.Type3), (id(constant), type3types.TYPE3_ASSERTION_ERROR)
|
||||||
|
|
||||||
|
if isinstance(constant, ourlang.ConstantMemoryStored) and block is not constant.data_block:
|
||||||
|
# It's stored in a different block
|
||||||
|
# We only need to store its address
|
||||||
|
# This happens for example when a tuple refers
|
||||||
|
# to a bytes constant
|
||||||
|
assert constant.data_block.address is not None, 'Referred memory not yet stored'
|
||||||
|
data_list.append(module_data_u32(constant.data_block.address))
|
||||||
|
continue
|
||||||
|
|
||||||
if constant.type3 == type3types.u8:
|
if constant.type3 == type3types.u8:
|
||||||
|
assert isinstance(constant, ourlang.ConstantPrimitive)
|
||||||
assert isinstance(constant.value, int)
|
assert isinstance(constant.value, int)
|
||||||
data_list.append(module_data_u8(constant.value))
|
data_list.append(module_data_u8(constant.value))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if constant.type3 == type3types.u32:
|
if constant.type3 == type3types.u32:
|
||||||
|
assert isinstance(constant, ourlang.ConstantPrimitive)
|
||||||
assert isinstance(constant.value, int)
|
assert isinstance(constant.value, int)
|
||||||
data_list.append(module_data_u32(constant.value))
|
data_list.append(module_data_u32(constant.value))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if constant.type3 == type3types.u64:
|
if constant.type3 == type3types.u64:
|
||||||
|
assert isinstance(constant, ourlang.ConstantPrimitive)
|
||||||
assert isinstance(constant.value, int)
|
assert isinstance(constant.value, int)
|
||||||
data_list.append(module_data_u64(constant.value))
|
data_list.append(module_data_u64(constant.value))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if constant.type3 == type3types.i32:
|
if constant.type3 == type3types.i32:
|
||||||
|
assert isinstance(constant, ourlang.ConstantPrimitive)
|
||||||
assert isinstance(constant.value, int)
|
assert isinstance(constant.value, int)
|
||||||
data_list.append(module_data_i32(constant.value))
|
data_list.append(module_data_i32(constant.value))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if constant.type3 == type3types.i64:
|
if constant.type3 == type3types.i64:
|
||||||
|
assert isinstance(constant, ourlang.ConstantPrimitive)
|
||||||
assert isinstance(constant.value, int)
|
assert isinstance(constant.value, int)
|
||||||
data_list.append(module_data_i64(constant.value))
|
data_list.append(module_data_i64(constant.value))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if constant.type3 == type3types.f32:
|
if constant.type3 == type3types.f32:
|
||||||
|
assert isinstance(constant, ourlang.ConstantPrimitive)
|
||||||
assert isinstance(constant.value, float)
|
assert isinstance(constant.value, float)
|
||||||
data_list.append(module_data_f32(constant.value))
|
data_list.append(module_data_f32(constant.value))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if constant.type3 == type3types.f64:
|
if constant.type3 == type3types.f64:
|
||||||
|
assert isinstance(constant, ourlang.ConstantPrimitive)
|
||||||
assert isinstance(constant.value, float)
|
assert isinstance(constant.value, float)
|
||||||
data_list.append(module_data_f64(constant.value))
|
data_list.append(module_data_f64(constant.value))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if constant.type3 == type3types.bytes:
|
if constant.type3 == type3types.bytes:
|
||||||
assert isinstance(constant, ourlang.ConstantBytes)
|
assert isinstance(constant, ourlang.ConstantBytes)
|
||||||
|
assert isinstance(constant.value, bytes)
|
||||||
if block is not constant.data_block:
|
data_list.append(module_data_u32(len(constant.value)))
|
||||||
# It's stored in a different block
|
data_list.append(constant.value)
|
||||||
# We only need to store its address
|
|
||||||
# This happens for example when a tuple refers
|
|
||||||
# to a bytes constant
|
|
||||||
assert constant.data_block.address is not None
|
|
||||||
data_list.append(module_data_u32(constant.data_block.address))
|
|
||||||
else:
|
|
||||||
data_list.append(module_data_u32(len(constant.value)))
|
|
||||||
data_list.append(constant.value)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
raise NotImplementedError(constant, constant.type3, constant.value)
|
raise NotImplementedError(constant, constant.type3)
|
||||||
|
|
||||||
block_data = b''.join(data_list)
|
block_data = b''.join(data_list)
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
Contains the syntax tree for ourlang
|
Contains the syntax tree for ourlang
|
||||||
"""
|
"""
|
||||||
from typing import Dict, List, Optional, Union
|
from typing import Dict, Iterable, List, Optional, Union
|
||||||
|
|
||||||
import enum
|
import enum
|
||||||
|
|
||||||
@ -47,19 +47,31 @@ class ConstantPrimitive(Constant):
|
|||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f'ConstantPrimitive({repr(self.value)})'
|
return f'ConstantPrimitive({repr(self.value)})'
|
||||||
|
|
||||||
class ConstantBytes(Constant):
|
class ConstantMemoryStored(Constant):
|
||||||
|
"""
|
||||||
|
An constant value expression within a statement
|
||||||
|
|
||||||
|
# FIXME: Rename to literal
|
||||||
|
"""
|
||||||
|
__slots__ = ('data_block', )
|
||||||
|
|
||||||
|
data_block: 'ModuleDataBlock'
|
||||||
|
|
||||||
|
def __init__(self, data_block: 'ModuleDataBlock') -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.data_block = data_block
|
||||||
|
|
||||||
|
class ConstantBytes(ConstantMemoryStored):
|
||||||
"""
|
"""
|
||||||
A bytes constant value expression within a statement
|
A bytes constant value expression within a statement
|
||||||
"""
|
"""
|
||||||
__slots__ = ('value', 'data_block', )
|
__slots__ = ('value', )
|
||||||
|
|
||||||
value: bytes
|
value: bytes
|
||||||
data_block: 'ModuleDataBlock'
|
|
||||||
|
|
||||||
def __init__(self, value: bytes, data_block: 'ModuleDataBlock') -> None:
|
def __init__(self, value: bytes, data_block: 'ModuleDataBlock') -> None:
|
||||||
super().__init__()
|
super().__init__(data_block)
|
||||||
self.value = value
|
self.value = value
|
||||||
self.data_block = data_block
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
# Do not repr the whole ModuleDataBlock
|
# Do not repr the whole ModuleDataBlock
|
||||||
@ -67,19 +79,17 @@ class ConstantBytes(Constant):
|
|||||||
# which it needs to compile the data into the program
|
# which it needs to compile the data into the program
|
||||||
return f'ConstantBytes({repr(self.value)}, @{repr(self.data_block.address)})'
|
return f'ConstantBytes({repr(self.value)}, @{repr(self.data_block.address)})'
|
||||||
|
|
||||||
class ConstantTuple(Constant):
|
class ConstantTuple(ConstantMemoryStored):
|
||||||
"""
|
"""
|
||||||
A Tuple constant value expression within a statement
|
A Tuple constant value expression within a statement
|
||||||
"""
|
"""
|
||||||
__slots__ = ('value', 'data_block', )
|
__slots__ = ('value', )
|
||||||
|
|
||||||
value: List[Union[ConstantPrimitive, ConstantBytes]] # FIXME: Tuple of tuples?
|
value: List[Union[ConstantPrimitive, ConstantBytes, 'ConstantTuple']]
|
||||||
data_block: 'ModuleDataBlock'
|
|
||||||
|
|
||||||
def __init__(self, value: List[Union[ConstantPrimitive, ConstantBytes]], data_block: 'ModuleDataBlock') -> None:
|
def __init__(self, value: List[Union[ConstantPrimitive, ConstantBytes, 'ConstantTuple']], data_block: 'ModuleDataBlock') -> None:
|
||||||
super().__init__()
|
super().__init__(data_block)
|
||||||
self.value = value
|
self.value = value
|
||||||
self.data_block = data_block
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
# Do not repr the whole ModuleDataBlock
|
# Do not repr the whole ModuleDataBlock
|
||||||
@ -87,21 +97,19 @@ class ConstantTuple(Constant):
|
|||||||
# which it needs to compile the data into the program
|
# which it needs to compile the data into the program
|
||||||
return f'ConstantTuple({repr(self.value)}, @{repr(self.data_block.address)})'
|
return f'ConstantTuple({repr(self.value)}, @{repr(self.data_block.address)})'
|
||||||
|
|
||||||
class ConstantStruct(Constant):
|
class ConstantStruct(ConstantMemoryStored):
|
||||||
"""
|
"""
|
||||||
A Struct constant value expression within a statement
|
A Struct constant value expression within a statement
|
||||||
"""
|
"""
|
||||||
__slots__ = ('struct_name', 'value', 'data_block', )
|
__slots__ = ('struct_name', 'value', )
|
||||||
|
|
||||||
struct_name: str
|
struct_name: str
|
||||||
value: List[Union[ConstantPrimitive, ConstantBytes]] # FIXME: Struct of structs?
|
value: List[Union[ConstantPrimitive, ConstantBytes, ConstantTuple]]
|
||||||
data_block: 'ModuleDataBlock'
|
|
||||||
|
|
||||||
def __init__(self, struct_name: str, value: List[Union[ConstantPrimitive, ConstantBytes]], data_block: 'ModuleDataBlock') -> None:
|
def __init__(self, struct_name: str, value: List[Union[ConstantPrimitive, ConstantBytes, ConstantTuple]], data_block: 'ModuleDataBlock') -> None:
|
||||||
super().__init__()
|
super().__init__(data_block)
|
||||||
self.struct_name = struct_name
|
self.struct_name = struct_name
|
||||||
self.value = value
|
self.value = value
|
||||||
self.data_block = data_block
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
# Do not repr the whole ModuleDataBlock
|
# Do not repr the whole ModuleDataBlock
|
||||||
@ -376,11 +384,11 @@ class ModuleDataBlock:
|
|||||||
"""
|
"""
|
||||||
__slots__ = ('data', 'address', )
|
__slots__ = ('data', 'address', )
|
||||||
|
|
||||||
data: List[Union[ConstantPrimitive, ConstantBytes]]
|
data: List[Union[ConstantPrimitive, ConstantMemoryStored]]
|
||||||
address: Optional[int]
|
address: Optional[int]
|
||||||
|
|
||||||
def __init__(self, data: List[Union[ConstantPrimitive, ConstantBytes]]) -> None:
|
def __init__(self, data: Iterable[Union[ConstantPrimitive, ConstantMemoryStored]]) -> None:
|
||||||
self.data = data
|
self.data = [*data]
|
||||||
self.address = None
|
self.address = None
|
||||||
|
|
||||||
class ModuleData:
|
class ModuleData:
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
Parses the source code from the plain text into a syntax tree
|
Parses the source code from the plain text into a syntax tree
|
||||||
"""
|
"""
|
||||||
from typing import Any, Dict, NoReturn, Union
|
from typing import Any, Dict, List, NoReturn, Union
|
||||||
|
|
||||||
import ast
|
import ast
|
||||||
|
|
||||||
@ -16,7 +16,8 @@ from .ourlang import (
|
|||||||
|
|
||||||
Expression,
|
Expression,
|
||||||
BinaryOp,
|
BinaryOp,
|
||||||
ConstantPrimitive, ConstantBytes, ConstantTuple, ConstantStruct,
|
ConstantPrimitive, ConstantMemoryStored,
|
||||||
|
ConstantBytes, ConstantTuple, ConstantStruct,
|
||||||
TupleInstantiation,
|
TupleInstantiation,
|
||||||
|
|
||||||
FunctionCall, AccessStructMember, Subscript,
|
FunctionCall, AccessStructMember, Subscript,
|
||||||
@ -219,24 +220,16 @@ class OurVisitor:
|
|||||||
)
|
)
|
||||||
|
|
||||||
if isinstance(node.value, ast.Tuple):
|
if isinstance(node.value, ast.Tuple):
|
||||||
tuple_data = [
|
value_data = self.visit_Module_Constant(module, node.value)
|
||||||
self.visit_Module_Constant(module, arg_node)
|
|
||||||
for arg_node in node.value.elts
|
|
||||||
if isinstance(arg_node, ast.Constant)
|
|
||||||
]
|
|
||||||
if len(node.value.elts) != len(tuple_data):
|
|
||||||
_raise_static_error(node, 'Tuple arguments must be constants')
|
|
||||||
|
|
||||||
# Allocate the data
|
assert isinstance(value_data, ConstantTuple) # type hint
|
||||||
data_block = ModuleDataBlock(tuple_data)
|
|
||||||
module.data.blocks.append(data_block)
|
|
||||||
|
|
||||||
# Then return the constant as a pointer
|
# Then return the constant as a pointer
|
||||||
return ModuleConstantDef(
|
return ModuleConstantDef(
|
||||||
node.target.id,
|
node.target.id,
|
||||||
node.lineno,
|
node.lineno,
|
||||||
self.visit_type(module, node.annotation),
|
self.visit_type(module, node.annotation),
|
||||||
ConstantTuple(tuple_data, data_block),
|
value_data,
|
||||||
)
|
)
|
||||||
|
|
||||||
if isinstance(node.value, ast.Call):
|
if isinstance(node.value, ast.Call):
|
||||||
@ -568,7 +561,23 @@ class OurVisitor:
|
|||||||
|
|
||||||
return Subscript(varref, slice_expr)
|
return Subscript(varref, slice_expr)
|
||||||
|
|
||||||
def visit_Module_Constant(self, module: Module, node: ast.Constant) -> Union[ConstantPrimitive, ConstantBytes]:
|
def visit_Module_Constant(self, module: Module, node: Union[ast.Constant, ast.Tuple]) -> Union[ConstantPrimitive, ConstantBytes, ConstantTuple]:
|
||||||
|
if isinstance(node, ast.Tuple):
|
||||||
|
tuple_data = [
|
||||||
|
self.visit_Module_Constant(module, arg_node)
|
||||||
|
for arg_node in node.elts
|
||||||
|
if isinstance(arg_node, (ast.Constant, ast.Tuple, ))
|
||||||
|
]
|
||||||
|
|
||||||
|
if len(node.elts) != len(tuple_data):
|
||||||
|
_raise_static_error(node, 'Tuple arguments must be constants')
|
||||||
|
|
||||||
|
# Allocate the data
|
||||||
|
data_block = ModuleDataBlock(tuple_data)
|
||||||
|
module.data.blocks.append(data_block)
|
||||||
|
|
||||||
|
return ConstantTuple(tuple_data, data_block)
|
||||||
|
|
||||||
_not_implemented(node.kind is None, 'Constant.kind')
|
_not_implemented(node.kind is None, 'Constant.kind')
|
||||||
|
|
||||||
if isinstance(node.value, (int, float, )):
|
if isinstance(node.value, (int, float, )):
|
||||||
|
|||||||
@ -119,6 +119,29 @@ def testEntry() -> u64:
|
|||||||
|
|
||||||
assert 128 == result.returned_value
|
assert 128 == result.returned_value
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_constant_tuple_of_tuple_of_tuple():
|
||||||
|
code_py = """
|
||||||
|
CONSTANT: (((u64, ), u64, ), u64, ) = (((128, ), 64, ), 32, )
|
||||||
|
|
||||||
|
def l1(c: (u64, )) -> u64:
|
||||||
|
return c[0]
|
||||||
|
|
||||||
|
def l2(c: ((u64, ), u64, )) -> u64:
|
||||||
|
return l1(c[0])
|
||||||
|
|
||||||
|
def l3(c: (((u64, ), u64, ), u64, )) -> u64:
|
||||||
|
return l2(c[0])
|
||||||
|
|
||||||
|
@exported
|
||||||
|
def testEntry() -> u64:
|
||||||
|
return l3(CONSTANT)
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
|
assert 128 == result.returned_value
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
def test_bytes_as_part_of_tuple():
|
def test_bytes_as_part_of_tuple():
|
||||||
code_py = """
|
code_py = """
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user