diff --git a/phasm/compiler.py b/phasm/compiler.py index 0fb65ea..3ff1eb0 100644 --- a/phasm/compiler.py +++ b/phasm/compiler.py @@ -233,7 +233,13 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None: wgn.f64.const(inp.value) return - raise NotImplementedError(f'Constants with type {inp.type3}') + raise NotImplementedError(f'Constants with type {inp.type3:s}') + + if isinstance(inp, ourlang.ConstantBytes): + assert inp.data_block is not None, 'Bytes must be memory stored' + assert inp.data_block.address is not None, 'Value not allocated' + wgn.i32.const(inp.data_block.address) + return if isinstance(inp, ourlang.VariableReference): if isinstance(inp.variable, ourlang.FunctionParam): @@ -243,6 +249,12 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None: if isinstance(inp.variable, ourlang.ModuleConstantDef): assert isinstance(inp.type3, type3types.Type3), type3types.TYPE3_ASSERTION_ERROR + if inp.type3 is type3types.bytes: + assert inp.variable.data_block is not None, 'Bytes must be memory stored' + assert inp.variable.data_block.address is not None, 'Value not allocated' + wgn.i32.const(inp.variable.data_block.address) + return + if isinstance(inp.type3, type3types.StructType3): assert inp.variable.data_block is not None, 'Structs must be memory stored' assert inp.variable.data_block.address is not None, 'Value not allocated' @@ -735,6 +747,12 @@ def module_data(inp: ourlang.ModuleData) -> bytes: data_list.append(module_data_f64(constant.value)) continue + if constant.type3 == type3types.bytes: + assert isinstance(constant.value, bytes) + data_list.append(module_data_u32(len(constant.value))) + data_list.append(constant.value) + continue + raise NotImplementedError(constant, constant.type3, constant.value) block_data = b''.join(data_list) diff --git a/phasm/ourlang.py b/phasm/ourlang.py index 677ca64..8e3dfc7 100644 --- a/phasm/ourlang.py +++ b/phasm/ourlang.py @@ -47,15 +47,32 @@ class ConstantPrimitive(Constant): def __repr__(self) -> str: return f'ConstantPrimitive({repr(self.value)})' +class ConstantBytes(Constant): + """ + A bytes constant value expression within a statement + """ + __slots__ = ('value', 'data_block', ) + + value: bytes + data_block: 'ModuleDataBlock' + + def __init__(self, value: bytes, data_block: 'ModuleDataBlock') -> None: + super().__init__() + self.value = value + self.data_block = data_block + + def __repr__(self) -> str: + return f'ConstantBytes({repr(self.value)}, @{repr(self.data_block.address)})' + class ConstantTuple(Constant): """ A Tuple constant value expression within a statement """ __slots__ = ('value', ) - value: List[ConstantPrimitive] + value: List[Union[ConstantPrimitive, ConstantBytes]] - def __init__(self, value: List[ConstantPrimitive]) -> None: # FIXME: Tuple of tuples? + def __init__(self, value: List[Union[ConstantPrimitive, ConstantBytes]]) -> None: # FIXME: Tuple of tuples? super().__init__() self.value = value @@ -69,9 +86,9 @@ class ConstantStruct(Constant): __slots__ = ('struct_name', 'value', ) struct_name: str - value: List[ConstantPrimitive] + value: List[Union[ConstantPrimitive, ConstantBytes]] - def __init__(self, struct_name: str, value: List[ConstantPrimitive]) -> None: # FIXME: Struct of structs? + def __init__(self, struct_name: str, value: List[Union[ConstantPrimitive, ConstantBytes]]) -> None: # FIXME: Struct of structs? super().__init__() self.struct_name = struct_name self.value = value @@ -361,10 +378,10 @@ class ModuleDataBlock: """ __slots__ = ('data', 'address', ) - data: List[ConstantPrimitive] + data: List[Union[ConstantPrimitive, ConstantBytes]] address: Optional[int] - def __init__(self, data: List[ConstantPrimitive]) -> None: + def __init__(self, data: List[Union[ConstantPrimitive, ConstantBytes]]) -> None: self.data = data self.address = None diff --git a/phasm/parser.py b/phasm/parser.py index 4f054ef..7780bdb 100644 --- a/phasm/parser.py +++ b/phasm/parser.py @@ -16,7 +16,7 @@ from .ourlang import ( Expression, BinaryOp, - ConstantPrimitive, ConstantTuple, ConstantStruct, + ConstantPrimitive, ConstantBytes, ConstantTuple, ConstantStruct, TupleInstantiation, FunctionCall, AccessStructMember, Subscript, @@ -191,12 +191,20 @@ class OurVisitor: if isinstance(node.value, ast.Constant): type3 = self.visit_type(module, node.annotation) + + value_data = self.visit_Module_Constant(module, node.value) + + if isinstance(value_data, ConstantBytes): + data_block = value_data.data_block + else: + data_block = None + return ModuleConstantDef( node.target.id, node.lineno, type3, - self.visit_Module_Constant(module, node.value), - None, + value_data, + data_block, ) if isinstance(node.value, ast.Tuple): @@ -554,14 +562,20 @@ class OurVisitor: return Subscript(varref, slice_expr) - def visit_Module_Constant(self, module: Module, node: ast.Constant) -> ConstantPrimitive: - del module - + def visit_Module_Constant(self, module: Module, node: ast.Constant) -> Union[ConstantPrimitive, ConstantBytes]: _not_implemented(node.kind is None, 'Constant.kind') if isinstance(node.value, (int, float, )): return ConstantPrimitive(node.value) + if isinstance(node.value, bytes): + data_block = ModuleDataBlock([]) + module.data.blocks.append(data_block) + + result = ConstantBytes(node.value, data_block) + data_block.data.append(result) + return result + raise NotImplementedError(f'{node.value} as constant') def visit_type(self, module: Module, node: ast.expr) -> type3types.Type3: diff --git a/phasm/type3/constraints.py b/phasm/type3/constraints.py index 31b8f20..2fbdb42 100644 --- a/phasm/type3/constraints.py +++ b/phasm/type3/constraints.py @@ -323,12 +323,12 @@ class LiteralFitsConstraint(ConstraintBase): __slots__ = ('type3', 'literal', ) type3: types.Type3OrPlaceholder - literal: Union[ourlang.ConstantPrimitive, ourlang.ConstantTuple, ourlang.ConstantStruct] + literal: Union[ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct] def __init__( self, type3: types.Type3OrPlaceholder, - literal: Union[ourlang.ConstantPrimitive, ourlang.ConstantTuple, ourlang.ConstantStruct], + literal: Union[ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct], comment: Optional[str] = None, ) -> None: super().__init__(comment=comment) @@ -380,6 +380,12 @@ class LiteralFitsConstraint(ConstraintBase): return Error('Must be real') # FIXME: Add line information + if self.type3 is types.bytes: + if isinstance(self.literal.value, bytes): + return None + + return Error('Must be bytes') # FIXME: Add line information + res: NewConstraintList if isinstance(self.type3, types.AppliedType3): diff --git a/phasm/type3/constraintsgenerator.py b/phasm/type3/constraintsgenerator.py index 85a8cb9..fcb1038 100644 --- a/phasm/type3/constraintsgenerator.py +++ b/phasm/type3/constraintsgenerator.py @@ -25,7 +25,7 @@ def phasm_type3_generate_constraints(inp: ourlang.Module) -> List[ConstraintBase return [*module(ctx, inp)] def constant(ctx: Context, inp: ourlang.Constant) -> ConstraintGenerator: - if isinstance(inp, (ourlang.ConstantPrimitive, ourlang.ConstantTuple, ourlang.ConstantStruct)): + if isinstance(inp, (ourlang.ConstantPrimitive, ourlang.ConstantBytes, ourlang.ConstantTuple, ourlang.ConstantStruct)): yield LiteralFitsConstraint(inp.type3, inp) return