Static Arrays. CRC32 compiles \o/

Doesn't give right answer yet and out of bound check fails.
No constructor yet for static arrays, but module constants
work. Which don't work yet for tuples and structs.

Also, u32 for indexing please.

Also, more module constant types.
This commit is contained in:
Johan B.W. de Vries 2022-08-18 20:53:21 +02:00
parent c4ee2ab3dc
commit e589223dbb
15 changed files with 448 additions and 46 deletions

View File

@ -1,5 +1,5 @@
@exported @exported
def index(inp: bytes, idx: i32) -> i32: def index(inp: bytes, idx: u32) -> u8:
return inp[idx] return inp[idx]
@exported @exported

47
examples/crc32.html Normal file
View File

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html>
<head>
<title>Examples - CRC32</title>
</head>
<body>
<h1>Buffer</h1>
<a href="index.html">List</a> - <a href="crc32.py.html">Source</a> - <a href="crc32.wat.html">WebAssembly</a>
<div style="white-space: pre;" id="results"></div>
<script type="text/javascript">
let importObject = {};
let results = document.getElementById('results');
function log(txt)
{
let span = document.createElement('span');
span.innerHTML = txt;
results.appendChild(span);
let br = document.createElement('br');
results.appendChild(br);
}
WebAssembly.instantiateStreaming(fetch('crc32.wasm'), importObject)
.then(app => {
// Allocate room within the memory of the WebAssembly class
stdlib_types___alloc_bytes__ = app.instance.exports['stdlib.types.__alloc_bytes__']
let offset0 = stdlib_types___alloc_bytes__(0);
let offset1 = stdlib_types___alloc_bytes__(1);
// Write into allocated memory
var i8arr0 = new Uint8Array(app.instance.exports.memory.buffer, offset0 + 4, 0);
var i8arr1 = new Uint8Array(app.instance.exports.memory.buffer, offset1 + 4, 1);
i8arr1[0] = 0x61;
log('crc32([' + i8arr0 + ']) = ' + app.instance.exports.crc32(offset0));
log('crc32([' + i8arr1 + ']) = ' + app.instance.exports.crc32(offset1));
});
</script>
</body>
</html>

View File

