""" 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], locals_: Iterable[Param], result: Optional[str], statements: Iterable[Statement], ) -> None: self.name = name self.exported = exported self.params = [*params] self.locals = [*locals_] 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 += f' (param ${nam} {typ})' if self.result: header += f' (result {self.result})' for nam, typ in self.locals: header += f' (local ${nam} {typ})' 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), )