#     Copyright 2019, Kay Hayen, mailto:kay.hayen@gmail.com
#
#     Part of "Nuitka", an optimizing Python compiler that is compatible and
#     integrates with CPython, but also works on its own.
#
#     Licensed under the Apache License, Version 2.0 (the "License");
#     you may not use this file except in compliance with the License.
#     You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#     Unless required by applicable law or agreed to in writing, software
#     distributed under the License is distributed on an "AS IS" BASIS,
#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#     See the License for the specific language governing permissions and
#     limitations under the License.
#
""" The code generation.

No language specifics at all are supposed to be present here. Instead it is
using primitives from the given generator to build code sequences (list of
strings).

As such this is the place that knows how to take a condition and two code
branches and make a code block out of it. But it doesn't contain any target
language syntax.
"""

from . import Contexts
from .AsyncgenCodes import (
    generateMakeAsyncgenObjectCode,
    getAsyncgenObjectCode,
    getAsyncgenObjectDeclCode,
)
from .AttributeCodes import (
    generateAssignmentAttributeCode,
    generateAttributeCheckCode,
    generateAttributeLookupCode,
    generateAttributeLookupSpecialCode,
    generateBuiltinGetattrCode,
    generateBuiltinHasattrCode,
    generateBuiltinSetattrCode,
    generateDelAttributeCode,
)
from .BranchCodes import generateBranchCode
from .BuiltinCodes import (
    generateBuiltinAnonymousRefCode,
    generateBuiltinBinCode,
    generateBuiltinBoolCode,
    generateBuiltinBytearray1Code,
    generateBuiltinBytearray3Code,
    generateBuiltinClassmethodCode,
    generateBuiltinComplex1Code,
    generateBuiltinComplex2Code,
    generateBuiltinFloatCode,
    generateBuiltinHexCode,
    generateBuiltinOctCode,
    generateBuiltinOpenCode,
    generateBuiltinRange1Code,
    generateBuiltinRange2Code,
    generateBuiltinRange3Code,
    generateBuiltinRefCode,
    generateBuiltinStaticmethodCode,
    generateBuiltinSum1Code,
    generateBuiltinSum2Code,
    generateBuiltinType1Code,
    generateBuiltinType3Code,
    generateBuiltinXrange1Code,
    generateBuiltinXrange2Code,
    generateBuiltinXrange3Code,
)
from .CallCodes import generateCallCode, getCallsCode, getCallsDecls
from .ClassCodes import generateBuiltinSuperCode, generateSelectMetaclassCode
from .CodeHelpers import setExpressionDispatchDict, setStatementDispatchDict
from .ComparisonCodes import (
    generateBuiltinIsinstanceCode,
    generateComparisonExpressionCode,
)
from .ConditionalCodes import generateConditionalAndOrCode, generateConditionalCode
from .ConstantCodes import (
    generateConstantEllipsisReferenceCode,
    generateConstantFalseReferenceCode,
    generateConstantNoneReferenceCode,
    generateConstantReferenceCode,
    generateConstantTrueReferenceCode,
)
from .CoroutineCodes import (
    generateAsyncIterCode,
    generateAsyncNextCode,
    generateAsyncWaitCode,
    generateMakeCoroutineObjectCode,
    getCoroutineObjectCode,
    getCoroutineObjectDeclCode,
)
from .DictCodes import (
    generateBuiltinDictCode,
    generateDictionaryCreationCode,
    generateDictOperationGetCode,
    generateDictOperationInCode,
    generateDictOperationRemoveCode,
    generateDictOperationSetCode,
    generateDictOperationUpdateCode,
)
from .EvalCodes import (
    generateBuiltinCompileCode,
    generateEvalCode,
    generateExecCode,
    generateExecfileCode,
    generateLocalsDictSyncCode,
)
from .ExceptionCodes import (
    generateBuiltinMakeExceptionCode,
    generateExceptionCaughtTracebackCode,
    generateExceptionCaughtTypeCode,
    generateExceptionCaughtValueCode,
    generateExceptionPublishCode,
    generateExceptionRefCode,
)
from .ExpressionCodes import generateExpressionOnlyCode, generateSideEffectsCode
from .FrameCodes import (
    generateFramePreserveExceptionCode,
    generateFrameRestoreExceptionCode,
)
from .FunctionCodes import (
    generateFunctionCallCode,
    generateFunctionCreationCode,
    generateFunctionOutlineCode,
    getExportScopeCode,
    getFunctionCode,
    getFunctionDirectDecl,
)
from .GeneratorCodes import (
    generateMakeGeneratorObjectCode,
    getGeneratorObjectCode,
    getGeneratorObjectDeclCode,
)
from .GlobalsLocalsCodes import (
    generateBuiltinDir1Code,
    generateBuiltinGlobalsCode,
    generateBuiltinLocalsCode,
    generateBuiltinLocalsRefCode,
    generateBuiltinVarsCode,
)
from .IdCodes import generateBuiltinHashCode, generateBuiltinIdCode
from .ImportCodes import (
    generateBuiltinImportCode,
    generateImportModuleHardCode,
    generateImportModuleNameHardCode,
    generateImportNameCode,
    generateImportStarCode,
)
from .IntegerCodes import (
    generateBuiltinInt1Code,
    generateBuiltinInt2Code,
    generateBuiltinLong1Code,
    generateBuiltinLong2Code,
)
from .IteratorCodes import (
    generateBuiltinIter1Code,
    generateBuiltinIter2Code,
    generateBuiltinIterForUnpackCode,
    generateBuiltinLenCode,
    generateBuiltinNext1Code,
    generateBuiltinNext2Code,
    generateSpecialUnpackCode,
    generateUnpackCheckCode,
)
from .ListCodes import (
    generateBuiltinListCode,
    generateListCreationCode,
    generateListOperationAppendCode,
    generateListOperationExtendCode,
    generateListOperationPopCode,
)
from .LoaderCodes import getMetapathLoaderBodyCode
from .LocalsDictCodes import (
    generateLocalsDictDelCode,
    generateLocalsDictSetCode,
    generateLocalsDictVariableCheckCode,
    generateLocalsDictVariableRefCode,
    generateLocalsDictVariableRefOrFallbackCode,
    generateReleaseLocalsDictCode,
    generateSetLocalsDictCode,
)
from .LoopCodes import generateLoopBreakCode, generateLoopCode, generateLoopContinueCode
from .ModuleCodes import (
    generateModuleAttributeCode,
    generateModuleAttributeFileCode,
    getModuleCode,
    getModuleValues,
)
from .OperationCodes import (
    generateOperationBinaryCode,
    generateOperationNotCode,
    generateOperationUnaryCode,
)
from .PrintCodes import generatePrintNewlineCode, generatePrintValueCode
from .RaisingCodes import (
    generateRaiseCode,
    generateRaiseExpressionCode,
    generateReraiseCode,
)
from .ReturnCodes import (
    generateGeneratorReturnNoneCode,
    generateGeneratorReturnValueCode,
    generateReturnCode,
    generateReturnConstantCode,
    generateReturnedValueRefCode,
)
from .SetCodes import (
    generateBuiltinFrozensetCode,
    generateBuiltinSetCode,
    generateSetCreationCode,
    generateSetLiteralCreationCode,
    generateSetOperationAddCode,
    generateSetOperationUpdateCode,
)
from .SliceCodes import (
    generateAssignmentSliceCode,
    generateBuiltinSliceCode,
    generateDelSliceCode,
    generateSliceLookupCode,
)
from .StringCodes import (
    generateBuiltinAsciiCode,
    generateBuiltinBytes1Code,
    generateBuiltinBytes3Code,
    generateBuiltinChrCode,
    generateBuiltinFormatCode,
    generateBuiltinOrdCode,
    generateBuiltinStrCode,
    generateBuiltinUnicodeCode,
    generateStringContenationCode,
)
from .SubscriptCodes import (
    generateAssignmentSubscriptCode,
    generateDelSubscriptCode,
    generateSubscriptLookupCode,
)
from .TryCodes import generateTryCode
from .TupleCodes import generateBuiltinTupleCode, generateTupleCreationCode
from .VariableCodes import (
    generateAssignmentVariableCode,
    generateDelVariableCode,
    generateVariableReferenceCode,
    generateVariableReleaseCode,
)
from .YieldCodes import (
    generateYieldCode,
    generateYieldFromCode,
    generateYieldFromWaitableCode,
)

_generated_functions = {}


def generateFunctionBodyCode(function_body, context):
    function_identifier = function_body.getCodeName()

    if function_identifier in _generated_functions:
        return _generated_functions[function_identifier]

    # TODO: Generate both codes, and base direct/etc. decisions on context.

    if function_body.isExpressionGeneratorObjectBody():
        function_context = Contexts.PythonGeneratorObjectContext(
            parent=context, function=function_body
        )
    elif function_body.isExpressionClassBody():
        function_context = Contexts.PythonFunctionDirectContext(
            parent=context, function=function_body
        )
    elif function_body.isExpressionCoroutineObjectBody():
        function_context = Contexts.PythonCoroutineObjectContext(
            parent=context, function=function_body
        )
    elif function_body.isExpressionAsyncgenObjectBody():
        function_context = Contexts.PythonAsyncgenObjectContext(
            parent=context, function=function_body
        )
    elif function_body.needsCreation():
        function_context = Contexts.PythonFunctionCreatedContext(
            parent=context, function=function_body
        )
    else:
        function_context = Contexts.PythonFunctionDirectContext(
            parent=context, function=function_body
        )

    needs_exception_exit = function_body.mayRaiseException(BaseException)

    if function_body.isExpressionGeneratorObjectBody():
        function_code = getGeneratorObjectCode(
            context=function_context,
            function_identifier=function_identifier,
            closure_variables=function_body.getClosureVariables(),
            user_variables=function_body.getUserLocalVariables(),
            outline_variables=function_body.getOutlineLocalVariables(),
            temp_variables=function_body.getTempVariables(),
            needs_exception_exit=needs_exception_exit,
            needs_generator_return=function_body.needsGeneratorReturnExit(),
        )
    elif function_body.isExpressionCoroutineObjectBody():
        function_code = getCoroutineObjectCode(
            context=function_context,
            function_identifier=function_identifier,
            closure_variables=function_body.getClosureVariables(),
            user_variables=function_body.getUserLocalVariables(),
            outline_variables=function_body.getOutlineLocalVariables(),
            temp_variables=function_body.getTempVariables(),
            needs_exception_exit=needs_exception_exit,
            needs_generator_return=function_body.needsGeneratorReturnExit(),
        )
    elif function_body.isExpressionAsyncgenObjectBody():
        function_code = getAsyncgenObjectCode(
            context=function_context,
            function_identifier=function_identifier,
            closure_variables=function_body.getClosureVariables(),
            user_variables=function_body.getUserLocalVariables(),
            outline_variables=function_body.getOutlineLocalVariables(),
            temp_variables=function_body.getTempVariables(),
            needs_exception_exit=needs_exception_exit,
            needs_generator_return=function_body.needsGeneratorReturnExit(),
        )
    elif function_body.isExpressionClassBody():
        function_code = getFunctionCode(
            context=function_context,
            function_identifier=function_identifier,
            parameters=None,
            closure_variables=function_body.getClosureVariables(),
            user_variables=function_body.getUserLocalVariables(),
            outline_variables=function_body.getOutlineLocalVariables(),
            temp_variables=function_body.getTempVariables(),
            function_doc=function_body.getDoc(),
            needs_exception_exit=needs_exception_exit,
            file_scope=getExportScopeCode(cross_module=False),
        )
    else:
        parameters = function_body.getParameters()

        function_code = getFunctionCode(
            context=function_context,
            function_identifier=function_identifier,
            parameters=parameters,
            closure_variables=function_body.getClosureVariables(),
            user_variables=function_body.getUserLocalVariables(),
            outline_variables=function_body.getOutlineLocalVariables(),
            temp_variables=function_body.getTempVariables(),
            function_doc=function_body.getDoc(),
            needs_exception_exit=needs_exception_exit,
            file_scope=getExportScopeCode(
                cross_module=function_body.isCrossModuleUsed()
            ),
        )

    return function_code, function_context


def _generateFunctionDeclCode(function_body, context):
    if function_body.isExpressionGeneratorObjectBody():
        return getGeneratorObjectDeclCode(
            function_identifier=function_body.getCodeName()
        )
    elif function_body.isExpressionCoroutineObjectBody():
        return getCoroutineObjectDeclCode(
            function_identifier=function_body.getCodeName()
        )
    elif function_body.isExpressionAsyncgenObjectBody():
        return getAsyncgenObjectDeclCode(
            function_identifier=function_body.getCodeName()
        )
    elif function_body.isExpressionClassBody():
        return getFunctionDirectDecl(
            function_identifier=function_body.getCodeName(),
            closure_variables=function_body.getClosureVariables(),
            file_scope=getExportScopeCode(cross_module=False),
            context=context,
        )
    elif function_body.needsDirectCall():
        return getFunctionDirectDecl(
            function_identifier=function_body.getCodeName(),
            closure_variables=function_body.getClosureVariables(),
            file_scope=getExportScopeCode(
                cross_module=function_body.isCrossModuleUsed()
            ),
            context=context,
        )
    else:
        return None


def prepareModuleCode(global_context, module, module_name):
    # As this not only creates all modules, but also functions, it deals
    # also with its functions.

    assert module.isCompiledPythonModule(), module

    context = Contexts.PythonModuleContext(
        module=module,
        module_name=module_name,
        code_name=module.getCodeName(),
        filename=module.getFilename(),
        global_context=global_context,
    )

    context.setExceptionEscape("module_exception_exit")

    function_decl_codes = []
    function_body_codes = []

    for function_body in module.getUsedFunctions():
        function_code, function_context = generateFunctionBodyCode(
            function_body=function_body, context=context
        )

        assert type(function_code) is str, type(function_code)

        function_body_codes.append(function_code)

        function_decl = _generateFunctionDeclCode(
            function_body=function_body, context=function_context
        )

        if function_decl is not None:
            function_decl_codes.append(function_decl)

    # These are for functions used from other modules. Due to cyclic
    # dependencies, we cannot rely on those to be already created.
    for function_body in module.getCrossUsedFunctions():
        assert function_body.isCrossModuleUsed()

        function_decl = getFunctionDirectDecl(
            function_identifier=function_body.getCodeName(),
            closure_variables=function_body.getClosureVariables(),
            file_scope=getExportScopeCode(
                cross_module=function_body.isCrossModuleUsed()
            ),
            context=Contexts.PythonFunctionDirectContext(
                parent=context, function=function_body
            ),
        )

        function_decl_codes.append(function_decl)

    template_values = getModuleValues(
        module_name=module_name,
        module_identifier=module.getCodeName(),
        function_decl_codes=function_decl_codes,
        function_body_codes=function_body_codes,
        temp_variables=module.getTempVariables(),
        outline_variables=module.getOutlineLocalVariables(),
        is_main_module=module.isMainModule(),
        is_top_module=module.isTopModule(),
        is_internal_module=module.isInternalModule(),
        is_package=module.isCompiledPythonPackage(),
        context=context,
    )

    return template_values, context


def generateModuleCode(module_context, template_values):
    return getModuleCode(module_context=module_context, template_values=template_values)


def generateHelpersCode(other_modules):
    calls_decl_code = getCallsDecls()

    loader_code = getMetapathLoaderBodyCode(other_modules)

    calls_body_code = getCallsCode()

    return calls_decl_code, calls_body_code + loader_code


def makeGlobalContext():
    return Contexts.PythonGlobalContext()


setExpressionDispatchDict(
    {
        "EXPRESSION_ATTRIBUTE_CHECK": generateAttributeCheckCode,
        "EXPRESSION_ATTRIBUTE_LOOKUP": generateAttributeLookupCode,
        "EXPRESSION_ATTRIBUTE_LOOKUP_SPECIAL": generateAttributeLookupSpecialCode,
        "EXPRESSION_BUILTIN_SLICE": generateBuiltinSliceCode,
        "EXPRESSION_BUILTIN_HASH": generateBuiltinHashCode,
        "EXPRESSION_BUILTIN_ID": generateBuiltinIdCode,
        "EXPRESSION_BUILTIN_COMPILE": generateBuiltinCompileCode,
        "EXPRESSION_BUILTIN_EXECFILE": generateExecfileCode,
        "EXPRESSION_BUILTIN_EVAL": generateEvalCode,
        "EXPRESSION_BUILTIN_EXEC": generateEvalCode,
        "EXPRESSION_BUILTIN_ITER_FOR_UNPACK": generateBuiltinIterForUnpackCode,
        "EXPRESSION_BUILTIN_ITER1": generateBuiltinIter1Code,
        "EXPRESSION_BUILTIN_ITER2": generateBuiltinIter2Code,
        "EXPRESSION_BUILTIN_NEXT1": generateBuiltinNext1Code,
        "EXPRESSION_BUILTIN_NEXT2": generateBuiltinNext2Code,
        "EXPRESSION_BUILTIN_SUM1": generateBuiltinSum1Code,
        "EXPRESSION_BUILTIN_SUM2": generateBuiltinSum2Code,
        "EXPRESSION_BUILTIN_TYPE1": generateBuiltinType1Code,
        "EXPRESSION_BUILTIN_TYPE3": generateBuiltinType3Code,
        "EXPRESSION_BUILTIN_IMPORT": generateBuiltinImportCode,
        "EXPRESSION_BUILTIN_BOOL": generateBuiltinBoolCode,
        "EXPRESSION_BUILTIN_BYTEARRAY1": generateBuiltinBytearray1Code,
        "EXPRESSION_BUILTIN_BYTEARRAY3": generateBuiltinBytearray3Code,
        "EXPRESSION_BUILTIN_INT1": generateBuiltinInt1Code,
        "EXPRESSION_BUILTIN_INT2": generateBuiltinInt2Code,
        "EXPRESSION_BUILTIN_LONG1": generateBuiltinLong1Code,
        "EXPRESSION_BUILTIN_LONG2": generateBuiltinLong2Code,
        "EXPRESSION_BUILTIN_FLOAT": generateBuiltinFloatCode,
        "EXPRESSION_BUILTIN_COMPLEX1": generateBuiltinComplex1Code,
        "EXPRESSION_BUILTIN_COMPLEX2": generateBuiltinComplex2Code,
        "EXPRESSION_BUILTIN_LEN": generateBuiltinLenCode,
        "EXPRESSION_BUILTIN_STR": generateBuiltinStrCode,
        "EXPRESSION_BUILTIN_BYTES1": generateBuiltinBytes1Code,
        "EXPRESSION_BUILTIN_BYTES3": generateBuiltinBytes3Code,
        "EXPRESSION_BUILTIN_UNICODE": generateBuiltinUnicodeCode,
        "EXPRESSION_BUILTIN_CHR": generateBuiltinChrCode,
        "EXPRESSION_BUILTIN_ORD": generateBuiltinOrdCode,
        "EXPRESSION_BUILTIN_BIN": generateBuiltinBinCode,
        "EXPRESSION_BUILTIN_OCT": generateBuiltinOctCode,
        "EXPRESSION_BUILTIN_HEX": generateBuiltinHexCode,
        "EXPRESSION_BUILTIN_TUPLE": generateBuiltinTupleCode,
        "EXPRESSION_BUILTIN_LIST": generateBuiltinListCode,
        "EXPRESSION_BUILTIN_SET": generateBuiltinSetCode,
        "EXPRESSION_BUILTIN_FROZENSET": generateBuiltinFrozensetCode,
        "EXPRESSION_BUILTIN_DICT": generateBuiltinDictCode,
        "EXPRESSION_BUILTIN_LOCALS_COPY": generateBuiltinLocalsCode,
        "EXPRESSION_BUILTIN_LOCALS_UPDATED": generateBuiltinLocalsCode,
        "EXPRESSION_BUILTIN_LOCALS_REF": generateBuiltinLocalsRefCode,
        "EXPRESSION_BUILTIN_GLOBALS": generateBuiltinGlobalsCode,
        "EXPRESSION_BUILTIN_SUPER": generateBuiltinSuperCode,
        "EXPRESSION_BUILTIN_ISINSTANCE": generateBuiltinIsinstanceCode,
        "EXPRESSION_BUILTIN_DIR1": generateBuiltinDir1Code,
        "EXPRESSION_BUILTIN_VARS": generateBuiltinVarsCode,
        "EXPRESSION_BUILTIN_HASATTR": generateBuiltinHasattrCode,
        "EXPRESSION_BUILTIN_GETATTR": generateBuiltinGetattrCode,
        "EXPRESSION_BUILTIN_SETATTR": generateBuiltinSetattrCode,
        "EXPRESSION_BUILTIN_OPEN": generateBuiltinOpenCode,
        "EXPRESSION_BUILTIN_STATICMETHOD": generateBuiltinStaticmethodCode,
        "EXPRESSION_BUILTIN_CLASSMETHOD": generateBuiltinClassmethodCode,
        "EXPRESSION_BUILTIN_RANGE1": generateBuiltinRange1Code,
        "EXPRESSION_BUILTIN_RANGE2": generateBuiltinRange2Code,
        "EXPRESSION_BUILTIN_RANGE3": generateBuiltinRange3Code,
        "EXPRESSION_BUILTIN_XRANGE1": generateBuiltinXrange1Code,
        "EXPRESSION_BUILTIN_XRANGE2": generateBuiltinXrange2Code,
        "EXPRESSION_BUILTIN_XRANGE3": generateBuiltinXrange3Code,
        "EXPRESSION_BUILTIN_MAKE_EXCEPTION": generateBuiltinMakeExceptionCode,
        "EXPRESSION_BUILTIN_REF": generateBuiltinRefCode,
        "EXPRESSION_BUILTIN_EXCEPTION_REF": generateExceptionRefCode,
        "EXPRESSION_BUILTIN_ANONYMOUS_REF": generateBuiltinAnonymousRefCode,
        "EXPRESSION_CAUGHT_EXCEPTION_TYPE_REF": generateExceptionCaughtTypeCode,
        "EXPRESSION_CAUGHT_EXCEPTION_VALUE_REF": generateExceptionCaughtValueCode,
        "EXPRESSION_CAUGHT_EXCEPTION_TRACEBACK_REF": generateExceptionCaughtTracebackCode,
        "EXPRESSION_CALL_EMPTY": generateCallCode,
        "EXPRESSION_CALL_KEYWORDS_ONLY": generateCallCode,
        "EXPRESSION_CALL_NO_KEYWORDS": generateCallCode,
        "EXPRESSION_CALL": generateCallCode,
        "EXPRESSION_CONSTANT_NONE_REF": generateConstantNoneReferenceCode,
        "EXPRESSION_CONSTANT_TRUE_REF": generateConstantTrueReferenceCode,
        "EXPRESSION_CONSTANT_FALSE_REF": generateConstantFalseReferenceCode,
        "EXPRESSION_CONSTANT_STR_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_UNICODE_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_BYTES_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_INT_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_LONG_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_FLOAT_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_COMPLEX_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_ELLIPSIS_REF": generateConstantEllipsisReferenceCode,
        "EXPRESSION_CONSTANT_DICT_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_DICT_EMPTY_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_TUPLE_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_TUPLE_EMPTY_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_LIST_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_LIST_EMPTY_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_SET_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_SET_EMPTY_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_FROZENSET_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_FROZENSET_EMPTY_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_SLICE_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_XRANGE_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_TYPE_REF": generateConstantReferenceCode,
        "EXPRESSION_CONSTANT_BYTEARRAY_REF": generateConstantReferenceCode,
        "EXPRESSION_CONDITIONAL": generateConditionalCode,
        "EXPRESSION_CONDITIONAL_OR": generateConditionalAndOrCode,
        "EXPRESSION_CONDITIONAL_AND": generateConditionalAndOrCode,
        "EXPRESSION_COMPARISON": generateComparisonExpressionCode,
        "EXPRESSION_COMPARISON_IS": generateComparisonExpressionCode,
        "EXPRESSION_COMPARISON_IS_NOT": generateComparisonExpressionCode,
        "EXPRESSION_COMPARISON_IN": generateComparisonExpressionCode,
        "EXPRESSION_COMPARISON_NOT_IN": generateComparisonExpressionCode,
        "EXPRESSION_COMPARISON_EXCEPTION_MATCH": generateComparisonExpressionCode,
        "EXPRESSION_COMPARISON_LT": generateComparisonExpressionCode,
        "EXPRESSION_COMPARISON_LTE": generateComparisonExpressionCode,
        "EXPRESSION_COMPARISON_GT": generateComparisonExpressionCode,
        "EXPRESSION_COMPARISON_GTE": generateComparisonExpressionCode,
        "EXPRESSION_COMPARISON_EQ": generateComparisonExpressionCode,
        "EXPRESSION_COMPARISON_NEQ": generateComparisonExpressionCode,
        "EXPRESSION_DICT_OPERATION_GET": generateDictOperationGetCode,
        "EXPRESSION_DICT_OPERATION_IN": generateDictOperationInCode,
        "EXPRESSION_DICT_OPERATION_NOT_IN": generateDictOperationInCode,
        "EXPRESSION_FUNCTION_CREATION": generateFunctionCreationCode,
        "EXPRESSION_FUNCTION_CALL": generateFunctionCallCode,
        "EXPRESSION_IMPORT_MODULE_HARD": generateImportModuleHardCode,
        "EXPRESSION_IMPORT_MODULE_NAME_HARD": generateImportModuleNameHardCode,
        "EXPRESSION_IMPORT_NAME": generateImportNameCode,
        "EXPRESSION_LIST_OPERATION_EXTEND": generateListOperationExtendCode,
        "EXPRESSION_LIST_OPERATION_POP": generateListOperationPopCode,
        "EXPRESSION_MODULE_ATTRIBUTE_FILE_REF": generateModuleAttributeFileCode,
        "EXPRESSION_MODULE_ATTRIBUTE_NAME_REF": generateModuleAttributeCode,
        "EXPRESSION_MODULE_ATTRIBUTE_PACKAGE_REF": generateModuleAttributeCode,
        "EXPRESSION_MODULE_ATTRIBUTE_LOADER_REF": generateModuleAttributeCode,
        "EXPRESSION_MODULE_ATTRIBUTE_SPEC_REF": generateModuleAttributeCode,
        "EXPRESSION_MAKE_GENERATOR_OBJECT": generateMakeGeneratorObjectCode,
        "EXPRESSION_MAKE_COROUTINE_OBJECT": generateMakeCoroutineObjectCode,
        "EXPRESSION_MAKE_ASYNCGEN_OBJECT": generateMakeAsyncgenObjectCode,
        "EXPRESSION_MAKE_SET": generateSetCreationCode,
        "EXPRESSION_MAKE_SET_LITERAL": generateSetLiteralCreationCode,
        "EXPRESSION_MAKE_TUPLE": generateTupleCreationCode,
        "EXPRESSION_MAKE_LIST": generateListCreationCode,
        "EXPRESSION_MAKE_DICT": generateDictionaryCreationCode,
        "EXPRESSION_OPERATION_BINARY": generateOperationBinaryCode,
        "EXPRESSION_OPERATION_BINARY_ADD": generateOperationBinaryCode,
        "EXPRESSION_OPERATION_BINARY_SUB": generateOperationBinaryCode,
        "EXPRESSION_OPERATION_BINARY_MULT": generateOperationBinaryCode,
        "EXPRESSION_OPERATION_BINARY_FLOOR_DIV": generateOperationBinaryCode,
        "EXPRESSION_OPERATION_BINARY_OLD_DIV": generateOperationBinaryCode,
        "EXPRESSION_OPERATION_BINARY_TRUE_DIV": generateOperationBinaryCode,
        "EXPRESSION_OPERATION_BINARY_DIVMOD": generateOperationBinaryCode,
        "EXPRESSION_OPERATION_BINARY_INPLACE": generateOperationBinaryCode,
        "EXPRESSION_OPERATION_UNARY": generateOperationUnaryCode,
        "EXPRESSION_OPERATION_NOT": generateOperationNotCode,
        "EXPRESSION_OUTLINE_BODY": generateFunctionOutlineCode,
        "EXPRESSION_OUTLINE_FUNCTION": generateFunctionOutlineCode,
        # TODO: Rename to make more clear it is an outline
        "EXPRESSION_CLASS_BODY": generateFunctionOutlineCode,
        "EXPRESSION_RETURNED_VALUE_REF": generateReturnedValueRefCode,
        "EXPRESSION_SUBSCRIPT_LOOKUP": generateSubscriptLookupCode,
        "EXPRESSION_SLICE_LOOKUP": generateSliceLookupCode,
        "EXPRESSION_SET_OPERATION_UPDATE": generateSetOperationUpdateCode,
        "EXPRESSION_SIDE_EFFECTS": generateSideEffectsCode,
        "EXPRESSION_SPECIAL_UNPACK": generateSpecialUnpackCode,
        "EXPRESSION_TEMP_VARIABLE_REF": generateVariableReferenceCode,
        "EXPRESSION_VARIABLE_REF": generateVariableReferenceCode,
        "EXPRESSION_YIELD": generateYieldCode,
        "EXPRESSION_YIELD_FROM": generateYieldFromCode,
        "EXPRESSION_YIELD_FROM_WAITABLE": generateYieldFromWaitableCode,
        "EXPRESSION_ASYNC_WAIT": generateAsyncWaitCode,
        "EXPRESSION_ASYNC_WAIT_ENTER": generateAsyncWaitCode,
        "EXPRESSION_ASYNC_WAIT_EXIT": generateAsyncWaitCode,
        "EXPRESSION_ASYNC_ITER": generateAsyncIterCode,
        "EXPRESSION_ASYNC_NEXT": generateAsyncNextCode,
        "EXPRESSION_SELECT_METACLASS": generateSelectMetaclassCode,
        "EXPRESSION_STRING_CONCATENATION": generateStringContenationCode,
        "EXPRESSION_BUILTIN_FORMAT": generateBuiltinFormatCode,
        "EXPRESSION_BUILTIN_ASCII": generateBuiltinAsciiCode,
        "EXPRESSION_LOCALS_VARIABLE_CHECK": generateLocalsDictVariableCheckCode,
        "EXPRESSION_LOCALS_VARIABLE_REF_OR_FALLBACK": generateLocalsDictVariableRefOrFallbackCode,
        "EXPRESSION_LOCALS_VARIABLE_REF": generateLocalsDictVariableRefCode,
        "EXPRESSION_RAISE_EXCEPTION": generateRaiseExpressionCode,
    }
)