@ -14,7 +14,7 @@
# } # }
# Might be the wrong table # Might be the wrong table
_CRC32_Table: u32[256] = [ _CRC32_Table: u32[256] = (
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
@ -79,7 +79,7 @@ _CRC32_Table: u32[256] = [
0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
] )
def _crc32_f(crc: u32, byt: u8) -> u32: def _crc32_f(crc: u32, byt: u8) -> u32:
return (crc >> 8) ^ _CRC32_Table[(crc & 0xFF) ^ u32(byt)] return (crc >> 8) ^ _CRC32_Table[(crc & 0xFF) ^ u32(byt)]

View File

@ -6,6 +6,7 @@
<h1>Examples</h1> <h1>Examples</h1>
<h2>Standard</h2> <h2>Standard</h2>
<ul> <ul>
<li><a href="crc32.html">CRC32</a></li>
<li><a href="fib.html">Fibonacci</a></li> <li><a href="fib.html">Fibonacci</a></li>
</ul> </ul>
<h2>Technical</h2> <h2>Technical</h2>

View File

@ -58,6 +58,9 @@ def type_(inp: typing.TypeBase) -> str:
return f'({mems}, )' return f'({mems}, )'
if isinstance(inp, typing.TypeStaticArray):
return f'{type_(inp.member_type)}[{len(inp.members)}]'
if isinstance(inp, typing.TypeStruct): if isinstance(inp, typing.TypeStruct):
return inp.name return inp.name
@ -94,7 +97,7 @@ def expression(inp: ourlang.Expression) -> str:
# could not fit in the given float type # could not fit in the given float type
return str(inp.value) return str(inp.value)
if isinstance(inp, ourlang.ConstantTuple): if isinstance(inp, (ourlang.ConstantTuple, ourlang.ConstantStaticArray, )):
return '(' + ', '.join( return '(' + ', '.join(
expression(x) expression(x)
for x in inp.value for x in inp.value
@ -137,7 +140,10 @@ def expression(inp: ourlang.Expression) -> str:
if isinstance(inp, ourlang.AccessStructMember): if isinstance(inp, ourlang.AccessStructMember):
return f'{expression(inp.varref)}.{inp.member.name}' return f'{expression(inp.varref)}.{inp.member.name}'
if isinstance(inp, ourlang.AccessTupleMember): 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}]' return f'{expression(inp.varref)}[{inp.member.idx}]'
if isinstance(inp, ourlang.Fold): if isinstance(inp, ourlang.Fold):

View File

@ -62,7 +62,7 @@ def type_(inp: typing.TypeBase) -> wasm.WasmType:
if isinstance(inp, typing.TypeFloat64): if isinstance(inp, typing.TypeFloat64):
return wasm.WasmTypeFloat64() return wasm.WasmTypeFloat64()
if isinstance(inp, (typing.TypeStruct, typing.TypeTuple, typing.TypeBytes)): if isinstance(inp, (typing.TypeStruct, typing.TypeTuple, typing.TypeStaticArray, typing.TypeBytes)):
# Structs and tuples are passed as pointer # Structs and tuples are passed as pointer
# And pointers are i32 # And pointers are i32
return wasm.WasmTypeInt32() return wasm.WasmTypeInt32()
@ -273,6 +273,26 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
wgn.add_statement(f'{mtyp}.load', 'offset=' + str(inp.member.offset)) wgn.add_statement(f'{mtyp}.load', 'offset=' + str(inp.member.offset))
return return
if isinstance(inp, ourlang.AccessStaticArrayMember):
mtyp = LOAD_STORE_TYPE_MAP.get(inp.static_array.member_type.__class__)
if mtyp is None:
# In the future might extend this by having structs or tuples
# as members of static arrays
raise NotImplementedError(expression, inp, inp.member)
if isinstance(inp.member, typing.TypeStaticArrayMember):
expression(wgn, inp.varref)
wgn.add_statement(f'{mtyp}.load', 'offset=' + str(inp.member.offset))
return
expression(wgn, inp.varref)
expression(wgn, inp.member)
wgn.i32.const(inp.static_array.member_type.alloc_size())
wgn.i32.mul()
wgn.i32.add()
wgn.add_statement(f'{mtyp}.load')
return
if isinstance(inp, ourlang.Fold): if isinstance(inp, ourlang.Fold):
expression_fold(wgn, inp) expression_fold(wgn, inp)
return return
@ -285,6 +305,13 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
wgn.i32.const(inp.definition.data_block.address) wgn.i32.const(inp.definition.data_block.address)
return 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.definition.data_block is None, 'Primitives are not memory stored'
mtyp = LOAD_STORE_TYPE_MAP.get(inp.type.__class__) mtyp = LOAD_STORE_TYPE_MAP.get(inp.type.__class__)
@ -471,7 +498,7 @@ def module_data_u32(inp: int) -> bytes:
""" """
Compile: module data, u32 value Compile: module data, u32 value
""" """
return struct.pack('<i', inp) return struct.pack('<I', inp)
def module_data_u64(inp: int) -> bytes: def module_data_u64(inp: int) -> bytes:
""" """
@ -479,6 +506,30 @@ def module_data_u64(inp: int) -> bytes:
""" """
return struct.pack('<Q', inp) return struct.pack('<Q', inp)
def module_data_i32(inp: int) -> bytes:
"""
Compile: module data, i32 value
"""
return struct.pack('<i', inp)
def module_data_i64(inp: int) -> bytes:
"""
Compile: module data, i64 value
"""
return struct.pack('<q', inp)
def module_data_f32(inp: float) -> bytes:
"""
Compile: module data, f32 value
"""
return struct.pack('<f', inp)
def module_data_f64(inp: float) -> bytes:
"""
Compile: module data, f64 value
"""
return struct.pack('<d', inp)
def module_data(inp: ourlang.ModuleData) -> bytes: def module_data(inp: ourlang.ModuleData) -> bytes:
""" """
Compile: module data Compile: module data
@ -505,6 +556,22 @@ def module_data(inp: ourlang.ModuleData) -> bytes:
data_list.append(module_data_u64(constant.value)) data_list.append(module_data_u64(constant.value))
continue continue
if isinstance(constant, ourlang.ConstantInt32):
data_list.append(module_data_i32(constant.value))
continue
if isinstance(constant, ourlang.ConstantInt64):
data_list.append(module_data_i64(constant.value))
continue
if isinstance(constant, ourlang.ConstantFloat32):
data_list.append(module_data_f32(constant.value))
continue
if isinstance(constant, ourlang.ConstantFloat64):
data_list.append(module_data_f64(constant.value))
continue
raise NotImplementedError(constant) raise NotImplementedError(constant)
block_data = b''.join(data_list) block_data = b''.join(data_list)
@ -579,7 +646,7 @@ def _generate_tuple_constructor(wgn: WasmGenerator, inp: ourlang.TupleConstructo
wgn.local.get(tmp_var) wgn.local.get(tmp_var)
def _generate_struct_constructor(wgn: WasmGenerator, inp: ourlang.StructConstructor) -> None: def _generate_struct_constructor(wgn: WasmGenerator, inp: ourlang.StructConstructor) -> None:
tmp_var = wgn.temp_var_i32('tuple_adr') tmp_var = wgn.temp_var_i32('struct_adr')
# Allocated the required amounts of bytes in memory # Allocated the required amounts of bytes in memory
wgn.i32.const(inp.struct.alloc_size()) wgn.i32.const(inp.struct.alloc_size())

View File

@ -1,7 +1,7 @@
""" """
Contains the syntax tree for ourlang Contains the syntax tree for ourlang
""" """
from typing import Dict, List, Tuple, Optional from typing import Dict, List, Tuple, Optional, Union
import enum import enum
@ -19,6 +19,7 @@ from .typing import (
TypeFloat32, TypeFloat64, TypeFloat32, TypeFloat64,
TypeBytes, TypeBytes,
TypeTuple, TypeTupleMember, TypeTuple, TypeTupleMember,
TypeStaticArray, TypeStaticArrayMember,
TypeStruct, TypeStructMember, TypeStruct, TypeStructMember,
) )
@ -135,6 +136,18 @@ class ConstantTuple(Constant):
super().__init__(type_) super().__init__(type_)
self.value = value self.value = value
class ConstantStaticArray(Constant):
"""
A StaticArray constant value expression within a statement
"""
__slots__ = ('value', )
value: List[Constant]
def __init__(self, type_: TypeStaticArray, value: List[Constant]) -> None:
super().__init__(type_)
self.value = value
class VariableReference(Expression): class VariableReference(Expression):
""" """
An variable reference expression within a statement An variable reference expression within a statement
@ -239,6 +252,23 @@ class AccessTupleMember(Expression):
self.varref = varref self.varref = varref
self.member = member 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__(static_array.member_type)
self.varref = varref
self.static_array = static_array
self.member = member
class Fold(Expression): class Fold(Expression):
""" """
A (left or right) fold A (left or right) fold

View File

@ -19,6 +19,8 @@ from .typing import (
TypeStructMember, TypeStructMember,
TypeTuple, TypeTuple,
TypeTupleMember, TypeTupleMember,
TypeStaticArray,
TypeStaticArrayMember,
) )
from . import codestyle from . import codestyle
@ -30,12 +32,12 @@ from .ourlang import (
Function, Function,
Expression, Expression,
AccessBytesIndex, AccessStructMember, AccessTupleMember, AccessBytesIndex, AccessStructMember, AccessTupleMember, AccessStaticArrayMember,
BinaryOp, BinaryOp,
Constant, Constant,
ConstantFloat32, ConstantFloat64, ConstantInt32, ConstantInt64, ConstantFloat32, ConstantFloat64, ConstantInt32, ConstantInt64,
ConstantUInt8, ConstantUInt32, ConstantUInt64, ConstantUInt8, ConstantUInt32, ConstantUInt64,
ConstantTuple, ConstantTuple, ConstantStaticArray,
FunctionCall, FunctionCall,
StructConstructor, TupleConstructor, StructConstructor, TupleConstructor,
@ -249,6 +251,34 @@ class OurVisitor:
data_block, data_block,
) )
if isinstance(exp_type, TypeStaticArray):
if not isinstance(node.value, ast.Tuple):
_raise_static_error(node, 'Must be static array')
if len(exp_type.members) != len(node.value.elts):
_raise_static_error(node, 'Invalid number of static array values')
static_array_data = [
self.visit_Module_Constant(module, exp_type.member_type, arg_node)
for arg_node in node.value.elts
if isinstance(arg_node, ast.Constant)
]
if len(exp_type.members) != len(static_array_data):
_raise_static_error(node, 'Static array arguments must be constants')
# Allocate the data
data_block = ModuleDataBlock(static_array_data)
module.data.blocks.append(data_block)
# Then return the constant as a pointer
return ModuleConstantDef(
node.target.id,
node.lineno,
exp_type,
ConstantStaticArray(exp_type, static_array_data),
data_block,
)
raise NotImplementedError(f'{node} on Module AnnAssign') raise NotImplementedError(f'{node} on Module AnnAssign')
def visit_Module_stmt(self, module: Module, node: ast.stmt) -> None: def visit_Module_stmt(self, module: Module, node: ast.stmt) -> None:
@ -416,22 +446,22 @@ class OurVisitor:
if not isinstance(node.ctx, ast.Load): if not isinstance(node.ctx, ast.Load):
_raise_static_error(node, 'Must be load context') _raise_static_error(node, 'Must be load context')
if not isinstance(exp_type, TypeTuple): if isinstance(exp_type, TypeTuple):
_raise_static_error(node, f'Expression is expecting a {codestyle.type_(exp_type)}, not a tuple') if len(exp_type.members) != len(node.elts):
_raise_static_error(node, f'Expression is expecting a tuple of size {len(exp_type.members)}, but {len(node.elts)} are given')
if len(exp_type.members) != len(node.elts): tuple_constructor = TupleConstructor(exp_type)
_raise_static_error(node, f'Expression is expecting a tuple of size {len(exp_type.members)}, but {len(node.elts)} are given')
tuple_constructor = TupleConstructor(exp_type) func = module.functions[tuple_constructor.name]
func = module.functions[tuple_constructor.name] result = FunctionCall(func)
result.arguments = [
self.visit_Module_FunctionDef_expr(module, function, our_locals, mem.type, arg_node)
for arg_node, mem in zip(node.elts, exp_type.members)
]
return result
result = FunctionCall(func) _raise_static_error(node, f'Expression is expecting a {codestyle.type_(exp_type)}, not a tuple')
result.arguments = [
self.visit_Module_FunctionDef_expr(module, function, our_locals, mem.type, arg_node)
for arg_node, mem in zip(node.elts, exp_type.members)
]
return result
raise NotImplementedError(f'{node} as expr in FunctionDef') raise NotImplementedError(f'{node} as expr in FunctionDef')
@ -582,24 +612,37 @@ class OurVisitor:
if not isinstance(node.ctx, ast.Load): if not isinstance(node.ctx, ast.Load):
_raise_static_error(node, 'Must be load context') _raise_static_error(node, 'Must be load context')
if not node.value.id in our_locals: varref: Union[ModuleConstantReference, VariableReference]
if node.value.id in our_locals:
node_typ = our_locals[node.value.id]
varref = VariableReference(node_typ, node.value.id)
elif node.value.id in module.constant_defs:
constant_def = module.constant_defs[node.value.id]
node_typ = constant_def.type
varref = ModuleConstantReference(node_typ, constant_def)
else:
_raise_static_error(node, f'Undefined variable {node.value.id}') _raise_static_error(node, f'Undefined variable {node.value.id}')
node_typ = our_locals[node.value.id]
slice_expr = self.visit_Module_FunctionDef_expr( slice_expr = self.visit_Module_FunctionDef_expr(
module, function, our_locals, module.types['i32'], node.slice.value, module, function, our_locals, module.types['u32'], node.slice.value,
) )
if isinstance(node_typ, TypeBytes): if isinstance(node_typ, TypeBytes):
t_u8 = module.types['u8']
if exp_type != t_u8:
_raise_static_error(node, f'Expected {codestyle.type_(exp_type)}, {node.value.id}[{codestyle.expression(slice_expr)}] is actually {codestyle.type_(t_u8)}')
if isinstance(varref, ModuleConstantReference):
raise NotImplementedError(f'{node} from module constant')
return AccessBytesIndex( return AccessBytesIndex(
module.types['u8'], t_u8,
VariableReference(node_typ, node.value.id), varref,
slice_expr, slice_expr,
) )
if isinstance(node_typ, TypeTuple): if isinstance(node_typ, TypeTuple):
if not isinstance(slice_expr, ConstantInt32): if not isinstance(slice_expr, ConstantUInt32):
_raise_static_error(node, 'Must subscript using a constant index') _raise_static_error(node, 'Must subscript using a constant index')
idx = slice_expr.value idx = slice_expr.value
@ -607,13 +650,40 @@ class OurVisitor:
if len(node_typ.members) <= idx: if len(node_typ.members) <= idx:
_raise_static_error(node, f'Index {idx} out of bounds for tuple {node.value.id}') _raise_static_error(node, f'Index {idx} out of bounds for tuple {node.value.id}')
member = node_typ.members[idx] tuple_member = node_typ.members[idx]
if exp_type != member.type: if exp_type != tuple_member.type:
_raise_static_error(node, f'Expected {codestyle.type_(exp_type)}, {node.value.id}[{idx}] is actually {codestyle.type_(member.type)}') _raise_static_error(node, f'Expected {codestyle.type_(exp_type)}, {node.value.id}[{idx}] is actually {codestyle.type_(tuple_member.type)}')
if isinstance(varref, ModuleConstantReference):
raise NotImplementedError(f'{node} from module constant')
return AccessTupleMember( return AccessTupleMember(
VariableReference(node_typ, node.value.id), varref,
member, tuple_member,
)
if isinstance(node_typ, TypeStaticArray):
if exp_type != node_typ.member_type:
_raise_static_error(node, f'Expected {codestyle.type_(exp_type)}, {node.value.id}[{idx}] is actually {codestyle.type_(node_typ.member_type)}')
if not isinstance(slice_expr, ConstantInt32):
return AccessStaticArrayMember(
varref,
node_typ,
slice_expr,
)
idx = slice_expr.value
if len(node_typ.members) <= idx:
_raise_static_error(node, f'Index {idx} out of bounds for static array {node.value.id}')
static_array_member = node_typ.members[idx]
return AccessStaticArrayMember(
varref,
node_typ,
static_array_member,
) )
_raise_static_error(node, f'Cannot take index of {node_typ} {node.value.id}') _raise_static_error(node, f'Cannot take index of {node_typ} {node.value.id}')
@ -705,25 +775,59 @@ class OurVisitor:
_raise_static_error(node, f'Unrecognized type {node.id}') _raise_static_error(node, f'Unrecognized type {node.id}')
if isinstance(node, ast.Subscript):
if not isinstance(node.value, ast.Name):
_raise_static_error(node, 'Must be name')
if not isinstance(node.slice, ast.Index):
_raise_static_error(node, 'Must subscript using an index')
if not isinstance(node.slice.value, ast.Constant):
_raise_static_error(node, 'Must subscript using a constant index')
if not isinstance(node.slice.value.value, int):
_raise_static_error(node, 'Must subscript using a constant integer index')
if not isinstance(node.ctx, ast.Load):
_raise_static_error(node, 'Must be load context')
if node.value.id in module.types:
member_type = module.types[node.value.id]
else:
_raise_static_error(node, f'Unrecognized type {node.value.id}')
type_static_array = TypeStaticArray(member_type)
offset = 0
for idx in range(node.slice.value.value):
static_array_member = TypeStaticArrayMember(idx, offset)
type_static_array.members.append(static_array_member)
offset += member_type.alloc_size()
key = f'{node.value.id}[{node.slice.value.value}]'
if key not in module.types:
module.types[key] = type_static_array
return module.types[key]
if isinstance(node, ast.Tuple): if isinstance(node, ast.Tuple):
if not isinstance(node.ctx, ast.Load): if not isinstance(node.ctx, ast.Load):
_raise_static_error(node, 'Must be load context') _raise_static_error(node, 'Must be load context')
result = TypeTuple() type_tuple = TypeTuple()
offset = 0 offset = 0
for idx, elt in enumerate(node.elts): for idx, elt in enumerate(node.elts):
member = TypeTupleMember(idx, self.visit_type(module, elt), offset) tuple_member = TypeTupleMember(idx, self.visit_type(module, elt), offset)
result.members.append(member) type_tuple.members.append(tuple_member)
offset += member.type.alloc_size() offset += tuple_member.type.alloc_size()
key = result.render_internal_name() key = type_tuple.render_internal_name()
if key not in module.types: if key not in module.types:
module.types[key] = result module.types[key] = type_tuple
constructor = TupleConstructor(result) constructor = TupleConstructor(type_tuple)
module.functions[constructor.name] = constructor module.functions[constructor.name] = constructor
return module.types[key] return module.types[key]

