First work on restoring StaticArray
Removed the separate ModuleConstantRef since you can tell by the variable property of VariableReference. We'll also add local variables there later on.
This commit is contained in:
parent
299551db1b
commit
0097ce782d
@ -95,26 +95,23 @@ def expression(inp: ourlang.Expression) -> str:
|
||||
# return f'({args}, )'
|
||||
|
||||
return f'{inp.function.name}({args})'
|
||||
|
||||
if isinstance(inp, ourlang.AccessBytesIndex):
|
||||
return f'{expression(inp.varref)}[{expression(inp.index)}]'
|
||||
|
||||
if isinstance(inp, ourlang.AccessStructMember):
|
||||
return f'{expression(inp.varref)}.{inp.member.name}'
|
||||
|
||||
if isinstance(inp, (ourlang.AccessTupleMember, ourlang.AccessStaticArrayMember, )):
|
||||
if isinstance(inp.member, ourlang.Expression):
|
||||
return f'{expression(inp.varref)}[{expression(inp.member)}]'
|
||||
|
||||
return f'{expression(inp.varref)}[{inp.member.idx}]'
|
||||
#
|
||||
# if isinstance(inp, ourlang.AccessBytesIndex):
|
||||
# return f'{expression(inp.varref)}[{expression(inp.index)}]'
|
||||
#
|
||||
# if isinstance(inp, ourlang.AccessStructMember):
|
||||
# return f'{expression(inp.varref)}.{inp.member.name}'
|
||||
#
|
||||
# if isinstance(inp, (ourlang.AccessTupleMember, ourlang.AccessStaticArrayMember, )):
|
||||
# if isinstance(inp.member, ourlang.Expression):
|
||||
# return f'{expression(inp.varref)}[{expression(inp.member)}]'
|
||||
#
|
||||
# return f'{expression(inp.varref)}[{inp.member.idx}]'
|
||||
|
||||
if isinstance(inp, ourlang.Fold):
|
||||
fold_name = 'foldl' if ourlang.Fold.Direction.LEFT == inp.dir else 'foldr'
|
||||
return f'{fold_name}({inp.func.name}, {expression(inp.base)}, {expression(inp.iter)})'
|
||||
|
||||
if isinstance(inp, ourlang.ModuleConstantReference):
|
||||
return inp.definition.name
|
||||
|
||||
raise NotImplementedError(expression, inp)
|
||||
|
||||
def statement(inp: ourlang.Statement) -> Statements:
|
||||
|
||||
@ -156,9 +156,40 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
||||
raise NotImplementedError(f'Constants with type {stp}')
|
||||
|
||||
if isinstance(inp, ourlang.VariableReference):
|
||||
if isinstance(inp.variable, ourlang.FunctionParam):
|
||||
wgn.add_statement('local.get', '${}'.format(inp.variable.name))
|
||||
return
|
||||
|
||||
if isinstance(inp.variable, ourlang.ModuleConstantDef):
|
||||
# FIXME: Tuple / Static Array broken after new type system
|
||||
# if isinstance(inp.type, typing.TypeTuple):
|
||||
# assert isinstance(inp.definition.constant, ourlang.ConstantTuple)
|
||||
# assert inp.definition.data_block is not None, 'Combined values are memory stored'
|
||||
# assert inp.definition.data_block.address is not None, 'Value not allocated'
|
||||
# wgn.i32.const(inp.definition.data_block.address)
|
||||
# return
|
||||
#
|
||||
# if isinstance(inp.type, typing.TypeStaticArray):
|
||||
# assert isinstance(inp.definition.constant, ourlang.ConstantStaticArray)
|
||||
# assert inp.definition.data_block is not None, 'Combined values are memory stored'
|
||||
# assert inp.definition.data_block.address is not None, 'Value not allocated'
|
||||
# wgn.i32.const(inp.definition.data_block.address)
|
||||
# return
|
||||
|
||||
assert inp.variable.data_block is None, 'Primitives are not memory stored'
|
||||
|
||||
assert inp.variable.type_var is not None, typing.ASSERTION_ERROR
|
||||
mtyp = typing.simplify(inp.variable.type_var)
|
||||
if mtyp is None:
|
||||
# In the future might extend this by having structs or tuples
|
||||
# as members of struct or tuples
|
||||
raise NotImplementedError(expression, inp, inp.type_var)
|
||||
|
||||
expression(wgn, inp.variable.constant)
|
||||
return
|
||||
|
||||
raise NotImplementedError(expression, inp.variable)
|
||||
|
||||
if isinstance(inp, ourlang.BinaryOp):
|
||||
expression(wgn, inp.left)
|
||||
expression(wgn, inp.right)
|
||||
@ -301,34 +332,6 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
||||
expression_fold(wgn, inp)
|
||||
return
|
||||
|
||||
if isinstance(inp, ourlang.ModuleConstantReference):
|
||||
# FIXME: Tuple / Static Array broken after new type system
|
||||
# if isinstance(inp.type, typing.TypeTuple):
|
||||
# assert isinstance(inp.definition.constant, ourlang.ConstantTuple)
|
||||
# assert inp.definition.data_block is not None, 'Combined values are memory stored'
|
||||
# assert inp.definition.data_block.address is not None, 'Value not allocated'
|
||||
# wgn.i32.const(inp.definition.data_block.address)
|
||||
# return
|
||||
#
|
||||
# if isinstance(inp.type, typing.TypeStaticArray):
|
||||
# assert isinstance(inp.definition.constant, ourlang.ConstantStaticArray)
|
||||
# assert inp.definition.data_block is not None, 'Combined values are memory stored'
|
||||
# assert inp.definition.data_block.address is not None, 'Value not allocated'
|
||||
# wgn.i32.const(inp.definition.data_block.address)
|
||||
# return
|
||||
|
||||
assert inp.definition.data_block is None, 'Primitives are not memory stored'
|
||||
|
||||
assert inp.type_var is not None, typing.ASSERTION_ERROR
|
||||
mtyp = typing.simplify(inp.type_var)
|
||||
if mtyp is None:
|
||||
# In the future might extend this by having structs or tuples
|
||||
# as members of struct or tuples
|
||||
raise NotImplementedError(expression, inp, inp.type_var)
|
||||
|
||||
expression(wgn, inp.definition.constant)
|
||||
return
|
||||
|
||||
raise NotImplementedError(expression, inp)
|
||||
|
||||
def expression_fold(wgn: WasmGenerator, inp: ourlang.Fold) -> None:
|
||||
@ -566,38 +569,46 @@ def module_data(inp: ourlang.ModuleData) -> bytes:
|
||||
|
||||
data_list: List[bytes] = []
|
||||
|
||||
raise NotImplementedError('Broken after new type system')
|
||||
|
||||
for constant in block.data:
|
||||
if isinstance(constant, ourlang.ConstantUInt8):
|
||||
assert constant.type_var is not None
|
||||
mtyp = typing.simplify(constant.type_var)
|
||||
|
||||
if mtyp == 'u8':
|
||||
assert isinstance(constant.value, int)
|
||||
data_list.append(module_data_u8(constant.value))
|
||||
continue
|
||||
|
||||
if isinstance(constant, ourlang.ConstantUInt32):
|
||||
if mtyp == 'u32':
|
||||
assert isinstance(constant.value, int)
|
||||
data_list.append(module_data_u32(constant.value))
|
||||
continue
|
||||
|
||||
if isinstance(constant, ourlang.ConstantUInt64):
|
||||
if mtyp == 'u64':
|
||||
assert isinstance(constant.value, int)
|
||||
data_list.append(module_data_u64(constant.value))
|
||||
continue
|
||||
|
||||
if isinstance(constant, ourlang.ConstantInt32):
|
||||
if mtyp == 'i32':
|
||||
assert isinstance(constant.value, int)
|
||||
data_list.append(module_data_i32(constant.value))
|
||||
continue
|
||||
|
||||
if isinstance(constant, ourlang.ConstantInt64):
|
||||
if mtyp == 'i64':
|
||||
assert isinstance(constant.value, int)
|
||||
data_list.append(module_data_i64(constant.value))
|
||||
continue
|
||||
|
||||
if isinstance(constant, ourlang.ConstantFloat32):
|
||||
if mtyp == 'f32':
|
||||
assert isinstance(constant.value, float)
|
||||
data_list.append(module_data_f32(constant.value))
|
||||
continue
|
||||
|
||||
if isinstance(constant, ourlang.ConstantFloat64):
|
||||
if mtyp == 'f64':
|
||||
assert isinstance(constant.value, float)
|
||||
data_list.append(module_data_f64(constant.value))
|
||||
continue
|
||||
|
||||
raise NotImplementedError(constant)
|
||||
raise NotImplementedError(constant, mtyp)
|
||||
|
||||
block_data = b''.join(data_list)
|
||||
|
||||
|
||||
@ -11,10 +11,7 @@ WEBASSEMBLY_BUILDIN_FLOAT_OPS: Final = ('abs', 'sqrt', 'ceil', 'floor', 'trunc',
|
||||
WEBASSEMBLY_BUILDIN_BYTES_OPS: Final = ('len', )
|
||||
|
||||
from .typing import (
|
||||
TypeBytes,
|
||||
TypeTuple, TypeTupleMember,
|
||||
TypeStaticArray, TypeStaticArrayMember,
|
||||
TypeStruct, TypeStructMember,
|
||||
TypeStruct,
|
||||
|
||||
TypeVar,
|
||||
)
|
||||
@ -78,9 +75,9 @@ class VariableReference(Expression):
|
||||
"""
|
||||
__slots__ = ('variable', )
|
||||
|
||||
variable: 'FunctionParam' # also possibly local
|
||||
variable: Union['ModuleConstantDef', 'FunctionParam'] # also possibly local
|
||||
|
||||
def __init__(self, variable: 'FunctionParam') -> None:
|
||||
def __init__(self, variable: Union['ModuleConstantDef', 'FunctionParam']) -> None:
|
||||
super().__init__()
|
||||
self.variable = variable
|
||||
|
||||
@ -131,9 +128,10 @@ class FunctionCall(Expression):
|
||||
self.function = function
|
||||
self.arguments = []
|
||||
|
||||
class AccessBytesIndex(Expression):
|
||||
class Subscript(Expression):
|
||||
"""
|
||||
Access a bytes index for reading
|
||||
A subscript, for example to refer to a static array or tuple
|
||||
by index
|
||||
"""
|
||||
__slots__ = ('varref', 'index', )
|
||||
|
||||
@ -146,53 +144,6 @@ class AccessBytesIndex(Expression):
|
||||
self.varref = varref
|
||||
self.index = index
|
||||
|
||||
class AccessStructMember(Expression):
|
||||
"""
|
||||
Access a struct member for reading of writing
|
||||
"""
|
||||
__slots__ = ('varref', 'member', )
|
||||
|
||||
varref: VariableReference
|
||||
member: TypeStructMember
|
||||
|
||||
def __init__(self, varref: VariableReference, member: TypeStructMember) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.varref = varref
|
||||
self.member = member
|
||||
|
||||
class AccessTupleMember(Expression):
|
||||
"""
|
||||
Access a tuple member for reading of writing
|
||||
"""
|
||||
__slots__ = ('varref', 'member', )
|
||||
|
||||
varref: VariableReference
|
||||
member: TypeTupleMember
|
||||
|
||||
def __init__(self, varref: VariableReference, member: TypeTupleMember, ) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.varref = varref
|
||||
self.member = member
|
||||
|
||||
class AccessStaticArrayMember(Expression):
|
||||
"""
|
||||
Access a tuple member for reading of writing
|
||||
"""
|
||||
__slots__ = ('varref', 'static_array', 'member', )
|
||||
|
||||
varref: Union['ModuleConstantReference', VariableReference]
|
||||
static_array: TypeStaticArray
|
||||
member: Union[Expression, TypeStaticArrayMember]
|
||||
|
||||
def __init__(self, varref: Union['ModuleConstantReference', VariableReference], static_array: TypeStaticArray, member: Union[TypeStaticArrayMember, Expression], ) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.varref = varref
|
||||
self.static_array = static_array
|
||||
self.member = member
|
||||
|
||||
class Fold(Expression):
|
||||
"""
|
||||
A (left or right) fold
|
||||
@ -223,18 +174,6 @@ class Fold(Expression):
|
||||
self.base = base
|
||||
self.iter = iter_
|
||||
|
||||
class ModuleConstantReference(Expression):
|
||||
"""
|
||||
An reference to a module constant expression within a statement
|
||||
"""
|
||||
__slots__ = ('definition', )
|
||||
|
||||
definition: 'ModuleConstantDef'
|
||||
|
||||
def __init__(self, definition: 'ModuleConstantDef') -> None:
|
||||
super().__init__()
|
||||
self.definition = definition
|
||||
|
||||
class Statement:
|
||||
"""
|
||||
A statement within a function
|
||||
|
||||
124
phasm/parser.py
124
phasm/parser.py
@ -22,15 +22,14 @@ from .ourlang import (
|
||||
Function,
|
||||
|
||||
Expression,
|
||||
AccessBytesIndex, AccessStructMember, AccessTupleMember, AccessStaticArrayMember,
|
||||
BinaryOp,
|
||||
ConstantPrimitive, ConstantTuple, ConstantStaticArray,
|
||||
|
||||
FunctionCall,
|
||||
FunctionCall, Subscript,
|
||||
# StructConstructor, TupleConstructor,
|
||||
UnaryOp, VariableReference,
|
||||
|
||||
Fold, ModuleConstantReference,
|
||||
Fold,
|
||||
|
||||
Statement,
|
||||
StatementIf, StatementPass, StatementReturn,
|
||||
@ -206,6 +205,27 @@ class OurVisitor:
|
||||
None,
|
||||
)
|
||||
|
||||
if isinstance(node.value, ast.Tuple):
|
||||
tuple_data = [
|
||||
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
|
||||
data_block = ModuleDataBlock(tuple_data)
|
||||
module.data.blocks.append(data_block)
|
||||
|
||||
# Then return the constant as a pointer
|
||||
return ModuleConstantDef(
|
||||
node.target.id,
|
||||
node.lineno,
|
||||
ConstantTuple(tuple_data),
|
||||
data_block,
|
||||
)
|
||||
|
||||
raise NotImplementedError('TODO: Broken after new typing system')
|
||||
|
||||
# if isinstance(exp_type, TypeTuple):
|
||||
@ -416,7 +436,7 @@ class OurVisitor:
|
||||
|
||||
if node.id in module.constant_defs:
|
||||
cdef = module.constant_defs[node.id]
|
||||
return ModuleConstantReference(cdef)
|
||||
return VariableReference(cdef)
|
||||
|
||||
_raise_static_error(node, f'Undefined variable {node.id}')
|
||||
|
||||
@ -454,13 +474,13 @@ class OurVisitor:
|
||||
if not isinstance(node.func.ctx, ast.Load):
|
||||
_raise_static_error(node, 'Must be load context')
|
||||
|
||||
if node.func.id in module.structs:
|
||||
raise NotImplementedError('TODO: Broken after new type system')
|
||||
# if node.func.id in module.structs:
|
||||
# raise NotImplementedError('TODO: Broken after new type system')
|
||||
# struct = module.structs[node.func.id]
|
||||
# struct_constructor = StructConstructor(struct)
|
||||
#
|
||||
# func = module.functions[struct_constructor.name]
|
||||
elif node.func.id in WEBASSEMBLY_BUILDIN_FLOAT_OPS:
|
||||
if node.func.id in WEBASSEMBLY_BUILDIN_FLOAT_OPS:
|
||||
if 1 != len(node.args):
|
||||
_raise_static_error(node, f'Function {node.func.id} requires 1 arguments but {len(node.args)} are given')
|
||||
|
||||
@ -533,61 +553,59 @@ class OurVisitor:
|
||||
|
||||
def visit_Module_FunctionDef_Attribute(self, module: Module, function: Function, our_locals: OurLocals, node: ast.Attribute) -> Expression:
|
||||
raise NotImplementedError('Broken after new type system')
|
||||
del module
|
||||
del function
|
||||
|
||||
if not isinstance(node.value, ast.Name):
|
||||
_raise_static_error(node, 'Must reference a name')
|
||||
|
||||
if not isinstance(node.ctx, ast.Load):
|
||||
_raise_static_error(node, 'Must be load context')
|
||||
|
||||
if not node.value.id in our_locals:
|
||||
_raise_static_error(node, f'Undefined variable {node.value.id}')
|
||||
|
||||
param = our_locals[node.value.id]
|
||||
|
||||
node_typ = param.type
|
||||
if not isinstance(node_typ, TypeStruct):
|
||||
_raise_static_error(node, f'Cannot take attribute of non-struct {node.value.id}')
|
||||
|
||||
member = node_typ.get_member(node.attr)
|
||||
if member is None:
|
||||
_raise_static_error(node, f'{node_typ.name} has no attribute {node.attr}')
|
||||
|
||||
return AccessStructMember(
|
||||
VariableReference(param),
|
||||
member,
|
||||
)
|
||||
|
||||
def visit_Module_FunctionDef_Subscript(self, module: Module, function: Function, our_locals: OurLocals, node: ast.Subscript) -> Expression:
|
||||
raise NotImplementedError('TODO: Broken after new type system')
|
||||
|
||||
# del module
|
||||
# del function
|
||||
#
|
||||
# if not isinstance(node.value, ast.Name):
|
||||
# _raise_static_error(node, 'Must reference a name')
|
||||
#
|
||||
# if not isinstance(node.slice, ast.Index):
|
||||
# _raise_static_error(node, 'Must subscript using an index')
|
||||
#
|
||||
# if not isinstance(node.ctx, ast.Load):
|
||||
# _raise_static_error(node, 'Must be load context')
|
||||
#
|
||||
# varref: Union[ModuleConstantReference, VariableReference]
|
||||
# if node.value.id in our_locals:
|
||||
# param = our_locals[node.value.id]
|
||||
# node_typ = param.type
|
||||
# varref = VariableReference(param)
|
||||
# elif node.value.id in module.constant_defs:
|
||||
# constant_def = module.constant_defs[node.value.id]
|
||||
# node_typ = constant_def.type
|
||||
# varref = ModuleConstantReference(constant_def)
|
||||
# else:
|
||||
# if not node.value.id in our_locals:
|
||||
# _raise_static_error(node, f'Undefined variable {node.value.id}')
|
||||
#
|
||||
# slice_expr = self.visit_Module_FunctionDef_expr(
|
||||
# module, function, our_locals, node.slice.value,
|
||||
# )
|
||||
# param = our_locals[node.value.id]
|
||||
#
|
||||
# node_typ = param.type
|
||||
# if not isinstance(node_typ, TypeStruct):
|
||||
# _raise_static_error(node, f'Cannot take attribute of non-struct {node.value.id}')
|
||||
#
|
||||
# member = node_typ.get_member(node.attr)
|
||||
# if member is None:
|
||||
# _raise_static_error(node, f'{node_typ.name} has no attribute {node.attr}')
|
||||
#
|
||||
# return AccessStructMember(
|
||||
# VariableReference(param),
|
||||
# member,
|
||||
# )
|
||||
|
||||
def visit_Module_FunctionDef_Subscript(self, module: Module, function: Function, our_locals: OurLocals, node: ast.Subscript) -> Expression:
|
||||
if not isinstance(node.value, ast.Name):
|
||||
_raise_static_error(node, 'Must reference a name')
|
||||
|
||||
if not isinstance(node.slice, ast.Index):
|
||||
_raise_static_error(node, 'Must subscript using an index')
|
||||
|
||||
if not isinstance(node.ctx, ast.Load):
|
||||
_raise_static_error(node, 'Must be load context')
|
||||
|
||||
varref: VariableReference
|
||||
if node.value.id in our_locals:
|
||||
param = our_locals[node.value.id]
|
||||
varref = VariableReference(param)
|
||||
elif node.value.id in module.constant_defs:
|
||||
constant_def = module.constant_defs[node.value.id]
|
||||
varref = VariableReference(constant_def)
|
||||
else:
|
||||
_raise_static_error(node, f'Undefined variable {node.value.id}')
|
||||
|
||||
slice_expr = self.visit_Module_FunctionDef_expr(
|
||||
module, function, our_locals, node.slice.value,
|
||||
)
|
||||
|
||||
return Subscript(varref, slice_expr)
|
||||
|
||||
# if isinstance(node_typ, TypeBytes):
|
||||
# if isinstance(varref, ModuleConstantReference):
|
||||
# raise NotImplementedError(f'{node} from module constant')
|
||||
|
||||
@ -62,7 +62,7 @@ def expression(ctx: Context, inp: ourlang.Expression) -> 'TypeVar':
|
||||
return constant(ctx, inp)
|
||||
|
||||
if isinstance(inp, ourlang.VariableReference):
|
||||
assert inp.variable.type_var is not None, inp
|
||||
assert inp.variable.type_var is not None
|
||||
return inp.variable.type_var
|
||||
|
||||
if isinstance(inp, ourlang.UnaryOp):
|
||||
@ -112,13 +112,6 @@ def expression(ctx: Context, inp: ourlang.Expression) -> 'TypeVar':
|
||||
|
||||
return inp.function.returns_type_var
|
||||
|
||||
if isinstance(inp, ourlang.ModuleConstantReference):
|
||||
assert inp.definition.type_var is not None
|
||||
|
||||
inp.type_var = inp.definition.type_var
|
||||
|
||||
return inp.definition.type_var
|
||||
|
||||
raise NotImplementedError(expression, inp)
|
||||
|
||||
def function(ctx: Context, inp: ourlang.Function) -> None:
|
||||
|
||||
@ -7,21 +7,18 @@ from ..helpers import Suite
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@pytest.mark.parametrize('type_', COMPLETE_PRIMITIVE_TYPES)
|
||||
def test_static_array_module_constant(type_):
|
||||
def test_module_constant(type_):
|
||||
code_py = f"""
|
||||
CONSTANT: {type_}[3] = (24, 57, 80, )
|
||||
|
||||
@exported
|
||||
def testEntry() -> {type_}:
|
||||
return helper(CONSTANT)
|
||||
|
||||
def helper(array: {type_}[3]) -> {type_}:
|
||||
return array[0] + array[1] + array[2]
|
||||
return CONSTANT[0]
|
||||
"""
|
||||
|
||||
result = Suite(code_py).run_code()
|
||||
|
||||
assert 161 == result.returned_value
|
||||
assert 24 == result.returned_value
|
||||
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@ -43,6 +40,25 @@ def helper(array: {type_}[3], i0: u32, i1: u32, i2: u32) -> {type_}:
|
||||
assert 161 == result.returned_value
|
||||
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@pytest.mark.parametrize('type_', COMPLETE_PRIMITIVE_TYPES)
|
||||
def test_function_call(type_):
|
||||
code_py = f"""
|
||||
CONSTANT: {type_}[3] = (24, 57, 80, )
|
||||
|
||||
@exported
|
||||
def testEntry() -> {type_}:
|
||||
return helper(CONSTANT)
|
||||
|
||||
def helper(array: {type_}[3]) -> {type_}:
|
||||
return array[0] + array[1] + array[2]
|
||||
"""
|
||||
|
||||
result = Suite(code_py).run_code()
|
||||
|
||||
assert 161 == result.returned_value
|
||||
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||
|
||||
@pytest.mark.integration_test
|
||||
def test_static_array_constant_too_few_values():
|
||||
code_py = """
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user