"""
    pygments.lexers.func
    ~~~~~~~~~~~~~~~~~~~~

    Lexers for FunC.

    :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
    :license: BSD, see LICENSE for details.
"""

from pygments.lexer import RegexLexer, include, words
from pygments.token import Text, Comment, Operator, Keyword, Name, String, Number, Whitespace, Punctuation

__all__ = ["FuncLexer"]


class FuncLexer(RegexLexer):
    """
    For FunC source code.
    """

    name = "FunC"
    aliases = ["func", "fc"]
    filenames = ["*.fc", "*.func"]

    # 1. Does not start from "
    # 2. Can start from ` and end with `, containing any character
    # 3. Starts with underscore or { or } and have more than 1 character after it
    # 4. Starts with letter, contains letters, numbers and underscores
    identifier = r'(?!")(`([^`]+)`|((?=_)_|(?=\{)\{|(?=\})\}|(?![_`{}]))([^;,\[\]\(\)\s~.]+))'

    tokens = {
        "root": [
            (r"\n", Whitespace),
            (r"\s+", Whitespace),
            include("keywords"),
            include("strings"),
            include("directives"),
            include("numeric"),
            include("comments"),
            include("storage"),
            include("functions"),
            include("variables"),
            (r"[.;(),\[\]~{}]", Punctuation),
        ],
        "keywords": [
            (
                words(
                    (
                        "<=>",
                        ">=",
                        "<=",
                        "!=",
                        "==",
                        "^>>",
                        "~>>",
                        ">>",
                        "<<",
                        "/%",
                        "^%",
                        "~%",
                        "^/",
                        "~/",
                        "+=",
                        "-=",
                        "*=",
                        "/=",
                        "~/=",
                        "^/=",
                        "%=",
                        "^%=",
                        "<<=",
                        ">>=",
                        "~>>=",
                        "^>>=",
                        "&=",
                        "|=",
                        "^=",
                        "^",
                        "=",
                        "~",
                        "/",
                        "%",
                        "-",
                        "*",
                        "+",
                        ">",
                        "<",
                        "&",
                        "|",
                        ":",
                        "?",
                    ),
                    prefix=r"(?<=\s)",
                    suffix=r"(?=\s)",
                ),
                Operator,
            ),
            (
                words(
                    (
                        "if",
                        "ifnot",
                        "else",
                        "elseif",
                        "elseifnot",
                        "while",
                        "do",
                        "until",
                        "repeat",
                        "return",
                        "impure",
                        "method_id",
                        "forall",
                        "asm",
                        "inline",
                        "inline_ref",
                    ),
                    prefix=r"\b",
                    suffix=r"\b",
                ),
                Keyword,
            ),
            (words(("true", "false"), prefix=r"\b", suffix=r"\b"), Keyword.Constant),
        ],
        "directives": [
            (r"#include|#pragma", Keyword, "directive"),
        ],
        "directive": [
            include("strings"),
            (r"\s+", Whitespace),
            (r"version|not-version", Keyword),
            (r"(>=|<=|=|>|<|\^)?([0-9]+)(.[0-9]+)?(.[0-9]+)?", Number),  # version
            (r";", Text, "#pop"),
        ],
        "strings": [
            (r"\"([^\n\"]+)\"[Hhcusa]?", String),
        ],
        "numeric": [(r"\b(-?(?!_)([\d_]+|0x[\d_a-fA-F]+)|0b[1_0]+)(?<!_)(?=[\s\)\],;])", Number)],
        "comments": [
            (r";;([^\n]*)", Comment.Singleline),
            (r"\{-", Comment.Multiline, "comment"),
        ],
        "comment": [
            (r"[^-}{]+", Comment.Multiline),
            (r"\{-", Comment.Multiline, "#push"),
            (r"-\}", Comment.Multiline, "#pop"),
            (r"[-}{]", Comment.Multiline),
        ],
        "storage": [
            (
                words(
                    ("var", "int", "slice", "tuple", "cell", "builder", "cont", "_"),
                    prefix=r"\b",
                    suffix=r"(?=[\s\(\),\[\]])",
                ),
                Keyword.Type,
            ),
            (words(("global", "const"), prefix=r"\b", suffix=r"\b"), Keyword.Constant),
        ],
        "variables": [
            (identifier, Name.Variable),
        ],
        "functions": [
            # identifier followed by (
            (identifier + r"(?=[\(])", Name.Function),
        ],
    }
