1"""
2 pygments.lexers.dotnet
3 ~~~~~~~~~~~~~~~~~~~~~~
4
5 Lexers for .net languages.
6
7 :copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
8 :license: BSD, see LICENSE for details.
9"""
10import re
11
12from pygments.lexer import RegexLexer, DelegatingLexer, bygroups, include, \
13 using, this, default, words
14from pygments.token import Punctuation, Text, Comment, Operator, Keyword, \
15 Name, String, Number, Literal, Other, Whitespace
16from pygments.util import get_choice_opt
17from pygments import unistring as uni
18
19from pygments.lexers.html import XmlLexer
20
21__all__ = ['CSharpLexer', 'NemerleLexer', 'BooLexer', 'VbNetLexer',
22 'CSharpAspxLexer', 'VbNetAspxLexer', 'FSharpLexer', 'XppLexer']
23
24
25class CSharpLexer(RegexLexer):
26 """
27 For C# source code.
28
29 Additional options accepted:
30
31 `unicodelevel`
32 Determines which Unicode characters this lexer allows for identifiers.
33 The possible values are:
34
35 * ``none`` -- only the ASCII letters and numbers are allowed. This
36 is the fastest selection.
37 * ``basic`` -- all Unicode characters from the specification except
38 category ``Lo`` are allowed.
39 * ``full`` -- all Unicode characters as specified in the C# specs
40 are allowed. Note that this means a considerable slowdown since the
41 ``Lo`` category has more than 40,000 characters in it!
42
43 The default value is ``basic``.
44
45 .. versionadded:: 0.8
46 """
47
48 name = 'C#'
49 url = 'https://docs.microsoft.com/en-us/dotnet/csharp/'
50 aliases = ['csharp', 'c#', 'cs']
51 filenames = ['*.cs']
52 mimetypes = ['text/x-csharp'] # inferred
53 version_added = ''
54
55 flags = re.MULTILINE | re.DOTALL
56
57 # for the range of allowed unicode characters in identifiers, see
58 # http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf
59
60 levels = {
61 'none': r'@?[_a-zA-Z]\w*',
62 'basic': ('@?[_' + uni.combine('Lu', 'Ll', 'Lt', 'Lm', 'Nl') + ']' +
63 '[' + uni.combine('Lu', 'Ll', 'Lt', 'Lm', 'Nl', 'Nd', 'Pc',
64 'Cf', 'Mn', 'Mc') + ']*'),
65 'full': ('@?(?:_|[^' +
66 uni.allexcept('Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl') + '])' +
67 '[^' + uni.allexcept('Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl',
68 'Nd', 'Pc', 'Cf', 'Mn', 'Mc') + ']*'),
69 }
70
71 tokens = {}
72 token_variants = True
73
74 for levelname, cs_ident in levels.items():
75 tokens[levelname] = {
76 'root': [
77 include('numbers'),
78 # method names
79 (r'^([ \t]*)((?:' + cs_ident + r'(?:\[\])?\s+)+?)' # return type
80 r'(' + cs_ident + ')' # method name
81 r'(\s*)(\()', # signature start
82 bygroups(Whitespace, using(this), Name.Function, Whitespace,
83 Punctuation)),
84 (r'^(\s*)(\[.*?\])', bygroups(Whitespace, Name.Attribute)),
85 (r'[^\S\n]+', Whitespace),
86 (r'(\\)(\n)', bygroups(Text, Whitespace)), # line continuation
87 (r'//.*?\n', Comment.Single),
88 (r'/[*].*?[*]/', Comment.Multiline),
89 (r'\n', Whitespace),
90 (words((
91 '>>>=', '>>=', '<<=', '<=', '>=', '+=', '-=', '*=', '/=',
92 '%=', '&=', '|=', '^=', '??=', '=>', '??', '?.', '!=', '==',
93 '&&', '||', '>>>', '>>', '<<', '++', '--', '+', '-', '*',
94 '/', '%', '&', '|', '^', '<', '>', '?', '!', '~', '=',
95 )), Operator),
96 (r'=~|!=|==|<<|>>|[-+/*%=<>&^|]', Operator),
97 (r'[()\[\];:,.]', Punctuation),
98 (r'[{}]', Punctuation),
99 (r'@"(""|[^"])*"', String),
100 (r'\$?"(\\\\|\\[^\\]|[^"\\\n])*["\n]', String),
101 (r"'\\.'|'[^\\]'", String.Char),
102 (r"[0-9]+(\.[0-9]*)?([eE][+-][0-9]+)?"
103 r"[flFLdD]?|0[xX][0-9a-fA-F]+[Ll]?", Number),
104 (r'(#)([ \t]*)(if|endif|else|elif|define|undef|'
105 r'line|error|warning|region|endregion|pragma)\b(.*?)(\n)',
106 bygroups(Comment.Preproc, Whitespace, Comment.Preproc,
107 Comment.Preproc, Whitespace)),
108 (r'\b(extern)(\s+)(alias)\b', bygroups(Keyword, Whitespace,
109 Keyword)),
110 (words((
111 'abstract', 'as', 'async', 'await', 'base', 'break', 'by',
112 'case', 'catch', 'checked', 'const', 'continue', 'default',
113 'delegate', 'do', 'else', 'enum', 'event', 'explicit',
114 'extern', 'false', 'finally', 'fixed', 'for', 'foreach',
115 'goto', 'if', 'implicit', 'in', 'interface', 'internal',
116 'is', 'let', 'lock', 'new', 'null', 'on', 'operator',
117 'out', 'override', 'params', 'private', 'protected',
118 'public', 'readonly', 'ref', 'return', 'sealed', 'sizeof',
119 'stackalloc', 'static', 'switch', 'this', 'throw', 'true',
120 'try', 'typeof', 'unchecked', 'unsafe', 'virtual', 'void',
121 'while', 'get', 'set', 'new', 'partial', 'yield', 'add',
122 'remove', 'value', 'alias', 'ascending', 'descending',
123 'from', 'group', 'into', 'orderby', 'select', 'thenby',
124 'where', 'join', 'equals', 'record', 'allows',
125 'and', 'init', 'managed', 'nameof', 'nint', 'not',
126 'notnull', 'nuint', 'or', 'scoped', 'unmanaged', 'when',
127 'with'
128 ), suffix=r'\b'), Keyword),
129 # version 1: assumes that 'file' is the only contextual keyword
130 # that is a class modifier
131 (r'(file)(\s+)(record|class|abstract|enum|new|sealed|static)\b',
132 bygroups(Keyword, Whitespace, Keyword)),
133 (r'(global)(::)', bygroups(Keyword, Punctuation)),
134 (r'(bool|byte|char|decimal|double|dynamic|float|int|long|object|'
135 r'sbyte|short|string|uint|ulong|ushort|var)\b\??', Keyword.Type),
136 (r'(class|struct)(\s+)', bygroups(Keyword, Whitespace), 'class'),
137 (r'(namespace|using)(\s+)', bygroups(Keyword, Whitespace), 'namespace'),
138 (cs_ident, Name),
139 ],
140 'numbers_int': [
141 (r"0[xX][0-9a-fA-F]+(([uU][lL]?)|[lL][uU]?)?", Number.Hex),
142 (r"0[bB][01]+(([uU][lL]?)|[lL][uU]?)?", Number.Bin),
143 (r"[0-9]+(([uU][lL]?)|[lL][uU]?)?", Number.Integer),
144 ],
145 'numbers_float': [
146 (r"([0-9]+\.[0-9]+([eE][+-]?[0-9]+)?[fFdDmM]?)|"
147 r"(\.[0-9]+([eE][+-]?[0-9]+)?[fFdDmM]?)|"
148 r"([0-9]+([eE][+-]?[0-9]+)[fFdDmM]?)|"
149 r"([0-9]+[fFdDmM])", Number.Float),
150 ],
151 'numbers': [
152 include('numbers_float'),
153 include('numbers_int'),
154 ],
155 'class': [
156 (cs_ident, Name.Class, '#pop'),
157 default('#pop'),
158 ],
159 'namespace': [
160 (r'(?=\()', Text, '#pop'), # using (resource)
161 ('(' + cs_ident + r'|\.)+', Name.Namespace, '#pop'),
162 ]
163 }
164
165 def __init__(self, **options):
166 level = get_choice_opt(options, 'unicodelevel', list(self.tokens), 'basic')
167 if level not in self._all_tokens:
168 # compile the regexes now
169 self._tokens = self.__class__.process_tokendef(level)
170 else:
171 self._tokens = self._all_tokens[level]
172
173 RegexLexer.__init__(self, **options)
174
175
176class NemerleLexer(RegexLexer):
177 """
178 For Nemerle source code.
179
180 Additional options accepted:
181
182 `unicodelevel`
183 Determines which Unicode characters this lexer allows for identifiers.
184 The possible values are:
185
186 * ``none`` -- only the ASCII letters and numbers are allowed. This
187 is the fastest selection.
188 * ``basic`` -- all Unicode characters from the specification except
189 category ``Lo`` are allowed.
190 * ``full`` -- all Unicode characters as specified in the C# specs
191 are allowed. Note that this means a considerable slowdown since the
192 ``Lo`` category has more than 40,000 characters in it!
193
194 The default value is ``basic``.
195 """
196
197 name = 'Nemerle'
198 url = 'http://nemerle.org'
199 aliases = ['nemerle']
200 filenames = ['*.n']
201 mimetypes = ['text/x-nemerle'] # inferred
202 version_added = '1.5'
203
204 flags = re.MULTILINE | re.DOTALL
205
206 # for the range of allowed unicode characters in identifiers, see
207 # http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf
208
209 levels = {
210 'none': r'@?[_a-zA-Z]\w*',
211 'basic': ('@?[_' + uni.combine('Lu', 'Ll', 'Lt', 'Lm', 'Nl') + ']' +
212 '[' + uni.combine('Lu', 'Ll', 'Lt', 'Lm', 'Nl', 'Nd', 'Pc',
213 'Cf', 'Mn', 'Mc') + ']*'),
214 'full': ('@?(?:_|[^' +
215 uni.allexcept('Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl') + '])' +
216 '[^' + uni.allexcept('Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl',
217 'Nd', 'Pc', 'Cf', 'Mn', 'Mc') + ']*'),
218 }
219
220 tokens = {}
221 token_variants = True
222
223 for levelname, cs_ident in levels.items():
224 tokens[levelname] = {
225 'root': [
226 # method names
227 (r'^([ \t]*)((?:' + cs_ident + r'(?:\[\])?\s+)+?)' # return type
228 r'(' + cs_ident + ')' # method name
229 r'(\s*)(\()', # signature start
230 bygroups(Whitespace, using(this), Name.Function, Whitespace, \
231 Punctuation)),
232 (r'^(\s*)(\[.*?\])', bygroups(Whitespace, Name.Attribute)),
233 (r'[^\S\n]+', Whitespace),
234 (r'(\\)(\n)', bygroups(Text, Whitespace)), # line continuation
235 (r'//.*?\n', Comment.Single),
236 (r'/[*].*?[*]/', Comment.Multiline),
237 (r'\n', Whitespace),
238 (r'(\$)(\s*)(")', bygroups(String, Whitespace, String),
239 'splice-string'),
240 (r'(\$)(\s*)(<#)', bygroups(String, Whitespace, String),
241 'splice-string2'),
242 (r'<#', String, 'recursive-string'),
243
244 (r'(<\[)(\s*)(' + cs_ident + ':)?',
245 bygroups(Keyword, Whitespace, Keyword)),
246 (r'\]\>', Keyword),
247
248 # quasiquotation only
249 (r'\$' + cs_ident, Name),
250 (r'(\$)(\()', bygroups(Name, Punctuation),
251 'splice-string-content'),
252
253 (r'[~!%^&*()+=|\[\]:;,.<>/?-]', Punctuation),
254 (r'[{}]', Punctuation),
255 (r'@"(""|[^"])*"', String),
256 (r'"(\\\\|\\[^\\]|[^"\\\n])*["\n]', String),
257 (r"'\\.'|'[^\\]'", String.Char),
258 (r"0[xX][0-9a-fA-F]+[Ll]?", Number),
259 (r"[0-9](\.[0-9]*)?([eE][+-][0-9]+)?[flFLdD]?", Number),
260 (r'(#)([ \t]*)(if|endif|else|elif|define|undef|'
261 r'line|error|warning|region|endregion|pragma)\b',
262 bygroups(Comment.Preproc, Whitespace, Comment.Preproc), 'preproc'),
263 (r'\b(extern)(\s+)(alias)\b', bygroups(Keyword, Whitespace, Keyword)),
264 (r'(abstract|and|as|base|catch|def|delegate|'
265 r'enum|event|extern|false|finally|'
266 r'fun|implements|interface|internal|'
267 r'is|macro|match|matches|module|mutable|new|'
268 r'null|out|override|params|partial|private|'
269 r'protected|public|ref|sealed|static|'
270 r'syntax|this|throw|true|try|type|typeof|'
271 r'virtual|volatile|when|where|with|'
272 r'assert|assert2|async|break|checked|continue|do|else|'
273 r'ensures|for|foreach|if|late|lock|new|nolate|'
274 r'otherwise|regexp|repeat|requires|return|surroundwith|'
275 r'unchecked|unless|using|while|yield)\b', Keyword),
276 (r'(global)(::)', bygroups(Keyword, Punctuation)),
277 (r'(bool|byte|char|decimal|double|float|int|long|object|sbyte|'
278 r'short|string|uint|ulong|ushort|void|array|list)\b\??',
279 Keyword.Type),
280 (r'(:>?)(\s*)(' + cs_ident + r'\??)',
281 bygroups(Punctuation, Whitespace, Keyword.Type)),
282 (r'(class|struct|variant|module)(\s+)',
283 bygroups(Keyword, Whitespace), 'class'),
284 (r'(namespace|using)(\s+)', bygroups(Keyword, Whitespace),
285 'namespace'),
286 (cs_ident, Name),
287 ],
288 'class': [
289 (cs_ident, Name.Class, '#pop')
290 ],
291 'preproc': [
292 (r'\w+', Comment.Preproc),
293 (r'[ \t]+', Whitespace),
294 (r'\n', Whitespace, '#pop')
295 ],
296 'namespace': [
297 (r'(?=\()', Text, '#pop'), # using (resource)
298 ('(' + cs_ident + r'|\.)+', Name.Namespace, '#pop')
299 ],
300 'splice-string': [
301 (r'[^"$]', String),
302 (r'\$' + cs_ident, Name),
303 (r'(\$)(\()', bygroups(Name, Punctuation),
304 'splice-string-content'),
305 (r'\\"', String),
306 (r'"', String, '#pop')
307 ],
308 'splice-string2': [
309 (r'[^#<>$]', String),
310 (r'\$' + cs_ident, Name),
311 (r'(\$)(\()', bygroups(Name, Punctuation),
312 'splice-string-content'),
313 (r'<#', String, '#push'),
314 (r'#>', String, '#pop')
315 ],
316 'recursive-string': [
317 (r'[^#<>]', String),
318 (r'<#', String, '#push'),
319 (r'#>', String, '#pop')
320 ],
321 'splice-string-content': [
322 (r'if|match', Keyword),
323 (r'[~!%^&*+=|\[\]:;,.<>/?-\\"$ ]', Punctuation),
324 (cs_ident, Name),
325 (r'\d+', Number),
326 (r'\(', Punctuation, '#push'),
327 (r'\)', Punctuation, '#pop')
328 ]
329 }
330
331 def __init__(self, **options):
332 level = get_choice_opt(options, 'unicodelevel', list(self.tokens),
333 'basic')
334 if level not in self._all_tokens:
335 # compile the regexes now
336 self._tokens = self.__class__.process_tokendef(level)
337 else:
338 self._tokens = self._all_tokens[level]
339
340 RegexLexer.__init__(self, **options)
341
342 def analyse_text(text):
343 """Nemerle is quite similar to Python, but @if is relatively uncommon
344 elsewhere."""
345 result = 0
346
347 if '@if' in text:
348 result += 0.1
349
350 return result
351
352
353class BooLexer(RegexLexer):
354 """
355 For Boo source code.
356 """
357
358 name = 'Boo'
359 url = 'https://github.com/boo-lang/boo'
360 aliases = ['boo']
361 filenames = ['*.boo']
362 mimetypes = ['text/x-boo']
363 version_added = ''
364
365 tokens = {
366 'root': [
367 (r'\s+', Whitespace),
368 (r'(#|//).*$', Comment.Single),
369 (r'/[*]', Comment.Multiline, 'comment'),
370 (r'[]{}:(),.;[]', Punctuation),
371 (r'(\\)(\n)', bygroups(Text, Whitespace)),
372 (r'\\', Text),
373 (r'(in|is|and|or|not)\b', Operator.Word),
374 (r'/(\\\\|\\[^\\]|[^/\\\s])/', String.Regex),
375 (r'@/(\\\\|\\[^\\]|[^/\\])*/', String.Regex),
376 (r'=~|!=|==|<<|>>|[-+/*%=<>&^|]', Operator),
377 (r'(as|abstract|callable|constructor|destructor|do|import|'
378 r'enum|event|final|get|interface|internal|of|override|'
379 r'partial|private|protected|public|return|set|static|'
380 r'struct|transient|virtual|yield|super|and|break|cast|'
381 r'continue|elif|else|ensure|except|for|given|goto|if|in|'
382 r'is|isa|not|or|otherwise|pass|raise|ref|try|unless|when|'
383 r'while|from|as)\b', Keyword),
384 (r'def(?=\s+\(.*?\))', Keyword),
385 (r'(def)(\s+)', bygroups(Keyword, Whitespace), 'funcname'),
386 (r'(class)(\s+)', bygroups(Keyword, Whitespace), 'classname'),
387 (r'(namespace)(\s+)', bygroups(Keyword, Whitespace), 'namespace'),
388 (r'(?<!\.)(true|false|null|self|__eval__|__switch__|array|'
389 r'assert|checked|enumerate|filter|getter|len|lock|map|'
390 r'matrix|max|min|normalArrayIndexing|print|property|range|'
391 r'rawArrayIndexing|required|typeof|unchecked|using|'
392 r'yieldAll|zip)\b', Name.Builtin),
393 (r'"""(\\\\|\\"|.*?)"""', String.Double),
394 (r'"(\\\\|\\[^\\]|[^"\\])*"', String.Double),
395 (r"'(\\\\|\\[^\\]|[^'\\])*'", String.Single),
396 (r'[a-zA-Z_]\w*', Name),
397 (r'(\d+\.\d*|\d*\.\d+)([fF][+-]?[0-9]+)?', Number.Float),
398 (r'[0-9][0-9.]*(ms?|d|h|s)', Number),
399 (r'0\d+', Number.Oct),
400 (r'0x[a-fA-F0-9]+', Number.Hex),
401 (r'\d+L', Number.Integer.Long),
402 (r'\d+', Number.Integer),
403 ],
404 'comment': [
405 ('/[*]', Comment.Multiline, '#push'),
406 ('[*]/', Comment.Multiline, '#pop'),
407 ('[^/*]', Comment.Multiline),
408 ('[*/]', Comment.Multiline)
409 ],
410 'funcname': [
411 (r'[a-zA-Z_]\w*', Name.Function, '#pop')
412 ],
413 'classname': [
414 (r'[a-zA-Z_]\w*', Name.Class, '#pop')
415 ],
416 'namespace': [
417 (r'[a-zA-Z_][\w.]*', Name.Namespace, '#pop')
418 ]
419 }
420
421
422class VbNetLexer(RegexLexer):
423 """
424 For Visual Basic.NET source code.
425 Also LibreOffice Basic, OpenOffice Basic, and StarOffice Basic.
426 """
427
428 name = 'VB.net'
429 url = 'https://docs.microsoft.com/en-us/dotnet/visual-basic/'
430 aliases = ['vb.net', 'vbnet', 'lobas', 'oobas', 'sobas', 'visual-basic', 'visualbasic']
431 filenames = ['*.vb', '*.bas']
432 mimetypes = ['text/x-vbnet', 'text/x-vba'] # (?)
433 version_added = ''
434
435 uni_name = '[_' + uni.combine('Ll', 'Lt', 'Lm', 'Nl') + ']' + \
436 '[' + uni.combine('Ll', 'Lt', 'Lm', 'Nl', 'Nd', 'Pc',
437 'Cf', 'Mn', 'Mc') + ']*'
438
439 flags = re.MULTILINE | re.IGNORECASE
440 tokens = {
441 'root': [
442 (r'^\s*<.*?>', Name.Attribute),
443 (r'\s+', Whitespace),
444 (r'\n', Whitespace),
445 (r'(rem\b.*?)(\n)', bygroups(Comment, Whitespace)),
446 (r"('.*?)(\n)", bygroups(Comment, Whitespace)),
447 (r'#If\s.*?\sThen|#ElseIf\s.*?\sThen|#Else|#End\s+If|#Const|'
448 r'#ExternalSource.*?\n|#End\s+ExternalSource|'
449 r'#Region.*?\n|#End\s+Region|#ExternalChecksum',
450 Comment.Preproc),
451 (r'[(){}!#,.:]', Punctuation),
452 (r'(Option)(\s+)(Strict|Explicit|Compare)(\s+)'
453 r'(On|Off|Binary|Text)',
454 bygroups(Keyword.Declaration, Whitespace, Keyword.Declaration,
455 Whitespace, Keyword.Declaration)),
456 (words((
457 'AddHandler', 'Alias', 'ByRef', 'ByVal', 'Call', 'Case',
458 'Catch', 'CBool', 'CByte', 'CChar', 'CDate', 'CDec', 'CDbl',
459 'CInt', 'CLng', 'CObj', 'Continue', 'CSByte', 'CShort', 'CSng',
460 'CStr', 'CType', 'CUInt', 'CULng', 'CUShort', 'Declare',
461 'Default', 'Delegate', 'DirectCast', 'Do', 'Each', 'Else',
462 'ElseIf', 'EndIf', 'Erase', 'Error', 'Event', 'Exit', 'False',
463 'Finally', 'For', 'Friend', 'Get', 'Global', 'GoSub', 'GoTo',
464 'Handles', 'If', 'Implements', 'Inherits', 'Interface', 'Let',
465 'Lib', 'Loop', 'Me', 'MustInherit', 'MustOverride', 'MyBase',
466 'MyClass', 'Narrowing', 'New', 'Next', 'Not', 'Nothing',
467 'NotInheritable', 'NotOverridable', 'Of', 'On', 'Operator',
468 'Option', 'Optional', 'Overloads', 'Overridable', 'Overrides',
469 'ParamArray', 'Partial', 'Private', 'Protected', 'Public',
470 'RaiseEvent', 'ReadOnly', 'ReDim', 'RemoveHandler', 'Resume',
471 'Return', 'Select', 'Set', 'Shadows', 'Shared', 'Single',
472 'Static', 'Step', 'Stop', 'SyncLock', 'Then', 'Throw', 'To',
473 'True', 'Try', 'TryCast', 'Wend', 'Using', 'When', 'While',
474 'Widening', 'With', 'WithEvents', 'WriteOnly'),
475 prefix=r'(?<!\.)', suffix=r'\b'), Keyword),
476 (r'(?<!\.)End\b', Keyword, 'end'),
477 (r'(?<!\.)(Dim|Const)\b', Keyword, 'dim'),
478 (r'(?<!\.)(Function|Sub|Property)(\s+)',
479 bygroups(Keyword, Whitespace), 'funcname'),
480 (r'(?<!\.)(Class|Structure|Enum)(\s+)',
481 bygroups(Keyword, Whitespace), 'classname'),
482 (r'(?<!\.)(Module|Namespace|Imports)(\s+)',
483 bygroups(Keyword, Whitespace), 'namespace'),
484 (r'(?<!\.)(Boolean|Byte|Char|Date|Decimal|Double|Integer|Long|'
485 r'Object|SByte|Short|Single|String|Variant|UInteger|ULong|'
486 r'UShort)\b', Keyword.Type),
487 (r'(?<!\.)(AddressOf|And|AndAlso|As|GetType|In|Is|IsNot|Like|Mod|'
488 r'Or|OrElse|TypeOf|Xor)\b', Operator.Word),
489 (r'&=|[*]=|/=|\\=|\^=|\+=|-=|<<=|>>=|<<|>>|:=|'
490 r'<=|>=|<>|[-&*/\\^+=<>\[\]]',
491 Operator),
492 ('"', String, 'string'),
493 (r'(_)(\n)', bygroups(Text, Whitespace)), # Line continuation (must be before Name)
494 (uni_name + '[%&@!#$]?', Name),
495 ('#.*?#', Literal.Date),
496 (r'(\d+\.\d*|\d*\.\d+)(F[+-]?[0-9]+)?', Number.Float),
497 (r'\d+([SILDFR]|US|UI|UL)?', Number.Integer),
498 (r'&H[0-9a-f]+([SILDFR]|US|UI|UL)?', Number.Integer),
499 (r'&O[0-7]+([SILDFR]|US|UI|UL)?', Number.Integer),
500 ],
501 'string': [
502 (r'""', String),
503 (r'"C?', String, '#pop'),
504 (r'[^"]+', String),
505 ],
506 'dim': [
507 (uni_name, Name.Variable, '#pop'),
508 default('#pop'), # any other syntax
509 ],
510 'funcname': [
511 (uni_name, Name.Function, '#pop'),
512 ],
513 'classname': [
514 (uni_name, Name.Class, '#pop'),
515 ],
516 'namespace': [
517 (uni_name, Name.Namespace),
518 (r'\.', Name.Namespace),
519 default('#pop'),
520 ],
521 'end': [
522 (r'\s+', Whitespace),
523 (r'(Function|Sub|Property|Class|Structure|Enum|Module|Namespace)\b',
524 Keyword, '#pop'),
525 default('#pop'),
526 ]
527 }
528
529 def analyse_text(text):
530 if re.search(r'^\s*(#If|Module|Namespace)', text, re.MULTILINE):
531 return 0.5
532
533
534class GenericAspxLexer(RegexLexer):
535 """
536 Lexer for ASP.NET pages.
537 """
538
539 name = 'aspx-gen'
540 filenames = []
541 mimetypes = []
542 url = 'https://dotnet.microsoft.com/en-us/apps/aspnet'
543
544 flags = re.DOTALL
545
546 tokens = {
547 'root': [
548 (r'(<%[@=#]?)(.*?)(%>)', bygroups(Name.Tag, Other, Name.Tag)),
549 (r'(<script.*?>)(.*?)(</script>)', bygroups(using(XmlLexer),
550 Other,
551 using(XmlLexer))),
552 (r'(.+?)(?=<)', using(XmlLexer)),
553 (r'.+', using(XmlLexer)),
554 ],
555 }
556
557
558# TODO support multiple languages within the same source file
559class CSharpAspxLexer(DelegatingLexer):
560 """
561 Lexer for highlighting C# within ASP.NET pages.
562 """
563
564 name = 'aspx-cs'
565 aliases = ['aspx-cs']
566 filenames = ['*.aspx', '*.asax', '*.ascx', '*.ashx', '*.asmx', '*.axd']
567 mimetypes = []
568 url = 'https://dotnet.microsoft.com/en-us/apps/aspnet'
569 version_added = ''
570
571 def __init__(self, **options):
572 super().__init__(CSharpLexer, GenericAspxLexer, **options)
573
574 def analyse_text(text):
575 if re.search(r'Page\s*Language="C#"', text, re.I) is not None:
576 return 0.2
577 elif re.search(r'script[^>]+language=["\']C#', text, re.I) is not None:
578 return 0.15
579
580
581class VbNetAspxLexer(DelegatingLexer):
582 """
583 Lexer for highlighting Visual Basic.net within ASP.NET pages.
584 """
585
586 name = 'aspx-vb'
587 aliases = ['aspx-vb']
588 filenames = ['*.aspx', '*.asax', '*.ascx', '*.ashx', '*.asmx', '*.axd']
589 mimetypes = []
590 url = 'https://dotnet.microsoft.com/en-us/apps/aspnet'
591 version_added = ''
592
593 def __init__(self, **options):
594 super().__init__(VbNetLexer, GenericAspxLexer, **options)
595
596 def analyse_text(text):
597 if re.search(r'Page\s*Language="Vb"', text, re.I) is not None:
598 return 0.2
599 elif re.search(r'script[^>]+language=["\']vb', text, re.I) is not None:
600 return 0.15
601
602
603# Very close to functional.OcamlLexer
604class FSharpLexer(RegexLexer):
605 """
606 For the F# language (version 3.0).
607 """
608
609 name = 'F#'
610 url = 'https://fsharp.org/'
611 aliases = ['fsharp', 'f#']
612 filenames = ['*.fs', '*.fsi', '*.fsx']
613 mimetypes = ['text/x-fsharp']
614 version_added = '1.5'
615
616 keywords = [
617 'abstract', 'as', 'assert', 'base', 'begin', 'class', 'default',
618 'delegate', 'do!', 'do', 'done', 'downcast', 'downto', 'elif', 'else',
619 'end', 'exception', 'extern', 'false', 'finally', 'for', 'function',
620 'fun', 'global', 'if', 'inherit', 'inline', 'interface', 'internal',
621 'in', 'lazy', 'let!', 'let', 'match', 'member', 'module', 'mutable',
622 'namespace', 'new', 'null', 'of', 'open', 'override', 'private', 'public',
623 'rec', 'return!', 'return', 'select', 'static', 'struct', 'then', 'to',
624 'true', 'try', 'type', 'upcast', 'use!', 'use', 'val', 'void', 'when',
625 'while', 'with', 'yield!', 'yield',
626 ]
627 # Reserved words; cannot hurt to color them as keywords too.
628 keywords += [
629 'atomic', 'break', 'checked', 'component', 'const', 'constraint',
630 'constructor', 'continue', 'eager', 'event', 'external', 'fixed',
631 'functor', 'include', 'method', 'mixin', 'object', 'parallel',
632 'process', 'protected', 'pure', 'sealed', 'tailcall', 'trait',
633 'virtual', 'volatile',
634 ]
635 keyopts = [
636 '!=', '#', '&&', '&', r'\(', r'\)', r'\*', r'\+', ',', r'-\.',
637 '->', '-', r'\.\.', r'\.', '::', ':=', ':>', ':', ';;', ';', '<-',
638 r'<\]', '<', r'>\]', '>', r'\?\?', r'\?', r'\[<', r'\[\|', r'\[', r'\]',
639 '_', '`', r'\{', r'\|\]', r'\|', r'\}', '~', '<@@', '<@', '=', '@>', '@@>',
640 ]
641
642 operators = r'[!$%&*+\./:<=>?@^|~-]'
643 word_operators = ['and', 'or', 'not']
644 prefix_syms = r'[!?~]'
645 infix_syms = r'[=<>@^|&+\*/$%-]'
646 primitives = [
647 'sbyte', 'byte', 'char', 'nativeint', 'unativeint', 'float32', 'single',
648 'float', 'double', 'int8', 'uint8', 'int16', 'uint16', 'int32',
649 'uint32', 'int64', 'uint64', 'decimal', 'unit', 'bool', 'string',
650 'list', 'exn', 'obj', 'enum',
651 ]
652
653 # See http://msdn.microsoft.com/en-us/library/dd233181.aspx and/or
654 # http://fsharp.org/about/files/spec.pdf for reference. Good luck.
655
656 tokens = {
657 'escape-sequence': [
658 (r'\\[\\"\'ntbrafv]', String.Escape),
659 (r'\\[0-9]{3}', String.Escape),
660 (r'\\u[0-9a-fA-F]{4}', String.Escape),
661 (r'\\U[0-9a-fA-F]{8}', String.Escape),
662 ],
663 'root': [
664 (r'\s+', Whitespace),
665 (r'\(\)|\[\]', Name.Builtin.Pseudo),
666 (r'\b(?<!\.)([A-Z][\w\']*)(?=\s*\.)',
667 Name.Namespace, 'dotted'),
668 (r'\b([A-Z][\w\']*)', Name),
669 (r'(///.*?)(\n)', bygroups(String.Doc, Whitespace)),
670 (r'(//.*?)(\n)', bygroups(Comment.Single, Whitespace)),
671 (r'\(\*(?!\))', Comment, 'comment'),
672
673 (r'@"', String, 'lstring'),
674 (r'"""', String, 'tqs'),
675 (r'"', String, 'string'),
676
677 (r'\b(open|module)(\s+)([\w.]+)',
678 bygroups(Keyword, Whitespace, Name.Namespace)),
679 (r'\b(let!?)(\s+)(\w+)',
680 bygroups(Keyword, Whitespace, Name.Variable)),
681 (r'\b(type)(\s+)(\w+)',
682 bygroups(Keyword, Whitespace, Name.Class)),
683 (r'\b(member|override)(\s+)(\w+)(\.)(\w+)',
684 bygroups(Keyword, Whitespace, Name, Punctuation, Name.Function)),
685 (r'\b({})\b'.format('|'.join(keywords)), Keyword),
686 (r'``([^`\n\r\t]|`[^`\n\r\t])+``', Name),
687 (r'({})'.format('|'.join(keyopts)), Operator),
688 (rf'({infix_syms}|{prefix_syms})?{operators}', Operator),
689 (r'\b({})\b'.format('|'.join(word_operators)), Operator.Word),
690 (r'\b({})\b'.format('|'.join(primitives)), Keyword.Type),
691 (r'(#)([ \t]*)(if|endif|else|line|nowarn|light|\d+)\b(.*?)(\n)',
692 bygroups(Comment.Preproc, Whitespace, Comment.Preproc,
693 Comment.Preproc, Whitespace)),
694
695 (r"[^\W\d][\w']*", Name),
696
697 (r'\d[\d_]*[uU]?[yslLnQRZINGmM]?', Number.Integer),
698 (r'0[xX][\da-fA-F][\da-fA-F_]*[uU]?[yslLn]?[fF]?', Number.Hex),
699 (r'0[oO][0-7][0-7_]*[uU]?[yslLn]?', Number.Oct),
700 (r'0[bB][01][01_]*[uU]?[yslLn]?', Number.Bin),
701 (r'-?\d[\d_]*(.[\d_]*)?([eE][+\-]?\d[\d_]*)[fFmM]?',
702 Number.Float),
703
704 (r"'(?:(\\[\\\"'ntbr ])|(\\[0-9]{3})|(\\x[0-9a-fA-F]{2}))'B?",
705 String.Char),
706 (r"'.'", String.Char),
707 (r"'", Keyword), # a stray quote is another syntax element
708
709 (r'@?"', String.Double, 'string'),
710
711 (r'[~?][a-z][\w\']*:', Name.Variable),
712 ],
713 'dotted': [
714 (r'\s+', Whitespace),
715 (r'\.', Punctuation),
716 (r'[A-Z][\w\']*(?=\s*\.)', Name.Namespace),
717 (r'[A-Z][\w\']*', Name, '#pop'),
718 (r'[a-z_][\w\']*', Name, '#pop'),
719 # e.g. dictionary index access
720 default('#pop'),
721 ],
722 'comment': [
723 (r'[^(*)@"]+', Comment),
724 (r'\(\*', Comment, '#push'),
725 (r'\*\)', Comment, '#pop'),
726 # comments cannot be closed within strings in comments
727 (r'@"', String, 'lstring'),
728 (r'"""', String, 'tqs'),
729 (r'"', String, 'string'),
730 (r'[(*)@]', Comment),
731 ],
732 'string': [
733 (r'[^\\"]+', String),
734 include('escape-sequence'),
735 (r'\\\n', String),
736 (r'\n', String), # newlines are allowed in any string
737 (r'"B?', String, '#pop'),
738 ],
739 'lstring': [
740 (r'[^"]+', String),
741 (r'\n', String),
742 (r'""', String),
743 (r'"B?', String, '#pop'),
744 ],
745 'tqs': [
746 (r'[^"]+', String),
747 (r'\n', String),
748 (r'"""B?', String, '#pop'),
749 (r'"', String),
750 ],
751 }
752
753 def analyse_text(text):
754 """F# doesn't have that many unique features -- |> and <| are weak
755 indicators."""
756 result = 0
757 if '|>' in text:
758 result += 0.05
759 if '<|' in text:
760 result += 0.05
761
762 return result
763
764
765class XppLexer(RegexLexer):
766
767 """
768 For X++ source code. This is based loosely on the CSharpLexer
769 """
770
771 name = 'X++'
772 url = 'https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/dev-ref/xpp-language-reference'
773 aliases = ['xpp', 'x++']
774 filenames = ['*.xpp']
775 version_added = '2.15'
776
777 flags = re.MULTILINE
778
779 XPP_CHARS = ('@?(?:_|[^' +
780 uni.allexcept('Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl') + '])' +
781 '[^' + uni.allexcept('Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl',
782 'Nd', 'Pc', 'Cf', 'Mn', 'Mc') + ']*')
783 # Temporary, see
784 # https://github.com/thatch/regexlint/pull/49
785 XPP_CHARS = XPP_CHARS.replace('\x00', '\x01')
786
787 OPERATORS = (
788 '<=', '>=', '+=', '-=', '*=', '/=', '!=', '==',
789 '&&', '||', '>>', '<<', '++', '--', '+', '-', '*',
790 '/', '%', '&', '|', '^', '<', '>', '?', '!', '~', '=',
791 )
792 KEYWORDS = ('abstract','anytype','as','async','asc','at','avg','break','breakpoint','by','byref','case','catch',
793 'changecompany','client','container','continue','count','crosscompany','default','delegate',
794 'delete_from','desc','display','div','do','edit','else','element','eventhandler','exists','false','final',
795 'firstfast','firstonly','firstonly10','firstonly100','firstonly1000','flush','for','forceliterals',
796 'forcenestedloop','forceplaceholders','forceselectorder','forupdate','from','group','if','insert_recordset',
797 'interface','is','join','like','maxof','minof','mod','new','next','nofetch','notexists','null','optimisticlock','order',
798 'outer','pause','pessimisticlock','print','private','protected','public','repeatableread','retry','return',
799 'reverse','select','server','setting','static','sum','super','switch','tablelock','this','throw','true','try','ttsabort','ttsbegin',
800 'ttscommit','update_recordset','validtimestate','void','where','while','window')
801 RUNTIME_FUNCTIONS = ('_duration','abs','acos','any2Date','any2Enum','any2Guid','any2Int','any2Int64','any2Real','any2Str','anytodate',
802 'anytoenum','anytoguid','anytoint','anytoint64','anytoreal','anytostr','asin','atan','beep','cTerm','char2Num','classIdGet',
803 'corrFlagGet','corrFlagSet','cos','cosh','curExt','curUserId','date2Num','date2Str','datetime2Str','dayName','dayOfMth',
804 'dayOfWk','dayOfYr','ddb','decRound','dg','dimOf','endMth','enum2str','exp','exp10','fV','fieldId2Name','fieldId2PName',
805 'fieldName2Id','frac','funcName','getCurrentPartition','getCurrentPartitionRecId','getPrefix','guid2Str','idg','indexId2Name',
806 'indexName2Id','int2Str','int642Str','intvMax','intvName','intvNo','intvNorm','log10','logN','match','max','min','mkDate','mthName',
807 'mthOfYr','newGuid','nextMth','nextQtr','nextYr','num2Char','num2Date','num2Str','pmt','power','prevMth','prevQtr','prevYr',
808 'prmIsDefault','pt','pv','rate','refPrintAll','round','runAs','sessionId','setPrefix','sin','sinh','sleep','sln','str2Date',
809 'str2Datetime','str2Enum','str2Guid','str2Int','str2Int64','str2Num','str2Time','strAlpha','strCmp','strColSeq','strDel',
810 'strFind','strFmt','strIns','strKeep','strLTrim','strLen','strLine','strLwr','strNFind','strPoke','strPrompt','strRTrim',
811 'strRem','strRep','strScan','strUpr','subStr','syd','systemDateGet','systemDateSet','tableId2Name',
812 'tableId2PName','tableName2Id','tan','tanh','term','time2Str','timeNow','today','trunc','typeOf','uint2Str','wkOfYr','year')
813 COMPILE_FUNCTIONS = ('attributeStr','classNum','classStr','configurationKeyNum','configurationKeyStr','dataEntityDataSourceStr','delegateStr',
814 'dimensionHierarchyLevelStr','dimensionHierarchyStr','dimensionReferenceStr','dutyStr','enumCnt','enumLiteralStr','enumNum','enumStr',
815 'extendedTypeNum','extendedTypeStr','fieldNum','fieldPName','fieldStr','formControlStr','formDataFieldStr','formDataSourceStr',
816 'formMethodStr','formStr','identifierStr','indexNum','indexStr','licenseCodeNum','licenseCodeStr','literalStr','maxDate','maxInt',
817 'measureStr','measurementStr','menuItemActionStr','menuItemDisplayStr','menuItemOutputStr','menuStr','methodStr','minInt','privilegeStr',
818 'queryDatasourceStr','queryMethodStr','queryStr','reportStr','resourceStr','roleStr','ssrsReportStr','staticDelegateStr','staticMethodStr',
819 'tableCollectionStr','tableFieldGroupStr','tableMethodStr','tableNum','tablePName','tableStaticMethodStr','tableStr','tileStr','varStr',
820 'webActionItemStr','webDisplayContentItemStr','webFormStr','webMenuStr','webOutputContentItemStr','webReportStr','webSiteTempStr',
821 'webStaticFileStr','webUrlItemStr','webWebPartStr','webletItemStr','webpageDefStr','websiteDefStr','workflowApprovalStr',
822 'workflowCategoryStr','workflowTaskStr','workflowTypeStr')
823
824 tokens = {}
825
826 tokens = {
827 'root': [
828 # method names
829 (r'(\s*)\b(else|if)\b([^\n])', bygroups(Whitespace, Keyword, using(this))), # ensure that if is not treated like a function
830 (r'^([ \t]*)((?:' + XPP_CHARS + r'(?:\[\])?\s+)+?)' # return type
831 r'(' + XPP_CHARS + ')' # method name
832 r'(\s*)(\()', # signature start
833 bygroups(Whitespace, using(this), Name.Function, Whitespace,
834 Punctuation)),
835 (r'^(\s*)(\[)([^\n]*?)(\])', bygroups(Whitespace, Name.Attribute, Name.Variable.Class, Name.Attribute)),
836 (r'[^\S\n]+', Whitespace),
837 (r'(\\)(\n)', bygroups(Text, Whitespace)), # line continuation
838 (r'//[^\n]*?\n', Comment.Single),
839 (r'/[*][^\n]*?[*]/', Comment.Multiline),
840 (r'\n', Whitespace),
841 (words(OPERATORS), Operator),
842 (r'=~|!=|==|<<|>>|[-+/*%=<>&^|]', Operator),
843 (r'[()\[\];:,.#@]', Punctuation),
844 (r'[{}]', Punctuation),
845 (r'@"(""|[^"])*"', String),
846 (r'\$?"(\\\\|\\[^\\]|[^"\\\n])*["\n]', String),
847 (r"'\\.'|'[^\\]'", String.Char),
848 (r"[0-9]+(\.[0-9]*)?([eE][+-][0-9]+)?"
849 r"[flFLdD]?|0[xX][0-9a-fA-F]+[Ll]?", Number),
850 (words(KEYWORDS, suffix=r'\b'), Keyword),
851 (r'(boolean|int|int64|str|real|guid|date)\b\??', Keyword.Type),
852 (r'(class|struct|extends|implements)(\s+)', bygroups(Keyword, Whitespace), 'class'),
853 (r'('+XPP_CHARS+')(::)', bygroups(Name.Variable.Class, Punctuation)),
854 (r'(\s*)(\w+)(\s+\w+(,|=)?[^\n]*;)', bygroups(Whitespace, Name.Variable.Class, using(this))), # declaration
855 # x++ specific function to get field should highlight the classname
856 (r'(fieldNum\()('+XPP_CHARS+r')(\s*,\s*)('+XPP_CHARS+r')(\s*\))',
857 bygroups(using(this), Name.Variable.Class, using(this), Name.Property, using(this))),
858 # x++ specific function to get table should highlight the classname
859 (r'(tableNum\()('+XPP_CHARS+r')(\s*\))',
860 bygroups(using(this), Name.Variable.Class, using(this))),
861 (words(RUNTIME_FUNCTIONS, suffix=r'(?=\()'), Name.Function.Magic),
862 (words(COMPILE_FUNCTIONS, suffix=r'(?=\()'), Name.Function.Magic),
863 (XPP_CHARS, Name),
864 ],
865 'class': [
866 (XPP_CHARS, Name.Class, '#pop'),
867 default('#pop'),
868 ],
869 'namespace': [
870 (r'(?=\()', Text, '#pop'), # using (resource)
871 ('(' + XPP_CHARS + r'|\.)+', Name.Namespace, '#pop'),
872 ]
873 }