View File

@ -137,6 +137,30 @@ class TypeTuple(TypeBase):
for x in self.members for x in self.members
) )
class TypeStaticArrayMember:
"""
Represents a static array member
"""
def __init__(self, idx: int, offset: int) -> None:
self.idx = idx
self.offset = offset
class TypeStaticArray(TypeBase):
"""
The static array type
"""
__slots__ = ('member_type', 'members', )
member_type: TypeBase
members: List[TypeStaticArrayMember]
def __init__(self, member_type: TypeBase) -> None:
self.member_type = member_type
self.members = []
def alloc_size(self) -> int:
return self.member_type.alloc_size() * len(self.members)
class TypeStructMember: class TypeStructMember:
""" """
Represents a struct member Represents a struct member

View File

@ -30,6 +30,8 @@ class Generator_i32i64:
# 2.4.1. Numeric Instructions # 2.4.1. Numeric Instructions
# ibinop # ibinop
self.add = functools.partial(self.generator.add_statement, f'{prefix}.add') self.add = functools.partial(self.generator.add_statement, f'{prefix}.add')
self.sub = functools.partial(self.generator.add_statement, f'{prefix}.sub')
self.mul = functools.partial(self.generator.add_statement, f'{prefix}.mul')
# irelop # irelop
self.eq = functools.partial(self.generator.add_statement, f'{prefix}.eq') self.eq = functools.partial(self.generator.add_statement, f'{prefix}.eq')