setStatementDispatchDict(
    {
        "STATEMENT_ASSIGNMENT_VARIABLE": generateAssignmentVariableCode,
        "STATEMENT_ASSIGNMENT_ATTRIBUTE": generateAssignmentAttributeCode,
        "STATEMENT_ASSIGNMENT_SUBSCRIPT": generateAssignmentSubscriptCode,
        "STATEMENT_ASSIGNMENT_SLICE": generateAssignmentSliceCode,
        "STATEMENT_DEL_VARIABLE": generateDelVariableCode,
        "STATEMENT_DEL_ATTRIBUTE": generateDelAttributeCode,
        "STATEMENT_DEL_SUBSCRIPT": generateDelSubscriptCode,
        "STATEMENT_DEL_SLICE": generateDelSliceCode,
        "STATEMENT_DICT_OPERATION_REMOVE": generateDictOperationRemoveCode,
        "STATEMENT_DICT_OPERATION_UPDATE": generateDictOperationUpdateCode,
        "STATEMENT_RELEASE_VARIABLE": generateVariableReleaseCode,
        "STATEMENT_EXPRESSION_ONLY": generateExpressionOnlyCode,
        "STATEMENT_RETURN": generateReturnCode,
        "STATEMENT_RETURN_TRUE": generateReturnConstantCode,
        "STATEMENT_RETURN_FALSE": generateReturnConstantCode,
        "STATEMENT_RETURN_NONE": generateReturnConstantCode,
        "STATEMENT_RETURN_CONSTANT": generateReturnConstantCode,
        "STATEMENT_GENERATOR_RETURN": generateGeneratorReturnValueCode,
        "STATEMENT_GENERATOR_RETURN_NONE": generateGeneratorReturnNoneCode,
        "STATEMENT_CONDITIONAL": generateBranchCode,
        "STATEMENT_TRY": generateTryCode,
        "STATEMENT_PRINT_VALUE": generatePrintValueCode,
        "STATEMENT_PRINT_NEWLINE": generatePrintNewlineCode,
        "STATEMENT_IMPORT_STAR": generateImportStarCode,
        "STATEMENT_LIST_OPERATION_APPEND": generateListOperationAppendCode,
        "STATEMENT_SET_OPERATION_ADD": generateSetOperationAddCode,
        "STATEMENT_DICT_OPERATION_SET": generateDictOperationSetCode,
        "STATEMENT_LOCALS_DICT_OPERATION_SET": generateLocalsDictSetCode,
        "STATEMENT_LOCALS_DICT_OPERATION_DEL": generateLocalsDictDelCode,
        "STATEMENT_LOOP": generateLoopCode,
        "STATEMENT_LOOP_BREAK": generateLoopBreakCode,
        "STATEMENT_LOOP_CONTINUE": generateLoopContinueCode,
        "STATEMENT_RAISE_EXCEPTION": generateRaiseCode,
        "STATEMENT_RAISE_EXCEPTION_IMPLICIT": generateRaiseCode,
        "STATEMENT_RERAISE_EXCEPTION": generateReraiseCode,
        "STATEMENT_SPECIAL_UNPACK_CHECK": generateUnpackCheckCode,
        "STATEMENT_EXEC": generateExecCode,
        "STATEMENT_LOCALS_DICT_SYNC": generateLocalsDictSyncCode,
        "STATEMENT_SET_LOCALS": generateSetLocalsDictCode,
        "STATEMENT_SET_LOCALS_DICTIONARY": generateSetLocalsDictCode,
        "STATEMENT_RELEASE_LOCALS": generateReleaseLocalsDictCode,
        "STATEMENT_PRESERVE_FRAME_EXCEPTION": generateFramePreserveExceptionCode,
        "STATEMENT_RESTORE_FRAME_EXCEPTION": generateFrameRestoreExceptionCode,
        "STATEMENT_PUBLISH_EXCEPTION": generateExceptionPublishCode,
    }
)
