diff --git a/src/api/global_.py b/src/api/global_.py index 9a490fcc3..f024355ba 100644 --- a/src/api/global_.py +++ b/src/api/global_.py @@ -8,11 +8,17 @@ # This program is Free Software and is released under the terms of # the GNU General License # ---------------------------------------------------------------------- -from typing import Dict, Final, List, NamedTuple, Optional, Set +from __future__ import annotations + +from typing import TYPE_CHECKING, Dict, Final, List, NamedTuple, Optional, Set from src.api.constants import TYPE, LoopType from src.api.opcodestemps import OpcodesTemps +if TYPE_CHECKING: + from src.symbols.id_ import SymbolID + + # ---------------------------------------------------------------------- # Simple global container for internal constants. # Internal constants might be architecture dependant. They're set @@ -86,7 +92,7 @@ class LoopInfo(NamedTuple): # Function calls pending to check # Each scope pushes (prepends) an empty list # ---------------------------------------------------------------------- -FUNCTION_CALLS = [] +FUNCTION_CALLS: list[SymbolID] = [] # ---------------------------------------------------------------------- # Function level entry ID in which scope we are in. If the list @@ -102,7 +108,7 @@ class LoopInfo(NamedTuple): # ---------------------------------------------------------------------- # FUNCTIONS pending to translate after parsing stage # ---------------------------------------------------------------------- -FUNCTIONS = [] +FUNCTIONS: list[SymbolID] = [] # ---------------------------------------------------------------------- # Parameter alignment. Must be set by arch..__init__ @@ -112,7 +118,7 @@ class LoopInfo(NamedTuple): # ---------------------------------------------------------------------- # Data type used for array boundaries. Must be an integral # ---------------------------------------------------------------------- -BOUND_TYPE = None # Set to None, so if not set will raise error +BOUND_TYPE: TYPE # Unset, so if not set will raise error # ---------------------------------------------------------------------- # Data type used for elements size. Must be an integral type @@ -155,7 +161,7 @@ class LoopInfo(NamedTuple): # ---------------------------------------------------------------------- # Type used internally for pointer and memory addresses # ---------------------------------------------------------------------- -PTR_TYPE = None +PTR_TYPE: TYPE # Unset, so if not set will raise error # ---------------------------------------------------------------------- # Character used for name mangling. Usually '_' or '.' diff --git a/src/api/symboltable/symboltable.py b/src/api/symboltable/symboltable.py index 0a0a34cce..459c69058 100644 --- a/src/api/symboltable/symboltable.py +++ b/src/api/symboltable/symboltable.py @@ -24,10 +24,11 @@ warning_implicit_type, warning_not_used, ) -from src.api.symboltable.scope import Scope from src.symbols import sym as symbols from src.symbols.symbol_ import Symbol +from .scope import Scope + class SymbolTable: """Implements a symbol table. diff --git a/src/arch/__init__.py b/src/arch/__init__.py index 301ca6fcb..5d7d8f21b 100755 --- a/src/arch/__init__.py +++ b/src/arch/__init__.py @@ -1,8 +1,14 @@ -#!/usr/bin/env python3 # -*- coding: utf-8 -*- -# vim:ts=4:et:sw=4: + +# ---------------------------------------------------------------------- +# Copyleft (K), Jose M. Rodriguez-Rosa (a.k.a. Boriel) +# +# This program is Free Software and is released under the terms of +# the GNUv3 General License +# ---------------------------------------------------------------------- import importlib +from types import ModuleType __all__ = ( "zx48k", @@ -10,7 +16,7 @@ ) AVAILABLE_ARCHITECTURES = __all__ -target = None +target: ModuleType def set_target_arch(target_arch: str): diff --git a/src/arch/z80/optimizer/common.py b/src/arch/z80/optimizer/common.py index 4d3858d33..53b7e4c62 100644 --- a/src/arch/z80/optimizer/common.py +++ b/src/arch/z80/optimizer/common.py @@ -17,7 +17,4 @@ JUMP_LABELS: Final[set[str]] = set() MEMORY: Final[list[MemCell]] = [] # Instructions emitted by the backend -# PROC labels name space counter -PROC_COUNTER = 0 - BLOCKS: Final[list[BasicBlock]] = [] # Memory blocks diff --git a/src/arch/z80/optimizer/main.py b/src/arch/z80/optimizer/main.py index 8e1dd4eb7..9fa4fbd88 100644 --- a/src/arch/z80/optimizer/main.py +++ b/src/arch/z80/optimizer/main.py @@ -1,3 +1,5 @@ +from collections import defaultdict + from src.api.config import OPTIONS from src.api.debug import __DEBUG__ from src.api.utils import flatten_list @@ -8,10 +10,14 @@ from .common import JUMP_LABELS, LABELS, MEMORY from .helpers import ALL_REGS, END_PROGRAM_LABEL from .labelinfo import LabelInfo +from .memcell import MemCell from .patterns import RE_LABEL, RE_PRAGMA __all__ = "init", "optimize" +# PROC labels name space counter +PROC_COUNTER: int = 0 + def init(): LABELS.clear() @@ -68,19 +74,19 @@ def cleanup_local_labels(block: BasicBlock) -> None: """ global PROC_COUNTER - stack = [[]] - hashes = [{}] - stackprc = [PROC_COUNTER] - used = [{}] # List of hashes of unresolved labels per scope + stack: list[list[str]] = [[]] + hashes: list[dict[str, str]] = [{}] + stackprc: list[int] = [PROC_COUNTER] + used: list[dict[str, list[MemCell]]] = [defaultdict(list)] # List of hashes of unresolved labels per scope MEMORY[:] = block.mem[:] for cell in MEMORY: if cell.inst.upper() == "PROC": - stack += [[]] - hashes += [{}] - stackprc += [PROC_COUNTER] - used += [{}] + stack.append([]) + hashes.append({}) + stackprc.append(PROC_COUNTER) + used.append(defaultdict(list)) PROC_COUNTER += 1 continue @@ -99,18 +105,17 @@ def cleanup_local_labels(block: BasicBlock) -> None: continue tmp = cell.asm.asm - if tmp.upper()[:5] == "LOCAL": + if tmp.upper().startswith("LOCAL"): tmp = tmp[5:].split(",") for lbl in tmp: lbl = lbl.strip() if lbl in stack[-1]: continue - stack[-1] += [lbl] - hashes[-1][lbl] = "PROC%i." % stackprc[-1] + lbl - if used[-1].get(lbl, None) is None: - used[-1][lbl] = [] - cell.asm = ";" + cell.asm # Remove it + stack[-1].append(lbl) + hashes[-1][lbl] = f"PROC{stackprc[-1]}.{lbl}" + + cell.asm = f";{str(cell.asm)}" # Remove it continue if cell.is_label: @@ -118,7 +123,7 @@ def cleanup_local_labels(block: BasicBlock) -> None: for i in range(len(stack) - 1, -1, -1): if label in stack[i]: label = hashes[i][label] - cell.asm = label + ":" + cell.asm = f"{label}:" break continue @@ -132,10 +137,7 @@ def cleanup_local_labels(block: BasicBlock) -> None: break if not labelUsed: - if used[-1].get(label, None) is None: - used[-1][label] = [] - - used[-1][label] += [cell] + used[-1][label].append(cell) for i in range(len(MEMORY) - 1, -1, -1): if MEMORY[i].asm.asm[0] == ";": diff --git a/src/ast/tree.py b/src/ast/tree.py index 70da83311..f8a0f4d54 100644 --- a/src/ast/tree.py +++ b/src/ast/tree.py @@ -2,11 +2,11 @@ # -*- coding: utf-8 -*- import collections.abc -from typing import Iterable, List, Optional, Union +from typing import Iterable, Optional, Union from src.api.exception import Error -__all__ = ["NotAnAstError", "Tree", "ChildrenList"] +__all__ = "NotAnAstError", "Tree", "ChildrenList" class NotAnAstError(Error): @@ -81,7 +81,7 @@ class ChildrenList: def __init__(self, node: Tree): assert isinstance(node, Tree) self.owner = node # Node having this children - self._children: List[Tree] = [] + self._children: list[Tree | None] = [] def __getitem__(self, key: Union[int, slice]): if isinstance(key, int): diff --git a/src/zxbc/args_config.py b/src/zxbc/args_config.py index b20001ec2..da07d1b24 100644 --- a/src/zxbc/args_config.py +++ b/src/zxbc/args_config.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 - +from __future__ import annotations import os -from typing import List +from typing import TYPE_CHECKING import src.api.config import src.api.global_ as gl @@ -9,7 +9,10 @@ from src.api import debug, errmsg from src.api.config import OPTIONS from src.api.utils import open_file -from src.zxbc import args_parser, zxbparser +from src.zxbc import args_parser + +if TYPE_CHECKING: + from argparse import Namespace __all__ = ["FileType", "parse_options", "set_option_defines"] @@ -21,7 +24,7 @@ class FileType: TZX = "tzx" -def parse_options(args: List[str] = None): +def parse_options(args: list[str] | None = None) -> Namespace: """Parses command line options and setup global Options container""" parser = args_parser.parser() options = parser.parse_args(args=args) @@ -56,7 +59,6 @@ def parse_options(args: List[str] = None): if options.arch not in arch.AVAILABLE_ARCHITECTURES: parser.error(f"Invalid architecture '{options.arch}'") - return 2 OPTIONS.architecture = options.arch @@ -67,7 +69,6 @@ def parse_options(args: List[str] = None): if duplicated_options: parser.error(f"Warning(s) {', '.join(duplicated_options)} cannot be enabled " f"and disabled simultaneously") - return 2 for warn_code in enabled_warnings: errmsg.enable_warning(warn_code) @@ -103,15 +104,12 @@ def parse_options(args: List[str] = None): if options.basic and not options.tzx and not options.tap: parser.error("Option --BASIC and --autorun requires --tzx or tap format") - return 4 if options.append_binary and not options.tzx and not options.tap: parser.error("Option --append-binary needs either --tap or --tzx") - return 5 if options.asm and options.memory_map: parser.error("Option --asm and --mmap cannot be used together") - return 6 OPTIONS.use_basic_loader = options.basic OPTIONS.autorun = options.autorun @@ -128,12 +126,11 @@ def parse_options(args: List[str] = None): args = [options.PROGRAM] if not os.path.exists(options.PROGRAM): parser.error("No such file or directory: '%s'" % args[0]) - return 2 set_option_defines() OPTIONS.include_path = options.include_path - OPTIONS.input_filename = zxbparser.FILENAME = os.path.basename(args[0]) + OPTIONS.input_filename = os.path.basename(args[0]) if not OPTIONS.output_filename: OPTIONS.output_filename = ( @@ -146,7 +143,7 @@ def parse_options(args: List[str] = None): return options -def set_option_defines(): +def set_option_defines() -> None: """Sets some macros automatically, according to options""" if OPTIONS.memory_check: OPTIONS.__DEFINES["__MEMORY_CHECK__"] = "" diff --git a/src/zxbc/zxbparser.py b/src/zxbc/zxbparser.py index bbc03c29e..9e4fef48d 100755 --- a/src/zxbc/zxbparser.py +++ b/src/zxbc/zxbparser.py @@ -15,20 +15,13 @@ from math import pi as PI # typings -from typing import List, NamedTuple, Optional +from typing import NamedTuple, Optional import src.api.config import src.api.dataref import src.api.options -import src.api.symboltable - -# Compiler API -import src.api.symboltable.symboltable import src.api.utils -# Lexers and parsers, etc -import src.ply.yacc as yacc - # Symbol Classes from src import arch @@ -54,6 +47,12 @@ from src.api.errmsg import error, warning from src.api.global_ import LoopInfo from src.api.opcodestemps import OpcodesTemps + +# Compiler API +from src.api.symboltable.symboltable import SymbolTable + +# Lexers and parsers, etc +from src.ply import yacc from src.symbols import sym from src.symbols.id_ import SymbolID from src.symbols.symbol_ import Symbol @@ -65,7 +64,7 @@ # Function level entry ID in which scope we are into. If the list # is empty, we are at global scope # ---------------------------------------------------------------------- -FUNCTION_LEVEL: List[SymbolID] = gl.FUNCTION_LEVEL +FUNCTION_LEVEL: list[SymbolID] = gl.FUNCTION_LEVEL # ---------------------------------------------------------------------- # Function calls pending to check @@ -81,7 +80,7 @@ # ---------------------------------------------------------------------- # Global Symbol Table # ---------------------------------------------------------------------- -SYMBOL_TABLE = gl.SYMBOL_TABLE = src.api.symboltable.symboltable.SymbolTable() +SYMBOL_TABLE = gl.SYMBOL_TABLE = SymbolTable() # ---------------------------------------------------------------------- # Defined user labels. They all are prepended _label_. Line numbers 10, @@ -92,17 +91,17 @@ # ---------------------------------------------------------------------- # True if we're in the middle of a LET sentence. False otherwise. # ---------------------------------------------------------------------- -LET_ASSIGNMENT = False +LET_ASSIGNMENT: bool = False # ---------------------------------------------------------------------- # True if PRINT sentence has been used. # ---------------------------------------------------------------------- -PRINT_IS_USED = False +PRINT_IS_USED: bool = False # ---------------------------------------------------------------------- # Last line number output for checking program key board BREAK # ---------------------------------------------------------------------- -last_brk_linenum = 0 +last_brk_linenum: int = 0 # ----------------------------------------------------------------------