84 yield amatch.start(), Error, amatch.group() |
87 yield amatch.start(), Error, amatch.group() |
85 ctx.end = len(ctx.text) |
88 ctx.end = len(ctx.text) |
86 del heredocstack[:] |
89 del heredocstack[:] |
87 |
90 |
88 def gen_crystalstrings_rules(): |
91 def gen_crystalstrings_rules(): |
89 def intp_regex_callback(self, match, ctx): |
|
90 yield match.start(1), String.Regex, match.group(1) # begin |
|
91 nctx = LexerContext(match.group(3), 0, ['interpolated-regex']) |
|
92 for i, t, v in self.get_tokens_unprocessed(context=nctx): |
|
93 yield match.start(3)+i, t, v |
|
94 yield match.start(4), String.Regex, match.group(4) # end[imsx]* |
|
95 ctx.pos = match.end() |
|
96 |
|
97 def intp_string_callback(self, match, ctx): |
|
98 yield match.start(1), String.Other, match.group(1) |
|
99 nctx = LexerContext(match.group(3), 0, ['interpolated-string']) |
|
100 for i, t, v in self.get_tokens_unprocessed(context=nctx): |
|
101 yield match.start(3)+i, t, v |
|
102 yield match.start(4), String.Other, match.group(4) # end |
|
103 ctx.pos = match.end() |
|
104 |
|
105 states = {} |
92 states = {} |
106 states['strings'] = [ |
93 states['strings'] = [ |
107 (r'\:@{0,2}[a-zA-Z_]\w*[!?]?', String.Symbol), |
94 (r'\:\w+[!?]?', String.Symbol), |
108 (words(CRYSTAL_OPERATORS, prefix=r'\:@{0,2}'), String.Symbol), |
95 (words(CRYSTAL_OPERATORS, prefix=r'\:'), String.Symbol), |
109 (r":'(\\\\|\\'|[^'])*'", String.Symbol), |
96 (r":'(\\\\|\\[^\\]|[^'\\])*'", String.Symbol), |
110 # This allows arbitrary text after '\ for simplicity |
97 # This allows arbitrary text after '\ for simplicity |
111 (r"'(\\\\|\\'|[^']|\\[^'\\]+)'", String.Char), |
98 (r"'(\\\\|\\'|[^']|\\[^'\\]+)'", String.Char), |
112 (r':"', String.Symbol, 'simple-sym'), |
99 (r':"', String.Symbol, 'simple-sym'), |
113 # Crystal doesn't have "symbol:"s but this simplifies function args |
100 # Crystal doesn't have "symbol:"s but this simplifies function args |
114 (r'([a-zA-Z_]\w*)(:)(?!:)', bygroups(String.Symbol, Punctuation)), |
101 (r'([a-zA-Z_]\w*)(:)(?!:)', bygroups(String.Symbol, Punctuation)), |
125 (r'[^\\%s#]+' % end, ttype), |
112 (r'[^\\%s#]+' % end, ttype), |
126 (r'[\\#]', ttype), |
113 (r'[\\#]', ttype), |
127 (end, ttype, '#pop'), |
114 (end, ttype, '#pop'), |
128 ] |
115 ] |
129 |
116 |
130 # braced quoted strings |
117 # https://crystal-lang.org/docs/syntax_and_semantics/literals/string.html#percent-string-literals |
131 for lbrace, rbrace, bracecc, name in \ |
118 for lbrace, rbrace, bracecc, name in \ |
132 ('\\{', '\\}', '{}', 'cb'), \ |
119 ('\\{', '\\}', '{}', 'cb'), \ |
133 ('\\[', '\\]', '\\[\\]', 'sb'), \ |
120 ('\\[', '\\]', '\\[\\]', 'sb'), \ |
134 ('\\(', '\\)', '()', 'pa'), \ |
121 ('\\(', '\\)', '()', 'pa'), \ |
135 ('<', '>', '<>', 'ab'): |
122 ('<', '>', '<>', 'ab'), \ |
|
123 ('\\|', '\\|', '\\|', 'pi'): |
136 states[name+'-intp-string'] = [ |
124 states[name+'-intp-string'] = [ |
137 (r'\\' + lbrace, String.Other), |
125 (r'\\' + lbrace, String.Other), |
|
126 ] + (lbrace != rbrace) * [ |
138 (lbrace, String.Other, '#push'), |
127 (lbrace, String.Other, '#push'), |
|
128 ] + [ |
139 (rbrace, String.Other, '#pop'), |
129 (rbrace, String.Other, '#pop'), |
140 include('string-intp-escaped'), |
130 include('string-intp-escaped'), |
141 (r'[\\#' + bracecc + ']', String.Other), |
131 (r'[\\#' + bracecc + ']', String.Other), |
142 (r'[^\\#' + bracecc + ']+', String.Other), |
132 (r'[^\\#' + bracecc + ']+', String.Other), |
143 ] |
133 ] |
144 states['strings'].append((r'%' + lbrace, String.Other, |
134 states['strings'].append((r'%Q?' + lbrace, String.Other, |
145 name+'-intp-string')) |
135 name+'-intp-string')) |
146 states[name+'-string'] = [ |
136 states[name+'-string'] = [ |
147 (r'\\[\\' + bracecc + ']', String.Other), |
137 (r'\\[\\' + bracecc + ']', String.Other), |
|
138 ] + (lbrace != rbrace) * [ |
148 (lbrace, String.Other, '#push'), |
139 (lbrace, String.Other, '#push'), |
|
140 ] + [ |
149 (rbrace, String.Other, '#pop'), |
141 (rbrace, String.Other, '#pop'), |
150 (r'[\\#' + bracecc + ']', String.Other), |
142 (r'[\\#' + bracecc + ']', String.Other), |
151 (r'[^\\#' + bracecc + ']+', String.Other), |
143 (r'[^\\#' + bracecc + ']+', String.Other), |
152 ] |
144 ] |
153 # http://crystal-lang.org/docs/syntax_and_semantics/literals/array.html |
145 # https://crystal-lang.org/docs/syntax_and_semantics/literals/array.html#percent-array-literals |
154 states['strings'].append((r'%[wi]' + lbrace, String.Other, |
146 states['strings'].append((r'%[qwi]' + lbrace, String.Other, |
155 name+'-string')) |
147 name+'-string')) |
156 states[name+'-regex'] = [ |
148 states[name+'-regex'] = [ |
157 (r'\\[\\' + bracecc + ']', String.Regex), |
149 (r'\\[\\' + bracecc + ']', String.Regex), |
|
150 ] + (lbrace != rbrace) * [ |
158 (lbrace, String.Regex, '#push'), |
151 (lbrace, String.Regex, '#push'), |
|
152 ] + [ |
159 (rbrace + '[imsx]*', String.Regex, '#pop'), |
153 (rbrace + '[imsx]*', String.Regex, '#pop'), |
160 include('string-intp'), |
154 include('string-intp'), |
161 (r'[\\#' + bracecc + ']', String.Regex), |
155 (r'[\\#' + bracecc + ']', String.Regex), |
162 (r'[^\\#' + bracecc + ']+', String.Regex), |
156 (r'[^\\#' + bracecc + ']+', String.Regex), |
163 ] |
157 ] |
164 states['strings'].append((r'%r' + lbrace, String.Regex, |
158 states['strings'].append((r'%r' + lbrace, String.Regex, |
165 name+'-regex')) |
159 name+'-regex')) |
166 |
160 |
167 # these must come after %<brace>! |
|
168 states['strings'] += [ |
|
169 # %r regex |
|
170 (r'(%r([\W_]))((?:\\\2|(?!\2).)*)(\2[imsx]*)', |
|
171 intp_regex_callback), |
|
172 # regular fancy strings with qsw |
|
173 (r'(%[wi]([\W_]))((?:\\\2|(?!\2).)*)(\2)', |
|
174 intp_string_callback), |
|
175 # special forms of fancy strings after operators or |
|
176 # in method calls with braces |
|
177 (r'(?<=[-+/*%=<>&!^|~,(])(\s*)(%([\t ])(?:(?:\\\3|(?!\3).)*)\3)', |
|
178 bygroups(Text, String.Other, None)), |
|
179 # and because of fixed width lookbehinds the whole thing a |
|
180 # second time for line startings... |
|
181 (r'^(\s*)(%([\t ])(?:(?:\\\3|(?!\3).)*)\3)', |
|
182 bygroups(Text, String.Other, None)), |
|
183 # all regular fancy strings without qsw |
|
184 (r'(%([\[{(<]))((?:\\\2|(?!\2).)*)(\2)', |
|
185 intp_string_callback), |
|
186 ] |
|
187 |
|
188 return states |
161 return states |
189 |
162 |
190 tokens = { |
163 tokens = { |
191 'root': [ |
164 'root': [ |
192 (r'#.*?$', Comment.Single), |
165 (r'#.*?$', Comment.Single), |
193 # keywords |
166 # keywords |
194 (words(''' |
167 (words(''' |
195 abstract asm as begin break case do else elsif end ensure extend ifdef if |
168 abstract asm begin break case do else elsif end ensure extend if in |
196 include instance_sizeof next of pointerof private protected rescue return |
169 include next of private protected require rescue return select self super |
197 require sizeof super then typeof unless until when while with yield |
170 then unless until when while with yield |
198 '''.split(), suffix=r'\b'), Keyword), |
171 '''.split(), suffix=r'\b'), Keyword), |
|
172 (words(''' |
|
173 previous_def forall out uninitialized __DIR__ __FILE__ __LINE__ |
|
174 __END_LINE__ |
|
175 '''.split(), prefix=r'(?<!\.)', suffix=r'\b'), Keyword.Pseudo), |
|
176 # https://crystal-lang.org/docs/syntax_and_semantics/is_a.html |
|
177 (r'\.(is_a\?|nil\?|responds_to\?|as\?|as\b)', Keyword.Pseudo), |
199 (words(['true', 'false', 'nil'], suffix=r'\b'), Keyword.Constant), |
178 (words(['true', 'false', 'nil'], suffix=r'\b'), Keyword.Constant), |
200 # start of function, class and module names |
179 # start of function, class and module names |
201 (r'(module|lib)(\s+)([a-zA-Z_]\w*(?:::[a-zA-Z_]\w*)*)', |
180 (r'(module|lib)(\s+)([a-zA-Z_]\w*(?:::[a-zA-Z_]\w*)*)', |
202 bygroups(Keyword, Text, Name.Namespace)), |
181 bygroups(Keyword, Text, Name.Namespace)), |
203 (r'(def|fun|macro)(\s+)((?:[a-zA-Z_]\w*::)*)', |
182 (r'(def|fun|macro)(\s+)((?:[a-zA-Z_]\w*::)*)', |
204 bygroups(Keyword, Text, Name.Namespace), 'funcname'), |
183 bygroups(Keyword, Text, Name.Namespace), 'funcname'), |
205 (r'def(?=[*%&^`~+-/\[<>=])', Keyword, 'funcname'), |
184 (r'def(?=[*%&^`~+-/\[<>=])', Keyword, 'funcname'), |
206 (r'(class|struct|union|type|alias|enum)(\s+)((?:[a-zA-Z_]\w*::)*)', |
185 (r'(annotation|class|struct|union|type|alias|enum)(\s+)((?:[a-zA-Z_]\w*::)*)', |
207 bygroups(Keyword, Text, Name.Namespace), 'classname'), |
186 bygroups(Keyword, Text, Name.Namespace), 'classname'), |
208 (r'(self|out|uninitialized)\b|(is_a|responds_to)\?', Keyword.Pseudo), |
187 # https://crystal-lang.org/api/toplevel.html |
|
188 (words(''' |
|
189 instance_sizeof offsetof pointerof sizeof typeof |
|
190 '''.split(), prefix=r'(?<!\.)', suffix=r'\b'), Keyword.Pseudo), |
209 # macros |
191 # macros |
|
192 (r'(?<!\.)(debugger\b|p!|pp!|record\b|spawn\b)', Name.Builtin.Pseudo), |
|
193 # builtins |
210 (words(''' |
194 (words(''' |
211 debugger record pp assert_responds_to spawn parallel |
195 abort at_exit caller exit gets loop main p pp print printf puts |
212 getter setter property delegate def_hash def_equals def_equals_and_hash |
196 raise rand read_line sleep spawn sprintf system |
213 forward_missing_to |
|
214 '''.split(), suffix=r'\b'), Name.Builtin.Pseudo), |
|
215 (r'getter[!?]|property[!?]|__(DIR|FILE|LINE)__\b', Name.Builtin.Pseudo), |
|
216 # builtins |
|
217 # http://crystal-lang.org/api/toplevel.html |
|
218 (words(''' |
|
219 Object Value Struct Reference Proc Class Nil Symbol Enum Void |
|
220 Bool Number Int Int8 Int16 Int32 Int64 UInt8 UInt16 UInt32 UInt64 |
|
221 Float Float32 Float64 Char String |
|
222 Pointer Slice Range Exception Regex |
|
223 Mutex StaticArray Array Hash Set Tuple Deque Box Process File |
|
224 Dir Time Channel Concurrent Scheduler |
|
225 abort at_exit caller delay exit fork future get_stack_top gets |
|
226 lazy loop main p print printf puts |
|
227 raise rand read_line sleep sprintf system with_color |
|
228 '''.split(), prefix=r'(?<!\.)', suffix=r'\b'), Name.Builtin), |
197 '''.split(), prefix=r'(?<!\.)', suffix=r'\b'), Name.Builtin), |
|
198 # https://crystal-lang.org/api/Object.html#macro-summary |
|
199 (r'(?<!\.)(((class_)?((getter|property)\b[!?]?|setter\b))|' |
|
200 r'(def_(clone|equals|equals_and_hash|hash)|delegate|forward_missing_to)\b)', |
|
201 Name.Builtin.Pseudo), |
229 # normal heredocs |
202 # normal heredocs |
230 (r'(?<!\w)(<<-?)(["`\']?)([a-zA-Z_]\w*)(\2)(.*?\n)', |
203 (r'(?<!\w)(<<-?)(["`\']?)([a-zA-Z_]\w*)(\2)(.*?\n)', |
231 heredoc_callback), |
204 heredoc_callback), |
232 # empty string heredocs |
205 # empty string heredocs |
233 (r'(<<-?)("|\')()(\2)(.*?\n)', heredoc_callback), |
206 (r'(<<-?)("|\')()(\2)(.*?\n)', heredoc_callback), |
295 (r'\$\w+', Name.Variable.Global), |
268 (r'\$\w+', Name.Variable.Global), |
296 (r'\$[!@&`\'+~=/\\,;.<>_*$?:"^-]', Name.Variable.Global), |
269 (r'\$[!@&`\'+~=/\\,;.<>_*$?:"^-]', Name.Variable.Global), |
297 (r'\$-[0adFiIlpvw]', Name.Variable.Global), |
270 (r'\$-[0adFiIlpvw]', Name.Variable.Global), |
298 (r'::', Operator), |
271 (r'::', Operator), |
299 include('strings'), |
272 include('strings'), |
300 # chars |
273 # https://crystal-lang.org/reference/syntax_and_semantics/literals/char.html |
301 (r'\?(\\[MC]-)*' # modifiers |
274 (r'\?(\\[MC]-)*' # modifiers |
302 r'(\\([\\befnrtv#"\']|x[a-fA-F0-9]{1,2}|[0-7]{1,3})|\S)' |
275 r'(\\([\\abefnrtv#"\']|[0-7]{1,3}|x[a-fA-F0-9]{2}|u[a-fA-F0-9]{4}|u\{[a-fA-F0-9 ]+\})|\S)' |
303 r'(?!\w)', |
276 r'(?!\w)', |
304 String.Char), |
277 String.Char), |
305 (r'[A-Z][A-Z_]+\b', Name.Constant), |
278 (r'[A-Z][A-Z_]+\b(?!::|\.)', Name.Constant), |
306 # macro expansion |
279 # macro expansion |
307 (r'\{%', String.Interpol, 'in-macro-control'), |
280 (r'\{%', String.Interpol, 'in-macro-control'), |
308 (r'\{\{', String.Interpol, 'in-macro-expr'), |
281 (r'\{\{', String.Interpol, 'in-macro-expr'), |
309 # attributes |
282 # annotations |
310 (r'(@\[)(\s*)([A-Z]\w*)', |
283 (r'(@\[)(\s*)([A-Z]\w*(::[A-Z]\w*)*)', |
311 bygroups(Operator, Text, Name.Decorator), 'in-attr'), |
284 bygroups(Operator, Text, Name.Decorator), 'in-annot'), |
312 # this is needed because Crystal attributes can look |
285 # this is needed because Crystal attributes can look |
313 # like keywords (class) or like this: ` ?!? |
286 # like keywords (class) or like this: ` ?!? |
314 (words(CRYSTAL_OPERATORS, prefix=r'(\.|::)'), |
287 (words(CRYSTAL_OPERATORS, prefix=r'(\.|::)'), |
315 bygroups(Operator, Name.Operator)), |
288 bygroups(Operator, Name.Operator)), |
316 (r'(\.|::)([a-zA-Z_]\w*[!?]?|[*%&^`~+\-/\[<>=])', |
289 (r'(\.|::)([a-zA-Z_]\w*[!?]?|[*%&^`~+\-/\[<>=])', |