Compare commits
14 Commits
97b61e3ee1
...
167560d7dd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
167560d7dd | ||
|
|
4236340ff6 | ||
|
|
4a4c62c728 | ||
|
|
fcbd32a880 | ||
|
|
bd80210ba3 | ||
|
|
a73a3b2bb4 | ||
|
|
8fa2e4830e | ||
|
|
ddc0bbdf30 | ||
|
|
0131b84146 | ||
|
|
f4f068137a | ||
|
|
769eaaf243 | ||
|
|
dff5feed86 | ||
|
|
ff0286bcf6 | ||
|
|
ef00b3a91c |
2
Makefile
2
Makefile
@ -28,7 +28,7 @@ test: venv/.done $(subst .json,.py,$(subst /generator_,/test_generated_,$(wildca
|
|||||||
venv/bin/pytest tests $(TEST_FLAGS)
|
venv/bin/pytest tests $(TEST_FLAGS)
|
||||||
|
|
||||||
lint: venv/.done
|
lint: venv/.done
|
||||||
venv/bin/ruff check phasm tests
|
venv/bin/ruff check phasm tests/integration/helpers.py tests/integration/runners.py
|
||||||
|
|
||||||
typecheck: venv/.done
|
typecheck: venv/.done
|
||||||
venv/bin/mypy --strict phasm tests/integration/helpers.py tests/integration/runners.py
|
venv/bin/mypy --strict phasm tests/integration/helpers.py tests/integration/runners.py
|
||||||
|
|||||||
@ -4,10 +4,9 @@ Functions for using this module from CLI
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from .compiler import phasm_compile
|
|
||||||
from .parser import phasm_parse
|
from .parser import phasm_parse
|
||||||
from .type3.entry import phasm_type3
|
from .type3.entry import phasm_type3
|
||||||
|
from .compiler import phasm_compile
|
||||||
|
|
||||||
def main(source: str, sink: str) -> int:
|
def main(source: str, sink: str) -> int:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -9,7 +9,6 @@ from . import ourlang
|
|||||||
from .type3 import types as type3types
|
from .type3 import types as type3types
|
||||||
from .type3.types import TYPE3_ASSERTION_ERROR, Type3, Type3OrPlaceholder
|
from .type3.types import TYPE3_ASSERTION_ERROR, Type3, Type3OrPlaceholder
|
||||||
|
|
||||||
|
|
||||||
def phasm_render(inp: ourlang.Module) -> str:
|
def phasm_render(inp: ourlang.Module) -> str:
|
||||||
"""
|
"""
|
||||||
Public method for rendering a Phasm module into Phasm code
|
Public method for rendering a Phasm module into Phasm code
|
||||||
|
|||||||
@ -1,14 +1,18 @@
|
|||||||
"""
|
"""
|
||||||
This module contains the code to convert parsed Ourlang into WebAssembly code
|
This module contains the code to convert parsed Ourlang into WebAssembly code
|
||||||
"""
|
"""
|
||||||
import struct
|
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from . import codestyle, ourlang, wasm
|
import struct
|
||||||
from .runtime import calculate_alloc_size, calculate_member_offset
|
|
||||||
|
from . import codestyle
|
||||||
|
from . import ourlang
|
||||||
|
from .type3 import types as type3types
|
||||||
|
from . import wasm
|
||||||
|
|
||||||
from .stdlib import alloc as stdlib_alloc
|
from .stdlib import alloc as stdlib_alloc
|
||||||
from .stdlib import types as stdlib_types
|
from .stdlib import types as stdlib_types
|
||||||
from .type3 import types as type3types
|
from .runtime import calculate_alloc_size, calculate_member_offset
|
||||||
from .wasmgenerator import Generator as WasmGenerator
|
from .wasmgenerator import Generator as WasmGenerator
|
||||||
|
|
||||||
LOAD_STORE_TYPE_MAP = {
|
LOAD_STORE_TYPE_MAP = {
|
||||||
|
|||||||
@ -1,16 +1,12 @@
|
|||||||
"""
|
"""
|
||||||
Contains the syntax tree for ourlang
|
Contains the syntax tree for ourlang
|
||||||
"""
|
"""
|
||||||
import enum
|
|
||||||
from typing import Dict, Iterable, List, Optional, Union
|
from typing import Dict, Iterable, List, Optional, Union
|
||||||
|
|
||||||
from typing_extensions import Final
|
import enum
|
||||||
|
|
||||||
from .type3 import types as type3types
|
from .type3 import types as type3types
|
||||||
from .type3.types import PlaceholderForType, StructType3, Type3, Type3OrPlaceholder
|
from .type3.types import Type3, Type3OrPlaceholder, PlaceholderForType, StructType3
|
||||||
|
|
||||||
WEBASSEMBLY_BUILTIN_FLOAT_OPS: Final = ('abs', 'sqrt', 'ceil', 'floor', 'trunc', 'nearest', )
|
|
||||||
WEBASSEMBLY_BUILTIN_BYTES_OPS: Final = ('len', )
|
|
||||||
|
|
||||||
class Expression:
|
class Expression:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -1,39 +1,37 @@
|
|||||||
"""
|
"""
|
||||||
Parses the source code from the plain text into a syntax tree
|
Parses the source code from the plain text into a syntax tree
|
||||||
"""
|
"""
|
||||||
import ast
|
|
||||||
from typing import Any, Dict, NoReturn, Union
|
from typing import Any, Dict, NoReturn, Union
|
||||||
|
|
||||||
|
import ast
|
||||||
|
|
||||||
|
from .type3 import types as type3types
|
||||||
|
|
||||||
from .exceptions import StaticError
|
from .exceptions import StaticError
|
||||||
from .ourlang import (
|
from .ourlang import (
|
||||||
WEBASSEMBLY_BUILTIN_FLOAT_OPS,
|
WEBASSEMBLY_BUILTIN_FLOAT_OPS,
|
||||||
AccessStructMember,
|
|
||||||
BinaryOp,
|
|
||||||
ConstantBytes,
|
|
||||||
ConstantPrimitive,
|
|
||||||
ConstantStruct,
|
|
||||||
ConstantTuple,
|
|
||||||
Expression,
|
|
||||||
Fold,
|
|
||||||
Function,
|
|
||||||
FunctionCall,
|
|
||||||
FunctionParam,
|
|
||||||
Module,
|
|
||||||
ModuleConstantDef,
|
|
||||||
ModuleDataBlock,
|
|
||||||
Statement,
|
|
||||||
StatementIf,
|
|
||||||
StatementPass,
|
|
||||||
StatementReturn,
|
|
||||||
StructConstructor,
|
|
||||||
StructDefinition,
|
|
||||||
Subscript,
|
|
||||||
TupleInstantiation,
|
|
||||||
UnaryOp,
|
|
||||||
VariableReference,
|
|
||||||
)
|
|
||||||
from .type3 import types as type3types
|
|
||||||
|
|
||||||
|
Module, ModuleDataBlock,
|
||||||
|
Function,
|
||||||
|
|
||||||
|
Expression,
|
||||||
|
BinaryOp,
|
||||||
|
ConstantPrimitive,
|
||||||
|
ConstantBytes, ConstantTuple, ConstantStruct,
|
||||||
|
TupleInstantiation,
|
||||||
|
|
||||||
|
FunctionCall, AccessStructMember, Subscript,
|
||||||
|
StructDefinition, StructConstructor,
|
||||||
|
UnaryOp, VariableReference,
|
||||||
|
|
||||||
|
Fold,
|
||||||
|
|
||||||
|
Statement,
|
||||||
|
StatementIf, StatementPass, StatementReturn,
|
||||||
|
|
||||||
|
FunctionParam,
|
||||||
|
ModuleConstantDef,
|
||||||
|
)
|
||||||
|
|
||||||
def phasm_parse(source: str) -> Module:
|
def phasm_parse(source: str) -> Module:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
from .type3 import types as type3types
|
from .type3 import types as type3types
|
||||||
|
|
||||||
|
|
||||||
def calculate_alloc_size(typ: type3types.Type3, is_member: bool = False) -> int:
|
def calculate_alloc_size(typ: type3types.Type3, is_member: bool = False) -> int:
|
||||||
if typ in (type3types.u8, type3types.i8, ):
|
if typ in (type3types.u8, type3types.i8, ):
|
||||||
return 4 # FIXME: We allocate 4 bytes for every u8 since you load them into an i32
|
return 4 # FIXME: We allocate 4 bytes for every u8 since you load them into an i32
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
stdlib: Memory allocation
|
stdlib: Memory allocation
|
||||||
"""
|
"""
|
||||||
from phasm.wasmgenerator import Generator, func_wrapper
|
from phasm.wasmgenerator import Generator, VarType_i32 as i32, func_wrapper
|
||||||
from phasm.wasmgenerator import VarType_i32 as i32
|
|
||||||
|
|
||||||
IDENTIFIER = 0xA1C0
|
IDENTIFIER = 0xA1C0
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
"""
|
"""
|
||||||
stdlib: Standard types that are not wasm primitives
|
stdlib: Standard types that are not wasm primitives
|
||||||
"""
|
"""
|
||||||
from phasm.stdlib import alloc
|
from phasm.wasmgenerator import Generator, VarType_i32 as i32, func_wrapper
|
||||||
from phasm.wasmgenerator import Generator, func_wrapper
|
|
||||||
from phasm.wasmgenerator import VarType_i32 as i32
|
|
||||||
|
|
||||||
|
from phasm.stdlib import alloc
|
||||||
|
|
||||||
@func_wrapper()
|
@func_wrapper()
|
||||||
def __alloc_bytes__(g: Generator, length: i32) -> i32:
|
def __alloc_bytes__(g: Generator, length: i32) -> i32:
|
||||||
|
|||||||
@ -3,11 +3,11 @@ This module contains possible constraints generated based on the AST
|
|||||||
|
|
||||||
These need to be resolved before the program can be compiled.
|
These need to be resolved before the program can be compiled.
|
||||||
"""
|
"""
|
||||||
from typing import Dict, List, Optional, Tuple, Union
|
from typing import Dict, Optional, List, Tuple, Union
|
||||||
|
|
||||||
from .. import ourlang
|
from .. import ourlang
|
||||||
from . import types
|
|
||||||
|
|
||||||
|
from . import types
|
||||||
|
|
||||||
class Error:
|
class Error:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -6,17 +6,17 @@ The constraints solver can then try to resolve all constraints.
|
|||||||
from typing import Generator, List
|
from typing import Generator, List
|
||||||
|
|
||||||
from .. import ourlang
|
from .. import ourlang
|
||||||
from . import types as type3types
|
|
||||||
from .constraints import (
|
from .constraints import (
|
||||||
CanBeSubscriptedConstraint,
|
|
||||||
CastableConstraint,
|
|
||||||
ConstraintBase,
|
|
||||||
Context,
|
Context,
|
||||||
LiteralFitsConstraint,
|
|
||||||
MustImplementTypeClassConstraint,
|
ConstraintBase,
|
||||||
SameTypeConstraint,
|
CastableConstraint, CanBeSubscriptedConstraint,
|
||||||
|
LiteralFitsConstraint, MustImplementTypeClassConstraint, SameTypeConstraint,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from . import types as type3types
|
||||||
|
|
||||||
ConstraintGenerator = Generator[ConstraintBase, None, None]
|
ConstraintGenerator = Generator[ConstraintBase, None, None]
|
||||||
|
|
||||||
def phasm_type3_generate_constraints(inp: ourlang.Module) -> List[ConstraintBase]:
|
def phasm_type3_generate_constraints(inp: ourlang.Module) -> List[ConstraintBase]:
|
||||||
|
|||||||
@ -3,24 +3,12 @@ Entry point to the type3 system
|
|||||||
"""
|
"""
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
|
|
||||||
from .. import codestyle, ourlang
|
from .. import codestyle
|
||||||
from .constraints import (
|
from .. import ourlang
|
||||||
ConstraintBase,
|
|
||||||
Error,
|
from .constraints import ConstraintBase, Error, RequireTypeSubstitutes, SameTypeConstraint, SubstitutionMap
|
||||||
RequireTypeSubstitutes,
|
|
||||||
SameTypeConstraint,
|
|
||||||
SubstitutionMap,
|
|
||||||
)
|
|
||||||
from .constraintsgenerator import phasm_type3_generate_constraints
|
from .constraintsgenerator import phasm_type3_generate_constraints
|
||||||
from .types import (
|
from .types import AppliedType3, IntType3, PlaceholderForType, PrimitiveType3, StructType3, Type3, Type3OrPlaceholder
|
||||||
AppliedType3,
|
|
||||||
IntType3,
|
|
||||||
PlaceholderForType,
|
|
||||||
PrimitiveType3,
|
|
||||||
StructType3,
|
|
||||||
Type3,
|
|
||||||
Type3OrPlaceholder,
|
|
||||||
)
|
|
||||||
|
|
||||||
MAX_RESTACK_COUNT = 100
|
MAX_RESTACK_COUNT = 100
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,6 @@ and being able to conver it to Web Assembly Text Format
|
|||||||
|
|
||||||
from typing import Iterable, List, Optional, Tuple
|
from typing import Iterable, List, Optional, Tuple
|
||||||
|
|
||||||
|
|
||||||
class WatSerializable:
|
class WatSerializable:
|
||||||
"""
|
"""
|
||||||
Mixin for clases that can be serialized as WebAssembly Text
|
Mixin for clases that can be serialized as WebAssembly Text
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
"""
|
"""
|
||||||
Helper functions to generate WASM code by writing Python functions
|
Helper functions to generate WASM code by writing Python functions
|
||||||
"""
|
"""
|
||||||
import functools
|
|
||||||
from typing import Any, Callable, Dict, List, Optional, Type
|
from typing import Any, Callable, Dict, List, Optional, Type
|
||||||
|
|
||||||
|
import functools
|
||||||
|
|
||||||
from . import wasm
|
from . import wasm
|
||||||
|
|
||||||
# pylint: disable=C0103,C0115,C0116,R0902
|
# pylint: disable=C0103,C0115,C0116,R0902
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
[tool.ruff.lint]
|
|
||||||
select = ["F", "E", "W", "I"]
|
|
||||||
ignore = ["E501"]
|
|
||||||
16
tests/integration/constants.py
Normal file
16
tests/integration/constants.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
Constants for use in the tests
|
||||||
|
"""
|
||||||
|
|
||||||
|
ALL_INT_TYPES = ['u8', 'u32', 'u64', 'i32', 'i64']
|
||||||
|
COMPLETE_INT_TYPES = ['u32', 'u64', 'i32', 'i64']
|
||||||
|
|
||||||
|
ALL_FLOAT_TYPES = ['f32', 'f64']
|
||||||
|
COMPLETE_FLOAT_TYPES = ALL_FLOAT_TYPES
|
||||||
|
|
||||||
|
TYPE_MAP = {
|
||||||
|
**{x: int for x in ALL_INT_TYPES},
|
||||||
|
**{x: float for x in ALL_FLOAT_TYPES},
|
||||||
|
}
|
||||||
|
|
||||||
|
COMPLETE_NUMERIC_TYPES = COMPLETE_INT_TYPES + COMPLETE_FLOAT_TYPES
|
||||||
@ -1,11 +1,12 @@
|
|||||||
|
from typing import Any, Generator, Iterable, List, TextIO, Union
|
||||||
|
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
from typing import Any, Generator, Iterable, List, TextIO, Union
|
|
||||||
|
|
||||||
from phasm import compiler
|
from phasm import compiler
|
||||||
from phasm.codestyle import phasm_render
|
from phasm.codestyle import phasm_render
|
||||||
from phasm.runtime import calculate_alloc_size
|
|
||||||
from phasm.type3 import types as type3types
|
from phasm.type3 import types as type3types
|
||||||
|
from phasm.runtime import calculate_alloc_size
|
||||||
|
|
||||||
from . import runners
|
from . import runners
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,21 @@
|
|||||||
"""
|
"""
|
||||||
Runners to help run WebAssembly code on various interpreters
|
Runners to help run WebAssembly code on various interpreters
|
||||||
"""
|
"""
|
||||||
|
from typing import Any, Callable, Dict, Iterable, Optional, TextIO
|
||||||
|
|
||||||
import ctypes
|
import ctypes
|
||||||
import io
|
import io
|
||||||
from typing import Any, Callable, Dict, Iterable, Optional, TextIO
|
|
||||||
|
|
||||||
import pywasm.binary
|
import pywasm.binary
|
||||||
import wasm3
|
import wasm3
|
||||||
import wasmer
|
import wasmer
|
||||||
import wasmtime
|
import wasmtime
|
||||||
|
|
||||||
from phasm import ourlang, wasm
|
|
||||||
from phasm.compiler import phasm_compile
|
from phasm.compiler import phasm_compile
|
||||||
from phasm.parser import phasm_parse
|
from phasm.parser import phasm_parse
|
||||||
from phasm.type3.entry import phasm_type3
|
from phasm.type3.entry import phasm_type3
|
||||||
|
from phasm import ourlang
|
||||||
|
from phasm import wasm
|
||||||
|
|
||||||
Imports = Optional[Dict[str, Callable[[Any], Any]]]
|
Imports = Optional[Dict[str, Callable[[Any], Any]]]
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import pytest
|
|||||||
|
|
||||||
from ..helpers import Suite
|
from ..helpers import Suite
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.slow_integration_test
|
@pytest.mark.slow_integration_test
|
||||||
def test_index():
|
def test_index():
|
||||||
with open('examples/buffer.py', 'r', encoding='ASCII') as fil:
|
with open('examples/buffer.py', 'r', encoding='ASCII') as fil:
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import binascii
|
import binascii
|
||||||
|
import struct
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from ..helpers import Suite
|
from ..helpers import Suite
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.slow_integration_test
|
@pytest.mark.slow_integration_test
|
||||||
def test_crc32():
|
def test_crc32():
|
||||||
# FIXME: Stub
|
# FIXME: Stub
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import pytest
|
|||||||
|
|
||||||
from ..helpers import Suite
|
from ..helpers import Suite
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.slow_integration_test
|
@pytest.mark.slow_integration_test
|
||||||
def test_fib():
|
def test_fib():
|
||||||
with open('./examples/fib.py', 'r', encoding='UTF-8') as fil:
|
with open('./examples/fib.py', 'r', encoding='UTF-8') as fil:
|
||||||
|
|||||||
@ -1,154 +1,156 @@
|
|||||||
|
from typing import Any, Dict
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
import marko
|
import marko
|
||||||
import marko.md_renderer
|
import marko.md_renderer
|
||||||
|
|
||||||
|
|
||||||
def get_tests(template):
|
def get_tests(template):
|
||||||
test_data = None
|
test_data = None
|
||||||
for el in template.children:
|
for el in template.children:
|
||||||
if isinstance(el, marko.block.BlankLine):
|
if isinstance(el, marko.block.BlankLine):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if isinstance(el, marko.block.Heading):
|
if isinstance(el, marko.block.Heading):
|
||||||
if test_data is not None:
|
if test_data is not None:
|
||||||
yield test_data
|
yield test_data
|
||||||
|
|
||||||
test_data = []
|
test_data = []
|
||||||
test_data.append(el)
|
test_data.append(el)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if test_data is not None:
|
if test_data is not None:
|
||||||
test_data.append(el)
|
test_data.append(el)
|
||||||
|
|
||||||
if test_data is not None:
|
if test_data is not None:
|
||||||
yield test_data
|
yield test_data
|
||||||
|
|
||||||
def apply_settings(settings, txt):
|
def apply_settings(settings, txt):
|
||||||
for k, v in settings.items():
|
for k, v in settings.items():
|
||||||
if k in ('CODE_HEADER', 'PYTHON'):
|
if k in ('CODE_HEADER', 'PYTHON'):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
txt = txt.replace(f'${k}', v)
|
txt = txt.replace(f'${k}', v)
|
||||||
return txt
|
return txt
|
||||||
|
|
||||||
def generate_assertion_expect(result, arg, given=None):
|
def generate_assertion_expect(result, arg, given=None):
|
||||||
given = given or []
|
given = given or []
|
||||||
|
|
||||||
result.append('result = Suite(code_py).run_code(' + ', '.join(repr(x) for x in given) + ')')
|
result.append('result = Suite(code_py).run_code(' + ', '.join(repr(x) for x in given) + ')')
|
||||||
result.append(f'assert {repr(arg)} == result.returned_value')
|
result.append(f'assert {repr(arg)} == result.returned_value')
|
||||||
|
|
||||||
def generate_assertion_expect_type_error(result, error_msg, error_comment = None):
|
def generate_assertion_expect_type_error(result, error_msg, error_comment = None):
|
||||||
result.append('with pytest.raises(Type3Exception) as exc_info:')
|
result.append('with pytest.raises(Type3Exception) as exc_info:')
|
||||||
result.append(' Suite(code_py).run_code()')
|
result.append(' Suite(code_py).run_code()')
|
||||||
result.append(f'assert {repr(error_msg)} == exc_info.value.args[0][0].msg')
|
result.append(f'assert {repr(error_msg)} == exc_info.value.args[0][0].msg')
|
||||||
result.append(f'assert {repr(error_comment)} == exc_info.value.args[0][0].comment')
|
result.append(f'assert {repr(error_comment)} == exc_info.value.args[0][0].comment')
|
||||||
|
|
||||||
def json_does_not_support_byte_or_tuple_values_fix(inp: Any):
|
def json_does_not_support_byte_or_tuple_values_fix(inp: Any):
|
||||||
if isinstance(inp, (int, float, )):
|
if isinstance(inp, (int, float, )):
|
||||||
return inp
|
return inp
|
||||||
|
|
||||||
if isinstance(inp, str):
|
if isinstance(inp, str):
|
||||||
if inp.startswith('bytes:'):
|
if inp.startswith('bytes:'):
|
||||||
return inp[6:].encode()
|
return inp[6:].encode()
|
||||||
return inp
|
return inp
|
||||||
|
|
||||||
if isinstance(inp, list):
|
if isinstance(inp, list):
|
||||||
return tuple(map(json_does_not_support_byte_or_tuple_values_fix, inp))
|
return tuple(map(json_does_not_support_byte_or_tuple_values_fix, inp))
|
||||||
|
|
||||||
if isinstance(inp, dict):
|
if isinstance(inp, dict):
|
||||||
return {
|
key_names = list(inp)
|
||||||
key: json_does_not_support_byte_or_tuple_values_fix(val)
|
return {
|
||||||
for key, val in inp.items()
|
key: json_does_not_support_byte_or_tuple_values_fix(val)
|
||||||
}
|
for key, val in inp.items()
|
||||||
|
}
|
||||||
|
|
||||||
raise NotImplementedError(inp)
|
raise NotImplementedError(inp)
|
||||||
|
|
||||||
def generate_assertions(settings, result_code):
|
def generate_assertions(settings, result_code):
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
locals_ = {
|
locals_ = {
|
||||||
'TYPE': settings['TYPE'],
|
'TYPE': settings['TYPE'],
|
||||||
'TYPE_NAME': settings['TYPE_NAME'],
|
'TYPE_NAME': settings['TYPE_NAME'],
|
||||||
'expect': functools.partial(generate_assertion_expect, result),
|
'expect': functools.partial(generate_assertion_expect, result),
|
||||||
'expect_type_error': functools.partial(generate_assertion_expect_type_error, result),
|
'expect_type_error': functools.partial(generate_assertion_expect_type_error, result),
|
||||||
}
|
}
|
||||||
|
|
||||||
if 'PYTHON' in settings:
|
if 'PYTHON' in settings:
|
||||||
locals_.update(json_does_not_support_byte_or_tuple_values_fix(settings['PYTHON']))
|
locals_.update(json_does_not_support_byte_or_tuple_values_fix(settings['PYTHON']))
|
||||||
|
|
||||||
if 'VAL0' not in locals_:
|
if 'VAL0' not in locals_:
|
||||||
locals_['VAL0'] = eval(settings['VAL0'])
|
locals_['VAL0'] = eval(settings['VAL0'])
|
||||||
|
|
||||||
exec(result_code, {}, locals_)
|
exec(result_code, {}, locals_)
|
||||||
|
|
||||||
return ' ' + '\n '.join(result) + '\n'
|
return ' ' + '\n '.join(result) + '\n'
|
||||||
|
|
||||||
def generate_code(markdown, template, settings):
|
def generate_code(markdown, template, settings):
|
||||||
type_name = settings['TYPE_NAME']
|
type_name = settings['TYPE_NAME']
|
||||||
|
|
||||||
print('"""')
|
print('"""')
|
||||||
print('AUTO GENERATED')
|
print('AUTO GENERATED')
|
||||||
print()
|
print()
|
||||||
print('TEMPLATE:', sys.argv[1])
|
print('TEMPLATE:', sys.argv[1])
|
||||||
print('SETTINGS:', sys.argv[2])
|
print('SETTINGS:', sys.argv[2])
|
||||||
print('"""')
|
print('"""')
|
||||||
print('import pytest')
|
print('import pytest')
|
||||||
print()
|
print()
|
||||||
print('from phasm.type3.entry import Type3Exception')
|
print('from phasm.type3.entry import Type3Exception')
|
||||||
print()
|
print()
|
||||||
print('from ..helpers import Suite')
|
print('from ..helpers import Suite')
|
||||||
print()
|
print()
|
||||||
|
|
||||||
for test in get_tests(template):
|
for test in get_tests(template):
|
||||||
assert len(test) == 4, test
|
assert len(test) == 4, test
|
||||||
heading, paragraph, code_block1, code_block2 = test
|
heading, paragraph, code_block1, code_block2 = test
|
||||||
|
|
||||||
assert isinstance(heading, marko.block.Heading)
|
assert isinstance(heading, marko.block.Heading)
|
||||||
assert isinstance(paragraph, marko.block.Paragraph)
|
assert isinstance(paragraph, marko.block.Paragraph)
|
||||||
assert isinstance(code_block1, marko.block.FencedCode)
|
assert isinstance(code_block1, marko.block.FencedCode)
|
||||||
assert isinstance(code_block2, marko.block.FencedCode)
|
assert isinstance(code_block2, marko.block.FencedCode)
|
||||||
|
|
||||||
test_id = apply_settings(settings, heading.children[0].children)
|
test_id = apply_settings(settings, heading.children[0].children)
|
||||||
user_story = apply_settings(settings, markdown.renderer.render(paragraph))
|
user_story = apply_settings(settings, markdown.renderer.render(paragraph))
|
||||||
inp_code = apply_settings(settings, code_block1.children[0].children)
|
inp_code = apply_settings(settings, code_block1.children[0].children)
|
||||||
|
|
||||||
result_code = markdown.renderer.render_children(code_block2)
|
result_code = markdown.renderer.render_children(code_block2)
|
||||||
|
|
||||||
print('@pytest.mark.integration_test')
|
print('@pytest.mark.integration_test')
|
||||||
print(f'def test_{type_name}_{test_id}():')
|
print(f'def test_{type_name}_{test_id}():')
|
||||||
print(' """')
|
print(' """')
|
||||||
print(' ' + user_story.replace('\n', '\n '))
|
print(' ' + user_story.replace('\n', '\n '))
|
||||||
print(' """')
|
print(' """')
|
||||||
print(' code_py = """')
|
print(' code_py = """')
|
||||||
if 'CODE_HEADER' in settings:
|
if 'CODE_HEADER' in settings:
|
||||||
for lin in settings['CODE_HEADER']:
|
for lin in settings['CODE_HEADER']:
|
||||||
print(lin)
|
print(lin)
|
||||||
print()
|
print()
|
||||||
print(inp_code.rstrip('\n'))
|
print(inp_code.rstrip('\n'))
|
||||||
print('"""')
|
print('"""')
|
||||||
print()
|
print()
|
||||||
|
|
||||||
print(generate_assertions(settings, result_code))
|
print(generate_assertions(settings, result_code))
|
||||||
print()
|
print()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
markdown = marko.Markdown(
|
markdown = marko.Markdown(
|
||||||
renderer=marko.md_renderer.MarkdownRenderer,
|
renderer=marko.md_renderer.MarkdownRenderer,
|
||||||
)
|
)
|
||||||
with open(sys.argv[1], 'r', encoding='utf-8') as fil:
|
with open(sys.argv[1], 'r', encoding='utf-8') as fil:
|
||||||
template = markdown.parse(fil.read())
|
template = markdown.parse(fil.read())
|
||||||
|
|
||||||
with open(sys.argv[2], 'r', encoding='utf-8') as fil:
|
with open(sys.argv[2], 'r', encoding='utf-8') as fil:
|
||||||
settings = json.load(fil)
|
settings = json.load(fil)
|
||||||
|
|
||||||
if 'TYPE_NAME' not in settings:
|
if 'TYPE_NAME' not in settings:
|
||||||
settings['TYPE_NAME'] = settings['TYPE']
|
settings['TYPE_NAME'] = settings['TYPE']
|
||||||
|
|
||||||
generate_code(markdown, template, settings)
|
generate_code(markdown, template, settings)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
@ -3,7 +3,7 @@ import pytest
|
|||||||
from phasm.type3.entry import Type3Exception
|
from phasm.type3.entry import Type3Exception
|
||||||
|
|
||||||
from ..helpers import Suite
|
from ..helpers import Suite
|
||||||
|
from ..constants import ALL_INT_TYPES, ALL_FLOAT_TYPES, COMPLETE_INT_TYPES, TYPE_MAP
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
@pytest.mark.parametrize('type_', ['u32', 'u64']) # FIXME: Support u8, requires an extra AND operation
|
@pytest.mark.parametrize('type_', ['u32', 'u64']) # FIXME: Support u8, requires an extra AND operation
|
||||||
@ -17,7 +17,7 @@ def testEntry() -> {type_}:
|
|||||||
result = Suite(code_py).run_code()
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
assert 80 == result.returned_value
|
assert 80 == result.returned_value
|
||||||
assert isinstance(result.returned_value, int)
|
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
@pytest.mark.parametrize('type_', ['u32', 'u64'])
|
@pytest.mark.parametrize('type_', ['u32', 'u64'])
|
||||||
@ -33,7 +33,7 @@ def testEntry() -> {type_}:
|
|||||||
result = Suite(code_py).run_code(runtime='wasmtime')
|
result = Suite(code_py).run_code(runtime='wasmtime')
|
||||||
|
|
||||||
assert 1 == result.returned_value
|
assert 1 == result.returned_value
|
||||||
assert isinstance(result.returned_value, int)
|
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
def test_logical_right_shift_left_bit_one():
|
def test_logical_right_shift_left_bit_one():
|
||||||
@ -59,7 +59,7 @@ def testEntry() -> {type_}:
|
|||||||
result = Suite(code_py).run_code()
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
assert 11 == result.returned_value
|
assert 11 == result.returned_value
|
||||||
assert isinstance(result.returned_value, int)
|
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
def test_bitwise_or_inv_type():
|
def test_bitwise_or_inv_type():
|
||||||
@ -98,7 +98,7 @@ def testEntry() -> {type_}:
|
|||||||
result = Suite(code_py).run_code()
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
assert 9 == result.returned_value
|
assert 9 == result.returned_value
|
||||||
assert isinstance(result.returned_value, int)
|
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
@pytest.mark.parametrize('type_', ['u8', 'u32', 'u64'])
|
@pytest.mark.parametrize('type_', ['u8', 'u32', 'u64'])
|
||||||
@ -112,4 +112,4 @@ def testEntry() -> {type_}:
|
|||||||
result = Suite(code_py).run_code()
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
assert 2 == result.returned_value
|
assert 2 == result.returned_value
|
||||||
assert isinstance(result.returned_value, int)
|
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import pytest
|
|||||||
from ..helpers import Suite, write_header
|
from ..helpers import Suite, write_header
|
||||||
from ..runners import RunnerPywasm
|
from ..runners import RunnerPywasm
|
||||||
|
|
||||||
|
|
||||||
def setup_interpreter(phash_code: str) -> RunnerPywasm:
|
def setup_interpreter(phash_code: str) -> RunnerPywasm:
|
||||||
runner = RunnerPywasm(phash_code)
|
runner = RunnerPywasm(phash_code)
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,6 @@ from phasm.type3.entry import Type3Exception
|
|||||||
|
|
||||||
from ..helpers import Suite
|
from ..helpers import Suite
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
def test_bytes_length():
|
def test_bytes_length():
|
||||||
code_py = """
|
code_py = """
|
||||||
@ -45,9 +44,9 @@ def testEntry(f: bytes, g: bytes) -> u8:
|
|||||||
def test_bytes_index_invalid_type():
|
def test_bytes_index_invalid_type():
|
||||||
code_py = """
|
code_py = """
|
||||||
@exported
|
@exported
|
||||||
def testEntry(f: bytes) -> u64:
|
def testEntry(f: bytes, g: bytes) -> u64:
|
||||||
return f[50]
|
return f[50]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
with pytest.raises(Type3Exception, match=r'u64 must be u8 instead'):
|
with pytest.raises(Type3Exception, match=r'u64 must be u8 instead'):
|
||||||
Suite(code_py).run_code(b'Short')
|
Suite(code_py).run_code(b'Short', b'Long' * 100)
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import pytest
|
|||||||
|
|
||||||
from ..helpers import Suite
|
from ..helpers import Suite
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
@pytest.mark.parametrize('type_', ['f32', 'f64'])
|
@pytest.mark.parametrize('type_', ['f32', 'f64'])
|
||||||
def test_builtins_sqrt(type_):
|
def test_builtins_sqrt(type_):
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import pytest
|
|||||||
|
|
||||||
from ..helpers import Suite
|
from ..helpers import Suite
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
def test_call_pre_defined():
|
def test_call_pre_defined():
|
||||||
code_py = """
|
code_py = """
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import pytest
|
|||||||
|
|
||||||
from ..helpers import Suite
|
from ..helpers import Suite
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
@pytest.mark.parametrize('inp', [9, 10, 11, 12])
|
@pytest.mark.parametrize('inp', [9, 10, 11, 12])
|
||||||
def test_if_simple(inp):
|
def test_if_simple(inp):
|
||||||
|
|||||||
@ -4,7 +4,6 @@ from phasm.type3.entry import Type3Exception
|
|||||||
|
|
||||||
from ..helpers import Suite
|
from ..helpers import Suite
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
def test_imported_ok():
|
def test_imported_ok():
|
||||||
code_py = """
|
code_py = """
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import pytest
|
|||||||
from phasm.type3.entry import Type3Exception
|
from phasm.type3.entry import Type3Exception
|
||||||
|
|
||||||
from ..helpers import Suite
|
from ..helpers import Suite
|
||||||
|
from ..constants import ALL_INT_TYPES, ALL_FLOAT_TYPES, COMPLETE_INT_TYPES, TYPE_MAP
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
def test_expr_constant_literal_does_not_fit():
|
def test_expr_constant_literal_does_not_fit():
|
||||||
|
|||||||
@ -1,21 +1,12 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from phasm.type3.entry import Type3Exception
|
||||||
|
|
||||||
from ..helpers import Suite
|
from ..helpers import Suite
|
||||||
|
from ..constants import ALL_INT_TYPES, ALL_FLOAT_TYPES, COMPLETE_INT_TYPES, TYPE_MAP
|
||||||
INT_TYPES = ['u32', 'u64', 'i32', 'i64']
|
|
||||||
FLOAT_TYPES = ['f32', 'f64']
|
|
||||||
|
|
||||||
TYPE_MAP = {
|
|
||||||
'u32': int,
|
|
||||||
'u64': int,
|
|
||||||
'i32': int,
|
|
||||||
'i64': int,
|
|
||||||
'f32': float,
|
|
||||||
'f64': float,
|
|
||||||
}
|
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
@pytest.mark.parametrize('type_', INT_TYPES)
|
@pytest.mark.parametrize('type_', COMPLETE_INT_TYPES)
|
||||||
def test_addition_int(type_):
|
def test_addition_int(type_):
|
||||||
code_py = f"""
|
code_py = f"""
|
||||||
@exported
|
@exported
|
||||||
@ -29,7 +20,7 @@ def testEntry() -> {type_}:
|
|||||||
assert TYPE_MAP[type_] == type(result.returned_value)
|
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
@pytest.mark.parametrize('type_', FLOAT_TYPES)
|
@pytest.mark.parametrize('type_', ALL_FLOAT_TYPES)
|
||||||
def test_addition_float(type_):
|
def test_addition_float(type_):
|
||||||
code_py = f"""
|
code_py = f"""
|
||||||
@exported
|
@exported
|
||||||
@ -43,7 +34,7 @@ def testEntry() -> {type_}:
|
|||||||
assert TYPE_MAP[type_] == type(result.returned_value)
|
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
@pytest.mark.parametrize('type_', INT_TYPES)
|
@pytest.mark.parametrize('type_', COMPLETE_INT_TYPES)
|
||||||
def test_subtraction_int(type_):
|
def test_subtraction_int(type_):
|
||||||
code_py = f"""
|
code_py = f"""
|
||||||
@exported
|
@exported
|
||||||
@ -57,7 +48,7 @@ def testEntry() -> {type_}:
|
|||||||
assert TYPE_MAP[type_] == type(result.returned_value)
|
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
@pytest.mark.parametrize('type_', FLOAT_TYPES)
|
@pytest.mark.parametrize('type_', ALL_FLOAT_TYPES)
|
||||||
def test_subtraction_float(type_):
|
def test_subtraction_float(type_):
|
||||||
code_py = f"""
|
code_py = f"""
|
||||||
@exported
|
@exported
|
||||||
@ -87,7 +78,7 @@ def testEntry() -> {type_}:
|
|||||||
# TODO: Multiplication
|
# TODO: Multiplication
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
@pytest.mark.parametrize('type_', INT_TYPES)
|
@pytest.mark.parametrize('type_', COMPLETE_INT_TYPES)
|
||||||
def test_call_with_expression_int(type_):
|
def test_call_with_expression_int(type_):
|
||||||
code_py = f"""
|
code_py = f"""
|
||||||
@exported
|
@exported
|
||||||
@ -104,7 +95,7 @@ def helper(left: {type_}, right: {type_}) -> {type_}:
|
|||||||
assert TYPE_MAP[type_] == type(result.returned_value)
|
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
@pytest.mark.parametrize('type_', FLOAT_TYPES)
|
@pytest.mark.parametrize('type_', ALL_FLOAT_TYPES)
|
||||||
def test_call_with_expression_float(type_):
|
def test_call_with_expression_float(type_):
|
||||||
code_py = f"""
|
code_py = f"""
|
||||||
@exported
|
@exported
|
||||||
|
|||||||
@ -2,31 +2,132 @@ import pytest
|
|||||||
|
|
||||||
from phasm.type3.entry import Type3Exception
|
from phasm.type3.entry import Type3Exception
|
||||||
|
|
||||||
|
from ..constants import (
|
||||||
|
ALL_FLOAT_TYPES, ALL_INT_TYPES, COMPLETE_INT_TYPES, COMPLETE_NUMERIC_TYPES, TYPE_MAP
|
||||||
|
)
|
||||||
from ..helpers import Suite
|
from ..helpers import Suite
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
def test_static_array_index_ok():
|
def test_module_constant_def():
|
||||||
code_py = """
|
code_py = """
|
||||||
|
CONSTANT: u8[3] = (24, 57, 80, )
|
||||||
|
|
||||||
@exported
|
@exported
|
||||||
def testEntry(f: u64[3]) -> u64:
|
def testEntry() -> i32:
|
||||||
return f[2]
|
return 0
|
||||||
"""
|
"""
|
||||||
|
|
||||||
result = Suite(code_py).run_code((1, 2, 3, ))
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
assert 3 == result.returned_value
|
assert 0 == result.returned_value
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
def test_static_array_index_invalid_type():
|
@pytest.mark.parametrize('type_', ALL_INT_TYPES)
|
||||||
code_py = """
|
def test_module_constant_3(type_):
|
||||||
|
code_py = f"""
|
||||||
|
CONSTANT: {type_}[3] = (24, 57, 80, )
|
||||||
|
|
||||||
@exported
|
@exported
|
||||||
def testEntry(f: f32[3]) -> u64:
|
def testEntry() -> {type_}:
|
||||||
return f[0]
|
return CONSTANT[1]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
with pytest.raises(Type3Exception, match=r'u64 must be f32 instead'):
|
result = Suite(code_py).run_code()
|
||||||
Suite(code_py).run_code((0.0, 1.5, 2.25, ))
|
|
||||||
|
assert 57 == result.returned_value
|
||||||
|
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
@pytest.mark.parametrize('type_', COMPLETE_INT_TYPES)
|
||||||
|
def test_function_call_int(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_', ALL_FLOAT_TYPES)
|
||||||
|
def test_function_call_float(type_):
|
||||||
|
code_py = f"""
|
||||||
|
CONSTANT: {type_}[3] = (24.0, 57.5, 80.75, )
|
||||||
|
|
||||||
|
@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 162.25 == result.returned_value
|
||||||
|
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_function_call_element_ok():
|
||||||
|
code_py = """
|
||||||
|
CONSTANT: u64[3] = (250, 250000, 250000000, )
|
||||||
|
|
||||||
|
@exported
|
||||||
|
def testEntry() -> u64:
|
||||||
|
return helper(CONSTANT[0])
|
||||||
|
|
||||||
|
def helper(x: u64) -> u64:
|
||||||
|
return x
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
|
assert 250 == result.returned_value
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_function_call_element_type_mismatch():
|
||||||
|
code_py = """
|
||||||
|
CONSTANT: u64[3] = (250, 250000, 250000000, )
|
||||||
|
|
||||||
|
@exported
|
||||||
|
def testEntry() -> u8:
|
||||||
|
return helper(CONSTANT[0])
|
||||||
|
|
||||||
|
def helper(x: u8) -> u8:
|
||||||
|
return x
|
||||||
|
"""
|
||||||
|
|
||||||
|
with pytest.raises(Type3Exception, match=r'u8 must be u64 instead'):
|
||||||
|
Suite(code_py).run_code()
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_module_constant_type_mismatch_bitwidth():
|
||||||
|
code_py = """
|
||||||
|
CONSTANT: u8[3] = (24, 57, 280, )
|
||||||
|
"""
|
||||||
|
|
||||||
|
with pytest.raises(Type3Exception, match=r'Must fit in 1 byte\(s\)'):
|
||||||
|
Suite(code_py).run_code()
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_return_as_int():
|
||||||
|
code_py = """
|
||||||
|
CONSTANT: u8[3] = (24, 57, 80, )
|
||||||
|
|
||||||
|
def testEntry() -> u32:
|
||||||
|
return CONSTANT
|
||||||
|
"""
|
||||||
|
|
||||||
|
with pytest.raises(Type3Exception, match=r'static_array \(u8\) \(3\) must be u32 instead'):
|
||||||
|
Suite(code_py).run_code()
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
def test_module_constant_type_mismatch_not_subscriptable():
|
def test_module_constant_type_mismatch_not_subscriptable():
|
||||||
|
|||||||
@ -2,20 +2,61 @@ import pytest
|
|||||||
|
|
||||||
from phasm.type3.entry import Type3Exception
|
from phasm.type3.entry import Type3Exception
|
||||||
|
|
||||||
|
from ..constants import (
|
||||||
|
ALL_INT_TYPES, TYPE_MAP
|
||||||
|
)
|
||||||
from ..helpers import Suite
|
from ..helpers import Suite
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
def test_struct_0():
|
def test_module_constant_def():
|
||||||
code_py = """
|
code_py = """
|
||||||
class CheckedValue:
|
class SomeStruct:
|
||||||
value: i32
|
value0: u8
|
||||||
|
value1: u32
|
||||||
|
value2: u64
|
||||||
|
|
||||||
|
CONSTANT: SomeStruct = SomeStruct(250, 250000, 250000000)
|
||||||
|
|
||||||
@exported
|
@exported
|
||||||
def testEntry() -> i32:
|
def testEntry() -> i32:
|
||||||
|
return 0
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
|
assert 0 == result.returned_value
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
@pytest.mark.parametrize('type_', ALL_INT_TYPES)
|
||||||
|
def test_module_constant(type_):
|
||||||
|
code_py = f"""
|
||||||
|
class CheckedValue:
|
||||||
|
value: {type_}
|
||||||
|
|
||||||
|
CONSTANT: CheckedValue = CheckedValue(24)
|
||||||
|
|
||||||
|
@exported
|
||||||
|
def testEntry() -> {type_}:
|
||||||
|
return CONSTANT.value
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
|
assert 24 == result.returned_value
|
||||||
|
assert TYPE_MAP[type_] == type(result.returned_value)
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
@pytest.mark.parametrize('type_', ALL_INT_TYPES)
|
||||||
|
def test_struct_0(type_):
|
||||||
|
code_py = f"""
|
||||||
|
class CheckedValue:
|
||||||
|
value: {type_}
|
||||||
|
|
||||||
|
@exported
|
||||||
|
def testEntry() -> {type_}:
|
||||||
return helper(CheckedValue(23))
|
return helper(CheckedValue(23))
|
||||||
|
|
||||||
def helper(cv: CheckedValue) -> i32:
|
def helper(cv: CheckedValue) -> {type_}:
|
||||||
return cv.value
|
return cv.value
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -63,6 +104,41 @@ def helper(shape1: Rectangle, shape2: Rectangle) -> i32:
|
|||||||
|
|
||||||
assert 545 == result.returned_value
|
assert 545 == result.returned_value
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_returned_struct():
|
||||||
|
code_py = """
|
||||||
|
class CheckedValue:
|
||||||
|
value: u8
|
||||||
|
|
||||||
|
CONSTANT: CheckedValue = CheckedValue(199)
|
||||||
|
|
||||||
|
def helper() -> CheckedValue:
|
||||||
|
return CONSTANT
|
||||||
|
|
||||||
|
def helper2(x: CheckedValue) -> u8:
|
||||||
|
return x.value
|
||||||
|
|
||||||
|
@exported
|
||||||
|
def testEntry() -> u8:
|
||||||
|
return helper2(helper())
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
|
assert 199 == result.returned_value
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_type_mismatch_arg_module_constant():
|
||||||
|
code_py = """
|
||||||
|
class Struct:
|
||||||
|
param: f32
|
||||||
|
|
||||||
|
STRUCT: Struct = Struct(1)
|
||||||
|
"""
|
||||||
|
|
||||||
|
with pytest.raises(Type3Exception, match='Must be real'):
|
||||||
|
Suite(code_py).run_code()
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
@pytest.mark.parametrize('type_', ['i32', 'i64', 'f32', 'f64'])
|
@pytest.mark.parametrize('type_', ['i32', 'i64', 'f32', 'f64'])
|
||||||
def test_type_mismatch_struct_member(type_):
|
def test_type_mismatch_struct_member(type_):
|
||||||
|
|||||||
@ -2,8 +2,51 @@ import pytest
|
|||||||
|
|
||||||
from phasm.type3.entry import Type3Exception
|
from phasm.type3.entry import Type3Exception
|
||||||
|
|
||||||
|
from ..constants import ALL_FLOAT_TYPES, COMPLETE_INT_TYPES, TYPE_MAP
|
||||||
from ..helpers import Suite
|
from ..helpers import Suite
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_module_constant_def():
|
||||||
|
code_py = """
|
||||||
|
CONSTANT: (u8, u32, u64, ) = (250, 250000, 250000000, )
|
||||||
|
|
||||||
|
@exported
|
||||||
|
def testEntry() -> i32:
|
||||||
|
return 0
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
|
assert 0 == result.returned_value
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
@pytest.mark.parametrize('type_', ['u8', 'u32', 'u64', ])
|
||||||
|
def test_module_constant_1(type_):
|
||||||
|
code_py = f"""
|
||||||
|
CONSTANT: ({type_}, ) = (65, )
|
||||||
|
|
||||||
|
@exported
|
||||||
|
def testEntry() -> {type_}:
|
||||||
|
return CONSTANT[0]
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
|
assert 65 == result.returned_value
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_module_constant_6():
|
||||||
|
code_py = """
|
||||||
|
CONSTANT: (u8, u8, u32, u32, u64, u64, ) = (11, 22, 3333, 4444, 555555, 666666, )
|
||||||
|
|
||||||
|
@exported
|
||||||
|
def testEntry() -> u32:
|
||||||
|
return CONSTANT[2]
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
|
assert 3333 == result.returned_value
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
def test_function_call_element_ok():
|
def test_function_call_element_ok():
|
||||||
@ -22,6 +65,175 @@ def helper(x: u64) -> u64:
|
|||||||
|
|
||||||
assert 250000000 == result.returned_value
|
assert 250000000 == result.returned_value
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_tuple():
|
||||||
|
code_py = """
|
||||||
|
def l1(c: (u64, )) -> u64:
|
||||||
|
return c[0]
|
||||||
|
|
||||||
|
@exported
|
||||||
|
def testEntry() -> u64:
|
||||||
|
return l1((32, ))
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
|
assert 32 == result.returned_value
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_tuple_of_tuple():
|
||||||
|
code_py = """
|
||||||
|
def l1(c: (u64, )) -> u64:
|
||||||
|
return c[0]
|
||||||
|
|
||||||
|
def l2(c: ((u64, ), u64, )) -> u64:
|
||||||
|
return l1(c[0])
|
||||||
|
|
||||||
|
@exported
|
||||||
|
def testEntry() -> u64:
|
||||||
|
return l2(((64, ), 32, ))
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
|
assert 64 == result.returned_value
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_tuple_of_tuple_of_tuple():
|
||||||
|
code_py = """
|
||||||
|
def l1(c: (u64, )) -> u64:
|
||||||
|
return c[0]
|
||||||
|
|
||||||
|
def l2(c: ((u64, ), u64, )) -> u64:
|
||||||
|
return l1(c[0])
|
||||||
|
|
||||||
|
def l3(c: (((u64, ), u64, ), u64, )) -> u64:
|
||||||
|
return l2(c[0])
|
||||||
|
|
||||||
|
@exported
|
||||||
|
def testEntry() -> u64:
|
||||||
|
return l3((((128, ), 64, ), 32, ))
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
|
assert 128 == result.returned_value
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_constant_tuple_of_tuple_of_tuple():
|
||||||
|
code_py = """
|
||||||
|
CONSTANT: (((u64, ), u64, ), u64, ) = (((128, ), 64, ), 32, )
|
||||||
|
|
||||||
|
def l1(c: (u64, )) -> u64:
|
||||||
|
return c[0]
|
||||||
|
|
||||||
|
def l2(c: ((u64, ), u64, )) -> u64:
|
||||||
|
return l1(c[0])
|
||||||
|
|
||||||
|
def l3(c: (((u64, ), u64, ), u64, )) -> u64:
|
||||||
|
return l2(c[0])
|
||||||
|
|
||||||
|
@exported
|
||||||
|
def testEntry() -> u64:
|
||||||
|
return l3(CONSTANT)
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
|
assert 128 == result.returned_value
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_bytes_as_part_of_tuple():
|
||||||
|
code_py = """
|
||||||
|
CONSTANT: (bytes, u64, ) = (b'ABCDEF', 19, )
|
||||||
|
|
||||||
|
def l0(c: bytes) -> u8:
|
||||||
|
return c[0]
|
||||||
|
|
||||||
|
def l1(c: (bytes, u64, )) -> u8:
|
||||||
|
return l0(c[0])
|
||||||
|
|
||||||
|
@exported
|
||||||
|
def testEntry() -> u8:
|
||||||
|
return l1(CONSTANT)
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
|
assert 0x41 == result.returned_value
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_struct_as_part_of_tuple():
|
||||||
|
code_py = """
|
||||||
|
class ValueStruct:
|
||||||
|
value: i32
|
||||||
|
|
||||||
|
CONSTANT: (ValueStruct, u64, ) = (ValueStruct(234), 19, )
|
||||||
|
|
||||||
|
def l0(c: ValueStruct) -> i32:
|
||||||
|
return c.value
|
||||||
|
|
||||||
|
def l1(c: (ValueStruct, u64, )) -> i32:
|
||||||
|
return l0(c[0])
|
||||||
|
|
||||||
|
@exported
|
||||||
|
def testEntry() -> i32:
|
||||||
|
return l1(CONSTANT)
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
|
assert 234 == result.returned_value
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_function_call_element_type_mismatch():
|
||||||
|
code_py = """
|
||||||
|
CONSTANT: (u8, u32, u64, ) = (250, 250000, 250000000, )
|
||||||
|
|
||||||
|
@exported
|
||||||
|
def testEntry() -> u8:
|
||||||
|
return helper(CONSTANT[2])
|
||||||
|
|
||||||
|
def helper(x: u8) -> u8:
|
||||||
|
return x
|
||||||
|
"""
|
||||||
|
|
||||||
|
with pytest.raises(Type3Exception, match=r'u8 must be u64 instead'):
|
||||||
|
Suite(code_py).run_code()
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
@pytest.mark.parametrize('type_', COMPLETE_INT_TYPES)
|
||||||
|
def test_tuple_simple_constructor_int(type_):
|
||||||
|
code_py = f"""
|
||||||
|
@exported
|
||||||
|
def testEntry() -> {type_}:
|
||||||
|
return helper((24, 57, 80, ))
|
||||||
|
|
||||||
|
def helper(vector: ({type_}, {type_}, {type_}, )) -> {type_}:
|
||||||
|
return vector[0] + vector[1] + vector[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_', ALL_FLOAT_TYPES)
|
||||||
|
def test_tuple_simple_constructor_float(type_):
|
||||||
|
code_py = f"""
|
||||||
|
@exported
|
||||||
|
def testEntry() -> {type_}:
|
||||||
|
return helper((1.0, 2.0, 3.0, ))
|
||||||
|
|
||||||
|
def helper(v: ({type_}, {type_}, {type_}, )) -> {type_}:
|
||||||
|
return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2])
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = Suite(code_py).run_code()
|
||||||
|
|
||||||
|
assert 3.74 < result.returned_value < 3.75
|
||||||
|
|
||||||
@pytest.mark.integration_test
|
@pytest.mark.integration_test
|
||||||
@pytest.mark.skip('SIMD support is but a dream')
|
@pytest.mark.skip('SIMD support is but a dream')
|
||||||
def test_tuple_i32x4():
|
def test_tuple_i32x4():
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import pytest
|
|||||||
from ..helpers import write_header
|
from ..helpers import write_header
|
||||||
from ..runners import RunnerPywasm3 as Runner
|
from ..runners import RunnerPywasm3 as Runner
|
||||||
|
|
||||||
|
|
||||||
def setup_interpreter(phash_code: str) -> Runner:
|
def setup_interpreter(phash_code: str) -> Runner:
|
||||||
runner = Runner(phash_code)
|
runner = Runner(phash_code)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user