idea / scaffolding [skip-ci]
This commit is contained in:
parent
98d3d8848a
commit
3aef459924
@ -45,6 +45,11 @@ class Visitor:
|
|||||||
function_body_map[stmt] = wnode
|
function_body_map[stmt] = wnode
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if isinstance(stmt, ast.ClassDef):
|
||||||
|
wclass = self.pre_visit_ClassDef(module, stmt)
|
||||||
|
module.classes.append(wclass)
|
||||||
|
continue
|
||||||
|
|
||||||
# No other pre visits to do
|
# No other pre visits to do
|
||||||
|
|
||||||
for stmt in node.body:
|
for stmt in node.body:
|
||||||
@ -54,6 +59,9 @@ class Visitor:
|
|||||||
# else: It's an import, no actual body to parse
|
# else: It's an import, no actual body to parse
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if isinstance(stmt, ast.ClassDef):
|
||||||
|
continue
|
||||||
|
|
||||||
raise NotImplementedError(stmt)
|
raise NotImplementedError(stmt)
|
||||||
|
|
||||||
return module
|
return module
|
||||||
@ -70,8 +78,6 @@ class Visitor:
|
|||||||
|
|
||||||
Nested / dynamicly created functions are not yet supported
|
Nested / dynamicly created functions are not yet supported
|
||||||
"""
|
"""
|
||||||
del module
|
|
||||||
|
|
||||||
exported = False
|
exported = False
|
||||||
|
|
||||||
if node.decorator_list:
|
if node.decorator_list:
|
||||||
@ -108,13 +114,22 @@ class Visitor:
|
|||||||
assert not node.args.kwarg
|
assert not node.args.kwarg
|
||||||
assert not node.args.defaults
|
assert not node.args.defaults
|
||||||
|
|
||||||
params = [
|
class_lookup = {
|
||||||
(a.arg, _parse_annotation(a.annotation), )
|
x.name: x
|
||||||
for a in [
|
for x in module.classes
|
||||||
*node.args.posonlyargs,
|
}
|
||||||
*node.args.args,
|
|
||||||
]
|
params = []
|
||||||
]
|
for arg in [*node.args.posonlyargs, *node.args.args]:
|
||||||
|
if not isinstance(arg.annotation, ast.Name):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
print(class_lookup)
|
||||||
|
print(arg.annotation.id)
|
||||||
|
if arg.annotation.id in class_lookup:
|
||||||
|
params.append((arg.arg, arg.annotation.id, ))
|
||||||
|
else:
|
||||||
|
params.append((arg.arg, _parse_annotation(arg.annotation), ))
|
||||||
|
|
||||||
return wasm.Function(node.name, exported, params, result, [])
|
return wasm.Function(node.name, exported, params, result, [])
|
||||||
|
|
||||||
@ -137,6 +152,51 @@ class Visitor:
|
|||||||
|
|
||||||
func.statements = statements
|
func.statements = statements
|
||||||
|
|
||||||
|
def pre_visit_ClassDef(
|
||||||
|
self,
|
||||||
|
module: wasm.Module,
|
||||||
|
node: ast.ClassDef,
|
||||||
|
) -> wasm.Class:
|
||||||
|
"""
|
||||||
|
TODO: Document this
|
||||||
|
"""
|
||||||
|
del module
|
||||||
|
|
||||||
|
if node.bases or node.keywords or node.decorator_list:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
members: List[wasm.ClassMember] = []
|
||||||
|
|
||||||
|
for stmt in node.body:
|
||||||
|
if not isinstance(stmt, ast.AnnAssign):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
if not isinstance(stmt.target, ast.Name):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
if not isinstance(stmt.annotation, ast.Name):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
if stmt.annotation.id != 'i32':
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
if stmt.value is None:
|
||||||
|
default = None
|
||||||
|
else:
|
||||||
|
if not isinstance(stmt.value, ast.Constant):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
if not isinstance(stmt.value.value, int):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
default = wasm.Constant(stmt.value.value)
|
||||||
|
|
||||||
|
members.append(wasm.ClassMember(
|
||||||
|
stmt.target.id, stmt.annotation.id, default
|
||||||
|
))
|
||||||
|
|
||||||
|
return wasm.Class(node.name, members)
|
||||||
|
|
||||||
def visit_stmt(
|
def visit_stmt(
|
||||||
self,
|
self,
|
||||||
module: wasm.Module,
|
module: wasm.Module,
|
||||||
@ -235,6 +295,9 @@ class Visitor:
|
|||||||
if isinstance(node, ast.Name):
|
if isinstance(node, ast.Name):
|
||||||
return self.visit_Name(wlocals, exp_type, node)
|
return self.visit_Name(wlocals, exp_type, node)
|
||||||
|
|
||||||
|
if isinstance(node, ast.Attribute):
|
||||||
|
return [] # TODO
|
||||||
|
|
||||||
raise NotImplementedError(node)
|
raise NotImplementedError(node)
|
||||||
|
|
||||||
def visit_UnaryOp(
|
def visit_UnaryOp(
|
||||||
@ -331,10 +394,11 @@ class Visitor:
|
|||||||
|
|
||||||
called_name = node.func.id
|
called_name = node.func.id
|
||||||
|
|
||||||
search_list: List[Union[wasm.Function, wasm.Import]]
|
search_list: List[Union[wasm.Function, wasm.Import, wasm.Class]]
|
||||||
search_list = [
|
search_list = [
|
||||||
*module.functions,
|
*module.functions,
|
||||||
*module.imports,
|
*module.imports,
|
||||||
|
*module.classes,
|
||||||
]
|
]
|
||||||
|
|
||||||
called_func_list = [
|
called_func_list = [
|
||||||
@ -346,8 +410,15 @@ class Visitor:
|
|||||||
assert 1 == len(called_func_list), \
|
assert 1 == len(called_func_list), \
|
||||||
'Could not find function {}'.format(node.func.id)
|
'Could not find function {}'.format(node.func.id)
|
||||||
|
|
||||||
called_params = called_func_list[0].params
|
if isinstance(called_func_list[0], wasm.Class):
|
||||||
called_result = called_func_list[0].result
|
called_params = [
|
||||||
|
(x.name, x.type, )
|
||||||
|
for x in called_func_list[0].members
|
||||||
|
]
|
||||||
|
called_result: Optional[str] = called_func_list[0].name
|
||||||
|
else:
|
||||||
|
called_params = called_func_list[0].params
|
||||||
|
called_result = called_func_list[0].result
|
||||||
|
|
||||||
assert exp_type == called_result
|
assert exp_type == called_result
|
||||||
|
|
||||||
@ -471,5 +542,5 @@ def _parse_annotation(ann: Optional[ast.expr]) -> str:
|
|||||||
assert ann is not None, 'Web Assembly requires type annotations'
|
assert ann is not None, 'Web Assembly requires type annotations'
|
||||||
assert isinstance(ann, ast.Name)
|
assert isinstance(ann, ast.Name)
|
||||||
result = ann.id
|
result = ann.id
|
||||||
assert result in ['i32', 'i64', 'f32', 'f64']
|
assert result in ['i32', 'i64', 'f32', 'f64'], result
|
||||||
return result
|
return result
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
Python classes for storing the representation of Web Assembly code
|
Python classes for storing the representation of Web Assembly code
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Iterable, List, Optional, Tuple
|
from typing import Iterable, List, Optional, Tuple, Union
|
||||||
|
|
||||||
Param = Tuple[str, str]
|
Param = Tuple[str, str]
|
||||||
|
|
||||||
@ -83,6 +83,30 @@ class Function:
|
|||||||
'\n '.join(x.generate() for x in self.statements),
|
'\n '.join(x.generate() for x in self.statements),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class Constant:
|
||||||
|
"""
|
||||||
|
TODO
|
||||||
|
"""
|
||||||
|
def __init__(self, value: Union[None, bool, int, float]) -> None:
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
class ClassMember:
|
||||||
|
"""
|
||||||
|
Represents a Web Assembly class member
|
||||||
|
"""
|
||||||
|
def __init__(self, name: str, type_: str, default: Optional[Constant]) -> None:
|
||||||
|
self.name = name
|
||||||
|
self.type = type_
|
||||||
|
self.default = default
|
||||||
|
|
||||||
|
class Class:
|
||||||
|
"""
|
||||||
|
Represents a Web Assembly class
|
||||||
|
"""
|
||||||
|
def __init__(self, name: str, members: List[ClassMember]) -> None:
|
||||||
|
self.name = name
|
||||||
|
self.members = members
|
||||||
|
|
||||||
class Module:
|
class Module:
|
||||||
"""
|
"""
|
||||||
Represents a Web Assembly module
|
Represents a Web Assembly module
|
||||||
@ -90,6 +114,7 @@ class Module:
|
|||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.imports: List[Import] = []
|
self.imports: List[Import] = []
|
||||||
self.functions: List[Function] = []
|
self.functions: List[Function] = []
|
||||||
|
self.classes: List[Class] = []
|
||||||
|
|
||||||
def generate(self) -> str:
|
def generate(self) -> str:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -28,3 +28,4 @@ def testEntry() -> i32:
|
|||||||
result = Suite(code_py, 'test_fib').run_code()
|
result = Suite(code_py, 'test_fib').run_code()
|
||||||
|
|
||||||
assert 102334155 == result.returned_value
|
assert 102334155 == result.returned_value
|
||||||
|
assert False
|
||||||
|
|||||||
@ -234,3 +234,40 @@ def helper(left: i32, right: i32) -> i32:
|
|||||||
|
|
||||||
assert 7 == result.returned_value
|
assert 7 == result.returned_value
|
||||||
assert [] == result.log_int32_list
|
assert [] == result.log_int32_list
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_assign():
|
||||||
|
code_py = """
|
||||||
|
|
||||||
|
@exported
|
||||||
|
def testEntry() -> i32:
|
||||||
|
a: i32 = 8947
|
||||||
|
return a
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = Suite(code_py, 'test_call').run_code()
|
||||||
|
|
||||||
|
assert 8947 == result.returned_value
|
||||||
|
assert [] == result.log_int32_list
|
||||||
|
|
||||||
|
@pytest.mark.integration_test
|
||||||
|
def test_struct():
|
||||||
|
code_py = """
|
||||||
|
|
||||||
|
class Rectangle:
|
||||||
|
height: i32
|
||||||
|
width: i32
|
||||||
|
border: i32 # = 5
|
||||||
|
|
||||||
|
@exported
|
||||||
|
def testEntry() -> i32:
|
||||||
|
return helper(Rectangle(100, 150, 2))
|
||||||
|
|
||||||
|
def helper(shape: Rectangle) -> i32:
|
||||||
|
return shape.height + shape.width + shape.border
|
||||||
|
"""
|
||||||
|
|
||||||
|
result = Suite(code_py, 'test_call').run_code()
|
||||||
|
|
||||||
|
assert 100 == result.returned_value
|
||||||
|
assert [] == result.log_int32_list
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user