Skip to content

Instantly share code, notes, and snippets.

@oprypin
Last active March 9, 2024 18:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oprypin/03bc702c151542c1172d to your computer and use it in GitHub Desktop.
Save oprypin/03bc702c151542c1172d to your computer and use it in GitHub Desktop.
diff --git a/pygments/lexers/ruby.py b/pygments/lexers/crystal.py
index f16416d..78c70b6 100644
--- a/pygments/lexers/ruby.py
+++ b/pygments/lexers/crystal.py
@@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
"""
- pygments.lexers.ruby
- ~~~~~~~~~~~~~~~~~~~~
+ pygments.lexers.crystal
+ ~~~~~~~~~~~~~~~~~~~~~~~
- Lexers for Ruby and related languages.
+ Lexer for Crystal.
- :copyright: Copyright 2006-2015 by the Pygments team, see AUTHORS.
+ :copyright: Copyright 2006-2016 by the Pygments team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
@@ -17,32 +17,33 @@ from pygments.token import Text, Comment, Operator, Keyword, Name, String, \
Number, Punctuation, Error, Generic
from pygments.util import shebang_matches
-__all__ = ['RubyLexer', 'RubyConsoleLexer', 'FancyLexer']
+__all__ = ['CrystalLexer']
line_re = re.compile('.*?\n')
-RUBY_OPERATORS = (
- '*', '**', '-', '+', '-@', '+@', '/', '%', '&', '|', '^', '`', '~',
- '[]', '[]=', '<<', '>>', '<', '<>', '<=>', '>', '>=', '==', '==='
-)
-class RubyLexer(ExtendedRegexLexer):
+CRYSTAL_OPERATORS = [
+ '!=', '!~', '!', '%', '&&', '&', '**', '*', '+', '-', '/', '<=>', '<<', '<=', '<',
+ '===', '==', '=~', '=', '>=', '>>', '>', '[]=', '[]?', '[]', '^', '||', '|', '~'
+]
+
+
+class CrystalLexer(ExtendedRegexLexer):
"""
- For `Ruby <http://www.ruby-lang.org>`_ source code.
+ For `Crystal <http://crystal-lang.org>`_ source code.
"""
- name = 'Ruby'
- aliases = ['rb', 'ruby', 'duby']
- filenames = ['*.rb', '*.rbw', 'Rakefile', '*.rake', '*.gemspec',
- '*.rbx', '*.duby', 'Gemfile']
- mimetypes = ['text/x-ruby', 'application/x-ruby']
+ name = 'Crystal'
+ aliases = ['cr', 'crystal']
+ filenames = ['*.cr']
+ mimetypes = ['text/x-crystal']
flags = re.DOTALL | re.MULTILINE
def heredoc_callback(self, match, ctx):
- # okay, this is the hardest part of parsing Ruby...
+ # okay, this is the hardest part of parsing Crystal...
# match: 1 = <<-?, 2 = quote? 3 = name 4 = quote? 5 = rest of line
start = match.start(1)
@@ -86,13 +87,13 @@ class RubyLexer(ExtendedRegexLexer):
ctx.end = len(ctx.text)
del heredocstack[:]
- def gen_rubystrings_rules():
+ def gen_crystalstrings_rules():
def intp_regex_callback(self, match, ctx):
yield match.start(1), String.Regex, match.group(1) # begin
nctx = LexerContext(match.group(3), 0, ['interpolated-regex'])
for i, t, v in self.get_tokens_unprocessed(context=nctx):
yield match.start(3)+i, t, v
- yield match.start(4), String.Regex, match.group(4) # end[mixounse]*
+ yield match.start(4), String.Regex, match.group(4) # end[imsx]*
ctx.pos = match.end()
def intp_string_callback(self, match, ctx):
@@ -105,14 +106,14 @@ class RubyLexer(ExtendedRegexLexer):
states = {}
states['strings'] = [
- # easy ones
(r'\:@{0,2}[a-zA-Z_]\w*[!?]?', String.Symbol),
- (words(RUBY_OPERATORS, prefix=r'\:@{0,2}'), String.Symbol),
+ (words(CRYSTAL_OPERATORS, prefix=r'\:@{0,2}'), String.Symbol),
(r":'(\\\\|\\'|[^'])*'", String.Symbol),
- (r"'(\\\\|\\'|[^'])*'", String.Single),
+ # This allows arbitrary text after '\ for simplicity
+ (r"'(\\\\|\\'|[^']|\\[^'\\]+)'", String.Char),
(r':"', String.Symbol, 'simple-sym'),
- (r'([a-zA-Z_]\w*)(:)(?!:)',
- bygroups(String.Symbol, Punctuation)), # Since Ruby 1.9
+ # Crystal doesn't have "symbol:"s but this simplifies function args
+ (r'([a-zA-Z_]\w*)(:)(?!:)', bygroups(String.Symbol, Punctuation)),
(r'"', String.Double, 'simple-string'),
(r'(?<!\.)`', String.Backtick, 'simple-backtick'),
]
@@ -122,7 +123,7 @@ class RubyLexer(ExtendedRegexLexer):
('sym', String.Symbol, '"'), \
('backtick', String.Backtick, '`'):
states['simple-'+name] = [
- include('string-intp-escaped'),
+ include('string-escaped' if name == 'sym' else 'string-intp-escaped'),
(r'[^\\%s#]+' % end, ttype),
(r'[\\#]', ttype),
(end, ttype, '#pop'),
@@ -135,14 +136,14 @@ class RubyLexer(ExtendedRegexLexer):
('\\(', '\\)', '()', 'pa'), \
('<', '>', '<>', 'ab'):
states[name+'-intp-string'] = [
- (r'\\[\\' + bracecc + ']', String.Other),
+ (r'\\[' + lbrace + ']', String.Other),
(lbrace, String.Other, '#push'),
(rbrace, String.Other, '#pop'),
include('string-intp-escaped'),
(r'[\\#' + bracecc + ']', String.Other),
(r'[^\\#' + bracecc + ']+', String.Other),
]
- states['strings'].append((r'%[QWx]?' + lbrace, String.Other,
+ states['strings'].append((r'%' + lbrace, String.Other,
name+'-intp-string'))
states[name+'-string'] = [
(r'\\[\\' + bracecc + ']', String.Other),
@@ -151,12 +152,13 @@ class RubyLexer(ExtendedRegexLexer):
(r'[\\#' + bracecc + ']', String.Other),
(r'[^\\#' + bracecc + ']+', String.Other),
]
- states['strings'].append((r'%[qsw]' + lbrace, String.Other,
+ # http://crystal-lang.org/docs/syntax_and_semantics/literals/array.html
+ states['strings'].append((r'%[wi]' + lbrace, String.Other,
name+'-string'))
states[name+'-regex'] = [
(r'\\[\\' + bracecc + ']', String.Regex),
(lbrace, String.Regex, '#push'),
- (rbrace + '[mixounse]*', String.Regex, '#pop'),
+ (rbrace + '[imsx]*', String.Regex, '#pop'),
include('string-intp'),
(r'[\\#' + bracecc + ']', String.Regex),
(r'[^\\#' + bracecc + ']+', String.Regex),
@@ -167,11 +169,10 @@ class RubyLexer(ExtendedRegexLexer):
# these must come after %<brace>!
states['strings'] += [
# %r regex
- (r'(%r([\W_]))((?:\\\2|(?!\2).)*)(\2[mixounse]*)',
+ (r'(%r([\W_]))((?:\\\2|(?!\2).)*)(\2[imsx]*)',
intp_regex_callback),
# regular fancy strings with qsw
- (r'%[qsw]([\W_])((?:\\\1|(?!\1).)*)\1', String.Other),
- (r'(%[QWx]([\W_]))((?:\\\2|(?!\2).)*)(\2)',
+ (r'(%[wi]([\W_]))((?:\\\2|(?!\2).)*)(\2)',
intp_string_callback),
# special forms of fancy strings after operators or
# in method calls with braces
@@ -182,7 +183,7 @@ class RubyLexer(ExtendedRegexLexer):
(r'^(\s*)(%([\t ])(?:(?:\\\3|(?!\3).)*)\3)',
bygroups(Text, String.Other, None)),
# all regular fancy strings without qsw
- (r'(%([^a-zA-Z0-9\s]))((?:\\\2|(?!\2).)*)(\2)',
+ (r'(%([\[{(<]))((?:\\\2|(?!\2).)*)(\2)',
intp_string_callback),
]
@@ -190,62 +191,39 @@ class RubyLexer(ExtendedRegexLexer):
tokens = {
'root': [
- (r'\A#!.+?$', Comment.Hashbang),
(r'#.*?$', Comment.Single),
- (r'=begin\s.*?\n=end.*?$', Comment.Multiline),
# keywords
- (words((
- 'BEGIN', 'END', 'alias', 'begin', 'break', 'case', 'defined?',
- 'do', 'else', 'elsif', 'end', 'ensure', 'for', 'if', 'in', 'next', 'redo',
- 'rescue', 'raise', 'retry', 'return', 'super', 'then', 'undef',
- 'unless', 'until', 'when', 'while', 'yield'), suffix=r'\b'),
- Keyword),
+ (words('''
+ abstract asm as begin break case do else elsif end ensure extend ifdef if
+ include instance_sizeof next of pointerof private protected rescue return
+ require sizeof super then typeof unless until when while with yield
+ '''.split(), suffix=r'\b'), Keyword),
+ (words(['true', 'false', 'nil'], suffix=r'\b'), Keyword.Constant),
# start of function, class and module names
- (r'(module)(\s+)([a-zA-Z_]\w*'
- r'(?:::[a-zA-Z_]\w*)*)',
+ (r'(module|lib)(\s+)([a-zA-Z_]\w*(?:::[a-zA-Z_]\w*)*)',
bygroups(Keyword, Text, Name.Namespace)),
- (r'(def)(\s+)', bygroups(Keyword, Text), 'funcname'),
+ (r'(def|fun|macro)(\s+)((?:[a-zA-Z_]\w*::)*)',
+ bygroups(Keyword, Text, Name.Namespace), 'funcname'),
(r'def(?=[*%&^`~+-/\[<>=])', Keyword, 'funcname'),
- (r'(class)(\s+)', bygroups(Keyword, Text), 'classname'),
- # special methods
- (words((
- 'initialize', 'new', 'loop', 'include', 'extend', 'raise', 'attr_reader',
- 'attr_writer', 'attr_accessor', 'attr', 'catch', 'throw', 'private',
- 'module_function', 'public', 'protected', 'true', 'false', 'nil'),
- suffix=r'\b'),
- Keyword.Pseudo),
- (r'(not|and|or)\b', Operator.Word),
- (words((
- 'autoload', 'block_given', 'const_defined', 'eql', 'equal', 'frozen', 'include',
- 'instance_of', 'is_a', 'iterator', 'kind_of', 'method_defined', 'nil',
- 'private_method_defined', 'protected_method_defined',
- 'public_method_defined', 'respond_to', 'tainted'), suffix=r'\?'),
- Name.Builtin),
- (r'(chomp|chop|exit|gsub|sub)!', Name.Builtin),
- (words((
- 'Array', 'Float', 'Integer', 'String', '__id__', '__send__', 'abort',
- 'ancestors', 'at_exit', 'autoload', 'binding', 'callcc', 'caller',
- 'catch', 'chomp', 'chop', 'class_eval', 'class_variables',
- 'clone', 'const_defined?', 'const_get', 'const_missing', 'const_set',
- 'constants', 'display', 'dup', 'eval', 'exec', 'exit', 'extend', 'fail', 'fork',
- 'format', 'freeze', 'getc', 'gets', 'global_variables', 'gsub',
- 'hash', 'id', 'included_modules', 'inspect', 'instance_eval',
- 'instance_method', 'instance_methods',
- 'instance_variable_get', 'instance_variable_set', 'instance_variables',
- 'lambda', 'load', 'local_variables', 'loop',
- 'method', 'method_missing', 'methods', 'module_eval', 'name',
- 'object_id', 'open', 'p', 'print', 'printf', 'private_class_method',
- 'private_instance_methods',
- 'private_methods', 'proc', 'protected_instance_methods',
- 'protected_methods', 'public_class_method',
- 'public_instance_methods', 'public_methods',
- 'putc', 'puts', 'raise', 'rand', 'readline', 'readlines', 'require',
- 'scan', 'select', 'self', 'send', 'set_trace_func', 'singleton_methods', 'sleep',
- 'split', 'sprintf', 'srand', 'sub', 'syscall', 'system', 'taint',
- 'test', 'throw', 'to_a', 'to_s', 'trace_var', 'trap', 'untaint',
- 'untrace_var', 'warn'), prefix=r'(?<!\.)', suffix=r'\b'),
- Name.Builtin),
- (r'__(FILE|LINE)__\b', Name.Builtin.Pseudo),
+ (r'(class|struct|union|type|alias|enum)(\s+)((?:[a-zA-Z_]\w*::)*)',
+ bygroups(Keyword, Text, Name.Namespace), 'classname'),
+ (r'(self|out|uninitialized)\b|(is_a|responds_to)\?', Keyword.Pseudo),
+ # macros
+ (words('''
+ debugger record pp assert_responds_to spawn parallel
+ getter setter property delegate def_hash def_equals def_equals_and_hash forward_missing_to
+ '''.split(), suffix=r'\b'), Name.Builtin.Pseudo),
+ (r'getter[!?]|property[!?]|__(DIR|FILE|LINE)__\b', Name.Builtin.Pseudo),
+ # builtins
+ # http://crystal-lang.org/api/toplevel.html
+ (words('''
+ Object Value Struct Reference Proc Class Nil Symbol Enum Void
+ Bool Number Int Int8 Int16 Int32 Int64 UInt8 UInt16 UInt32 UInt64 Float Float32 Float64 Char String
+ Pointer Slice Range Exception Regex
+ Mutex StaticArray Array Hash Set Tuple Deque Box Process File Dir Time Channel Concurrent Scheduler
+ abort at_exit caller delay exit fork future get_stack_top gets lazy loop main p print printf puts
+ raise rand read_line sleep sprintf system with_color
+ '''.split(), prefix=r'(?<!\.)', suffix=r'\b'), Name.Builtin),
# normal heredocs
(r'(?<!\w)(<<-?)(["`\']?)([a-zA-Z_]\w*)(\2)(.*?\n)',
heredoc_callback),
@@ -290,13 +268,20 @@ class RubyLexer(ExtendedRegexLexer):
# there so that you can use the ternary operator.
# stupid example:
# x>=0?n[x]:""
- (r'(0_?[0-7]+(?:_[0-7]+)*)(\s*)([/?])?',
+ (r'(0o[0-7]+(?:_[0-7]+)*(?:_?[iu][0-9]+)?)\b(\s*)([/?])?',
bygroups(Number.Oct, Text, Operator)),
- (r'(0x[0-9A-Fa-f]+(?:_[0-9A-Fa-f]+)*)(\s*)([/?])?',
+ (r'(0x[0-9A-Fa-f]+(?:_[0-9A-Fa-f]+)*(?:_?[iu][0-9]+)?)\b(\s*)([/?])?',
bygroups(Number.Hex, Text, Operator)),
- (r'(0b[01]+(?:_[01]+)*)(\s*)([/?])?',
+ (r'(0b[01]+(?:_[01]+)*(?:_?[iu][0-9]+)?)\b(\s*)([/?])?',
bygroups(Number.Bin, Text, Operator)),
- (r'([\d]+(?:_\d+)*)(\s*)([/?])?',
+ # 3 separate expressions for floats because any of the 3 optional parts makes it a float
+ (r'((?:0(?![0-9])|[1-9][\d_]*)(?:\.\d[\d_]*)(?:e[+-]?[0-9]+)?(?:_?[f][0-9]+)?)(\s*)([/?])?',
+ bygroups(Number.Float, Text, Operator)),
+ (r'((?:0(?![0-9])|[1-9][\d_]*)(?:\.\d[\d_]*)?(?:e[+-]?[0-9]+)(?:_?[f][0-9]+)?)(\s*)([/?])?',
+ bygroups(Number.Float, Text, Operator)),
+ (r'((?:0(?![0-9])|[1-9][\d_]*)(?:\.\d[\d_]*)?(?:e[+-]?[0-9]+)?(?:_?[f][0-9]+))(\s*)([/?])?',
+ bygroups(Number.Float, Text, Operator)),
+ (r'(0\b|[1-9][\d]*(?:_\d+)*(?:_?[iu][0-9]+)?)\b(\s*)([/?])?',
bygroups(Number.Integer, Text, Operator)),
# Names
(r'@@[a-zA-Z_]\w*', Name.Variable.Class),
@@ -308,25 +293,30 @@ class RubyLexer(ExtendedRegexLexer):
include('strings'),
# chars
(r'\?(\\[MC]-)*' # modifiers
- r'(\\([\\abefnrstv#"\']|x[a-fA-F0-9]{1,2}|[0-7]{1,3})|\S)'
+ r'(\\([\\befnrtv#"\']|x[a-fA-F0-9]{1,2}|[0-7]{1,3})|\S)'
r'(?!\w)',
String.Char),
- (r'[A-Z]\w+', Name.Constant),
- # this is needed because ruby attributes can look
+ (r'[A-Z][A-Z_]+\b', Name.Constant),
+ # macro expansion
+ (r'\{%', String.Interpol, 'in-macro-control'),
+ (r'\{\{', String.Interpol, 'in-macro-expr'),
+ # attributes
+ (r'(@\[)(\s*)([A-Z]\w*)', bygroups(Operator, Text, Name.Decorator), 'in-attr'),
+ # this is needed because Crystal attributes can look
# like keywords (class) or like this: ` ?!?
- (words(RUBY_OPERATORS, prefix=r'(\.|::)'),
+ (words(CRYSTAL_OPERATORS, prefix=r'(\.|::)'),
bygroups(Operator, Name.Operator)),
(r'(\.|::)([a-zA-Z_]\w*[!?]?|[*%&^`~+\-/\[<>=])',
bygroups(Operator, Name)),
- (r'[a-zA-Z_]\w*[!?]?', Name),
- (r'(\[|\]|\*\*|<<?|>>?|>=|<=|<=>|=~|={3}|'
+ # Names can end with [!?] unless it's "!="
+ (r'[a-zA-Z_]\w*(?:[!?](?!=))?', Name),
+ (r'(\[|\]\??|\*\*|<=>?|>=|<<?|>>?|=~|===|'
r'!~|&&?|\|\||\.{1,3})', Operator),
(r'[-+/*%=<>&!^|~]=?', Operator),
(r'[(){};,/?:\\]', Punctuation),
(r'\s+', Text)
],
'funcname': [
- (r'\(', Punctuation, 'defexpr'),
(r'(?:([a-zA-Z_]\w*)(\.))?'
r'([a-zA-Z_]\w*[!?]?|\*\*?|[-+]@?|'
r'[/%&|^`~]|\[\]=?|<<|>>|<=?>|>=?|===?)',
@@ -334,16 +324,10 @@ class RubyLexer(ExtendedRegexLexer):
default('#pop')
],
'classname': [
- (r'\(', Punctuation, 'defexpr'),
- (r'<<', Operator, '#pop'),
- (r'[A-Z_]\w*', Name.Class, '#pop'),
+ (r'[A-Z_]\w*', Name.Class),
+ (r'(\()(\s*)([A-Z_]\w*)(\s*)(\))', bygroups(Punctuation, Text, Name.Class, Text, Punctuation)),
default('#pop')
],
- 'defexpr': [
- (r'(\))(\.|::)?', bygroups(Punctuation, Operator), '#pop'),
- (r'\(', Operator, '#push'),
- include('root')
- ],
'in-intp': [
(r'\{', String.Interpol, '#push'),
(r'\}', String.Interpol, '#pop'),
@@ -351,13 +335,13 @@ class RubyLexer(ExtendedRegexLexer):
],
'string-intp': [
(r'#\{', String.Interpol, 'in-intp'),
- (r'#@@?[a-zA-Z_]\w*', String.Interpol),
- (r'#\$[a-zA-Z_]\w*', String.Interpol)
+ ],
+ 'string-escaped': [
+ (r'\\([\\befnstv#"\']|x[a-fA-F0-9]{1,2}|[0-7]{1,3})', String.Escape)
],
'string-intp-escaped': [
include('string-intp'),
- (r'\\([\\abefnrstv#"\']|x[a-fA-F0-9]{1,2}|[0-7]{1,3})',
- String.Escape)
+ include('string-escaped'),
],
'interpolated-regex': [
include('string-intp'),
@@ -375,145 +359,26 @@ class RubyLexer(ExtendedRegexLexer):
(r'\\/', String.Regex),
(r'[\\#]', String.Regex),
(r'[^\\/#]+', String.Regex),
- (r'/[mixounse]*', String.Regex, '#pop'),
+ (r'/[imsx]*', String.Regex, '#pop'),
],
'end-part': [
(r'.+', Comment.Preproc, '#pop')
- ]
- }
- tokens.update(gen_rubystrings_rules())
-
- def analyse_text(text):
- return shebang_matches(text, r'ruby(1\.\d)?')
-
-
-class RubyConsoleLexer(Lexer):
- """
- For Ruby interactive console (**irb**) output like:
-
- .. sourcecode:: rbcon
-
- irb(main):001:0> a = 1
- => 1
- irb(main):002:0> puts a
- 1
- => nil
- """
- name = 'Ruby irb session'
- aliases = ['rbcon', 'irb']
- mimetypes = ['text/x-ruby-shellsession']
-
- _prompt_re = re.compile('irb\([a-zA-Z_]\w*\):\d{3}:\d+[>*"\'] '
- '|>> |\?> ')
-
- def get_tokens_unprocessed(self, text):
- rblexer = RubyLexer(**self.options)
-
- curcode = ''
- insertions = []
- for match in line_re.finditer(text):
- line = match.group()
- m = self._prompt_re.match(line)
- if m is not None:
- end = m.end()
- insertions.append((len(curcode),
- [(0, Generic.Prompt, line[:end])]))
- curcode += line[end:]
- else:
- if curcode:
- for item in do_insertions(
- insertions, rblexer.get_tokens_unprocessed(curcode)):
- yield item
- curcode = ''
- insertions = []
- yield match.start(), Generic.Output, line
- if curcode:
- for item in do_insertions(
- insertions, rblexer.get_tokens_unprocessed(curcode)):
- yield item
-
-
-class FancyLexer(RegexLexer):
- """
- Pygments Lexer For `Fancy <http://www.fancy-lang.org/>`_.
-
- Fancy is a self-hosted, pure object-oriented, dynamic,
- class-based, concurrent general-purpose programming language
- running on Rubinius, the Ruby VM.
-
- .. versionadded:: 1.5
- """
- name = 'Fancy'
- filenames = ['*.fy', '*.fancypack']
- aliases = ['fancy', 'fy']
- mimetypes = ['text/x-fancysrc']
-
- tokens = {
- # copied from PerlLexer:
- 'balanced-regex': [
- (r'/(\\\\|\\/|[^/])*/[egimosx]*', String.Regex, '#pop'),
- (r'!(\\\\|\\!|[^!])*![egimosx]*', String.Regex, '#pop'),
- (r'\\(\\\\|[^\\])*\\[egimosx]*', String.Regex, '#pop'),
- (r'\{(\\\\|\\\}|[^}])*\}[egimosx]*', String.Regex, '#pop'),
- (r'<(\\\\|\\>|[^>])*>[egimosx]*', String.Regex, '#pop'),
- (r'\[(\\\\|\\\]|[^\]])*\][egimosx]*', String.Regex, '#pop'),
- (r'\((\\\\|\\\)|[^)])*\)[egimosx]*', String.Regex, '#pop'),
- (r'@(\\\\|\\@|[^@])*@[egimosx]*', String.Regex, '#pop'),
- (r'%(\\\\|\\%|[^%])*%[egimosx]*', String.Regex, '#pop'),
- (r'\$(\\\\|\\\$|[^$])*\$[egimosx]*', String.Regex, '#pop'),
],
- 'root': [
- (r'\s+', Text),
-
- # balanced delimiters (copied from PerlLexer):
- (r's\{(\\\\|\\\}|[^}])*\}\s*', String.Regex, 'balanced-regex'),
- (r's<(\\\\|\\>|[^>])*>\s*', String.Regex, 'balanced-regex'),
- (r's\[(\\\\|\\\]|[^\]])*\]\s*', String.Regex, 'balanced-regex'),
- (r's\((\\\\|\\\)|[^)])*\)\s*', String.Regex, 'balanced-regex'),
- (r'm?/(\\\\|\\/|[^/\n])*/[gcimosx]*', String.Regex),
- (r'm(?=[/!\\{<\[(@%$])', String.Regex, 'balanced-regex'),
-
- # Comments
- (r'#(.*?)\n', Comment.Single),
- # Symbols
- (r'\'([^\'\s\[\](){}]+|\[\])', String.Symbol),
- # Multi-line DoubleQuotedString
- (r'"""(\\\\|\\"|[^"])*"""', String),
- # DoubleQuotedString
- (r'"(\\\\|\\"|[^"])*"', String),
- # keywords
- (r'(def|class|try|catch|finally|retry|return|return_local|match|'
- r'case|->|=>)\b', Keyword),
- # constants
- (r'(self|super|nil|false|true)\b', Name.Constant),
- (r'[(){};,/?|:\\]', Punctuation),
- # names
- (words((
- 'Object', 'Array', 'Hash', 'Directory', 'File', 'Class', 'String',
- 'Number', 'Enumerable', 'FancyEnumerable', 'Block', 'TrueClass',
- 'NilClass', 'FalseClass', 'Tuple', 'Symbol', 'Stack', 'Set',
- 'FancySpec', 'Method', 'Package', 'Range'), suffix=r'\b'),
- Name.Builtin),
- # functions
- (r'[a-zA-Z](\w|[-+?!=*/^><%])*:', Name.Function),
- # operators, must be below functions
- (r'[-+*/~,<>=&!?%^\[\].$]+', Operator),
- ('[A-Z]\w*', Name.Constant),
- ('@[a-zA-Z_]\w*', Name.Variable.Instance),
- ('@@[a-zA-Z_]\w*', Name.Variable.Class),
- ('@@?', Operator),
- ('[a-zA-Z_]\w*', Name),
- # numbers - / checks are necessary to avoid mismarking regexes,
- # see comment in RubyLexer
- (r'(0[oO]?[0-7]+(?:_[0-7]+)*)(\s*)([/?])?',
- bygroups(Number.Oct, Text, Operator)),
- (r'(0[xX][0-9A-Fa-f]+(?:_[0-9A-Fa-f]+)*)(\s*)([/?])?',
- bygroups(Number.Hex, Text, Operator)),
- (r'(0[bB][01]+(?:_[01]+)*)(\s*)([/?])?',
- bygroups(Number.Bin, Text, Operator)),
- (r'([\d]+(?:_\d+)*)(\s*)([/?])?',
- bygroups(Number.Integer, Text, Operator)),
- (r'\d+([eE][+-]?[0-9]+)|\d+\.\d+([eE][+-]?[0-9]+)?', Number.Float),
- (r'\d+', Number.Integer)
- ]
+ 'in-macro-control': [
+ (r'\{%', String.Interpol, '#push'),
+ (r'%\}', String.Interpol, '#pop'),
+ (r'for\b|in\b', Keyword),
+ include('root'),
+ ],
+ 'in-macro-expr': [
+ (r'\{\{', String.Interpol, '#push'),
+ (r'\}\}', String.Interpol, '#pop'),
+ include('root'),
+ ],
+ 'in-attr': [
+ (r'\[', Operator, '#push'),
+ (r'\]', Operator, '#pop'),
+ include('root'),
+ ],
}
+ tokens.update(gen_crystalstrings_rules())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment