"""Token types for the MicroBasic lexer.

Keyword and operator lists are taken directly from the Roboteq MicroBasic
Scripting Language User & Reference Manual (V2.0, July 8, 2019), "Keywords"
and "Operators" sections. That grammar is publicly documented and is a
reliable source of truth for tokenizing/parsing .mb source. (The bytecode
this eventually compiles to is NOT publicly documented -- see
docs/reverse_engineering.md.)
"""

from __future__ import annotations

from enum import Enum, auto


class TokenType(Enum):
    # Literals
    INTEGER = auto()
    STRING = auto()
    IDENT = auto()
    LABEL = auto()  # identifier immediately followed by ':' at start of line

    # Keywords (case-insensitive in source)
    KEYWORD = auto()

    # Operators / punctuation
    OP = auto()
    LPAREN = auto()
    RPAREN = auto()
    LBRACKET = auto()
    RBRACKET = auto()
    COMMA = auto()
    COLON = auto()

    NEWLINE = auto()
    EOF = auto()


# Reserved words, from the manual's Keywords list.
KEYWORDS = {
    "#define", "and", "andwhile", "as", "boolean",
    "continue", "dim", "do", "else", "elseif",
    "end", "evaluate", "exit", "explicit", "false",
    "for", "gosub", "goto", "if", "integer",
    "loop", "mod", "next", "not", "option",
    "or", "print", "return", "step", "terminate",
    "then", "to", "tobool", "true", "until",
    "while", "xor",
}

# Built-in functions (device I/O + math). Not reserved words -- these are
# ordinary identifiers that happen to be recognized by codegen -- but it's
# useful for the lexer/parser to know about them for tooling (e.g. syntax
# highlighting, "did you mean" errors).
BUILTIN_FUNCTIONS = {
    "abs", "atan", "cos", "sin", "sqrt",
    "setconfig", "setcommand", "getconfig", "getvalue",
    "settimercount", "settimerstate", "gettimercount", "gettimerstate",
    "wait",
}

# Multi-character operators must be listed before their single-character
# prefixes so the lexer's maximal-munch scan matches them first.
MULTI_CHAR_OPERATORS = [
    "<<=", ">>=",
    "++", "--", "<<", ">>", "<=", ">=", "<>",
    "+=", "-=", "*=", "/=",
]

SINGLE_CHAR_OPERATORS = set("+-*/=<>")


class Token:
    __slots__ = ("type", "value", "line", "col")

    def __init__(self, type_: TokenType, value: str, line: int, col: int):
        self.type = type_
        self.value = value
        self.line = line
        self.col = col

    def __repr__(self) -> str:
        return f"Token({self.type.name}, {self.value!r}, line={self.line}, col={self.col})"

    def __eq__(self, other) -> bool:
        if not isinstance(other, Token):
            return NotImplemented
        return (self.type, self.value) == (other.type, other.value)
