From 04405b422ce27337b754e393f35b165b7c6a4cbf Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 23 Nov 2024 16:48:50 +0100 Subject: [PATCH 1/5] refact: show more human readable help for format options Even using StrEnum, while it worked, when showing the help for this option it was showing the repr() of the instances, not the value. --- src/zxbc/args_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zxbc/args_parser.py b/src/zxbc/args_parser.py index e50047a74..bbd1f66ac 100644 --- a/src/zxbc/args_parser.py +++ b/src/zxbc/args_parser.py @@ -86,7 +86,7 @@ def parser() -> argparse.ArgumentParser: "-f", "--output-format", type=str, - choices=FileType, + choices=[str(x) for x in FileType], required=False, help="Output format", ) From 43efd57c7d7b9456ae06b38a745f04451b806903 Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 23 Nov 2024 16:52:02 +0100 Subject: [PATCH 2/5] refact: improve typing --- src/api/check.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/check.py b/src/api/check.py index b2dedbdba..7d252c49a 100644 --- a/src/api/check.py +++ b/src/api/check.py @@ -406,7 +406,7 @@ def is_temporary_value(node) -> bool: return node.token not in ("STRING", "VAR") and node.t[0] not in ("_", "#") -def common_type(a, b): +def common_type(a: symbols.TYPE | Type | None, b: symbols.TYPE | Type | None) -> symbols.TYPE | Type | None: """Returns a type which is common for both a and b types. Returns None if no common types allowed. """ @@ -435,7 +435,7 @@ def common_type(a, b): assert a.is_basic assert b.is_basic - types = (a, b) + types = a, b if Type.float_ in types: return Type.float_ From ab9d43f4419eaab5429c51c8c04591944408457e Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 23 Nov 2024 16:54:25 +0100 Subject: [PATCH 3/5] refact: use enum constants for u8, i8, u16, i16, etc... Also added "bool" (not used yet) for future bool management. --- src/arch/z80/backend/common.py | 110 +++++++++++++++++++++------------ 1 file changed, 69 insertions(+), 41 deletions(-) diff --git a/src/arch/z80/backend/common.py b/src/arch/z80/backend/common.py index d870ca89d..b04895d2d 100644 --- a/src/arch/z80/backend/common.py +++ b/src/arch/z80/backend/common.py @@ -1,8 +1,8 @@ -# vim ts=4:et:sw=4:ai - import math import re -from typing import Any, Final +from enum import StrEnum +from types import MappingProxyType +from typing import Final from src.api import global_, tmp_labels from src.api.exception import TempAlreadyFreedError @@ -22,18 +22,46 @@ "strslice.asm", } + +class DataType(StrEnum): + bool = "bool" + u8 = "u8" + u16 = "u16" + u32 = "u32" + i8 = "i8" + i16 = "i16" + i32 = "i32" + f16 = "f16" + f = "f" + + +# Handy constants, to not having to type long names :-) +BOOL_t: Final[DataType] = DataType.bool +U8_t: Final[DataType] = DataType.u8 +U16_t: Final[DataType] = DataType.u16 +U32_t: Final[DataType] = DataType.u32 +I8_t: Final[DataType] = DataType.i8 +I16_t: Final[DataType] = DataType.i16 +I32_t: Final[DataType] = DataType.i32 +F16_t: Final[DataType] = DataType.f16 +F_t: Final[DataType] = DataType.f + + # Internal data types definition, with its size in bytes, or -1 if it is variable (string) # Compound types are only arrays, and have the t -YY_TYPES = { - "u8": 1, # 8 bit unsigned integer - "u16": 2, # 16 bit unsigned integer - "u32": 4, # 32 bit unsigned integer - "i8": 1, # 8 bit SIGNED integer - "i16": 2, # 16 bit SIGNED integer - "i32": 4, # 32 bit SIGNED integer - "f16": 4, # -32768.9999 to 32767.9999 -aprox.- fixed point decimal (step = 1/2^16) - "f": 5, # Floating point -} +YY_TYPES: Final[MappingProxyType[DataType, int]] = MappingProxyType( + { + BOOL_t: 1, + U8_t: 1, # 8 bit unsigned integer + U16_t: 2, # 16 bit unsigned integer + U32_t: 4, # 32 bit unsigned integer + I8_t: 1, # 8 bit SIGNED integer + I16_t: 2, # 16 bit SIGNED integer + I32_t: 4, # 32 bit SIGNED integer + F16_t: 4, # -32768.9999 to 32767.9999 -aprox.- fixed point decimal (step = 1/2^16) + F_t: 5, # Floating point + } +) # Matches a boolean instruction like 'equ16' or 'andi32' RE_BOOL: Final[re.Pattern] = re.compile(r"^(eq|ne|lt|le|gt|ge|and|or|xor|not)(([ui](8|16|32))|(f16|f|str))$") @@ -109,14 +137,14 @@ def is_2n(x: float) -> bool: return n == int(n) -def tmp_remove(label: str): +def tmp_remove(label: str) -> None: if label not in TMP_STORAGES: raise TempAlreadyFreedError(label) TMP_STORAGES.pop(TMP_STORAGES.index(label)) -def runtime_call(label: str): +def runtime_call(label: str) -> str: assert label in RUNTIME_LABELS, f"Invalid runtime label '{label}'" if label in LABEL_REQUIRED_MODULES: REQUIRES.add(LABEL_REQUIRED_MODULES[label]) @@ -129,7 +157,7 @@ def runtime_call(label: str): # ------------------------------------------------------------------ -def is_int(op: Any) -> bool: +def is_int(op: str) -> bool: """Returns True if the given operand (string) contains an integer number """ @@ -143,7 +171,7 @@ def is_int(op: Any) -> bool: return False -def is_float(op: Any) -> bool: +def is_float(op: str) -> bool: """Returns True if the given operand (string) contains a floating point number """ @@ -161,7 +189,7 @@ def _int_ops(op1: str, op2: str) -> tuple[str, str | int] | None: """Receives a list with two strings (operands). If none of them contains integers, returns None. Otherwise, returns a t-uple with (op[0], op[1]), - where op[1] (2nd operan) is always the integer one (the list is swapped) + where op[1] (2nd operand) is always the integer one (the list is swapped) This cannot be used by non-commutative operations like sub and div used this because they're not commutative). @@ -198,7 +226,7 @@ def _f_ops(op1: str, op2: str, *, swap: bool = True) -> tuple[str | float, str | return None -def is_int_type(stype: str) -> bool: +def is_int_type(stype: DataType) -> bool: """Returns whether a given type is integer""" return stype[0] in ("u", "i") @@ -268,65 +296,65 @@ def get_bytes_size(elements: list[str]) -> int: return len(get_bytes(elements)) -def to_byte(stype: str) -> list[str]: +def to_byte(stype: DataType) -> list[str]: """Returns the instruction sequence for converting from the given type to byte. """ output = [] - if stype in ("i8", "u8"): + if stype in (I8_t, U8_t): return [] if is_int_type(stype): output.append("ld a, l") - elif stype == "f16": + elif stype == F16_t: output.append("ld a, e") - elif stype == "f": # Converts C ED LH to byte + elif stype == F_t: # Converts C ED LH to byte output.append(runtime_call(RuntimeLabel.FTOU32REG)) output.append("ld a, l") return output -def to_word(stype: str) -> list[str]: +def to_word(stype: DataType) -> list[str]: """Returns the instruction sequence for converting the given type stored in DE,HL to word (unsigned) HL. """ output = [] # List of instructions - if stype == "u8": # Byte to word + if stype == U8_t: # Byte to word output.append("ld l, a") output.append("ld h, 0") - elif stype == "i8": # Signed byte to word + elif stype == I8_t: # Signed byte to word output.append("ld l, a") output.append("add a, a") output.append("sbc a, a") output.append("ld h, a") - elif stype == "f16": # Must MOVE HL into DE + elif stype == F16_t: # Must MOVE HL into DE output.append("ex de, hl") - elif stype == "f": + elif stype == F_t: output.append(runtime_call(RuntimeLabel.FTOU32REG)) return output -def to_long(stype: str) -> list[str]: +def to_long(stype: DataType) -> list[str]: """Returns the instruction sequence for converting the given type stored in DE,HL to long (DE, HL). """ output = [] # List of instructions - if stype in ("i8", "u8", "f16"): # Byte to word + if stype in {I8_t, U8_t, F16_t}: # Byte to word output = to_word(stype) - if stype != "f16": # If its a byte, just copy H to D,E + if stype != F16_t: # If it's a byte, just copy H to D,E output.append("ld e, h") output.append("ld d, h") - if stype in ("i16", "f16"): # Signed byte or fixed to word + if stype in (I16_t, F16_t): # Signed byte or fixed to word output.append("ld a, h") output.append("add a, a") output.append("sbc a, a") @@ -336,13 +364,13 @@ def to_long(stype: str) -> list[str]: elif stype == "u16": output.append("ld de, 0") - elif stype == "f": + elif stype == F_t: output.append(runtime_call(RuntimeLabel.FTOU32REG)) return output -def to_fixed(stype: str) -> list[str]: +def to_fixed(stype: DataType) -> list[str]: """Returns the instruction sequence for converting the given type stored in DE,HL to fixed DE,HL. """ @@ -352,33 +380,33 @@ def to_fixed(stype: str) -> list[str]: output = to_word(stype) output.append("ex de, hl") output.append("ld hl, 0") # 'Truncate' the fixed point - elif stype == "f": + elif stype == F_t: output.append(runtime_call(RuntimeLabel.FTOF16REG)) return output -def to_float(stype: str) -> list[str]: +def to_float(stype: DataType) -> list[str]: """Returns the instruction sequence for converting the given type stored in DE,HL to fixed DE,HL. """ output: list[str] = [] # List of instructions - if stype == "f": + if stype == F_t: return output # Nothing to do - if stype == "f16": + if stype == F16_t: output.append(runtime_call(RuntimeLabel.F16TOFREG)) return output # If we reach this point, it's an integer type - if stype == "u8": + if stype == U8_t: output.append(runtime_call(RuntimeLabel.U8TOFREG)) - elif stype == "i8": + elif stype == I8_t: output.append(runtime_call(RuntimeLabel.I8TOFREG)) else: output = to_long(stype) - if stype in ("i16", "i32"): + if stype in (I16_t, I32_t): output.append(runtime_call(RuntimeLabel.I32TOFREG)) else: output.append(runtime_call(RuntimeLabel.U32TOFREG)) From 6dc075df9d0ed8697517c8d7accbdf1f6fffe1ca Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 23 Nov 2024 16:57:47 +0100 Subject: [PATCH 4/5] refact: improve typing and fix signatures Unbelievably, most of the binary functions where incorrect (and never used indeed). Fixed the signature of all of them, and make usage from the translator_inst_visitor.py module. This allows safe type-checking during editing time! --- .../z80/visitor/translator_inst_visitor.py | 289 +++++++++--------- 1 file changed, 148 insertions(+), 141 deletions(-) diff --git a/src/arch/z80/visitor/translator_inst_visitor.py b/src/arch/z80/visitor/translator_inst_visitor.py index d731de347..a16a89640 100644 --- a/src/arch/z80/visitor/translator_inst_visitor.py +++ b/src/arch/z80/visitor/translator_inst_visitor.py @@ -2,6 +2,7 @@ from src.api.debug import __DEBUG__ from src.arch.interface.quad import Quad from src.arch.z80.backend import Backend +from src.arch.z80.backend.common import BOOL_t, F16_t, F_t, I8_t, I16_t, I32_t, U8_t, U16_t, U32_t from src.ast import NodeVisitor from src.symbols import sym as symbols @@ -10,26 +11,27 @@ class TranslatorInstVisitor(NodeVisitor): def __init__(self, backend: Backend): self.backend = backend - def emit(self, *args): + def emit(self, *args: str) -> None: """Convert the given args to a Quad (3 address code) instruction""" quad = Quad(*args) - __DEBUG__("EMIT " + str(quad)) + __DEBUG__(f"EMIT {quad!s}") self.backend.MEMORY.append(quad) @staticmethod - def TSUFFIX(type_): + def TSUFFIX(type_: TYPE | symbols.TYPEREF | symbols.BASICTYPE) -> str: assert isinstance(type_, symbols.TYPE) or TYPE.is_valid(type_) _TSUFFIX = { - TYPE.byte: "i8", - TYPE.ubyte: "u8", - TYPE.integer: "i16", - TYPE.uinteger: "u16", - TYPE.long: "i32", - TYPE.ulong: "u32", - TYPE.fixed: "f16", - TYPE.float: "f", + TYPE.byte: I8_t, + TYPE.ubyte: U8_t, + TYPE.integer: I16_t, + TYPE.uinteger: U16_t, + TYPE.long: I32_t, + TYPE.ulong: U32_t, + TYPE.fixed: F16_t, + TYPE.float: F_t, TYPE.string: "str", + TYPE.boolean: BOOL_t, } if isinstance(type_, symbols.TYPEREF): @@ -41,200 +43,205 @@ def TSUFFIX(type_): return _TSUFFIX[type_] - def ic_aaddr(self, t1, t2): - return self.emit("aaddr", t1, t2) + @classmethod + def _no_bool(cls, type_: TYPE | symbols.TYPEREF | symbols.BASICTYPE) -> str: + """Returns the corresponding type suffix except for bool which maps to U8_t""" + return cls.TSUFFIX(type_) if cls.TSUFFIX(type_) != BOOL_t else U8_t - def ic_abs(self, type_, t1, t2): - return self.emit("abs" + self.TSUFFIX(type_), t1, t2) + def ic_aaddr(self, t1, t2) -> None: + self.emit("aaddr", t1, t2) - def ic_add(self, type_, t1, t2, t3): - return self.emit("add" + self.TSUFFIX(type_), t1, t2, t3) + def ic_abs(self, type_: TYPE | symbols.BASICTYPE, t1, t2) -> None: + self.emit("abs" + self.TSUFFIX(type_), t1, t2) - def ic_aload(self, type_, t1, mangle: str): - return self.emit("aload" + self.TSUFFIX(type_), t1, mangle) + def ic_add(self, type_: TYPE | symbols.BASICTYPE, t1, t2, t3) -> None: + self.emit("add" + self.TSUFFIX(type_), t1, t2, t3) - def ic_and(self, type_): - return self.emit("and" + self.TSUFFIX(type_)) + def ic_aload(self, type_: TYPE | symbols.BASICTYPE, t1, mangle: str) -> None: + self.emit("aload" + self.TSUFFIX(type_), t1, mangle) - def ic_astore(self, type_, addr: str, t): - return self.emit("astore" + self.TSUFFIX(type_), addr, t) + def ic_and(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit(f"and{self._no_bool(type_)}", t, t1, t2) - def ic_band(self, type_): - return self.emit("band" + self.TSUFFIX(type_)) + def ic_astore(self, type_: TYPE | symbols.BASICTYPE, addr: str, t) -> None: + self.emit("astore" + self.TSUFFIX(type_), addr, t) - def ic_bnot(self, type_, t1, t2): - return self.emit("bnot" + self.TSUFFIX(type_), t1, t2) + def ic_band(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit("band" + self.TSUFFIX(type_), t, t1, t2) - def ic_bor(self, type_): - return self.emit("bor" + self.TSUFFIX(type_)) + def ic_bnot(self, type_: TYPE | symbols.BASICTYPE, t1, t2) -> None: + self.emit("bnot" + self.TSUFFIX(type_), t1, t2) - def ic_bxor(self, type_): - return self.emit("bxor" + self.TSUFFIX(type_)) + def ic_bor(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit("bor" + self.TSUFFIX(type_), t, t1, t2) - def ic_call(self, label: str, num: int): - return self.emit("call", label, num) + def ic_bxor(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit("bxor" + self.TSUFFIX(type_), t, t1, t2) - def ic_cast(self, t1, type1, type2, t2): + def ic_call(self, label: str, num: int) -> None: + self.emit("call", label, num) + + def ic_cast(self, t1, type1, type2, t2) -> None: self.emit("cast", t1, self.TSUFFIX(type1), self.TSUFFIX(type2), t2) - def ic_data(self, type_, data: list): - return self.emit("data", self.TSUFFIX(type_), data) + def ic_data(self, type_: TYPE | symbols.BASICTYPE, data: list) -> None: + self.emit("data", self.TSUFFIX(type_), data) - def ic_deflabel(self, label: str, t): - return self.emit("deflabel", label, t) + def ic_deflabel(self, label: str, t) -> None: + self.emit("deflabel", label, t) - def ic_div(self, type_): - return self.emit("div" + self.TSUFFIX(type_)) + def ic_div(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit("div" + self.TSUFFIX(type_), t, t1, t2) - def ic_end(self, t): - return self.emit("end", t) + def ic_end(self, t) -> None: + self.emit("end", t) - def ic_enter(self, arg): - return self.emit("enter", arg) + def ic_enter(self, arg) -> None: + self.emit("enter", arg) - def ic_eq(self, type_, t, t1, t2): - return self.emit("eq" + self.TSUFFIX(type_), t, t1, t2) + def ic_eq(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit("eq" + self.TSUFFIX(type_), t, t1, t2) - def ic_exchg(self): - return self.emit("exchg") + def ic_exchg(self) -> None: + self.emit("exchg") - def ic_fparam(self, type_, t): - return self.emit("fparam" + self.TSUFFIX(type_), t) + def ic_fparam(self, type_: TYPE | symbols.BASICTYPE, t) -> None: + self.emit("fparam" + self.TSUFFIX(type_), t) - def ic_fpload(self, type_, t, offset): - return self.emit("fpload" + self.TSUFFIX(type_), t, offset) + def ic_fpload(self, type_: TYPE | symbols.BASICTYPE, t, offset) -> None: + self.emit("fpload" + self.TSUFFIX(type_), t, offset) - def ic_ge(self, type_, t, t1, t2): - return self.emit("ge" + self.TSUFFIX(type_), t, t1, t2) + def ic_ge(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit("ge" + self.TSUFFIX(type_), t, t1, t2) - def ic_gt(self, type_, t, t1, t2): - return self.emit("gt" + self.TSUFFIX(type_), t, t1, t2) + def ic_gt(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit("gt" + self.TSUFFIX(type_), t, t1, t2) - def ic_in(self, t): - return self.emit("in", t) + def ic_in(self, t) -> None: + self.emit("in", t) - def ic_inline(self, asm_code: str): - return self.emit("inline", asm_code) + def ic_inline(self, asm_code: str) -> None: + self.emit("inline", asm_code) - def ic_jgezero(self, type_, t, label: str): - return self.emit("jgezero" + self.TSUFFIX(type_), t, label) + def ic_jgezero(self, type_: TYPE | symbols.BASICTYPE, t, label: str) -> None: + self.emit(f"jgezero{self._no_bool(type_)}", t, label) - def ic_jnzero(self, type_, t, label: str): - return self.emit("jnzero" + self.TSUFFIX(type_), t, label) + def ic_jnzero(self, type_: TYPE | symbols.BASICTYPE, t, label: str) -> None: + self.emit(f"jnzero{self._no_bool(type_)}", t, label) - def ic_jump(self, label: str): - return self.emit("jump", label) + def ic_jump(self, label: str) -> None: + self.emit("jump", label) - def ic_jzero(self, type_, t, label: str): - return self.emit("jzero" + self.TSUFFIX(type_), t, label) + def ic_jzero(self, type_: TYPE | symbols.BASICTYPE, t, label: str) -> None: + self.emit(f"jzero{self._no_bool(type_)}", t, label) - def ic_label(self, label: str): - return self.emit("label", label) + def ic_label(self, label: str) -> None: + self.emit("label", label) - def ic_larrd(self, offset, arg1, size, arg2, bound_ptrs): - return self.emit("larrd", offset, arg1, size, arg2, bound_ptrs) + def ic_larrd(self, offset, arg1, size, arg2, bound_ptrs) -> None: + self.emit("larrd", offset, arg1, size, arg2, bound_ptrs) - def ic_le(self, type_, t, t1, t2): - return self.emit("le" + self.TSUFFIX(type_), t, t1, t2) + def ic_le(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit("le" + self.TSUFFIX(type_), t, t1, t2) - def ic_leave(self, convention: str): - return self.emit("leave", convention) + def ic_leave(self, convention: str) -> None: + self.emit("leave", convention) - def ic_lenstr(self, t1, t2): - return self.emit("lenstr", t1, t2) + def ic_lenstr(self, t1, t2) -> None: + self.emit("lenstr", t1, t2) - def ic_load(self, type_, t1, t2): - return self.emit("load" + self.TSUFFIX(type_), t1, t2) + def ic_load(self, type_: TYPE | symbols.BASICTYPE, t1, t2) -> None: + self.emit("load" + self.TSUFFIX(type_), t1, t2) - def ic_lt(self, type_, t, t1, t2): - return self.emit("lt" + self.TSUFFIX(type_), t, t1, t2) + def ic_lt(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit("lt" + self.TSUFFIX(type_), t, t1, t2) - def ic_lvard(self, offset, default_value: list): - return self.emit("lvard", offset, default_value) + def ic_lvard(self, offset, default_value: list) -> None: + self.emit("lvard", offset, default_value) - def ic_lvarx(self, type_, offset, default_value: list): + def ic_lvarx(self, type_: TYPE | symbols.BASICTYPE, offset, default_value: list) -> None: self.emit("lvarx", offset, self.TSUFFIX(type_), default_value) - def ic_memcopy(self, t1, t2, t3): - return self.emit("memcopy", t1, t2, t3) + def ic_memcopy(self, t1, t2, t3) -> None: + self.emit("memcopy", t1, t2, t3) - def ic_mod(self, type_): - return self.emit("mod" + self.TSUFFIX(type_)) + def ic_mod(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit("mod" + self.TSUFFIX(type_), t, t1, t2) - def ic_mul(self, type_): - return self.emit("mul" + self.TSUFFIX(type_)) + def ic_mul(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit("mul" + self.TSUFFIX(type_), t, t1, t2) - def ic_ne(self, type_, t, t1, t2): - return self.emit("ne" + self.TSUFFIX(type_), t, t1, t2) + def ic_ne(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit("ne" + self.TSUFFIX(type_), t, t1, t2) - def ic_neg(self, type_, t1, t2): - return self.emit("neg" + self.TSUFFIX(type_), t1, t2) + def ic_neg(self, type_: TYPE | symbols.BASICTYPE, t1, t2) -> None: + self.emit("neg" + self.TSUFFIX(type_), t1, t2) - def ic_nop(self): - return self.emit("nop") + def ic_nop(self) -> None: + self.emit("nop") - def ic_not(self, type_, t1, t2): - return self.emit("not" + self.TSUFFIX(type_), t1, t2) + def ic_not(self, type_: TYPE | symbols.BASICTYPE, t1, t2) -> None: + self.emit("not" + self.TSUFFIX(type_), t1, t2) - def ic_or(self, type_): - return self.emit("or" + self.TSUFFIX(type_)) + def ic_or(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit(f"or{self._no_bool(type_)}", t, t1, t2) - def ic_org(self, type_): - return self.emit("org" + self.TSUFFIX(type_)) + def ic_org(self, type_: TYPE | symbols.BASICTYPE) -> None: + self.emit("org" + self.TSUFFIX(type_)) - def ic_out(self, t1, t2): - return self.emit("out", t1, t2) + def ic_out(self, t1, t2) -> None: + self.emit("out", t1, t2) - def ic_paaddr(self, t1, t2): - return self.emit("paaddr", t1, t2) + def ic_paaddr(self, t1, t2) -> None: + self.emit("paaddr", t1, t2) - def ic_paddr(self, t1, t2): - return self.emit("paddr", t1, t2) + def ic_paddr(self, t1, t2) -> None: + self.emit("paddr", t1, t2) - def ic_paload(self, type_, t, offset: int): - return self.emit("paload" + self.TSUFFIX(type_), t, offset) + def ic_paload(self, type_: TYPE | symbols.BASICTYPE, t, offset: int) -> None: + self.emit("paload" + self.TSUFFIX(type_), t, offset) - def ic_param(self, type_, t): - return self.emit("param" + self.TSUFFIX(type_), t) + def ic_param(self, type_: TYPE | symbols.BASICTYPE, t) -> None: + self.emit("param" + self.TSUFFIX(type_), t) - def ic_pastore(self, type_, offset, t): - return self.emit("pastore" + self.TSUFFIX(type_), offset, t) + def ic_pastore(self, type_: TYPE | symbols.BASICTYPE, offset, t) -> None: + self.emit("pastore" + self.TSUFFIX(type_), offset, t) - def ic_pload(self, type_, t1, offset): - return self.emit("pload" + self.TSUFFIX(type_), t1, offset) + def ic_pload(self, type_: TYPE | symbols.BASICTYPE, t1, offset) -> None: + self.emit("pload" + self.TSUFFIX(type_), t1, offset) - def ic_pow(self, type_): - return self.emit("pow" + self.TSUFFIX(type_)) + def ic_pow(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit("pow" + self.TSUFFIX(type_), t, t1, t2) - def ic_pstore(self, type_, offset, t): - return self.emit("pstore" + self.TSUFFIX(type_), offset, t) + def ic_pstore(self, type_: TYPE | symbols.BASICTYPE, offset, t) -> None: + self.emit("pstore" + self.TSUFFIX(type_), offset, t) - def ic_ret(self, type_, t, addr): - return self.emit("ret" + self.TSUFFIX(type_), t, addr) + def ic_ret(self, type_: TYPE | symbols.BASICTYPE, t, addr) -> None: + self.emit("ret" + self.TSUFFIX(type_), t, addr) - def ic_return(self, addr): - return self.emit("ret", addr) + def ic_return(self, addr) -> None: + self.emit("ret", addr) - def ic_shl(self, type_): - return self.emit("shl" + self.TSUFFIX(type_)) + def ic_shl(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit("shl" + self.TSUFFIX(type_), t, t1, t2) - def ic_shr(self, type_): - return self.emit("shr" + self.TSUFFIX(type_)) + def ic_shr(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit("shr" + self.TSUFFIX(type_), t, t1, t2) - def ic_store(self, type_, t1, t2): - return self.emit("store" + self.TSUFFIX(type_), t1, t2) + def ic_store(self, type_: TYPE | symbols.BASICTYPE, t1, t2) -> None: + self.emit("store" + self.TSUFFIX(type_), t1, t2) - def ic_sub(self, type_): - return self.emit("sub" + self.TSUFFIX(type_)) + def ic_sub(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit("sub" + self.TSUFFIX(type_), t, t1, t2) - def ic_var(self, name: str, size_): - return self.emit("var", name, size_) + def ic_var(self, name: str, size_) -> None: + self.emit("var", name, size_) - def ic_vard(self, name: str, data: list): - return self.emit("vard", name, data) + def ic_vard(self, name: str, data: list) -> None: + self.emit("vard", name, data) - def ic_varx(self, name: str, type_, default_value: list): - return self.emit("varx", name, self.TSUFFIX(type_), default_value) + def ic_varx(self, name: str, type_: TYPE | symbols.BASICTYPE, default_value: list) -> None: + self.emit("varx", name, self.TSUFFIX(type_), default_value) - def ic_xor(self, type_): - return self.emit("xor" + self.TSUFFIX(type_)) + def ic_xor(self, type_: TYPE | symbols.BASICTYPE, t, t1, t2) -> None: + self.emit("xor" + self.TSUFFIX(type_), t, t1, t2) From 445d4ccfd0aab66adb32acd9d9148ddf135bd37d Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sat, 23 Nov 2024 16:58:51 +0100 Subject: [PATCH 5/5] refact: make actual use of binary functions operations --- src/arch/z80/visitor/translator.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/arch/z80/visitor/translator.py b/src/arch/z80/visitor/translator.py index 745367e1b..86f735e72 100644 --- a/src/arch/z80/visitor/translator.py +++ b/src/arch/z80/visitor/translator.py @@ -1,4 +1,6 @@ from collections import namedtuple +from collections.abc import Callable +from typing import Any import src.api.errmsg import src.api.global_ as gl @@ -145,8 +147,29 @@ def visit_BINARY(self, node): yield node.right ins = {"PLUS": "add", "MINUS": "sub"}.get(node.operator, node.operator.lower()) - s = self.TSUFFIX(node.left.type_) # Operands type - self.emit(ins + s, node.t, str(node.left.t), str(node.right.t)) + ins_t: dict[str, Callable[[TYPE | symbols.BASICTYPE, Any, Any, Any], None]] = { + "add": self.ic_add, + "sub": self.ic_sub, + "mul": self.ic_mul, + "div": self.ic_div, + "or": self.ic_or, + "xor": self.ic_xor, + "and": self.ic_and, + "eq": self.ic_eq, + "ne": self.ic_ne, + "gt": self.ic_gt, + "lt": self.ic_lt, + "le": self.ic_le, + "ge": self.ic_ge, + "band": self.ic_band, + "bor": self.ic_bor, + "bxor": self.ic_bxor, + "shl": self.ic_shl, + "shr": self.ic_shr, + "pow": self.ic_pow, + "mod": self.ic_mod, + } + ins_t[ins](node.left.type_, node.t, str(node.left.t), str(node.right.t)) def visit_TYPECAST(self, node): yield node.operand