View File

@ -1,5 +1,10 @@
[MASTER] [MASTER]
disable=C0122,R0903,R0911,R0912,R0913,R0915,R1710,W0223 disable=C0122,R0903,R0911,R0912,R0913,R0915,R1710,W0223
max-line-length=180
[stdlib] [stdlib]
good-names=g good-names=g
[tests]
disable=C0116,

View File

@ -50,3 +50,38 @@ def helper(vector: (u8, u8, u32, u32, u64, u64, )) -> u32:
result = Suite(code_py).run_code() result = Suite(code_py).run_code()
assert 3333 == result.returned_value assert 3333 == result.returned_value
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', ['u8', 'u32', 'u64', ])
def test_static_array_1(type_):
code_py = f"""
CONSTANT: {type_}[1] = (65, )
@exported
def testEntry() -> {type_}:
return helper(CONSTANT)
def helper(vector: {type_}[1]) -> {type_}:
return vector[0]
"""
result = Suite(code_py).run_code()
assert 65 == result.returned_value
@pytest.mark.integration_test
def test_static_array_6():
code_py = """
CONSTANT: u32[6] = (11, 22, 3333, 4444, 555555, 666666, )
@exported
def testEntry() -> u32:
return helper(CONSTANT)
def helper(vector: u32[6]) -> u32:
return vector[2]
"""
result = Suite(code_py).run_code()
assert 3333 == result.returned_value

