MVP #1
@ -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
|
||||
|
||||
152
phasm/parser.py
152
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,9 +446,7 @@ 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')
|
||||
|
||||
@ -433,6 +461,8 @@ class OurVisitor:
|
||||
]
|
||||
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')
|
||||
|
||||
def visit_Module_FunctionDef_Call(self, module: Module, function: Function, our_locals: OurLocals, exp_type: TypeBase, node: ast.Call) -> Union[Fold, FunctionCall, UnaryOp]:
|
||||
@ -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