# Path: krakatau-lib/src/main/resources/Lib/Krakatau/ssa/objtypes.py
# def TypeTT(baset, dim):
# def baset(tt): return tt[0]
# def dim(tt): return tt[1]
# def withDimInc(tt, inc): return TypeTT(baset(tt), dim(tt)+inc)
# def withNoDim(tt): return TypeTT(baset(tt), 0)
# def isBaseTClass(tt): return not baset(tt).startswith('.')
# def className(tt): return baset(tt) if not baset(tt).startswith('.') else None
# def primName(tt): return baset(tt)[1:] if baset(tt).startswith('.') else None
# def isSubtype(env, x, y):
# def commonSupertype(env, tts):
# def verifierToSynthetic_seq(vtypes):
# def verifierToSynthetic(vtype):
# def declTypeToActual(env, decltype):


from . import ast
from ..ssa import objtypes

# A simple throws declaration inferrer that only considers throw statements within the method
# this is mostly just useful to make sure the ExceptionHandlers test compiles

def _visit_statement(env, stmt):
    if isinstance(stmt, ast.ThrowStatement):
        return stmt.expr.dtype

    result = objtypes.NullTT
    if isinstance(stmt, ast.TryStatement):
        caught_types = []
        for catch, b in stmt.pairs:
            caught_types.extend(objtypes.className(tn.tt) for tn in catch.typename.tnames)
        if objtypes.ThrowableTT not in caught_types:
            temp = _visit_statement(env, stmt.tryb)
            if temp != objtypes.NullTT:
                assert(objtypes.dim(temp) == 0)
                name = objtypes.className(temp)
                if not any(env.isSubclass(name, caught) for caught in caught_types):
                    result = temp

        statements = zip(*stmt.pairs)[1]
    elif isinstance(stmt, ast.StatementBlock):
        statements = stmt.statements
    else:
        statements = stmt.getScopes()

    for sub in statements:
        if result == objtypes.ThrowableTT:
            break

# Path: krakatau-lib/src/main/resources/Lib/Krakatau/ssa/objtypes.py
# def TypeTT(baset, dim):
# def baset(tt): return tt[0]
# def dim(tt): return tt[1]
# def withDimInc(tt, inc): return TypeTT(baset(tt), dim(tt)+inc)
# def withNoDim(tt): return TypeTT(baset(tt), 0)
# def isBaseTClass(tt): return not baset(tt).startswith('.')
# def className(tt): return baset(tt) if not baset(tt).startswith('.') else None
# def primName(tt): return baset(tt)[1:] if baset(tt).startswith('.') else None
# def isSubtype(env, x, y):
# def commonSupertype(env, tts):
# def verifierToSynthetic_seq(vtypes):
# def verifierToSynthetic(vtype):
# def declTypeToActual(env, decltype):


# Path: krakatau-lib/src/main/resources/Lib/Krakatau/java/throws.py
from . import ast
from ..ssa import objtypes


# A simple throws declaration inferrer that only considers throw statements within the method
# this is mostly just useful to make sure the ExceptionHandlers test compiles

def _visit_statement(env, stmt):
    if isinstance(stmt, ast.ThrowStatement):
        return stmt.expr.dtype

    result = objtypes.NullTT
    if isinstance(stmt, ast.TryStatement):
        caught_types = []
        for catch, b in stmt.pairs:
            caught_types.extend(objtypes.className(tn.tt) for tn in catch.typename.tnames)
        if objtypes.ThrowableTT not in caught_types:
            temp = _visit_statement(env, stmt.tryb)
            if temp != objtypes.NullTT:
                assert(objtypes.dim(temp) == 0)
                name = objtypes.className(temp)
                if not any(env.isSubclass(name, caught) for caught in caught_types):
                    result = temp

        statements = zip(*stmt.pairs)[1]
    elif isinstance(stmt, ast.StatementBlock):
        statements = stmt.statements
    else:
        statements = stmt.getScopes()

    for sub in statements:
        if result == objtypes.ThrowableTT:
            break

        result = objtypes.commonSupertype(env, [result, _visit_statement(env, sub)])