import ASTTypes.ASTNode
from .ParserContainers import Parseable
from ASTTypes.ASTNodeSubtypes import Expression
import XMLParse.ParserGlobals as Globals
from typing import Type
from ASTTypes.Operators import *
from ASTTypes.ExpressionSubtypes import Symbol, ParensStructure


KNOWN_WORDS: dict[str, Type[Parseable]] = {}


def add_to_known_words(word: str):
    def wrapper(fun):
        KNOWN_WORDS[word] = fun
        return fun
    return wrapper


@add_to_known_words("my")
class OperatorMYContainer(Parseable):
    left_binding_power = OperatorMY.PRIORITY

    def null_denotation(self) -> Expression:
        right = Globals.PARSER(self.left_binding_power)
        if isinstance(right, Symbol):
            return OperatorMY([right])
        if isinstance(right, ParensStructure) and right.looks_like_varlist:
            return OperatorMY([right])
        raise SyntaxError(f"Bad 'my' statement on line {self._line}, column {self._column}")


@add_to_known_words("print")
class OperatorPRINTContainer(Parseable):
    left_binding_power = OperatorPRINT.PRIORITY

    def null_denotation(self) -> Expression:
        try:
            parens_possibly = Globals.TOKENIZER.get().token._value  # NOQA Yes, im cheating :|
            if isinstance(parens_possibly, ParensStructure):
                Globals.TOKENIZER.get().next()
                return OperatorPRINT(parens_possibly.children)
        except AttributeError:
            pass
        right = Globals.PARSER(self.left_binding_power)
        if isinstance(right, OperatorList):
            return OperatorPRINT(right.children)
        if isinstance(right, ParensStructure):
            return OperatorPRINT(right.children)
        return OperatorPRINT([right])


@add_to_known_words("shift")
class OperatorSHIFTContainer(Parseable):
    left_binding_power = OperatorSHIFT.PRIORITY

    def null_denotation(self) -> Expression:
        try:
            array_possibly = Globals.TOKENIZER.get().token._value  # NOQA
            if isinstance(array_possibly, Symbol):
                if array_possibly.type == SymbolType.Array:
                    Globals.TOKENIZER.get().next()
                    return OperatorSHIFT([array_possibly])
        except AttributeError:
            pass
        raise SyntaxError(f"Bad shift operator at line {self._line} column {self._column}")
