"""
    pygments.lexers.bibtex
    ~~~~~~~~~~~~~~~~~~~~~~

    Lexers for BibTeX bibliography data and styles

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

import re

from pygments.lexer import RegexLexer, ExtendedRegexLexer, include, default, words
from pygments.token import Name, Comment, String, Error, Number, Keyword, Punctuation, Whitespace

__all__ = ["BibTeXLexer", "BSTLexer"]


class BibTeXLexer(ExtendedRegexLexer):
    """
    A lexer for BibTeX bibliography data format.

    .. versionadded:: 2.2
    """

    name = "BibTeX"
    aliases = ["bibtex", "bib"]
    filenames = ["*.bib"]
    mimetypes = ["text/x-bibtex"]
    flags = re.IGNORECASE

    ALLOWED_CHARS = r"@!$&*+\-./:;<>?\[\\\]^`|~"
    IDENTIFIER = "[{}][{}]*".format("a-z_" + ALLOWED_CHARS, r"\w" + ALLOWED_CHARS)

    def open_brace_callback(self, match, ctx):
        opening_brace = match.group()
        ctx.opening_brace = opening_brace
        yield match.start(), Punctuation, opening_brace
        ctx.pos = match.end()

    def close_brace_callback(self, match, ctx):
        closing_brace = match.group()
        if ctx.opening_brace == "{" and closing_brace != "}" or ctx.opening_brace == "(" and closing_brace != ")":
            yield match.start(), Error, closing_brace
        else:
            yield match.start(), Punctuation, closing_brace
        del ctx.opening_brace
        ctx.pos = match.end()

    tokens = {
        "root": [
            include("whitespace"),
            (r"@comment(?!ary)", Comment),
            ("@preamble", Name.Class, ("closing-brace", "value", "opening-brace")),
            ("@string", Name.Class, ("closing-brace", "field", "opening-brace")),
            ("@" + IDENTIFIER, Name.Class, ("closing-brace", "command-body", "opening-brace")),
            (".+", Comment),
        ],
        "opening-brace": [
            include("whitespace"),
            (r"[{(]", open_brace_callback, "#pop"),
        ],
        "closing-brace": [
            include("whitespace"),
            (r"[})]", close_brace_callback, "#pop"),
        ],
        "command-body": [
            include("whitespace"),
            (r"[^\s\,\}]+", Name.Label, ("#pop", "fields")),
        ],
        "fields": [
            include("whitespace"),
            (",", Punctuation, "field"),
            default("#pop"),
        ],
        "field": [
            include("whitespace"),
            (IDENTIFIER, Name.Attribute, ("value", "=")),
            default("#pop"),
        ],
        "=": [
            include("whitespace"),
            ("=", Punctuation, "#pop"),
        ],
        "value": [
            include("whitespace"),
            (IDENTIFIER, Name.Variable),
            ('"', String, "quoted-string"),
            (r"\{", String, "braced-string"),
            (r"[\d]+", Number),
            ("#", Punctuation),
            default("#pop"),
        ],
        "quoted-string": [
            (r"\{", String, "braced-string"),
            ('"', String, "#pop"),
            (r"[^\{\"]+", String),
        ],
        "braced-string": [
            (r"\{", String, "#push"),
            (r"\}", String, "#pop"),
            (r"[^\{\}]+", String),
        ],
        "whitespace": [
            (r"\s+", Whitespace),
        ],
    }


class BSTLexer(RegexLexer):
    """
    A lexer for BibTeX bibliography styles.

    .. versionadded:: 2.2
    """

    name = "BST"
    aliases = ["bst", "bst-pybtex"]
    filenames = ["*.bst"]
    flags = re.IGNORECASE | re.MULTILINE

    tokens = {
        "root": [
            include("whitespace"),
            (words(["read", "sort"]), Keyword),
            (words(["execute", "integers", "iterate", "reverse", "strings"]), Keyword, ("group")),
            (words(["function", "macro"]), Keyword, ("group", "group")),
            (words(["entry"]), Keyword, ("group", "group", "group")),
        ],
        "group": [
            include("whitespace"),
            (r"\{", Punctuation, ("#pop", "group-end", "body")),
        ],
        "group-end": [
            include("whitespace"),
            (r"\}", Punctuation, "#pop"),
        ],
        "body": [
            include("whitespace"),
            (r"\'[^#\"\{\}\s]+", Name.Function),
            (r"[^#\"\{\}\s]+\$", Name.Builtin),
            (r"[^#\"\{\}\s]+", Name.Variable),
            (r'"[^\"]*"', String),
            (r"#-?\d+", Number),
            (r"\{", Punctuation, ("group-end", "body")),
            default("#pop"),
        ],
        "whitespace": [
            (r"\s+", Whitespace),
            ("%.*?$", Comment.Single),
        ],
    }
