ThirdParty/Pygments/pygments/lexers/sql.py

changeset 1705
b0fbc9300f2b
child 2426
da76c71624de
equal deleted inserted replaced
1704:02ae6c55b35b 1705:b0fbc9300f2b
1 # -*- coding: utf-8 -*-
2 """
3 pygments.lexers.sql
4 ~~~~~~~~~~~~~~~~~~~
5
6 Lexers for various SQL dialects and related interactive sessions.
7
8 Postgres specific lexers:
9
10 `PostgresLexer`
11 A SQL lexer for the PostgreSQL dialect. Differences w.r.t. the SQL
12 lexer are:
13
14 - keywords and data types list parsed from the PG docs (run the
15 `_postgres_builtins` module to update them);
16 - Content of $-strings parsed using a specific lexer, e.g. the content
17 of a PL/Python function is parsed using the Python lexer;
18 - parse PG specific constructs: E-strings, $-strings, U&-strings,
19 different operators and punctuation.
20
21 `PlPgsqlLexer`
22 A lexer for the PL/pgSQL language. Adds a few specific construct on
23 top of the PG SQL lexer (such as <<label>>).
24
25 `PostgresConsoleLexer`
26 A lexer to highlight an interactive psql session:
27
28 - identifies the prompt and does its best to detect the end of command
29 in multiline statement where not all the lines are prefixed by a
30 prompt, telling them apart from the output;
31 - highlights errors in the output and notification levels;
32 - handles psql backslash commands.
33
34 The ``tests/examplefiles`` contains a few test files with data to be
35 parsed by these lexers.
36
37 :copyright: Copyright 2006-2012 by the Pygments team, see AUTHORS.
38 :license: BSD, see LICENSE for details.
39 """
40
41 import re
42 from copy import deepcopy
43
44 from pygments.lexer import Lexer, RegexLexer, do_insertions, bygroups
45 from pygments.token import Punctuation, \
46 Text, Comment, Operator, Keyword, Name, String, Number, Generic
47 from pygments.lexers import get_lexer_by_name, ClassNotFound
48
49 from pygments.lexers._postgres_builtins import KEYWORDS, DATATYPES, \
50 PSEUDO_TYPES, PLPGSQL_KEYWORDS
51
52
53 __all__ = ['PostgresLexer', 'PlPgsqlLexer', 'PostgresConsoleLexer',
54 'SqlLexer', 'MySqlLexer', 'SqliteConsoleLexer']
55
56 line_re = re.compile('.*?\n')
57
58 language_re = re.compile(r"\s+LANGUAGE\s+'?(\w+)'?", re.IGNORECASE)
59
60 def language_callback(lexer, match):
61 """Parse the content of a $-string using a lexer
62
63 The lexer is chosen looking for a nearby LANGUAGE.
64
65 Note: this function should have been a `PostgresBase` method, but the
66 rules deepcopy fails in this case.
67 """
68 l = None
69 m = language_re.match(lexer.text[match.end():match.end()+100])
70 if m is not None:
71 l = lexer._get_lexer(m.group(1))
72 else:
73 m = list(language_re.finditer(
74 lexer.text[max(0, match.start()-100):match.start()]))
75 if m:
76 l = lexer._get_lexer(m[-1].group(1))
77
78 if l:
79 yield (match.start(1), String, match.group(1))
80 for x in l.get_tokens_unprocessed(match.group(2)):
81 yield x
82 yield (match.start(3), String, match.group(3))
83
84 else:
85 yield (match.start(), String, match.group())
86
87
88 class PostgresBase(object):
89 """Base class for Postgres-related lexers.
90
91 This is implemented as a mixin to avoid the Lexer metaclass kicking in.
92 this way the different lexer don't have a common Lexer ancestor. If they
93 had, _tokens could be created on this ancestor and not updated for the
94 other classes, resulting e.g. in PL/pgSQL parsed as SQL. This shortcoming
95 seem to suggest that regexp lexers are not really subclassable.
96
97 `language_callback` should really be our method, but this breaks deepcopy.
98 """
99 def get_tokens_unprocessed(self, text, *args):
100 # Have a copy of the entire text to be used by `language_callback`.
101 self.text = text
102 for x in super(PostgresBase, self).get_tokens_unprocessed(
103 text, *args):
104 yield x
105
106 def _get_lexer(self, lang):
107 if lang.lower() == 'sql':
108 return get_lexer_by_name('postgresql', **self.options)
109
110 tries = [ lang ]
111 if lang.startswith('pl'):
112 tries.append(lang[2:])
113 if lang.endswith('u'):
114 tries.append(lang[:-1])
115 if lang.startswith('pl') and lang.endswith('u'):
116 tries.append(lang[2:-1])
117
118 for l in tries:
119 try:
120 return get_lexer_by_name(l, **self.options)
121 except ClassNotFound:
122 pass
123 else:
124 # TODO: better logging
125 # print >>sys.stderr, "language not found:", lang
126 return None
127
128
129 class PostgresLexer(PostgresBase, RegexLexer):
130 """
131 Lexer for the PostgreSQL dialect of SQL.
132
133 *New in Pygments 1.5.*
134 """
135
136 name = 'PostgreSQL SQL dialect'
137 aliases = ['postgresql', 'postgres']
138 mimetypes = ['text/x-postgresql']
139
140 flags = re.IGNORECASE
141 tokens = {
142 'root': [
143 (r'\s+', Text),
144 (r'--.*?\n', Comment.Single),
145 (r'/\*', Comment.Multiline, 'multiline-comments'),
146 (r'(' + '|'.join([s.replace(" ", "\s+")
147 for s in DATATYPES + PSEUDO_TYPES])
148 + r')\b', Name.Builtin),
149 (r'(' + '|'.join(KEYWORDS) + r')\b', Keyword),
150 (r'[+*/<>=~!@#%^&|`?-]+', Operator),
151 (r'::', Operator), # cast
152 (r'\$\d+', Name.Variable),
153 (r'([0-9]*\.[0-9]*|[0-9]+)(e[+-]?[0-9]+)?', Number.Float),
154 (r'[0-9]+', Number.Integer),
155 (r"(E|U&)?'(''|[^'])*'", String.Single),
156 (r'(U&)?"(""|[^"])*"', String.Name), # quoted identifier
157 (r'(?s)(\$[^\$]*\$)(.*?)(\1)', language_callback),
158 (r'[a-zA-Z_][a-zA-Z0-9_]*', Name),
159
160 # psql variable in SQL
161 (r""":(['"]?)[a-z][a-z0-9_]*\b\1""", Name.Variable),
162
163 (r'[;:()\[\]\{\},\.]', Punctuation),
164 ],
165 'multiline-comments': [
166 (r'/\*', Comment.Multiline, 'multiline-comments'),
167 (r'\*/', Comment.Multiline, '#pop'),
168 (r'[^/\*]+', Comment.Multiline),
169 (r'[/*]', Comment.Multiline)
170 ],
171 }
172
173
174 class PlPgsqlLexer(PostgresBase, RegexLexer):
175 """
176 Handle the extra syntax in Pl/pgSQL language.
177
178 *New in Pygments 1.5.*
179 """
180 name = 'PL/pgSQL'
181 aliases = ['plpgsql']
182 mimetypes = ['text/x-plpgsql']
183
184 flags = re.IGNORECASE
185 tokens = deepcopy(PostgresLexer.tokens)
186
187 # extend the keywords list
188 for i, pattern in enumerate(tokens['root']):
189 if pattern[1] == Keyword:
190 tokens['root'][i] = (
191 r'(' + '|'.join(KEYWORDS + PLPGSQL_KEYWORDS) + r')\b',
192 Keyword)
193 del i
194 break
195 else:
196 assert 0, "SQL keywords not found"
197
198 # Add specific PL/pgSQL rules (before the SQL ones)
199 tokens['root'][:0] = [
200 (r'\%[a-z][a-z0-9_]*\b', Name.Builtin), # actually, a datatype
201 (r':=', Operator),
202 (r'\<\<[a-z][a-z0-9_]*\>\>', Name.Label),
203 (r'\#[a-z][a-z0-9_]*\b', Keyword.Pseudo), # #variable_conflict
204 ]
205
206
207 class PsqlRegexLexer(PostgresBase, RegexLexer):
208 """
209 Extend the PostgresLexer adding support specific for psql commands.
210
211 This is not a complete psql lexer yet as it lacks prompt support
212 and output rendering.
213 """
214
215 name = 'PostgreSQL console - regexp based lexer'
216 aliases = [] # not public
217
218 flags = re.IGNORECASE
219 tokens = deepcopy(PostgresLexer.tokens)
220
221 tokens['root'].append(
222 (r'\\[^\s]+', Keyword.Pseudo, 'psql-command'))
223 tokens['psql-command'] = [
224 (r'\n', Text, 'root'),
225 (r'\s+', Text),
226 (r'\\[^\s]+', Keyword.Pseudo),
227 (r""":(['"]?)[a-z][a-z0-9_]*\b\1""", Name.Variable),
228 (r"'(''|[^'])*'", String.Single),
229 (r"`([^`])*`", String.Backtick),
230 (r"[^\s]+", String.Symbol),
231 ]
232
233 re_prompt = re.compile(r'^(\S.*?)??[=\-\(\$\'\"][#>]')
234 re_psql_command = re.compile(r'\s*\\')
235 re_end_command = re.compile(r';\s*(--.*?)?$')
236 re_psql_command = re.compile(r'(\s*)(\\.+?)(\s+)$')
237 re_error = re.compile(r'(ERROR|FATAL):')
238 re_message = re.compile(
239 r'((?:DEBUG|INFO|NOTICE|WARNING|ERROR|'
240 r'FATAL|HINT|DETAIL|CONTEXT|LINE [0-9]+):)(.*?\n)')
241
242
243 class lookahead(object):
244 """Wrap an iterator and allow pushing back an item."""
245 def __init__(self, x):
246 self.iter = iter(x)
247 self._nextitem = None
248 def __iter__(self):
249 return self
250 def send(self, i):
251 self._nextitem = i
252 return i
253 def __next__(self):
254 if self._nextitem is not None:
255 ni = self._nextitem
256 self._nextitem = None
257 return ni
258 return next(self.iter)
259
260
261 class PostgresConsoleLexer(Lexer):
262 """
263 Lexer for psql sessions.
264
265 *New in Pygments 1.5.*
266 """
267
268 name = 'PostgreSQL console (psql)'
269 aliases = ['psql', 'postgresql-console', 'postgres-console']
270 mimetypes = ['text/x-postgresql-psql']
271
272 def get_tokens_unprocessed(self, data):
273 sql = PsqlRegexLexer(**self.options)
274
275 lines = lookahead(line_re.findall(data))
276
277 # prompt-output cycle
278 while 1:
279
280 # consume the lines of the command: start with an optional prompt
281 # and continue until the end of command is detected
282 curcode = ''
283 insertions = []
284 while 1:
285 try:
286 line = next(lines)
287 except StopIteration:
288 # allow the emission of partially collected items
289 # the repl loop will be broken below
290 break
291
292 # Identify a shell prompt in case of psql commandline example
293 if line.startswith('$') and not curcode:
294 lexer = get_lexer_by_name('console', **self.options)
295 for x in lexer.get_tokens_unprocessed(line):
296 yield x
297 break
298
299 # Identify a psql prompt
300 mprompt = re_prompt.match(line)
301 if mprompt is not None:
302 insertions.append((len(curcode),
303 [(0, Generic.Prompt, mprompt.group())]))
304 curcode += line[len(mprompt.group()):]
305 else:
306 curcode += line
307
308 # Check if this is the end of the command
309 # TODO: better handle multiline comments at the end with
310 # a lexer with an external state?
311 if re_psql_command.match(curcode) \
312 or re_end_command.search(curcode):
313 break
314
315 # Emit the combined stream of command and prompt(s)
316 for item in do_insertions(insertions,
317 sql.get_tokens_unprocessed(curcode)):
318 yield item
319
320 # Emit the output lines
321 out_token = Generic.Output
322 while 1:
323 line = next(lines)
324 mprompt = re_prompt.match(line)
325 if mprompt is not None:
326 # push the line back to have it processed by the prompt
327 lines.send(line)
328 break
329
330 mmsg = re_message.match(line)
331 if mmsg is not None:
332 if mmsg.group(1).startswith("ERROR") \
333 or mmsg.group(1).startswith("FATAL"):
334 out_token = Generic.Error
335 yield (mmsg.start(1), Generic.Strong, mmsg.group(1))
336 yield (mmsg.start(2), out_token, mmsg.group(2))
337 else:
338 yield (0, out_token, line)
339
340
341 class SqlLexer(RegexLexer):
342 """
343 Lexer for Structured Query Language. Currently, this lexer does
344 not recognize any special syntax except ANSI SQL.
345 """
346
347 name = 'SQL'
348 aliases = ['sql']
349 filenames = ['*.sql']
350 mimetypes = ['text/x-sql']
351
352 flags = re.IGNORECASE
353 tokens = {
354 'root': [
355 (r'\s+', Text),
356 (r'--.*?\n', Comment.Single),
357 (r'/\*', Comment.Multiline, 'multiline-comments'),
358 (r'(ABORT|ABS|ABSOLUTE|ACCESS|ADA|ADD|ADMIN|AFTER|AGGREGATE|'
359 r'ALIAS|ALL|ALLOCATE|ALTER|ANALYSE|ANALYZE|AND|ANY|ARE|AS|'
360 r'ASC|ASENSITIVE|ASSERTION|ASSIGNMENT|ASYMMETRIC|AT|ATOMIC|'
361 r'AUTHORIZATION|AVG|BACKWARD|BEFORE|BEGIN|BETWEEN|BITVAR|'
362 r'BIT_LENGTH|BOTH|BREADTH|BY|C|CACHE|CALL|CALLED|CARDINALITY|'
363 r'CASCADE|CASCADED|CASE|CAST|CATALOG|CATALOG_NAME|CHAIN|'
364 r'CHARACTERISTICS|CHARACTER_LENGTH|CHARACTER_SET_CATALOG|'
365 r'CHARACTER_SET_NAME|CHARACTER_SET_SCHEMA|CHAR_LENGTH|CHECK|'
366 r'CHECKED|CHECKPOINT|CLASS|CLASS_ORIGIN|CLOB|CLOSE|CLUSTER|'
367 r'COALSECE|COBOL|COLLATE|COLLATION|COLLATION_CATALOG|'
368 r'COLLATION_NAME|COLLATION_SCHEMA|COLUMN|COLUMN_NAME|'
369 r'COMMAND_FUNCTION|COMMAND_FUNCTION_CODE|COMMENT|COMMIT|'
370 r'COMMITTED|COMPLETION|CONDITION_NUMBER|CONNECT|CONNECTION|'
371 r'CONNECTION_NAME|CONSTRAINT|CONSTRAINTS|CONSTRAINT_CATALOG|'
372 r'CONSTRAINT_NAME|CONSTRAINT_SCHEMA|CONSTRUCTOR|CONTAINS|'
373 r'CONTINUE|CONVERSION|CONVERT|COPY|CORRESPONTING|COUNT|'
374 r'CREATE|CREATEDB|CREATEUSER|CROSS|CUBE|CURRENT|CURRENT_DATE|'
375 r'CURRENT_PATH|CURRENT_ROLE|CURRENT_TIME|CURRENT_TIMESTAMP|'
376 r'CURRENT_USER|CURSOR|CURSOR_NAME|CYCLE|DATA|DATABASE|'
377 r'DATETIME_INTERVAL_CODE|DATETIME_INTERVAL_PRECISION|DAY|'
378 r'DEALLOCATE|DECLARE|DEFAULT|DEFAULTS|DEFERRABLE|DEFERRED|'
379 r'DEFINED|DEFINER|DELETE|DELIMITER|DELIMITERS|DEREF|DESC|'
380 r'DESCRIBE|DESCRIPTOR|DESTROY|DESTRUCTOR|DETERMINISTIC|'
381 r'DIAGNOSTICS|DICTIONARY|DISCONNECT|DISPATCH|DISTINCT|DO|'
382 r'DOMAIN|DROP|DYNAMIC|DYNAMIC_FUNCTION|DYNAMIC_FUNCTION_CODE|'
383 r'EACH|ELSE|ENCODING|ENCRYPTED|END|END-EXEC|EQUALS|ESCAPE|EVERY|'
384 r'EXCEPT|ESCEPTION|EXCLUDING|EXCLUSIVE|EXEC|EXECUTE|EXISTING|'
385 r'EXISTS|EXPLAIN|EXTERNAL|EXTRACT|FALSE|FETCH|FINAL|FIRST|FOR|'
386 r'FORCE|FOREIGN|FORTRAN|FORWARD|FOUND|FREE|FREEZE|FROM|FULL|'
387 r'FUNCTION|G|GENERAL|GENERATED|GET|GLOBAL|GO|GOTO|GRANT|GRANTED|'
388 r'GROUP|GROUPING|HANDLER|HAVING|HIERARCHY|HOLD|HOST|IDENTITY|'
389 r'IGNORE|ILIKE|IMMEDIATE|IMMUTABLE|IMPLEMENTATION|IMPLICIT|IN|'
390 r'INCLUDING|INCREMENT|INDEX|INDITCATOR|INFIX|INHERITS|INITIALIZE|'
391 r'INITIALLY|INNER|INOUT|INPUT|INSENSITIVE|INSERT|INSTANTIABLE|'
392 r'INSTEAD|INTERSECT|INTO|INVOKER|IS|ISNULL|ISOLATION|ITERATE|JOIN|'
393 r'KEY|KEY_MEMBER|KEY_TYPE|LANCOMPILER|LANGUAGE|LARGE|LAST|'
394 r'LATERAL|LEADING|LEFT|LENGTH|LESS|LEVEL|LIKE|LIMIT|LISTEN|LOAD|'
395 r'LOCAL|LOCALTIME|LOCALTIMESTAMP|LOCATION|LOCATOR|LOCK|LOWER|'
396 r'MAP|MATCH|MAX|MAXVALUE|MESSAGE_LENGTH|MESSAGE_OCTET_LENGTH|'
397 r'MESSAGE_TEXT|METHOD|MIN|MINUTE|MINVALUE|MOD|MODE|MODIFIES|'
398 r'MODIFY|MONTH|MORE|MOVE|MUMPS|NAMES|NATIONAL|NATURAL|NCHAR|'
399 r'NCLOB|NEW|NEXT|NO|NOCREATEDB|NOCREATEUSER|NONE|NOT|NOTHING|'
400 r'NOTIFY|NOTNULL|NULL|NULLABLE|NULLIF|OBJECT|OCTET_LENGTH|OF|OFF|'
401 r'OFFSET|OIDS|OLD|ON|ONLY|OPEN|OPERATION|OPERATOR|OPTION|OPTIONS|'
402 r'OR|ORDER|ORDINALITY|OUT|OUTER|OUTPUT|OVERLAPS|OVERLAY|OVERRIDING|'
403 r'OWNER|PAD|PARAMETER|PARAMETERS|PARAMETER_MODE|PARAMATER_NAME|'
404 r'PARAMATER_ORDINAL_POSITION|PARAMETER_SPECIFIC_CATALOG|'
405 r'PARAMETER_SPECIFIC_NAME|PARAMATER_SPECIFIC_SCHEMA|PARTIAL|'
406 r'PASCAL|PENDANT|PLACING|PLI|POSITION|POSTFIX|PRECISION|PREFIX|'
407 r'PREORDER|PREPARE|PRESERVE|PRIMARY|PRIOR|PRIVILEGES|PROCEDURAL|'
408 r'PROCEDURE|PUBLIC|READ|READS|RECHECK|RECURSIVE|REF|REFERENCES|'
409 r'REFERENCING|REINDEX|RELATIVE|RENAME|REPEATABLE|REPLACE|RESET|'
410 r'RESTART|RESTRICT|RESULT|RETURN|RETURNED_LENGTH|'
411 r'RETURNED_OCTET_LENGTH|RETURNED_SQLSTATE|RETURNS|REVOKE|RIGHT|'
412 r'ROLE|ROLLBACK|ROLLUP|ROUTINE|ROUTINE_CATALOG|ROUTINE_NAME|'
413 r'ROUTINE_SCHEMA|ROW|ROWS|ROW_COUNT|RULE|SAVE_POINT|SCALE|SCHEMA|'
414 r'SCHEMA_NAME|SCOPE|SCROLL|SEARCH|SECOND|SECURITY|SELECT|SELF|'
415 r'SENSITIVE|SERIALIZABLE|SERVER_NAME|SESSION|SESSION_USER|SET|'
416 r'SETOF|SETS|SHARE|SHOW|SIMILAR|SIMPLE|SIZE|SOME|SOURCE|SPACE|'
417 r'SPECIFIC|SPECIFICTYPE|SPECIFIC_NAME|SQL|SQLCODE|SQLERROR|'
418 r'SQLEXCEPTION|SQLSTATE|SQLWARNINIG|STABLE|START|STATE|STATEMENT|'
419 r'STATIC|STATISTICS|STDIN|STDOUT|STORAGE|STRICT|STRUCTURE|STYPE|'
420 r'SUBCLASS_ORIGIN|SUBLIST|SUBSTRING|SUM|SYMMETRIC|SYSID|SYSTEM|'
421 r'SYSTEM_USER|TABLE|TABLE_NAME| TEMP|TEMPLATE|TEMPORARY|TERMINATE|'
422 r'THAN|THEN|TIMESTAMP|TIMEZONE_HOUR|TIMEZONE_MINUTE|TO|TOAST|'
423 r'TRAILING|TRANSATION|TRANSACTIONS_COMMITTED|'
424 r'TRANSACTIONS_ROLLED_BACK|TRANSATION_ACTIVE|TRANSFORM|'
425 r'TRANSFORMS|TRANSLATE|TRANSLATION|TREAT|TRIGGER|TRIGGER_CATALOG|'
426 r'TRIGGER_NAME|TRIGGER_SCHEMA|TRIM|TRUE|TRUNCATE|TRUSTED|TYPE|'
427 r'UNCOMMITTED|UNDER|UNENCRYPTED|UNION|UNIQUE|UNKNOWN|UNLISTEN|'
428 r'UNNAMED|UNNEST|UNTIL|UPDATE|UPPER|USAGE|USER|'
429 r'USER_DEFINED_TYPE_CATALOG|USER_DEFINED_TYPE_NAME|'
430 r'USER_DEFINED_TYPE_SCHEMA|USING|VACUUM|VALID|VALIDATOR|VALUES|'
431 r'VARIABLE|VERBOSE|VERSION|VIEW|VOLATILE|WHEN|WHENEVER|WHERE|'
432 r'WITH|WITHOUT|WORK|WRITE|YEAR|ZONE)\b', Keyword),
433 (r'(ARRAY|BIGINT|BINARY|BIT|BLOB|BOOLEAN|CHAR|CHARACTER|DATE|'
434 r'DEC|DECIMAL|FLOAT|INT|INTEGER|INTERVAL|NUMBER|NUMERIC|REAL|'
435 r'SERIAL|SMALLINT|VARCHAR|VARYING|INT8|SERIAL8|TEXT)\b',
436 Name.Builtin),
437 (r'[+*/<>=~!@#%^&|`?-]', Operator),
438 (r'[0-9]+', Number.Integer),
439 # TODO: Backslash escapes?
440 (r"'(''|[^'])*'", String.Single),
441 (r'"(""|[^"])*"', String.Symbol), # not a real string literal in ANSI SQL
442 (r'[a-zA-Z_][a-zA-Z0-9_]*', Name),
443 (r'[;:()\[\],\.]', Punctuation)
444 ],
445 'multiline-comments': [
446 (r'/\*', Comment.Multiline, 'multiline-comments'),
447 (r'\*/', Comment.Multiline, '#pop'),
448 (r'[^/\*]+', Comment.Multiline),
449 (r'[/*]', Comment.Multiline)
450 ]
451 }
452
453
454 class MySqlLexer(RegexLexer):
455 """
456 Special lexer for MySQL.
457 """
458
459 name = 'MySQL'
460 aliases = ['mysql']
461 mimetypes = ['text/x-mysql']
462
463 flags = re.IGNORECASE
464 tokens = {
465 'root': [
466 (r'\s+', Text),
467 (r'(#|--\s+).*?\n', Comment.Single),
468 (r'/\*', Comment.Multiline, 'multiline-comments'),
469 (r'[0-9]+', Number.Integer),
470 (r'[0-9]*\.[0-9]+(e[+-][0-9]+)', Number.Float),
471 # TODO: add backslash escapes
472 (r"'(''|[^'])*'", String.Single),
473 (r'"(""|[^"])*"', String.Double),
474 (r"`(``|[^`])*`", String.Symbol),
475 (r'[+*/<>=~!@#%^&|`?-]', Operator),
476 (r'\b(tinyint|smallint|mediumint|int|integer|bigint|date|'
477 r'datetime|time|bit|bool|tinytext|mediumtext|longtext|text|'
478 r'tinyblob|mediumblob|longblob|blob|float|double|double\s+'
479 r'precision|real|numeric|dec|decimal|timestamp|year|char|'
480 r'varchar|varbinary|varcharacter|enum|set)(\b\s*)(\()?',
481 bygroups(Keyword.Type, Text, Punctuation)),
482 (r'\b(add|all|alter|analyze|and|as|asc|asensitive|before|between|'
483 r'bigint|binary|blob|both|by|call|cascade|case|change|char|'
484 r'character|check|collate|column|condition|constraint|continue|'
485 r'convert|create|cross|current_date|current_time|'
486 r'current_timestamp|current_user|cursor|database|databases|'
487 r'day_hour|day_microsecond|day_minute|day_second|dec|decimal|'
488 r'declare|default|delayed|delete|desc|describe|deterministic|'
489 r'distinct|distinctrow|div|double|drop|dual|each|else|elseif|'
490 r'enclosed|escaped|exists|exit|explain|fetch|float|float4|float8'
491 r'|for|force|foreign|from|fulltext|grant|group|having|'
492 r'high_priority|hour_microsecond|hour_minute|hour_second|if|'
493 r'ignore|in|index|infile|inner|inout|insensitive|insert|int|'
494 r'int1|int2|int3|int4|int8|integer|interval|into|is|iterate|'
495 r'join|key|keys|kill|leading|leave|left|like|limit|lines|load|'
496 r'localtime|localtimestamp|lock|long|loop|low_priority|match|'
497 r'minute_microsecond|minute_second|mod|modifies|natural|'
498 r'no_write_to_binlog|not|numeric|on|optimize|option|optionally|'
499 r'or|order|out|outer|outfile|precision|primary|procedure|purge|'
500 r'raid0|read|reads|real|references|regexp|release|rename|repeat|'
501 r'replace|require|restrict|return|revoke|right|rlike|schema|'
502 r'schemas|second_microsecond|select|sensitive|separator|set|'
503 r'show|smallint|soname|spatial|specific|sql|sql_big_result|'
504 r'sql_calc_found_rows|sql_small_result|sqlexception|sqlstate|'
505 r'sqlwarning|ssl|starting|straight_join|table|terminated|then|'
506 r'to|trailing|trigger|undo|union|unique|unlock|unsigned|update|'
507 r'usage|use|using|utc_date|utc_time|utc_timestamp|values|'
508 r'varying|when|where|while|with|write|x509|xor|year_month|'
509 r'zerofill)\b', Keyword),
510 # TODO: this list is not complete
511 (r'\b(auto_increment|engine|charset|tables)\b', Keyword.Pseudo),
512 (r'(true|false|null)', Name.Constant),
513 (r'([a-zA-Z_][a-zA-Z0-9_]*)(\s*)(\()',
514 bygroups(Name.Function, Text, Punctuation)),
515 (r'[a-zA-Z_][a-zA-Z0-9_]*', Name),
516 (r'@[A-Za-z0-9]*[._]*[A-Za-z0-9]*', Name.Variable),
517 (r'[;:()\[\],\.]', Punctuation)
518 ],
519 'multiline-comments': [
520 (r'/\*', Comment.Multiline, 'multiline-comments'),
521 (r'\*/', Comment.Multiline, '#pop'),
522 (r'[^/\*]+', Comment.Multiline),
523 (r'[/*]', Comment.Multiline)
524 ]
525 }
526
527
528 class SqliteConsoleLexer(Lexer):
529 """
530 Lexer for example sessions using sqlite3.
531
532 *New in Pygments 0.11.*
533 """
534
535 name = 'sqlite3con'
536 aliases = ['sqlite3']
537 filenames = ['*.sqlite3-console']
538 mimetypes = ['text/x-sqlite3-console']
539
540 def get_tokens_unprocessed(self, data):
541 sql = SqlLexer(**self.options)
542
543 curcode = ''
544 insertions = []
545 for match in line_re.finditer(data):
546 line = match.group()
547 if line.startswith('sqlite> ') or line.startswith(' ...> '):
548 insertions.append((len(curcode),
549 [(0, Generic.Prompt, line[:8])]))
550 curcode += line[8:]
551 else:
552 if curcode:
553 for item in do_insertions(insertions,
554 sql.get_tokens_unprocessed(curcode)):
555 yield item
556 curcode = ''
557 insertions = []
558 if line.startswith('SQL error: '):
559 yield (match.start(), Generic.Traceback, line)
560 else:
561 yield (match.start(), Generic.Output, line)
562 if curcode:
563 for item in do_insertions(insertions,
564 sql.get_tokens_unprocessed(curcode)):
565 yield item

eric ide

mercurial