Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
sql.py1112 linesDownload Raw Back to lexers
1"""2    pygments.lexers.sql3    ~~~~~~~~~~~~~~~~~~~4 5    Lexers for various SQL dialects and related interactive sessions.6 7    Postgres specific lexers:8 9    `PostgresLexer`10        A SQL lexer for the PostgreSQL dialect. Differences w.r.t. the SQL11        lexer are:12 13        - keywords and data types list parsed from the PG docs (run the14          `_postgres_builtins` module to update them);15        - Content of $-strings parsed using a specific lexer, e.g. the content16          of a PL/Python function is parsed using the Python lexer;17        - parse PG specific constructs: E-strings, $-strings, U&-strings,18          different operators and punctuation.19 20    `PlPgsqlLexer`21        A lexer for the PL/pgSQL language. Adds a few specific construct on22        top of the PG SQL lexer (such as <<label>>).23 24    `PostgresConsoleLexer`25        A lexer to highlight an interactive psql session:26 27        - identifies the prompt and does its best to detect the end of command28          in multiline statement where not all the lines are prefixed by a29          prompt, telling them apart from the output;30        - highlights errors in the output and notification levels;31        - handles psql backslash commands.32 33    `PostgresExplainLexer`34        A lexer to highlight Postgres execution plan.35 36    The ``tests/examplefiles`` contains a few test files with data to be37    parsed by these lexers.38 39    :copyright: Copyright 2006-present by the Pygments team, see AUTHORS.40    :license: BSD, see LICENSE for details.41"""42 43import collections44import re45 46from pygments.lexer import Lexer, RegexLexer, do_insertions, bygroups, words47from pygments.lexers import _googlesql_builtins48from pygments.lexers import _mysql_builtins49from pygments.lexers import _postgres_builtins50from pygments.lexers import _sql_builtins51from pygments.lexers import _tsql_builtins52from pygments.lexers import get_lexer_by_name, ClassNotFound53from pygments.token import Punctuation, Whitespace, Text, Comment, Operator, \54    Keyword, Name, String, Number, Generic, Literal55 56 57__all__ = ['GoogleSqlLexer', 'PostgresLexer', 'PlPgsqlLexer',58           'PostgresConsoleLexer', 'PostgresExplainLexer', 'SqlLexer',59           'TransactSqlLexer', 'MySqlLexer', 'SqliteConsoleLexer', 'RqlLexer']60 61line_re  = re.compile('.*?\n')62sqlite_prompt_re = re.compile(r'^(?:sqlite|   ...)>(?= )')63 64language_re = re.compile(r"\s+LANGUAGE\s+'?(\w+)'?", re.IGNORECASE)65 66do_re = re.compile(r'\bDO\b', re.IGNORECASE)67 68# Regular expressions for analyse_text()69name_between_bracket_re = re.compile(r'\[[a-zA-Z_]\w*\]')70name_between_backtick_re = re.compile(r'`[a-zA-Z_]\w*`')71tsql_go_re = re.compile(r'\bgo\b', re.IGNORECASE)72tsql_declare_re = re.compile(r'\bdeclare\s+@', re.IGNORECASE)73tsql_variable_re = re.compile(r'@[a-zA-Z_]\w*\b')74 75# Identifiers for analyse_text()76googlesql_identifiers = (77    _googlesql_builtins.functionnames78    + _googlesql_builtins.keywords79    + _googlesql_builtins.types)80 81 82def language_callback(lexer, match):83    """Parse the content of a $-string using a lexer84 85    The lexer is chosen looking for a nearby LANGUAGE or assumed as86    plpgsql if inside a DO statement and no LANGUAGE has been found.87    """88    lx = None89    m = language_re.match(lexer.text[match.end():match.end()+100])90    if m is not None:91        lx = lexer._get_lexer(m.group(1))92    else:93        m = list(language_re.finditer(94            lexer.text[max(0, match.start()-100):match.start()]))95        if m:96            lx = lexer._get_lexer(m[-1].group(1))97        else:98            m = list(do_re.finditer(99                lexer.text[max(0, match.start()-25):match.start()]))100            if m:101                lx = lexer._get_lexer('plpgsql')102 103    # 1 = $, 2 = delimiter, 3 = $104    yield (match.start(1), String, match.group(1))105    yield (match.start(2), String.Delimiter, match.group(2))106    yield (match.start(3), String, match.group(3))107    # 4 = string contents108    if lx:109        yield from lx.get_tokens_unprocessed(match.group(4))110    else:111        yield (match.start(4), String, match.group(4))112    # 5 = $, 6 = delimiter, 7 = $113    yield (match.start(5), String, match.group(5))114    yield (match.start(6), String.Delimiter, match.group(6))115    yield (match.start(7), String, match.group(7))116 117 118class PostgresBase:119    """Base class for Postgres-related lexers.120 121    This is implemented as a mixin to avoid the Lexer metaclass kicking in.122    this way the different lexer don't have a common Lexer ancestor. If they123    had, _tokens could be created on this ancestor and not updated for the124    other classes, resulting e.g. in PL/pgSQL parsed as SQL. This shortcoming125    seem to suggest that regexp lexers are not really subclassable.126    """127    def get_tokens_unprocessed(self, text, *args):128        # Have a copy of the entire text to be used by `language_callback`.129        self.text = text130        yield from super().get_tokens_unprocessed(text, *args)131 132    def _get_lexer(self, lang):133        if lang.lower() == 'sql':134            return get_lexer_by_name('postgresql', **self.options)135 136        tries = [lang]137        if lang.startswith('pl'):138            tries.append(lang[2:])139        if lang.endswith('u'):140            tries.append(lang[:-1])141        if lang.startswith('pl') and lang.endswith('u'):142            tries.append(lang[2:-1])143 144        for lx in tries:145            try:146                return get_lexer_by_name(lx, **self.options)147            except ClassNotFound:148                pass149        else:150            # TODO: better logging151            # print >>sys.stderr, "language not found:", lang152            return None153 154 155class PostgresLexer(PostgresBase, RegexLexer):156    """157    Lexer for the PostgreSQL dialect of SQL.158    """159 160    name = 'PostgreSQL SQL dialect'161    aliases = ['postgresql', 'postgres']162    mimetypes = ['text/x-postgresql']163    url = 'https://www.postgresql.org'164    version_added = '1.5'165 166    flags = re.IGNORECASE167    tokens = {168        'root': [169            (r'\s+', Whitespace),170            (r'--.*\n?', Comment.Single),171            (r'/\*', Comment.Multiline, 'multiline-comments'),172            (r'(' + '|'.join(s.replace(" ", r"\s+")173                             for s in _postgres_builtins.DATATYPES +174                             _postgres_builtins.PSEUDO_TYPES) + r')\b',175             Name.Builtin),176            (words(_postgres_builtins.KEYWORDS, suffix=r'\b'), Keyword),177            (r'[+*/<>=~!@#%^&|`?-]+', Operator),178            (r'::', Operator),  # cast179            (r'\$\d+', Name.Variable),180            (r'([0-9]*\.[0-9]*|[0-9]+)(e[+-]?[0-9]+)?', Number.Float),181            (r'[0-9]+', Number.Integer),182            (r"((?:E|U&)?)(')", bygroups(String.Affix, String.Single), 'string'),183            # quoted identifier184            (r'((?:U&)?)(")', bygroups(String.Affix, String.Name), 'quoted-ident'),185            (r'(?s)(\$)([^$]*)(\$)(.*?)(\$)(\2)(\$)', language_callback),186            (r'[a-z_]\w*', Name),187 188            # psql variable in SQL189            (r""":(['"]?)[a-z]\w*\b\1""", Name.Variable),190 191            (r'[;:()\[\]{},.]', Punctuation),192        ],193        'multiline-comments': [194            (r'/\*', Comment.Multiline, 'multiline-comments'),195            (r'\*/', Comment.Multiline, '#pop'),196            (r'[^/*]+', Comment.Multiline),197            (r'[/*]', Comment.Multiline)198        ],199        'string': [200            (r"[^']+", String.Single),201            (r"''", String.Single),202            (r"'", String.Single, '#pop'),203        ],204        'quoted-ident': [205            (r'[^"]+', String.Name),206            (r'""', String.Name),207            (r'"', String.Name, '#pop'),208        ],209    }210 211 212class PlPgsqlLexer(PostgresBase, RegexLexer):213    """214    Handle the extra syntax in Pl/pgSQL language.215    """216    name = 'PL/pgSQL'217    aliases = ['plpgsql']218    mimetypes = ['text/x-plpgsql']219    url = 'https://www.postgresql.org/docs/current/plpgsql.html'220    version_added = '1.5'221 222    flags = re.IGNORECASE223    # FIXME: use inheritance224    tokens = {name: state[:] for (name, state) in PostgresLexer.tokens.items()}225 226    # extend the keywords list227    for i, pattern in enumerate(tokens['root']):228        if pattern[1] == Keyword:229            tokens['root'][i] = (230                words(_postgres_builtins.KEYWORDS +231                      _postgres_builtins.PLPGSQL_KEYWORDS, suffix=r'\b'),232                Keyword)233            del i234            break235    else:236        assert 0, "SQL keywords not found"237 238    # Add specific PL/pgSQL rules (before the SQL ones)239    tokens['root'][:0] = [240        (r'\%[a-z]\w*\b', Name.Builtin),     # actually, a datatype241        (r':=', Operator),242        (r'\<\<[a-z]\w*\>\>', Name.Label),243        (r'\#[a-z]\w*\b', Keyword.Pseudo),   # #variable_conflict244    ]245 246 247class PsqlRegexLexer(PostgresBase, RegexLexer):248    """249    Extend the PostgresLexer adding support specific for psql commands.250 251    This is not a complete psql lexer yet as it lacks prompt support252    and output rendering.253    """254 255    name = 'PostgreSQL console - regexp based lexer'256    aliases = []    # not public257 258    flags = re.IGNORECASE259    tokens = {name: state[:] for (name, state) in PostgresLexer.tokens.items()}260 261    tokens['root'].append(262        (r'\\[^\s]+', Keyword.Pseudo, 'psql-command'))263    tokens['psql-command'] = [264        (r'\n', Text, 'root'),265        (r'\s+', Whitespace),266        (r'\\[^\s]+', Keyword.Pseudo),267        (r""":(['"]?)[a-z]\w*\b\1""", Name.Variable),268        (r"'(''|[^'])*'", String.Single),269        (r"`([^`])*`", String.Backtick),270        (r"[^\s]+", String.Symbol),271    ]272 273 274re_prompt = re.compile(r'^(\S.*?)??[=\-\(\$\'\"][#>]')275re_psql_command = re.compile(r'\s*\\')276re_end_command = re.compile(r';\s*(--.*?)?$')277re_psql_command = re.compile(r'(\s*)(\\.+?)(\s+)$')278re_error = re.compile(r'(ERROR|FATAL):')279re_message = re.compile(280    r'((?:DEBUG|INFO|NOTICE|WARNING|ERROR|'281    r'FATAL|HINT|DETAIL|CONTEXT|LINE [0-9]+):)(.*?\n)')282 283 284class lookahead:285    """Wrap an iterator and allow pushing back an item."""286    def __init__(self, x):287        self.iter = iter(x)288        self._nextitem = None289 290    def __iter__(self):291        return self292 293    def send(self, i):294        self._nextitem = i295        return i296 297    def __next__(self):298        if self._nextitem is not None:299            ni = self._nextitem300            self._nextitem = None301            return ni302        return next(self.iter)303    next = __next__304 305 306class PostgresConsoleLexer(Lexer):307    """308    Lexer for psql sessions.309    """310 311    name = 'PostgreSQL console (psql)'312    aliases = ['psql', 'postgresql-console', 'postgres-console']313    mimetypes = ['text/x-postgresql-psql']314    url = 'https://www.postgresql.org'315    version_added = '1.5'316    _example = "psql/psql_session.txt"317 318    def get_tokens_unprocessed(self, data):319        sql = PsqlRegexLexer(**self.options)320 321        lines = lookahead(line_re.findall(data))322 323        # prompt-output cycle324        while 1:325 326            # consume the lines of the command: start with an optional prompt327            # and continue until the end of command is detected328            curcode = ''329            insertions = []330            for line in lines:331                # Identify a shell prompt in case of psql commandline example332                if line.startswith('$') and not curcode:333                    lexer = get_lexer_by_name('console', **self.options)334                    yield from lexer.get_tokens_unprocessed(line)335                    break336 337                # Identify a psql prompt338                mprompt = re_prompt.match(line)339                if mprompt is not None:340                    insertions.append((len(curcode),341                                       [(0, Generic.Prompt, mprompt.group())]))342                    curcode += line[len(mprompt.group()):]343                else:344                    curcode += line345 346                # Check if this is the end of the command347                # TODO: better handle multiline comments at the end with348                # a lexer with an external state?349                if re_psql_command.match(curcode) \350                   or re_end_command.search(curcode):351                    break352 353            # Emit the combined stream of command and prompt(s)354            yield from do_insertions(insertions,355                                     sql.get_tokens_unprocessed(curcode))356 357            # Emit the output lines358            out_token = Generic.Output359            for line in lines:360                mprompt = re_prompt.match(line)361                if mprompt is not None:362                    # push the line back to have it processed by the prompt363                    lines.send(line)364                    break365 366                mmsg = re_message.match(line)367                if mmsg is not None:368                    if mmsg.group(1).startswith("ERROR") \369                       or mmsg.group(1).startswith("FATAL"):370                        out_token = Generic.Error371                    yield (mmsg.start(1), Generic.Strong, mmsg.group(1))372                    yield (mmsg.start(2), out_token, mmsg.group(2))373                else:374                    yield (0, out_token, line)375            else:376                return377 378 379class PostgresExplainLexer(RegexLexer):380    """381    Handle PostgreSQL EXPLAIN output382    """383 384    name = 'PostgreSQL EXPLAIN dialect'385    aliases = ['postgres-explain']386    filenames = ['*.explain']387    mimetypes = ['text/x-postgresql-explain']388    url = 'https://www.postgresql.org/docs/current/using-explain.html'389    version_added = '2.15'390 391    tokens = {392        'root': [393            (r'(:|\(|\)|ms|kB|->|\.\.|\,|\/|=|%)', Punctuation),394            (r'(\s+)', Whitespace),395 396            # This match estimated cost and effectively measured counters with ANALYZE397            # Then, we move to instrumentation state398            (r'(cost)(=?)', bygroups(Name.Class, Punctuation), 'instrumentation'),399            (r'(actual)( )(=?)', bygroups(Name.Class, Whitespace, Punctuation), 'instrumentation'),400 401            # Misc keywords402            (words(('actual', 'Memory Usage', 'Disk Usage', 'Memory', 'Buckets',403                    'Batches', 'originally', 'row', 'rows', 'Hits', 'Misses',404                    'Evictions', 'Overflows', 'Planned Partitions', 'Estimates',405                    'capacity', 'distinct keys', 'lookups', 'hit percent',406                    'Index Searches', 'Storage', 'Disk Maximum Storage'), suffix=r'\b'),407             Comment.Single),408 409            (r'(hit|read|dirtied|written|write|time|calls)(=)', bygroups(Comment.Single, Operator)),410            (r'(shared|temp|local)', Keyword.Pseudo),411 412            # We move to sort state in order to emphasize specific keywords (especially disk access)413            (r'(Sort Method)(: )', bygroups(Comment.Preproc, Punctuation), 'sort'),414 415            # These keywords can be followed by an object, like a table416            (r'(Sort Key|Group Key|Presorted Key|Hash Key)(:)( )',417             bygroups(Comment.Preproc, Punctuation, Whitespace), 'object_name'),418            (r'(Cache Key|Cache Mode)(:)( )', bygroups(Comment, Punctuation, Whitespace), 'object_name'),419 420            # These keywords can be followed by a predicate421            (words(('Join Filter', 'Subplans Removed', 'Filter', 'Merge Cond',422                    'Hash Cond', 'Index Cond', 'Recheck Cond', 'Heap Blocks',423                    'TID Cond', 'Run Condition', 'Order By', 'Function Call',424                    'Table Function Call', 'Inner Unique', 'Params Evaluated',425                    'Single Copy', 'Sampling', 'One-Time Filter', 'Output',426                    'Relations', 'Remote SQL', 'Disabled'), suffix=r'\b'),427             Comment.Preproc, 'predicate'),428 429            # Special keyword to handle ON CONFLICT430            (r'Conflict ', Comment.Preproc, 'conflict'),431 432            # Special keyword for InitPlan or SubPlan433            (r'(InitPlan|SubPlan)( )(\d+)( )',434             bygroups(Keyword, Whitespace, Number.Integer, Whitespace),435             'init_plan'),436 437            (words(('Sort Method', 'Join Filter', 'Planning time',438                    'Planning Time', 'Execution time', 'Execution Time',439                    'Workers Planned', 'Workers Launched', 'Buffers',440                    'Planning', 'Worker', 'Query Identifier', 'Time',441                    'Full-sort Groups', 'Pre-sorted Groups'), suffix=r'\b'), Comment.Preproc),442 443            # Emphasize these keywords444 445            (words(('Rows Removed by Join Filter', 'Rows Removed by Filter',446                    'Rows Removed by Index Recheck',447                    'Heap Fetches', 'never executed'),448                   suffix=r'\b'), Name.Exception),449            (r'(I/O Timings)(:)( )', bygroups(Name.Exception, Punctuation, Whitespace)),450 451            (words(_postgres_builtins.EXPLAIN_KEYWORDS, suffix=r'\b'), Keyword),452 453            # join keywords454            (r'((Right|Left|Full|Semi|Anti) Join)', Keyword.Type),455            (r'(Parallel |Async |Finalize |Partial )', Comment.Preproc),456            (r'Backward', Comment.Preproc),457            (r'(Intersect|Except|Hash)', Comment.Preproc),458 459            (r'(CTE)( )(\w*)?', bygroups(Comment, Whitespace, Name.Variable)),460 461 462            # Treat "on" and "using" as a punctuation463            (r'(on|using)', Punctuation, 'object_name'),464 465 466            # strings467            (r"'(''|[^'])*'", String.Single),468            # numbers469            (r'-?\d+\.\d+', Number.Float),470            (r'(-?\d+)', Number.Integer),471 472            # boolean473            (r'(true|false)', Name.Constant),474            # explain header475            (r'\s*QUERY PLAN\s*\n\s*-+', Comment.Single),476            # Settings477            (r'(Settings)(:)( )', bygroups(Comment.Preproc, Punctuation, Whitespace), 'setting'),478 479            # Handle JIT counters480            (r'(JIT|Functions|Options|Timing)(:)', bygroups(Comment.Preproc, Punctuation)),481            (r'(Inlining|Optimization|Expressions|Deforming|Generation|Emission|Total)', Keyword.Pseudo),482 483            # Handle Triggers counters484            (r'(Trigger)( )(\S*)(:)( )',485             bygroups(Comment.Preproc, Whitespace, Name.Variable, Punctuation, Whitespace)),486 487        ],488        'expression': [489            # matches any kind of parenthesized expression490            # the first opening paren is matched by the 'caller'491            (r'\(', Punctuation, '#push'),492            (r'\)', Punctuation, '#pop'),493            (r'(never executed)', Name.Exception),494            (r'[^)(]+', Comment),495        ],496        'object_name': [497 498            # This is a cost or analyze measure499            (r'(\(cost)(=?)', bygroups(Name.Class, Punctuation), 'instrumentation'),500            (r'(\(actual)( )(=?)', bygroups(Name.Class, Whitespace, Punctuation), 'instrumentation'),501 502            # if object_name is parenthesized, mark opening paren as503            # punctuation, call 'expression', and exit state504            (r'\(', Punctuation, 'expression'),505            (r'(on)', Punctuation),506            # matches possibly schema-qualified table and column names507            (r'\w+(\.\w+)*( USING \S+| \w+ USING \S+)', Name.Variable),508            (r'\"?\w+\"?(?:\.\"?\w+\"?)?', Name.Variable),509            (r'\'\S*\'', Name.Variable),510 511            # if we encounter a comma, another object is listed512            (r',\n', Punctuation, 'object_name'),513            (r',', Punctuation, 'object_name'),514 515            # special case: "*SELECT*"516            (r'"\*SELECT\*( \d+)?"(.\w+)?', Name.Variable),517            (r'"\*VALUES\*(_\d+)?"(.\w+)?', Name.Variable),518            (r'"ANY_subquery"', Name.Variable),519 520            # Variable $1 ...521            (r'\$\d+', Name.Variable),522            # cast523            (r'::\w+', Name.Variable),524            (r' +', Whitespace),525            (r'"', Punctuation),526            (r'\[\.\.\.\]', Punctuation),527            (r'\)', Punctuation, '#pop'),528        ],529        'predicate': [530            # if predicate is parenthesized, mark paren as punctuation531            (r'(\()([^\n]*)(\))', bygroups(Punctuation, Name.Variable, Punctuation), '#pop'),532            # otherwise color until newline533            (r'[^\n]*', Name.Variable, '#pop'),534        ],535        'instrumentation': [536            (r'=|\.\.', Punctuation),537            (r' +', Whitespace),538            (r'(rows|width|time|loops)', Name.Class),539            (r'\d+\.\d+', Number.Float),540            (r'(\d+)', Number.Integer),541            (r'\)', Punctuation, '#pop'),542        ],543        'conflict': [544            (r'(Resolution: )(\w+)', bygroups(Comment.Preproc, Name.Variable)),545            (r'(Arbiter \w+:)', Comment.Preproc, 'object_name'),546            (r'(Filter: )', Comment.Preproc, 'predicate'),547        ],548        'setting': [549            (r'([a-z_]*?)(\s*)(=)(\s*)(\'.*?\')', bygroups(Name.Attribute, Whitespace, Operator, Whitespace, String)),550            (r'\, ', Punctuation),551        ],552        'init_plan': [553            (r'\(', Punctuation),554            (r'returns \$\d+(,\$\d+)?', Name.Variable),555            (r'\)', Punctuation, '#pop'),556        ],557        'sort': [558            (r':|kB', Punctuation),559            (r'(quicksort|top-N|heapsort|Average|Memory|Peak)', Comment.Prepoc),560            (r'(external|merge|Disk|sort)', Name.Exception),561            (r'(\d+)', Number.Integer),562            (r' +', Whitespace),563        ],564    }565 566 567class SqlLexer(RegexLexer):568    """569    Lexer for Structured Query Language. Currently, this lexer does570    not recognize any special syntax except ANSI SQL.571    """572 573    name = 'SQL'574    aliases = ['sql']575    filenames = ['*.sql']576    mimetypes = ['text/x-sql']577    url = 'https://en.wikipedia.org/wiki/SQL'578    version_added = ''579 580    flags = re.IGNORECASE581    tokens = {582        'root': [583            (r'\s+', Whitespace),584            (r'--.*\n?', Comment.Single),585            (r'/\*', Comment.Multiline, 'multiline-comments'),586            (words(_sql_builtins.KEYWORDS, suffix=r'\b'), Keyword),587            (words(_sql_builtins.DATATYPES, suffix=r'\b'), Name.Builtin),588            (r'[+*/<>=~!@#%^&|`?-]', Operator),589            (r'[0-9]+', Number.Integer),590            # TODO: Backslash escapes?591            (r"'(''|[^'])*'", String.Single),592            (r'"(""|[^"])*"', String.Symbol),  # not a real string literal in ANSI SQL593            (r'[a-z_][\w$]*', Name),  # allow $s in strings for Oracle594            (r'[;:()\[\],.]', Punctuation)595        ],596        'multiline-comments': [597            (r'/\*', Comment.Multiline, 'multiline-comments'),598            (r'\*/', Comment.Multiline, '#pop'),599            (r'[^/*]+', Comment.Multiline),600            (r'[/*]', Comment.Multiline)601        ]602    }603 604    def analyse_text(self, text):605        return606 607 608class TransactSqlLexer(RegexLexer):609    """610    Transact-SQL (T-SQL) is Microsoft's and Sybase's proprietary extension to611    SQL.612 613    The list of keywords includes ODBC and keywords reserved for future use.614    """615 616    name = 'Transact-SQL'617    aliases = ['tsql', 't-sql']618    filenames = ['*.sql']619    mimetypes = ['text/x-tsql']620    url = 'https://www.tsql.info'621    version_added = ''622 623    flags = re.IGNORECASE624 625    tokens = {626        'root': [627            (r'\s+', Whitespace),628            (r'--.*[$|\n]?', Comment.Single),629            (r'/\*', Comment.Multiline, 'multiline-comments'),630            (words(_tsql_builtins.OPERATORS), Operator),631            (words(_tsql_builtins.OPERATOR_WORDS, suffix=r'\b'), Operator.Word),632            (words(_tsql_builtins.TYPES, suffix=r'\b'), Name.Class),633            (words(_tsql_builtins.FUNCTIONS, suffix=r'\b'), Name.Function),634            (r'(goto)(\s+)(\w+\b)', bygroups(Keyword, Whitespace, Name.Label)),635            (words(_tsql_builtins.KEYWORDS, suffix=r'\b'), Keyword),636            (r'(\[)([^]]+)(\])', bygroups(Operator, Name, Operator)),637            (r'0x[0-9a-f]+', Number.Hex),638            # Float variant 1, for example: 1., 1.e2, 1.2e3639            (r'[0-9]+\.[0-9]*(e[+-]?[0-9]+)?', Number.Float),640            # Float variant 2, for example: .1, .1e2641            (r'\.[0-9]+(e[+-]?[0-9]+)?', Number.Float),642            # Float variant 3, for example: 123e45643            (r'[0-9]+e[+-]?[0-9]+', Number.Float),644            (r'[0-9]+', Number.Integer),645            (r"'(''|[^'])*'", String.Single),646            (r'"(""|[^"])*"', String.Symbol),647            (r'[;(),.]', Punctuation),648            # Below we use \w even for the first "real" character because649            # tokens starting with a digit have already been recognized650            # as Number above.651            (r'@@\w+', Name.Builtin),652            (r'@\w+', Name.Variable),653            (r'(\w+)(:)', bygroups(Name.Label, Punctuation)),654            (r'#?#?\w+', Name),  # names for temp tables and anything else655            (r'\?', Name.Variable.Magic),  # parameter for prepared statements656        ],657        'multiline-comments': [658            (r'/\*', Comment.Multiline, 'multiline-comments'),659            (r'\*/', Comment.Multiline, '#pop'),660            (r'[^/*]+', Comment.Multiline),661            (r'[/*]', Comment.Multiline)662        ]663    }664 665    def analyse_text(text):666        rating = 0667        if tsql_declare_re.search(text):668            # Found T-SQL variable declaration.669            rating = 1.0670        else:671            name_between_backtick_count = len(672                name_between_backtick_re.findall(text))673            name_between_bracket_count = len(674                name_between_bracket_re.findall(text))675            # We need to check if there are any names using676            # backticks or brackets, as otherwise both are 0677            # and 0 >= 2 * 0, so we would always assume it's true678            dialect_name_count = name_between_backtick_count + name_between_bracket_count679            if dialect_name_count >= 1 and \680               name_between_bracket_count >= 2 * name_between_backtick_count:681                # Found at least twice as many [name] as `name`.682                rating += 0.5683            elif name_between_bracket_count > name_between_backtick_count:684                rating += 0.2685            elif name_between_bracket_count > 0:686                rating += 0.1687            if tsql_variable_re.search(text) is not None:688                rating += 0.1689            if tsql_go_re.search(text) is not None:690                rating += 0.1691        return rating692 693 694class MySqlLexer(RegexLexer):695    """The Oracle MySQL lexer.696 697    This lexer does not attempt to maintain strict compatibility with698    MariaDB syntax or keywords. Although MySQL and MariaDB's common code699    history suggests there may be significant overlap between the two,700    compatibility between the two is not a target for this lexer.701    """702 703    name = 'MySQL'704    aliases = ['mysql']705    mimetypes = ['text/x-mysql']706    url = 'https://www.mysql.com'707    version_added = ''708 709    flags = re.IGNORECASE710    tokens = {711        'root': [712            (r'\s+', Whitespace),713 714            # Comments715            (r'(?:#|--\s+).*', Comment.Single),716            (r'/\*\+', Comment.Special, 'optimizer-hints'),717            (r'/\*', Comment.Multiline, 'multiline-comment'),718 719            # Hexadecimal literals720            (r"x'([0-9a-f]{2})+'", Number.Hex),  # MySQL requires paired hex characters in this form.721            (r'0x[0-9a-f]+', Number.Hex),722 723            # Binary literals724            (r"b'[01]+'", Number.Bin),725            (r'0b[01]+', Number.Bin),726 727            # Numeric literals728            (r'[0-9]+\.[0-9]*(e[+-]?[0-9]+)?', Number.Float),  # Mandatory integer, optional fraction and exponent729            (r'[0-9]*\.[0-9]+(e[+-]?[0-9]+)?', Number.Float),  # Mandatory fraction, optional integer and exponent730            (r'[0-9]+e[+-]?[0-9]+', Number.Float),  # Exponents with integer significands are still floats731            (r'[0-9]+(?=[^0-9a-z$_\u0080-\uffff])', Number.Integer),  # Integers that are not in a schema object name732 733            # Date literals734            (r"\{\s*d\s*(?P<quote>['\"])\s*\d{2}(\d{2})?.?\d{2}.?\d{2}\s*(?P=quote)\s*\}",735             Literal.Date),736 737            # Time literals738            (r"\{\s*t\s*(?P<quote>['\"])\s*(?:\d+\s+)?\d{1,2}.?\d{1,2}.?\d{1,2}(\.\d*)?\s*(?P=quote)\s*\}",739             Literal.Date),740 741            # Timestamp literals742            (743                r"\{\s*ts\s*(?P<quote>['\"])\s*"744                r"\d{2}(?:\d{2})?.?\d{2}.?\d{2}"  # Date part745                r"\s+"  # Whitespace between date and time746                r"\d{1,2}.?\d{1,2}.?\d{1,2}(\.\d*)?"  # Time part747                r"\s*(?P=quote)\s*\}",748                Literal.Date749            ),750 751            # String literals752            (r"'", String.Single, 'single-quoted-string'),753            (r'"', String.Double, 'double-quoted-string'),754 755            # Variables756            (r'@@(?:global\.|persist\.|persist_only\.|session\.)?[a-z_]+', Name.Variable),757            (r'@[a-z0-9_$.]+', Name.Variable),758            (r"@'", Name.Variable, 'single-quoted-variable'),759            (r'@"', Name.Variable, 'double-quoted-variable'),760            (r"@`", Name.Variable, 'backtick-quoted-variable'),761            (r'\?', Name.Variable),  # For demonstrating prepared statements762 763            # Operators764            (r'[!%&*+/:<=>^|~-]+', Operator),765 766            # Exceptions; these words tokenize differently in different contexts.767            (r'\b(set)(?!\s*\()', Keyword),768            (r'\b(character)(\s+)(set)\b', bygroups(Keyword, Whitespace, Keyword)),769            # In all other known cases, "SET" is tokenized by MYSQL_DATATYPES.770 771            (words(_mysql_builtins.MYSQL_CONSTANTS, prefix=r'\b', suffix=r'\b'),772             Name.Constant),773            (words(_mysql_builtins.MYSQL_DATATYPES, prefix=r'\b', suffix=r'\b'),774             Keyword.Type),775            (words(_mysql_builtins.MYSQL_KEYWORDS, prefix=r'\b', suffix=r'\b'),776             Keyword),777            (words(_mysql_builtins.MYSQL_FUNCTIONS, prefix=r'\b', suffix=r'\b(\s*)(\()'),778             bygroups(Name.Function, Whitespace, Punctuation)),779 780            # Schema object names781            #782            # Note: Although the first regex supports unquoted all-numeric783            # identifiers, this will not be a problem in practice because784            # numeric literals have already been handled above.785            #786            ('[0-9a-z$_\u0080-\uffff]+', Name),787            (r'`', Name.Quoted, 'schema-object-name'),788 789            # Punctuation790            (r'[(),.;]', Punctuation),791        ],792 793        # Multiline comment substates794        # ---------------------------795 796        'optimizer-hints': [797            (r'[^*a-z]+', Comment.Special),798            (r'\*/', Comment.Special, '#pop'),799            (words(_mysql_builtins.MYSQL_OPTIMIZER_HINTS, suffix=r'\b'),800             Comment.Preproc),801            ('[a-z]+', Comment.Special),802            (r'\*', Comment.Special),803        ],804 805        'multiline-comment': [806            (r'[^*]+', Comment.Multiline),807            (r'\*/', Comment.Multiline, '#pop'),808            (r'\*', Comment.Multiline),809        ],810 811        # String substates812        # ----------------813 814        'single-quoted-string': [815            (r"[^'\\]+", String.Single),816            (r"''", String.Escape),817            (r"""\\[0'"bnrtZ\\%_]""", String.Escape),818            (r"'", String.Single, '#pop'),819        ],820 821        'double-quoted-string': [822            (r'[^"\\]+', String.Double),823            (r'""', String.Escape),824            (r"""\\[0'"bnrtZ\\%_]""", String.Escape),825            (r'"', String.Double, '#pop'),826        ],827 828        # Variable substates829        # ------------------830 831        'single-quoted-variable': [832            (r"[^']+", Name.Variable),833            (r"''", Name.Variable),834            (r"'", Name.Variable, '#pop'),835        ],836 837        'double-quoted-variable': [838            (r'[^"]+', Name.Variable),839            (r'""', Name.Variable),840            (r'"', Name.Variable, '#pop'),841        ],842 843        'backtick-quoted-variable': [844            (r'[^`]+', Name.Variable),845            (r'``', Name.Variable),846            (r'`', Name.Variable, '#pop'),847        ],848 849        # Schema object name substates850        # ----------------------------851        #852        # "Name.Quoted" and "Name.Quoted.Escape" are non-standard but853        # formatters will style them as "Name" by default but add854        # additional styles based on the token name. This gives users855        # flexibility to add custom styles as desired.856        #857        'schema-object-name': [858            (r'[^`]+', Name.Quoted),859            (r'``', Name.Quoted.Escape),860            (r'`', Name.Quoted, '#pop'),861        ],862    }863 864    def analyse_text(text):865        rating = 0866        name_between_backtick_count = len(867            name_between_backtick_re.findall(text))868        name_between_bracket_count = len(869            name_between_bracket_re.findall(text))870        # Same logic as above in the TSQL analysis871        dialect_name_count = name_between_backtick_count + name_between_bracket_count872        if dialect_name_count >= 1 and \873           name_between_backtick_count >= 2 * name_between_bracket_count:874            # Found at least twice as many `name` as [name].875            rating += 0.5876        elif name_between_backtick_count > name_between_bracket_count:877            rating += 0.2878        elif name_between_backtick_count > 0:879            rating += 0.1880        return rating881 882 883class GoogleSqlLexer(RegexLexer):884    """885    GoogleSQL is Google's standard SQL dialect, formerly known as ZetaSQL.886 887    The list of keywords includes reserved words for future use.888    """889 890    name = 'GoogleSQL'891    aliases = ['googlesql', 'zetasql']892    filenames = ['*.googlesql', '*.googlesql.sql']893    mimetypes = ['text/x-google-sql', 'text/x-google-sql-aux']894    url = 'https://cloud.google.com/bigquery/googlesql'895    version_added = '2.19'896 897    flags = re.IGNORECASE898    tokens = {899        'root': [900            (r'\s+', Whitespace),901 902            # Comments903            (r'(?:#|--\s+).*', Comment.Single),904            (r'/\*', Comment.Multiline, 'multiline-comment'),905 906            # Hexadecimal literals907            (r"x'([0-9a-f]{2})+'", Number.Hex),908            (r'0x[0-9a-f]+', Number.Hex),909 910            # Binary literals911            (r"b'[01]+'", Number.Bin),912            (r'0b[01]+', Number.Bin),913 914            # Numeric literals915            (r'[0-9]+\.[0-9]*(e[+-]?[0-9]+)?', Number.Float),  # Mandatory integer, optional fraction and exponent916            (r'[0-9]*\.[0-9]+(e[+-]?[0-9]+)?', Number.Float),  # Mandatory fraction, optional integer and exponent917            (r'[0-9]+e[+-]?[0-9]+', Number.Float),  # Exponents with integer significands are still floats918            (r'[0-9]+(?=[^0-9a-z$_\u0080-\uffff])', Number.Integer),  # Integers that are not in a schema object name919 920            # Date literals921            (r"\{\s*d\s*(?P<quote>['\"])\s*\d{2}(\d{2})?.?\d{2}.?\d{2}\s*(?P=quote)\s*\}",922             Literal.Date),923 924            # Time literals925            (r"\{\s*t\s*(?P<quote>['\"])\s*(?:\d+\s+)?\d{1,2}.?\d{1,2}.?\d{1,2}(\.\d*)?\s*(?P=quote)\s*\}",926             Literal.Date),927 928            # Timestamp literals929            (930                r"\{\s*ts\s*(?P<quote>['\"])\s*"931                r"\d{2}(?:\d{2})?.?\d{2}.?\d{2}"  # Date part932                r"\s+"  # Whitespace between date and time933                r"\d{1,2}.?\d{1,2}.?\d{1,2}(\.\d*)?"  # Time part934                r"\s*(?P=quote)\s*\}",935                Literal.Date936            ),937 938            # String literals939            (r"'", String.Single, 'single-quoted-string'),940            (r'"', String.Double, 'double-quoted-string'),941 942            # Variables943            (r'@@(?:global\.|persist\.|persist_only\.|session\.)?[a-z_]+', Name.Variable),944            (r'@[a-z0-9_$.]+', Name.Variable),945            (r"@'", Name.Variable, 'single-quoted-variable'),946            (r'@"', Name.Variable, 'double-quoted-variable'),947            (r"@`", Name.Variable, 'backtick-quoted-variable'),948            (r'\?', Name.Variable),  # For demonstrating prepared statements949 950            # Exceptions; these words tokenize differently in different contexts.951            (r'\b(set)(?!\s*\()', Keyword),952            (r'\b(character)(\s+)(set)\b', bygroups(Keyword, Whitespace, Keyword)),953 954            # Constants, types, keywords, functions, operators955            (words(_googlesql_builtins.constants, prefix=r'\b', suffix=r'\b'), Name.Constant),956            (words(_googlesql_builtins.types, prefix=r'\b', suffix=r'\b'), Keyword.Type),957            (words(_googlesql_builtins.keywords, prefix=r'\b', suffix=r'\b'), Keyword),958            (words(_googlesql_builtins.functionnames, prefix=r'\b', suffix=r'\b(\s*)(\()'),959             bygroups(Name.Function, Whitespace, Punctuation)),960            (words(_googlesql_builtins.operators, prefix=r'\b', suffix=r'\b'), Operator),961 962            # Schema object names963            #964            # Note: Although the first regex supports unquoted all-numeric965            # identifiers, this will not be a problem in practice because966            # numeric literals have already been handled above.967            #968            ('[0-9a-z$_\u0080-\uffff]+', Name),969            (r'`', Name.Quoted, 'schema-object-name'),970 971            # Punctuation972            (r'[(),.;]', Punctuation),973        ],974 975        # Multiline comment substates976        # ---------------------------977 978        'multiline-comment': [979            (r'[^*]+', Comment.Multiline),980            (r'\*/', Comment.Multiline, '#pop'),981            (r'\*', Comment.Multiline),982        ],983 984        # String substates985        # ----------------986 987        'single-quoted-string': [988            (r"[^'\\]+", String.Single),989            (r"''", String.Escape),990            (r"""\\[0'"bnrtZ\\%_]""", String.Escape),991            (r"'", String.Single, '#pop'),992        ],993 994        'double-quoted-string': [995            (r'[^"\\]+', String.Double),996            (r'""', String.Escape),997            (r"""\\[0'"bnrtZ\\%_]""", String.Escape),998            (r'"', String.Double, '#pop'),999        ],1000 1001        # Variable substates1002        # ------------------1003 1004        'single-quoted-variable': [1005            (r"[^']+", Name.Variable),1006            (r"''", Name.Variable),1007            (r"'", Name.Variable, '#pop'),1008        ],1009 1010        'double-quoted-variable': [1011            (r'[^"]+', Name.Variable),1012            (r'""', Name.Variable),1013            (r'"', Name.Variable, '#pop'),1014        ],1015 1016        'backtick-quoted-variable': [1017            (r'[^`]+', Name.Variable),1018            (r'``', Name.Variable),1019            (r'`', Name.Variable, '#pop'),1020        ],1021 1022        # Schema object name substates1023        # ----------------------------1024        #1025        # "Name.Quoted" and "Name.Quoted.Escape" are non-standard but1026        # formatters will style them as "Name" by default but add1027        # additional styles based on the token name. This gives users1028        # flexibility to add custom styles as desired.1029        #1030        'schema-object-name': [1031            (r'[^`]+', Name.Quoted),1032            (r'``', Name.Quoted.Escape),1033            (r'`', Name.Quoted, '#pop'),1034        ],1035    }1036 1037    def analyse_text(text):1038        tokens = collections.Counter(text.split())1039        return 0.001 * sum(count for t, count in tokens.items()1040                           if t in googlesql_identifiers)1041 1042 1043class SqliteConsoleLexer(Lexer):1044    """1045    Lexer for example sessions using sqlite3.1046    """1047 1048    name = 'sqlite3con'1049    aliases = ['sqlite3']1050    filenames = ['*.sqlite3-console']1051    mimetypes = ['text/x-sqlite3-console']1052    url = 'https://www.sqlite.org'1053    version_added = '0.11'1054    _example = "sqlite3/sqlite3.sqlite3-console"1055 1056    def get_tokens_unprocessed(self, data):1057        sql = SqlLexer(**self.options)1058 1059        curcode = ''1060        insertions = []1061        for match in line_re.finditer(data):1062            line = match.group()1063            prompt_match = sqlite_prompt_re.match(line)1064            if prompt_match is not None:1065                insertions.append((len(curcode),1066                                   [(0, Generic.Prompt, line[:7])]))1067                insertions.append((len(curcode),1068                                   [(7, Whitespace, ' ')]))1069                curcode += line[8:]1070            else:1071                if curcode:1072                    yield from do_insertions(insertions,1073                                             sql.get_tokens_unprocessed(curcode))1074                    curcode = ''1075                    insertions = []1076                if line.startswith('SQL error: '):1077                    yield (match.start(), Generic.Traceback, line)1078                else:1079                    yield (match.start(), Generic.Output, line)1080        if curcode:1081            yield from do_insertions(insertions,1082                                     sql.get_tokens_unprocessed(curcode))1083 1084 1085class RqlLexer(RegexLexer):1086    """1087    Lexer for Relation Query Language.1088    """1089    name = 'RQL'1090    url = 'http://www.logilab.org/project/rql'1091    aliases = ['rql']1092    filenames = ['*.rql']1093    mimetypes = ['text/x-rql']1094    version_added = '2.0'1095 1096    flags = re.IGNORECASE1097    tokens = {1098        'root': [1099            (r'\s+', Whitespace),1100            (r'(DELETE|SET|INSERT|UNION|DISTINCT|WITH|WHERE|BEING|OR'1101             r'|AND|NOT|GROUPBY|HAVING|ORDERBY|ASC|DESC|LIMIT|OFFSET'1102             r'|TODAY|NOW|TRUE|FALSE|NULL|EXISTS)\b', Keyword),1103            (r'[+*/<>=%-]', Operator),1104            (r'(Any|is|instance_of|CWEType|CWRelation)\b', Name.Builtin),1105            (r'[0-9]+', Number.Integer),1106            (r'[A-Z_]\w*\??', Name),1107            (r"'(''|[^'])*'", String.Single),1108            (r'"(""|[^"])*"', String.Single),1109            (r'[;:()\[\],.]', Punctuation)1110        ],1111    }1112 
codekingpro/portable-devtools · Team Ai