View File

@ -13,3 +13,19 @@ def testEntry(f: bytes) -> u8:
result = Suite(code_py).run_code(b'Short', b'Long' * 100) result = Suite(code_py).run_code(b'Short', b'Long' * 100)
assert 0 == result.returned_value assert 0 == result.returned_value
@pytest.mark.integration_test
def test_static_array_index_out_of_bounds():
code_py = """
CONSTANT0: u32[3] = (24, 57, 80, )
CONSTANT1: u32[16] = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, )
@exported
def testEntry() -> u32:
return CONSTANT0[16]
"""
result = Suite(code_py).run_code()
assert 0 == result.returned_value

View File

@ -427,7 +427,7 @@ def helper(shape1: Rectangle, shape2: Rectangle) -> i32:
@pytest.mark.integration_test @pytest.mark.integration_test
@pytest.mark.parametrize('type_', COMPLETE_SIMPLE_TYPES) @pytest.mark.parametrize('type_', COMPLETE_SIMPLE_TYPES)
def test_tuple_simple(type_): def test_tuple_simple_constructor(type_):
code_py = f""" code_py = f"""
@exported @exported
def testEntry() -> {type_}: def testEntry() -> {type_}:
@ -457,6 +457,44 @@ def helper(v: (f32, f32, f32, )) -> f32:
assert 3.74 < result.returned_value < 3.75 assert 3.74 < result.returned_value < 3.75
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', COMPLETE_SIMPLE_TYPES)
def test_static_array_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]
"""
result = Suite(code_py).run_code()
assert 161 == result.returned_value
assert TYPE_MAP[type_] == type(result.returned_value)
@pytest.mark.integration_test
@pytest.mark.parametrize('type_', COMPLETE_SIMPLE_TYPES)
def test_static_array_indexed(type_):
code_py = f"""
CONSTANT: {type_}[3] = (24, 57, 80, )
@exported
def testEntry() -> {type_}:
return helper(CONSTANT, 0, 1, 2)
def helper(array: {type_}[3], i0: u32, i1: u32, i2: u32) -> {type_}:
return array[i0] + array[i1] + array[i2]
"""
result = Suite(code_py).run_code()
assert 161 == result.returned_value
assert TYPE_MAP[type_] == type(result.returned_value)
@pytest.mark.integration_test @pytest.mark.integration_test
def test_bytes_address(): def test_bytes_address():
code_py = """ code_py = """

View File

@ -60,7 +60,7 @@ def test_tuple_constant_too_few_values():
CONSTANT: (u32, u8, u8, ) = (24, 57, ) CONSTANT: (u32, u8, u8, ) = (24, 57, )
""" """
with pytest.raises(StaticError, match=f'Static error on line 2: Invalid number of tuple values'): with pytest.raises(StaticError, match='Static error on line 2: Invalid number of tuple values'):
phasm_parse(code_py) phasm_parse(code_py)
@pytest.mark.integration_test @pytest.mark.integration_test
@ -69,7 +69,7 @@ def test_tuple_constant_too_many_values():
CONSTANT: (u32, u8, u8, ) = (24, 57, 1, 1, ) CONSTANT: (u32, u8, u8, ) = (24, 57, 1, 1, )
""" """
with pytest.raises(StaticError, match=f'Static error on line 2: Invalid number of tuple values'): with pytest.raises(StaticError, match='Static error on line 2: Invalid number of tuple values'):
phasm_parse(code_py) phasm_parse(code_py)
@pytest.mark.integration_test @pytest.mark.integration_test
@ -78,5 +78,32 @@ def test_tuple_constant_type_mismatch():
CONSTANT: (u32, u8, u8, ) = (24, 4000, 1, ) CONSTANT: (u32, u8, u8, ) = (24, 4000, 1, )
""" """
with pytest.raises(StaticError, match=f'Static error on line 2: Integer value out of range; expected 0..255, actual 4000'): with pytest.raises(StaticError, match='Static error on line 2: Integer value out of range; expected 0..255, actual 4000'):
phasm_parse(code_py)
@pytest.mark.integration_test
def test_static_array_constant_too_few_values():
code_py = """
CONSTANT: u8[3] = (24, 57, )
"""
with pytest.raises(StaticError, match='Static error on line 2: Invalid number of static array values'):
phasm_parse(code_py)
@pytest.mark.integration_test
def test_static_array_constant_too_many_values():
code_py = """
CONSTANT: u8[3] = (24, 57, 1, 1, )
"""
with pytest.raises(StaticError, match='Static error on line 2: Invalid number of static array values'):
phasm_parse(code_py)
@pytest.mark.integration_test
def test_static_array_constant_type_mismatch():
code_py = """
CONSTANT: u8[3] = (24, 4000, 1, )
"""
with pytest.raises(StaticError, match='Static error on line 2: Integer value out of range; expected 0..255, actual 4000'):
phasm_parse(code_py) phasm_parse(code_py)