git @ Cat's Eye Technologies SixtyPical / master src / sixtypical / fallthru.py
master

Tree @master (Download .tar.gz)

fallthru.py @masterraw · history · blame

# Copyright (c) 2014-2024, Chris Pressey, Cat's Eye Technologies.
# This file is distributed under a 2-clause BSD license.  See LICENSES/ dir.
# SPDX-License-Identifier: LicenseRef-BSD-2-Clause-X-SixtyPical

# encoding: UTF-8

from copy import copy

from sixtypical.model import RoutineType


class FallthruAnalyzer(object):

    def __init__(self, symtab, debug=False):
        self.symtab = symtab
        self.debug = debug

    def analyze_program(self, program):
        self.program = program

        self.fallthru_map = {}
        for routine in program.routines:
            encountered_gotos = list(routine.encountered_gotos)
            if len(encountered_gotos) == 1 and isinstance(self.symtab.fetch_global_type(encountered_gotos[0].name), RoutineType):
                self.fallthru_map[routine.name] = encountered_gotos[0].name
            else:
                self.fallthru_map[routine.name] = None

    def find_chain(self, routine_name, available):
        chain = [routine_name]
        seen = set(chain)
        while True:
            next = self.fallthru_map.get(routine_name)
            if next is None or next in seen or next not in available:
                return chain
            seen.add(next)
            chain.append(next)
            routine_name = next

    def serialize(self):
        pending_routines = copy(self.fallthru_map)
        roster = []

        main_chain = self.find_chain('main', pending_routines)
        roster.append(main_chain)
        for k in main_chain:
            del pending_routines[k]

        while pending_routines:
            chains = [self.find_chain(k, pending_routines) for k in pending_routines.keys()]
            chains.sort(key=lambda x: (len(x), str(x)), reverse=True)
            c = chains[0]
            roster.append(c)
            for k in c:
                del pending_routines[k]

        return roster