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:
parent
c4ee2ab3dc
commit
e589223dbb
@ -1,5 +1,5 @@
|
||||
@exported
|
||||
def index(inp: bytes, idx: i32) -> i32:
|
||||
def index(inp: bytes, idx: u32) -> u8:
|
||||
return inp[idx]
|
||||
|
||||
@exported
|
||||
|
||||
47
examples/crc32.html
Normal file
47
examples/crc32.html
Normal 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>
|
||||
@ -14,7 +14,7 @@
|
||||
# }
|
||||
|
||||
# Might be the wrong table
|
||||
_CRC32_Table: u32[256] = [
|
||||
_CRC32_Table: u32[256] = (
|
||||
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
|
||||
0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
|
||||
0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
|
||||
@ -79,7 +79,7 @@ _CRC32_Table: u32[256] = [
|
||||
0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
|
||||
0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
|
||||
0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
|
||||
]
|
||||
)
|
||||
|
||||
def _crc32_f(crc: u32, byt: u8) -> u32:
|
||||
return (crc >> 8) ^ _CRC32_Table[(crc & 0xFF) ^ u32(byt)]
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
<h1>Examples</h1>
|
||||
<h2>Standard</h2>
|
||||
<ul>
|
||||
<li><a href="crc32.html">CRC32</a></li>
|
||||
<li><a href="fib.html">Fibonacci</a></li>
|
||||
</ul>
|
||||
<h2>Technical</h2>
|
||||
|
||||
@ -58,6 +58,9 @@ def type_(inp: typing.TypeBase) -> str:
|
||||
|
||||
return f'({mems}, )'
|
||||
|
||||
if isinstance(inp, typing.TypeStaticArray):
|
||||
return f'{type_(inp.member_type)}[{len(inp.members)}]'
|
||||
|
||||
if isinstance(inp, typing.TypeStruct):
|
||||
return inp.name
|
||||
|
||||
@ -94,7 +97,7 @@ def expression(inp: ourlang.Expression) -> str:
|
||||
# could not fit in the given float type
|
||||
return str(inp.value)
|
||||
|
||||
if isinstance(inp, ourlang.ConstantTuple):
|
||||
if isinstance(inp, (ourlang.ConstantTuple, ourlang.ConstantStaticArray, )):
|
||||
return '(' + ', '.join(
|
||||
expression(x)
|
||||
for x in inp.value
|
||||
@ -137,7 +140,10 @@ def expression(inp: ourlang.Expression) -> str:
|
||||
if isinstance(inp, ourlang.AccessStructMember):
|
||||
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}]'
|
||||
|
||||
if isinstance(inp, ourlang.Fold):
|
||||
|
||||
@ -62,7 +62,7 @@ def type_(inp: typing.TypeBase) -> wasm.WasmType:
|
||||
if isinstance(inp, typing.TypeFloat64):
|
||||
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
|
||||
# And pointers are i32
|
||||
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))
|
||||
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):
|
||||
expression_fold(wgn, inp)
|
||||
return
|
||||
@ -285,6 +305,13 @@ def expression(wgn: WasmGenerator, inp: ourlang.Expression) -> None:
|
||||
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'
|
||||
|
||||
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
|
||||
"""
|
||||
return struct.pack('<i', inp)
|
||||
return struct.pack('<I', inp)
|
||||
|
||||
def module_data_u64(inp: int) -> bytes:
|
||||
"""
|
||||
@ -479,6 +506,30 @@ def module_data_u64(inp: int) -> bytes:
|
||||
"""
|
||||
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:
|
||||
"""
|
||||
Compile: module data
|
||||
@ -505,6 +556,22 @@ def module_data(inp: ourlang.ModuleData) -> bytes:
|
||||
data_list.append(module_data_u64(constant.value))
|
||||
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)
|
||||
|
||||
block_data = b''.join(data_list)
|
||||
@ -579,7 +646,7 @@ def _generate_tuple_constructor(wgn: WasmGenerator, inp: ourlang.TupleConstructo
|
||||
wgn.local.get(tmp_var)
|
||||
|
||||
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
|
||||
wgn.i32.const(inp.struct.alloc_size())
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
"""
|
||||
Contains the syntax tree for ourlang
|
||||
"""
|
||||
from typing import Dict, List, Tuple, Optional
|
||||
from typing import Dict, List, Tuple, Optional, Union
|
||||
|
||||
import enum
|
||||
|
||||
@ -19,6 +19,7 @@ from .typing import (
|
||||
TypeFloat32, TypeFloat64,
|
||||
TypeBytes,
|
||||
TypeTuple, TypeTupleMember,
|
||||
TypeStaticArray, TypeStaticArrayMember,
|
||||
TypeStruct, TypeStructMember,
|
||||
)
|
||||
|
||||
@ -135,6 +136,18 @@ class ConstantTuple(Constant):
|
||||
super().__init__(type_)
|
||||
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):
|
||||
"""
|
||||
An variable reference expression within a statement
|
||||
@ -239,6 +252,23 @@ class AccessTupleMember(Expression):
|
||||
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__(static_array.member_type)
|
||||
|
||||
self.varref = varref
|
||||
self.static_array = static_array
|
||||
self.member = member
|
||||
|
||||
class Fold(Expression):
|
||||
"""
|
||||
A (left or right) fold
|
||||
|
||||
170
phasm/parser.py
170
phasm/parser.py
@ -19,6 +19,8 @@ from .typing import (
|
||||
TypeStructMember,
|
||||
TypeTuple,
|
||||
TypeTupleMember,
|
||||
TypeStaticArray,
|
||||
TypeStaticArrayMember,
|
||||
)
|
||||
|
||||
from . import codestyle
|
||||
@ -30,12 +32,12 @@ from .ourlang import (
|
||||
Function,
|
||||
|
||||
Expression,
|
||||
AccessBytesIndex, AccessStructMember, AccessTupleMember,
|
||||
AccessBytesIndex, AccessStructMember, AccessTupleMember, AccessStaticArrayMember,
|
||||
BinaryOp,
|
||||
Constant,
|
||||
ConstantFloat32, ConstantFloat64, ConstantInt32, ConstantInt64,
|
||||
ConstantUInt8, ConstantUInt32, ConstantUInt64,
|
||||
ConstantTuple,
|
||||
ConstantTuple, ConstantStaticArray,
|
||||
|
||||
FunctionCall,
|
||||
StructConstructor, TupleConstructor,
|
||||
@ -249,6 +251,34 @@ class OurVisitor:
|
||||
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')
|
||||
|
||||
def visit_Module_stmt(self, module: Module, node: ast.stmt) -> None:
|
||||
@ -416,22 +446,22 @@ class OurVisitor:
|
||||
if not isinstance(node.ctx, ast.Load):
|
||||
_raise_static_error(node, 'Must be load context')
|
||||
|
||||
if not isinstance(exp_type, TypeTuple):
|
||||
_raise_static_error(node, f'Expression is expecting a {codestyle.type_(exp_type)}, not a tuple')
|
||||
if isinstance(exp_type, TypeTuple):
|
||||
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):
|
||||
_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)
|
||||
|
||||
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)
|
||||
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_static_error(node, f'Expression is expecting a {codestyle.type_(exp_type)}, not a tuple')
|
||||
|
||||
raise NotImplementedError(f'{node} as expr in FunctionDef')
|
||||
|
||||
@ -582,24 +612,37 @@ class OurVisitor:
|
||||
if not isinstance(node.ctx, ast.Load):
|
||||
_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}')
|
||||
|
||||
node_typ = our_locals[node.value.id]
|
||||
|
||||
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):
|
||||
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(
|
||||
module.types['u8'],
|
||||
VariableReference(node_typ, node.value.id),
|
||||
t_u8,
|
||||
varref,
|
||||
slice_expr,
|
||||
)
|
||||
|
||||
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')
|
||||
|
||||
idx = slice_expr.value
|
||||
@ -607,13 +650,40 @@ class OurVisitor:
|
||||
if len(node_typ.members) <= idx:
|
||||
_raise_static_error(node, f'Index {idx} out of bounds for tuple {node.value.id}')
|
||||
|
||||
member = node_typ.members[idx]
|
||||
if exp_type != member.type:
|
||||
_raise_static_error(node, f'Expected {codestyle.type_(exp_type)}, {node.value.id}[{idx}] is actually {codestyle.type_(member.type)}')
|
||||
tuple_member = node_typ.members[idx]
|
||||
if exp_type != tuple_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(
|
||||
VariableReference(node_typ, node.value.id),
|
||||
member,
|
||||
varref,
|
||||
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}')
|
||||
@ -705,25 +775,59 @@ class OurVisitor:
|
||||
|
||||
_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 not isinstance(node.ctx, ast.Load):
|
||||
_raise_static_error(node, 'Must be load context')
|
||||
|
||||
result = TypeTuple()
|
||||
type_tuple = TypeTuple()
|
||||
|
||||
offset = 0
|
||||
|
||||
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)
|
||||
offset += member.type.alloc_size()
|
||||
type_tuple.members.append(tuple_member)
|
||||
offset += tuple_member.type.alloc_size()
|
||||
|
||||
key = result.render_internal_name()
|
||||
key = type_tuple.render_internal_name()
|
||||
|
||||
if key not in module.types:
|
||||
module.types[key] = result
|
||||
constructor = TupleConstructor(result)
|
||||
module.types[key] = type_tuple
|
||||
constructor = TupleConstructor(type_tuple)
|
||||
module.functions[constructor.name] = constructor
|
||||
|
||||
return module.types[key]
|
||||
|
||||
@ -137,6 +137,30 @@ class TypeTuple(TypeBase):
|
||||
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:
|
||||
"""
|
||||
Represents a struct member
|
||||
|
||||
@ -30,6 +30,8 @@ class Generator_i32i64:
|
||||
# 2.4.1. Numeric Instructions
|
||||
# ibinop
|
||||
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
|
||||
self.eq = functools.partial(self.generator.add_statement, f'{prefix}.eq')
|
||||
|
||||
5
pylintrc
5
pylintrc
@ -1,5 +1,10 @@
|
||||
[MASTER]
|
||||
disable=C0122,R0903,R0911,R0912,R0913,R0915,R1710,W0223
|
||||
|
||||
max-line-length=180
|
||||
|
||||
[stdlib]
|
||||
good-names=g
|
||||
|
||||
[tests]
|
||||
disable=C0116,
|
||||
|
||||
@ -50,3 +50,38 @@ def helper(vector: (u8, u8, u32, u32, u64, u64, )) -> u32:
|
||||
result = Suite(code_py).run_code()
|
||||
|
||||
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
|
||||
|
||||
@ -13,3 +13,19 @@ def testEntry(f: bytes) -> u8:
|
||||
result = Suite(code_py).run_code(b'Short', b'Long' * 100)
|
||||
|
||||
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
|
||||
|
||||
@ -427,7 +427,7 @@ def helper(shape1: Rectangle, shape2: Rectangle) -> i32:
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@pytest.mark.parametrize('type_', COMPLETE_SIMPLE_TYPES)
|
||||
def test_tuple_simple(type_):
|
||||
def test_tuple_simple_constructor(type_):
|
||||
code_py = f"""
|
||||
@exported
|
||||
def testEntry() -> {type_}:
|
||||
@ -457,6 +457,44 @@ def helper(v: (f32, f32, f32, )) -> f32:
|
||||
|
||||
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
|
||||
def test_bytes_address():
|
||||
code_py = """
|
||||
|
||||
@ -60,7 +60,7 @@ def test_tuple_constant_too_few_values():
|
||||
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)
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@ -69,7 +69,7 @@ def test_tuple_constant_too_many_values():
|
||||
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)
|
||||
|
||||
@pytest.mark.integration_test
|
||||
@ -78,5 +78,32 @@ def test_tuple_constant_type_mismatch():
|
||||
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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user