phasm/py2wasm/wasm.py
2022-03-04 15:50:53 +01:00

146 lines
3.7 KiB
Python

"""
Python classes for storing the representation of Web Assembly code
"""
from typing import Iterable, List, Optional, Tuple, Union
Param = Tuple[str, str]
class Import:
"""
Represents a Web Assembly import
"""
def __init__(
self,
module: str,
name: str,
intname: str,
params: Iterable[Param],
) -> None:
self.module = module
self.name = name
self.intname = intname
self.params = [*params]
self.result: str = 'None'
def generate(self) -> str:
"""
Generates the text version
"""
return '(import "{}" "{}" (func ${}{}))'.format(
self.module,
self.name,
self.intname,
''.join(' (param {})'.format(x[1]) for x in self.params)
)
class Statement:
"""
Represents a Web Assembly statement
"""
def __init__(self, name: str, *args: str, comment: Optional[str] = None):
self.name = name
self.args = args
self.comment = comment
def generate(self) -> str:
"""
Generates the text version
"""
args = ' '.join(self.args)
comment = f' ;; {self.comment}' if self.comment else ''
return f'{self.name} {args}{comment}'
class Function:
"""
Represents a Web Assembly function
"""
def __init__(
self,
name: str,
exported: bool,
params: Iterable[Param],
result: Optional[str],
statements: Iterable[Statement],
) -> None:
self.name = name
self.exported = exported
self.params = [*params]
self.result = result
self.statements = [*statements]
def generate(self) -> str:
"""
Generates the text version
"""
header = ('(export "{}")' if self.exported else '${}').format(self.name)
for nam, typ in self.params:
header += ' (param ${} {})'.format(nam, typ)
if self.result:
header += ' (result {})'.format(self.result)
header += ' (local $___new_reference___addr i32)'
return '(func {}\n {}\n )'.format(
header,
'\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, offset: int, default: Optional[Constant]) -> None:
self.name = name
self.type = type_
self.offset = offset
self.default = default
def alloc_size(self) -> int:
SIZE_MAP = {
'i32': 4,
'i64': 4,
}
return SIZE_MAP[self.type]
class Class:
"""
Represents a Web Assembly class
"""
def __init__(self, name: str, members: List[ClassMember]) -> None:
self.name = name
self.members = members
def alloc_size(self) -> int:
return sum(x.alloc_size() for x in self.members)
class Module:
"""
Represents a Web Assembly module
"""
def __init__(self) -> None:
self.imports: List[Import] = []
self.functions: List[Function] = []
self.classes: List[Class] = []
def generate(self) -> str:
"""
Generates the text version
"""
return '(module\n (memory 1)\n (data (memory 0) (i32.const 0) {})\n {}\n {})\n'.format(
'"\\04\\00\\00\\00"',
'\n '.join(x.generate() for x in self.imports),
'\n '.join(x.generate() for x in self.functions),
)