1"""
2 pygments.lexers.basic
3 ~~~~~~~~~~~~~~~~~~~~~
4
5 Lexers for BASIC like languages (other than VB.net).
6
7 :copyright: Copyright 2006-present by the Pygments team, see AUTHORS.
8 :license: BSD, see LICENSE for details.
9"""
10
11import re
12
13from pygments.lexer import RegexLexer, bygroups, default, words, include
14from pygments.token import Comment, Error, Keyword, Name, Number, \
15 Punctuation, Operator, String, Text, Whitespace
16from pygments.lexers import _vbscript_builtins
17
18
19__all__ = ['BlitzBasicLexer', 'BlitzMaxLexer', 'MonkeyLexer', 'CbmBasicV2Lexer',
20 'QBasicLexer', 'VBScriptLexer', 'BBCBasicLexer']
21
22
23class BlitzMaxLexer(RegexLexer):
24 """
25 For BlitzMax source code.
26 """
27
28 name = 'BlitzMax'
29 url = 'http://blitzbasic.com'
30 aliases = ['blitzmax', 'bmax']
31 filenames = ['*.bmx']
32 mimetypes = ['text/x-bmx']
33 version_added = '1.4'
34
35 bmax_vopwords = r'\b(Shl|Shr|Sar|Mod)\b'
36 bmax_sktypes = r'@{1,2}|[!#$%]'
37 bmax_lktypes = r'\b(Int|Byte|Short|Float|Double|Long)\b'
38 bmax_name = r'[a-z_]\w*'
39 bmax_var = (rf'({bmax_name})(?:(?:([ \t]*)({bmax_sktypes})|([ \t]*:[ \t]*\b(?:Shl|Shr|Sar|Mod)\b)'
40 rf'|([ \t]*)(:)([ \t]*)(?:{bmax_lktypes}|({bmax_name})))(?:([ \t]*)(Ptr))?)')
41 bmax_func = bmax_var + r'?((?:[ \t]|\.\.\n)*)([(])'
42
43 flags = re.MULTILINE | re.IGNORECASE
44 tokens = {
45 'root': [
46 # Text
47 (r'\s+', Whitespace),
48 (r'(\.\.)(\n)', bygroups(Text, Whitespace)), # Line continuation
49 # Comments
50 (r"'.*?\n", Comment.Single),
51 (r'([ \t]*)\bRem\n[\s\S]*?\s*\bEnd([ \t]*)Rem', Comment.Multiline),
52 # Data types
53 ('"', String.Double, 'string'),
54 # Numbers
55 (r'[0-9]+\.[0-9]*(?!\.)', Number.Float),
56 (r'\.[0-9]*(?!\.)', Number.Float),
57 (r'[0-9]+', Number.Integer),
58 (r'\$[0-9a-f]+', Number.Hex),
59 (r'\%[10]+', Number.Bin),
60 # Other
61 (rf'(?:(?:(:)?([ \t]*)(:?{bmax_vopwords}|([+\-*/&|~]))|Or|And|Not|[=<>^]))', Operator),
62 (r'[(),.:\[\]]', Punctuation),
63 (r'(?:#[\w \t]*)', Name.Label),
64 (r'(?:\?[\w \t]*)', Comment.Preproc),
65 # Identifiers
66 (rf'\b(New)\b([ \t]?)([(]?)({bmax_name})',
67 bygroups(Keyword.Reserved, Whitespace, Punctuation, Name.Class)),
68 (rf'\b(Import|Framework|Module)([ \t]+)({bmax_name}\.{bmax_name})',
69 bygroups(Keyword.Reserved, Whitespace, Keyword.Namespace)),
70 (bmax_func, bygroups(Name.Function, Whitespace, Keyword.Type,
71 Operator, Whitespace, Punctuation, Whitespace,
72 Keyword.Type, Name.Class, Whitespace,
73 Keyword.Type, Whitespace, Punctuation)),
74 (bmax_var, bygroups(Name.Variable, Whitespace, Keyword.Type, Operator,
75 Whitespace, Punctuation, Whitespace, Keyword.Type,
76 Name.Class, Whitespace, Keyword.Type)),
77 (rf'\b(Type|Extends)([ \t]+)({bmax_name})',
78 bygroups(Keyword.Reserved, Whitespace, Name.Class)),
79 # Keywords
80 (r'\b(Ptr)\b', Keyword.Type),
81 (r'\b(Pi|True|False|Null|Self|Super)\b', Keyword.Constant),
82 (r'\b(Local|Global|Const|Field)\b', Keyword.Declaration),
83 (words((
84 'TNullMethodException', 'TNullFunctionException',
85 'TNullObjectException', 'TArrayBoundsException',
86 'TRuntimeException'), prefix=r'\b', suffix=r'\b'), Name.Exception),
87 (words((
88 'Strict', 'SuperStrict', 'Module', 'ModuleInfo',
89 'End', 'Return', 'Continue', 'Exit', 'Public', 'Private',
90 'Var', 'VarPtr', 'Chr', 'Len', 'Asc', 'SizeOf', 'Sgn', 'Abs', 'Min', 'Max',
91 'New', 'Release', 'Delete', 'Incbin', 'IncbinPtr', 'IncbinLen',
92 'Framework', 'Include', 'Import', 'Extern', 'EndExtern',
93 'Function', 'EndFunction', 'Type', 'EndType', 'Extends', 'Method', 'EndMethod',
94 'Abstract', 'Final', 'If', 'Then', 'Else', 'ElseIf', 'EndIf',
95 'For', 'To', 'Next', 'Step', 'EachIn', 'While', 'Wend', 'EndWhile',
96 'Repeat', 'Until', 'Forever', 'Select', 'Case', 'Default', 'EndSelect',
97 'Try', 'Catch', 'EndTry', 'Throw', 'Assert', 'Goto', 'DefData', 'ReadData',
98 'RestoreData'), prefix=r'\b', suffix=r'\b'),
99 Keyword.Reserved),
100 # Final resolve (for variable names and such)
101 (rf'({bmax_name})', Name.Variable),
102 ],
103 'string': [
104 (r'""', String.Double),
105 (r'"C?', String.Double, '#pop'),
106 (r'[^"]+', String.Double),
107 ],
108 }
109
110
111class BlitzBasicLexer(RegexLexer):
112 """
113 For BlitzBasic source code.
114 """
115
116 name = 'BlitzBasic'
117 url = 'http://blitzbasic.com'
118 aliases = ['blitzbasic', 'b3d', 'bplus']
119 filenames = ['*.bb', '*.decls']
120 mimetypes = ['text/x-bb']
121 version_added = '2.0'
122
123 bb_sktypes = r'@{1,2}|[#$%]'
124 bb_name = r'[a-z]\w*'
125 bb_var = (rf'({bb_name})(?:([ \t]*)({bb_sktypes})|([ \t]*)([.])([ \t]*)(?:({bb_name})))?')
126
127 flags = re.MULTILINE | re.IGNORECASE
128 tokens = {
129 'root': [
130 # Text
131 (r'\s+', Whitespace),
132 # Comments
133 (r";.*?\n", Comment.Single),
134 # Data types
135 ('"', String.Double, 'string'),
136 # Numbers
137 (r'[0-9]+\.[0-9]*(?!\.)', Number.Float),
138 (r'\.[0-9]+(?!\.)', Number.Float),
139 (r'[0-9]+', Number.Integer),
140 (r'\$[0-9a-f]+', Number.Hex),
141 (r'\%[10]+', Number.Bin),
142 # Other
143 (words(('Shl', 'Shr', 'Sar', 'Mod', 'Or', 'And', 'Not',
144 'Abs', 'Sgn', 'Handle', 'Int', 'Float', 'Str',
145 'First', 'Last', 'Before', 'After'),
146 prefix=r'\b', suffix=r'\b'),
147 Operator),
148 (r'([+\-*/~=<>^])', Operator),
149 (r'[(),:\[\]\\]', Punctuation),
150 (rf'\.([ \t]*)({bb_name})', Name.Label),
151 # Identifiers
152 (rf'\b(New)\b([ \t]+)({bb_name})',
153 bygroups(Keyword.Reserved, Whitespace, Name.Class)),
154 (rf'\b(Gosub|Goto)\b([ \t]+)({bb_name})',
155 bygroups(Keyword.Reserved, Whitespace, Name.Label)),
156 (rf'\b(Object)\b([ \t]*)([.])([ \t]*)({bb_name})\b',
157 bygroups(Operator, Whitespace, Punctuation, Whitespace, Name.Class)),
158 (rf'\b{bb_var}\b([ \t]*)(\()',
159 bygroups(Name.Function, Whitespace, Keyword.Type, Whitespace, Punctuation,
160 Whitespace, Name.Class, Whitespace, Punctuation)),
161 (rf'\b(Function)\b([ \t]+){bb_var}',
162 bygroups(Keyword.Reserved, Whitespace, Name.Function, Whitespace, Keyword.Type,
163 Whitespace, Punctuation, Whitespace, Name.Class)),
164 (rf'\b(Type)([ \t]+)({bb_name})',
165 bygroups(Keyword.Reserved, Whitespace, Name.Class)),
166 # Keywords
167 (r'\b(Pi|True|False|Null)\b', Keyword.Constant),
168 (r'\b(Local|Global|Const|Field|Dim)\b', Keyword.Declaration),
169 (words((
170 'End', 'Return', 'Exit', 'Chr', 'Len', 'Asc', 'New', 'Delete', 'Insert',
171 'Include', 'Function', 'Type', 'If', 'Then', 'Else', 'ElseIf', 'EndIf',
172 'For', 'To', 'Next', 'Step', 'Each', 'While', 'Wend',
173 'Repeat', 'Until', 'Forever', 'Select', 'Case', 'Default',
174 'Goto', 'Gosub', 'Data', 'Read', 'Restore'), prefix=r'\b', suffix=r'\b'),
175 Keyword.Reserved),
176 # Final resolve (for variable names and such)
177 # (r'(%s)' % (bb_name), Name.Variable),
178 (bb_var, bygroups(Name.Variable, Whitespace, Keyword.Type,
179 Whitespace, Punctuation, Whitespace, Name.Class)),
180 ],
181 'string': [
182 (r'""', String.Double),
183 (r'"C?', String.Double, '#pop'),
184 (r'[^"\n]+', String.Double),
185 ],
186 }
187
188
189class MonkeyLexer(RegexLexer):
190 """
191 For Monkey source code.
192 """
193
194 name = 'Monkey'
195 aliases = ['monkey']
196 filenames = ['*.monkey']
197 mimetypes = ['text/x-monkey']
198 url = 'https://blitzresearch.itch.io/monkeyx'
199 version_added = '1.6'
200
201 name_variable = r'[a-z_]\w*'
202 name_function = r'[A-Z]\w*'
203 name_constant = r'[A-Z_][A-Z0-9_]*'
204 name_class = r'[A-Z]\w*'
205 name_module = r'[a-z0-9_]*'
206
207 keyword_type = r'(?:Int|Float|String|Bool|Object|Array|Void)'
208 # ? == Bool // % == Int // # == Float // $ == String
209 keyword_type_special = r'[?%#$]'
210
211 flags = re.MULTILINE
212
213 tokens = {
214 'root': [
215 # Text
216 (r'\s+', Whitespace),
217 # Comments
218 (r"'.*", Comment),
219 (r'(?i)^#rem\b', Comment.Multiline, 'comment'),
220 # preprocessor directives
221 (r'(?i)^(?:#If|#ElseIf|#Else|#EndIf|#End|#Print|#Error)\b', Comment.Preproc),
222 # preprocessor variable (any line starting with '#' that is not a directive)
223 (r'^#', Comment.Preproc, 'variables'),
224 # String
225 ('"', String.Double, 'string'),
226 # Numbers
227 (r'[0-9]+\.[0-9]*(?!\.)', Number.Float),
228 (r'\.[0-9]+(?!\.)', Number.Float),
229 (r'[0-9]+', Number.Integer),
230 (r'\$[0-9a-fA-Z]+', Number.Hex),
231 (r'\%[10]+', Number.Bin),
232 # Native data types
233 (rf'\b{keyword_type}\b', Keyword.Type),
234 # Exception handling
235 (r'(?i)\b(?:Try|Catch|Throw)\b', Keyword.Reserved),
236 (r'Throwable', Name.Exception),
237 # Builtins
238 (r'(?i)\b(?:Null|True|False)\b', Name.Builtin),
239 (r'(?i)\b(?:Self|Super)\b', Name.Builtin.Pseudo),
240 (r'\b(?:HOST|LANG|TARGET|CONFIG)\b', Name.Constant),
241 # Keywords
242 (r'(?i)^(Import)(\s+)(.*)(\n)',
243 bygroups(Keyword.Namespace, Whitespace, Name.Namespace, Whitespace)),
244 (r'(?i)^Strict\b.*\n', Keyword.Reserved),
245 (r'(?i)(Const|Local|Global|Field)(\s+)',
246 bygroups(Keyword.Declaration, Whitespace), 'variables'),
247 (r'(?i)(New|Class|Interface|Extends|Implements)(\s+)',
248 bygroups(Keyword.Reserved, Whitespace), 'classname'),
249 (r'(?i)(Function|Method)(\s+)',
250 bygroups(Keyword.Reserved, Whitespace), 'funcname'),
251 (r'(?i)(?:End|Return|Public|Private|Extern|Property|'
252 r'Final|Abstract)\b', Keyword.Reserved),
253 # Flow Control stuff
254 (r'(?i)(?:If|Then|Else|ElseIf|EndIf|'
255 r'Select|Case|Default|'
256 r'While|Wend|'
257 r'Repeat|Until|Forever|'
258 r'For|To|Until|Step|EachIn|Next|'
259 r'Exit|Continue)(?=\s)', Keyword.Reserved),
260 # not used yet
261 (r'(?i)\b(?:Module|Inline)\b', Keyword.Reserved),
262 # Array
263 (r'[\[\]]', Punctuation),
264 # Other
265 (r'<=|>=|<>|\*=|/=|\+=|-=|&=|~=|\|=|[-&*/^+=<>|~]', Operator),
266 (r'(?i)(?:Not|Mod|Shl|Shr|And|Or)', Operator.Word),
267 (r'[(){}!#,.:]', Punctuation),
268 # catch the rest
269 (rf'{name_constant}\b', Name.Constant),
270 (rf'{name_function}\b', Name.Function),
271 (rf'{name_variable}\b', Name.Variable),
272 ],
273 'funcname': [
274 (rf'(?i){name_function}\b', Name.Function),
275 (r':', Punctuation, 'classname'),
276 (r'\s+', Whitespace),
277 (r'\(', Punctuation, 'variables'),
278 (r'\)', Punctuation, '#pop')
279 ],
280 'classname': [
281 (rf'{name_module}\.', Name.Namespace),
282 (rf'{keyword_type}\b', Keyword.Type),
283 (rf'{name_class}\b', Name.Class),
284 # array (of given size)
285 (r'(\[)(\s*)(\d*)(\s*)(\])',
286 bygroups(Punctuation, Whitespace, Number.Integer, Whitespace, Punctuation)),
287 # generics
288 (r'\s+(?!<)', Whitespace, '#pop'),
289 (r'<', Punctuation, '#push'),
290 (r'>', Punctuation, '#pop'),
291 (r'\n', Whitespace, '#pop'),
292 default('#pop')
293 ],
294 'variables': [
295 (rf'{name_constant}\b', Name.Constant),
296 (rf'{name_variable}\b', Name.Variable),
297 (rf'{keyword_type_special}', Keyword.Type),
298 (r'\s+', Whitespace),
299 (r':', Punctuation, 'classname'),
300 (r',', Punctuation, '#push'),
301 default('#pop')
302 ],
303 'string': [
304 (r'[^"~]+', String.Double),
305 (r'~q|~n|~r|~t|~z|~~', String.Escape),
306 (r'"', String.Double, '#pop'),
307 ],
308 'comment': [
309 (r'(?i)^#rem.*?', Comment.Multiline, "#push"),
310 (r'(?i)^#end.*?', Comment.Multiline, "#pop"),
311 (r'\n', Comment.Multiline),
312 (r'.+', Comment.Multiline),
313 ],
314 }
315
316
317class CbmBasicV2Lexer(RegexLexer):
318 """
319 For CBM BASIC V2 sources.
320 """
321 name = 'CBM BASIC V2'
322 aliases = ['cbmbas']
323 filenames = ['*.bas']
324 url = 'https://en.wikipedia.org/wiki/Commodore_BASIC'
325 version_added = '1.6'
326
327 flags = re.IGNORECASE
328
329 tokens = {
330 'root': [
331 (r'rem.*\n', Comment.Single),
332 (r'\s+', Whitespace),
333 (r'new|run|end|for|to|next|step|go(to|sub)?|on|return|stop|cont'
334 r'|if|then|input#?|read|wait|load|save|verify|poke|sys|print#?'
335 r'|list|clr|cmd|open|close|get#?', Keyword.Reserved),
336 (r'data|restore|dim|let|def|fn', Keyword.Declaration),
337 (r'tab|spc|sgn|int|abs|usr|fre|pos|sqr|rnd|log|exp|cos|sin|tan|atn'
338 r'|peek|len|val|asc|(str|chr|left|right|mid)\$', Name.Builtin),
339 (r'[-+*/^<>=]', Operator),
340 (r'not|and|or', Operator.Word),
341 (r'"[^"\n]*.', String),
342 (r'\d+|[-+]?\d*\.\d*(e[-+]?\d+)?', Number.Float),
343 (r'[(),:;]', Punctuation),
344 (r'\w+[$%]?', Name),
345 ]
346 }
347
348 def analyse_text(text):
349 # if it starts with a line number, it shouldn't be a "modern" Basic
350 # like VB.net
351 if re.match(r'^\d+', text):
352 return 0.2
353
354
355class QBasicLexer(RegexLexer):
356 """
357 For QBasic source code.
358 """
359
360 name = 'QBasic'
361 aliases = ['qbasic', 'basic']
362 filenames = ['*.BAS', '*.bas']
363 mimetypes = ['text/basic']
364 url = 'https://en.wikipedia.org/wiki/QBasic'
365 version_added = '2.0'
366
367 declarations = ('DATA', 'LET')
368
369 functions = (
370 'ABS', 'ASC', 'ATN', 'CDBL', 'CHR$', 'CINT', 'CLNG',
371 'COMMAND$', 'COS', 'CSNG', 'CSRLIN', 'CVD', 'CVDMBF', 'CVI',
372 'CVL', 'CVS', 'CVSMBF', 'DATE$', 'ENVIRON$', 'EOF', 'ERDEV',
373 'ERDEV$', 'ERL', 'ERR', 'EXP', 'FILEATTR', 'FIX', 'FRE',
374 'FREEFILE', 'HEX$', 'INKEY$', 'INP', 'INPUT$', 'INSTR', 'INT',
375 'IOCTL$', 'LBOUND', 'LCASE$', 'LEFT$', 'LEN', 'LOC', 'LOF',
376 'LOG', 'LPOS', 'LTRIM$', 'MID$', 'MKD$', 'MKDMBF$', 'MKI$',
377 'MKL$', 'MKS$', 'MKSMBF$', 'OCT$', 'PEEK', 'PEN', 'PLAY',
378 'PMAP', 'POINT', 'POS', 'RIGHT$', 'RND', 'RTRIM$', 'SADD',
379 'SCREEN', 'SEEK', 'SETMEM', 'SGN', 'SIN', 'SPACE$', 'SPC',
380 'SQR', 'STICK', 'STR$', 'STRIG', 'STRING$', 'TAB', 'TAN',
381 'TIME$', 'TIMER', 'UBOUND', 'UCASE$', 'VAL', 'VARPTR',
382 'VARPTR$', 'VARSEG'
383 )
384
385 metacommands = ('$DYNAMIC', '$INCLUDE', '$STATIC')
386
387 operators = ('AND', 'EQV', 'IMP', 'NOT', 'OR', 'XOR')
388
389 statements = (
390 'BEEP', 'BLOAD', 'BSAVE', 'CALL', 'CALL ABSOLUTE',
391 'CALL INTERRUPT', 'CALLS', 'CHAIN', 'CHDIR', 'CIRCLE', 'CLEAR',
392 'CLOSE', 'CLS', 'COLOR', 'COM', 'COMMON', 'CONST', 'DATA',
393 'DATE$', 'DECLARE', 'DEF FN', 'DEF SEG', 'DEFDBL', 'DEFINT',
394 'DEFLNG', 'DEFSNG', 'DEFSTR', 'DEF', 'DIM', 'DO', 'LOOP',
395 'DRAW', 'END', 'ENVIRON', 'ERASE', 'ERROR', 'EXIT', 'FIELD',
396 'FILES', 'FOR', 'NEXT', 'FUNCTION', 'GET', 'GOSUB', 'GOTO',
397 'IF', 'THEN', 'INPUT', 'INPUT #', 'IOCTL', 'KEY', 'KEY',
398 'KILL', 'LET', 'LINE', 'LINE INPUT', 'LINE INPUT #', 'LOCATE',
399 'LOCK', 'UNLOCK', 'LPRINT', 'LSET', 'MID$', 'MKDIR', 'NAME',
400 'ON COM', 'ON ERROR', 'ON KEY', 'ON PEN', 'ON PLAY',
401 'ON STRIG', 'ON TIMER', 'ON UEVENT', 'ON', 'OPEN', 'OPEN COM',
402 'OPTION BASE', 'OUT', 'PAINT', 'PALETTE', 'PCOPY', 'PEN',
403 'PLAY', 'POKE', 'PRESET', 'PRINT', 'PRINT #', 'PRINT USING',
404 'PSET', 'PUT', 'PUT', 'RANDOMIZE', 'READ', 'REDIM', 'REM',
405 'RESET', 'RESTORE', 'RESUME', 'RETURN', 'RMDIR', 'RSET', 'RUN',
406 'SCREEN', 'SEEK', 'SELECT CASE', 'SHARED', 'SHELL', 'SLEEP',
407 'SOUND', 'STATIC', 'STOP', 'STRIG', 'SUB', 'SWAP', 'SYSTEM',
408 'TIME$', 'TIMER', 'TROFF', 'TRON', 'TYPE', 'UEVENT', 'UNLOCK',
409 'VIEW', 'WAIT', 'WHILE', 'WEND', 'WIDTH', 'WINDOW', 'WRITE'
410 )
411
412 keywords = (
413 'ACCESS', 'ALIAS', 'ANY', 'APPEND', 'AS', 'BASE', 'BINARY',
414 'BYVAL', 'CASE', 'CDECL', 'DOUBLE', 'ELSE', 'ELSEIF', 'ENDIF',
415 'INTEGER', 'IS', 'LIST', 'LOCAL', 'LONG', 'LOOP', 'MOD',
416 'NEXT', 'OFF', 'ON', 'OUTPUT', 'RANDOM', 'SIGNAL', 'SINGLE',
417 'STEP', 'STRING', 'THEN', 'TO', 'UNTIL', 'USING', 'WEND'
418 )
419
420 tokens = {
421 'root': [
422 (r'\n+', Text),
423 (r'\s+', Text.Whitespace),
424 (r'^(\s*)(\d*)(\s*)(REM .*)$',
425 bygroups(Text.Whitespace, Name.Label, Text.Whitespace,
426 Comment.Single)),
427 (r'^(\s*)(\d+)(\s*)',
428 bygroups(Text.Whitespace, Name.Label, Text.Whitespace)),
429 (r'(?=[\s]*)(\w+)(?=[\s]*=)', Name.Variable.Global),
430 (r'(?=[^"]*)\'.*$', Comment.Single),
431 (r'"[^\n"]*"', String.Double),
432 (r'(END)(\s+)(FUNCTION|IF|SELECT|SUB)',
433 bygroups(Keyword.Reserved, Text.Whitespace, Keyword.Reserved)),
434 (r'(DECLARE)(\s+)([A-Z]+)(\s+)(\S+)',
435 bygroups(Keyword.Declaration, Text.Whitespace, Name.Variable,
436 Text.Whitespace, Name)),
437 (r'(DIM)(\s+)(SHARED)(\s+)([^\s(]+)',
438 bygroups(Keyword.Declaration, Text.Whitespace, Name.Variable,
439 Text.Whitespace, Name.Variable.Global)),
440 (r'(DIM)(\s+)([^\s(]+)',
441 bygroups(Keyword.Declaration, Text.Whitespace, Name.Variable.Global)),
442 (r'^(\s*)([a-zA-Z_]+)(\s*)(\=)',
443 bygroups(Text.Whitespace, Name.Variable.Global, Text.Whitespace,
444 Operator)),
445 (r'(GOTO|GOSUB)(\s+)(\w+\:?)',
446 bygroups(Keyword.Reserved, Text.Whitespace, Name.Label)),
447 (r'(SUB)(\s+)(\w+\:?)',
448 bygroups(Keyword.Reserved, Text.Whitespace, Name.Label)),
449 include('declarations'),
450 include('functions'),
451 include('metacommands'),
452 include('operators'),
453 include('statements'),
454 include('keywords'),
455 (r'[a-zA-Z_]\w*[$@#&!]', Name.Variable.Global),
456 (r'[a-zA-Z_]\w*\:', Name.Label),
457 (r'\-?\d*\.\d+[@|#]?', Number.Float),
458 (r'\-?\d+[@|#]', Number.Float),
459 (r'\-?\d+#?', Number.Integer.Long),
460 (r'!=|==|:=|\.=|<<|>>|[-~+/\\*%=<>&^|?:!.]', Operator),
461 (r'[\[\]{}(),;]', Punctuation),
462 (r'[\w]+', Name.Variable.Global),
463 ],
464 # can't use regular \b because of X$()
465 # XXX: use words() here
466 'declarations': [
467 (r'\b({})(?=\(|\b)'.format('|'.join(map(re.escape, declarations))),
468 Keyword.Declaration),
469 ],
470 'functions': [
471 (r'\b({})(?=\(|\b)'.format('|'.join(map(re.escape, functions))),
472 Keyword.Reserved),
473 ],
474 'metacommands': [
475 (r'\b({})(?=\(|\b)'.format('|'.join(map(re.escape, metacommands))),
476 Keyword.Constant),
477 ],
478 'operators': [
479 (r'\b({})(?=\(|\b)'.format('|'.join(map(re.escape, operators))), Operator.Word),
480 ],
481 'statements': [
482 (r'\b({})\b'.format('|'.join(map(re.escape, statements))),
483 Keyword.Reserved),
484 ],
485 'keywords': [
486 (r'\b({})\b'.format('|'.join(keywords)), Keyword),
487 ],
488 }
489
490 def analyse_text(text):
491 if '$DYNAMIC' in text or '$STATIC' in text:
492 return 0.9
493
494
495class VBScriptLexer(RegexLexer):
496 """
497 VBScript is scripting language that is modeled on Visual Basic.
498 """
499 name = 'VBScript'
500 aliases = ['vbscript']
501 filenames = ['*.vbs', '*.VBS']
502 url = 'https://learn.microsoft.com/en-us/previous-versions/t0aew7h6(v=vs.85)'
503 version_added = '2.4'
504
505 flags = re.IGNORECASE
506
507 tokens = {
508 'root': [
509 (r"'[^\n]*", Comment.Single),
510 (r'\s+', Whitespace),
511 ('"', String.Double, 'string'),
512 ('&h[0-9a-f]+', Number.Hex),
513 # Float variant 1, for example: 1., 1.e2, 1.2e3
514 (r'[0-9]+\.[0-9]*(e[+-]?[0-9]+)?', Number.Float),
515 (r'\.[0-9]+(e[+-]?[0-9]+)?', Number.Float), # Float variant 2, for example: .1, .1e2
516 (r'[0-9]+e[+-]?[0-9]+', Number.Float), # Float variant 3, for example: 123e45
517 (r'[0-9]+', Number.Integer),
518 ('#.+#', String), # date or time value
519 (r'(dim)(\s+)([a-z_][a-z0-9_]*)',
520 bygroups(Keyword.Declaration, Whitespace, Name.Variable), 'dim_more'),
521 (r'(function|sub)(\s+)([a-z_][a-z0-9_]*)',
522 bygroups(Keyword.Declaration, Whitespace, Name.Function)),
523 (r'(class)(\s+)([a-z_][a-z0-9_]*)',
524 bygroups(Keyword.Declaration, Whitespace, Name.Class)),
525 (r'(const)(\s+)([a-z_][a-z0-9_]*)',
526 bygroups(Keyword.Declaration, Whitespace, Name.Constant)),
527 (r'(end)(\s+)(class|function|if|property|sub|with)',
528 bygroups(Keyword, Whitespace, Keyword)),
529 (r'(on)(\s+)(error)(\s+)(goto)(\s+)(0)',
530 bygroups(Keyword, Whitespace, Keyword, Whitespace, Keyword, Whitespace, Number.Integer)),
531 (r'(on)(\s+)(error)(\s+)(resume)(\s+)(next)',
532 bygroups(Keyword, Whitespace, Keyword, Whitespace, Keyword, Whitespace, Keyword)),
533 (r'(option)(\s+)(explicit)', bygroups(Keyword, Whitespace, Keyword)),
534 (r'(property)(\s+)(get|let|set)(\s+)([a-z_][a-z0-9_]*)',
535 bygroups(Keyword.Declaration, Whitespace, Keyword.Declaration, Whitespace, Name.Property)),
536 (r'rem\s.*[^\n]*', Comment.Single),
537 (words(_vbscript_builtins.KEYWORDS, suffix=r'\b'), Keyword),
538 (words(_vbscript_builtins.OPERATORS), Operator),
539 (words(_vbscript_builtins.OPERATOR_WORDS, suffix=r'\b'), Operator.Word),
540 (words(_vbscript_builtins.BUILTIN_CONSTANTS, suffix=r'\b'), Name.Constant),
541 (words(_vbscript_builtins.BUILTIN_FUNCTIONS, suffix=r'\b'), Name.Builtin),
542 (words(_vbscript_builtins.BUILTIN_VARIABLES, suffix=r'\b'), Name.Builtin),
543 (r'[a-z_][a-z0-9_]*', Name),
544 (r'\b_\n', Operator),
545 (words(r'(),.:'), Punctuation),
546 (r'.+(\n)?', Error)
547 ],
548 'dim_more': [
549 (r'(\s*)(,)(\s*)([a-z_][a-z0-9]*)',
550 bygroups(Whitespace, Punctuation, Whitespace, Name.Variable)),
551 default('#pop'),
552 ],
553 'string': [
554 (r'[^"\n]+', String.Double),
555 (r'\"\"', String.Double),
556 (r'"', String.Double, '#pop'),
557 (r'\n', Error, '#pop'), # Unterminated string
558 ],
559 }
560
561
562class BBCBasicLexer(RegexLexer):
563 """
564 BBC Basic was supplied on the BBC Micro, and later Acorn RISC OS.
565 It is also used by BBC Basic For Windows.
566 """
567 base_keywords = ['OTHERWISE', 'AND', 'DIV', 'EOR', 'MOD', 'OR', 'ERROR',
568 'LINE', 'OFF', 'STEP', 'SPC', 'TAB', 'ELSE', 'THEN',
569 'OPENIN', 'PTR', 'PAGE', 'TIME', 'LOMEM', 'HIMEM', 'ABS',
570 'ACS', 'ADVAL', 'ASC', 'ASN', 'ATN', 'BGET', 'COS', 'COUNT',
571 'DEG', 'ERL', 'ERR', 'EVAL', 'EXP', 'EXT', 'FALSE', 'FN',
572 'GET', 'INKEY', 'INSTR', 'INT', 'LEN', 'LN', 'LOG', 'NOT',
573 'OPENUP', 'OPENOUT', 'PI', 'POINT', 'POS', 'RAD', 'RND',
574 'SGN', 'SIN', 'SQR', 'TAN', 'TO', 'TRUE', 'USR', 'VAL',
575 'VPOS', 'CHR$', 'GET$', 'INKEY$', 'LEFT$', 'MID$',
576 'RIGHT$', 'STR$', 'STRING$', 'EOF', 'PTR', 'PAGE', 'TIME',
577 'LOMEM', 'HIMEM', 'SOUND', 'BPUT', 'CALL', 'CHAIN', 'CLEAR',
578 'CLOSE', 'CLG', 'CLS', 'DATA', 'DEF', 'DIM', 'DRAW', 'END',
579 'ENDPROC', 'ENVELOPE', 'FOR', 'GOSUB', 'GOTO', 'GCOL', 'IF',
580 'INPUT', 'LET', 'LOCAL', 'MODE', 'MOVE', 'NEXT', 'ON',
581 'VDU', 'PLOT', 'PRINT', 'PROC', 'READ', 'REM', 'REPEAT',
582 'REPORT', 'RESTORE', 'RETURN', 'RUN', 'STOP', 'COLOUR',
583 'TRACE', 'UNTIL', 'WIDTH', 'OSCLI']
584
585 basic5_keywords = ['WHEN', 'OF', 'ENDCASE', 'ENDIF', 'ENDWHILE', 'CASE',
586 'CIRCLE', 'FILL', 'ORIGIN', 'POINT', 'RECTANGLE', 'SWAP',
587 'WHILE', 'WAIT', 'MOUSE', 'QUIT', 'SYS', 'INSTALL',
588 'LIBRARY', 'TINT', 'ELLIPSE', 'BEATS', 'TEMPO', 'VOICES',
589 'VOICE', 'STEREO', 'OVERLAY', 'APPEND', 'AUTO', 'CRUNCH',
590 'DELETE', 'EDIT', 'HELP', 'LIST', 'LOAD', 'LVAR', 'NEW',
591 'OLD', 'RENUMBER', 'SAVE', 'TEXTLOAD', 'TEXTSAVE',
592 'TWIN', 'TWINO', 'INSTALL', 'SUM', 'BEAT']
593
594
595 name = 'BBC Basic'
596 aliases = ['bbcbasic']
597 filenames = ['*.bbc']
598 url = 'https://www.bbcbasic.co.uk/bbcbasic.html'
599 version_added = '2.4'
600
601 tokens = {
602 'root': [
603 (r"[0-9]+", Name.Label),
604 (r"(\*)([^\n]*)",
605 bygroups(Keyword.Pseudo, Comment.Special)),
606 default('code'),
607 ],
608
609 'code': [
610 (r"(REM)([^\n]*)",
611 bygroups(Keyword.Declaration, Comment.Single)),
612 (r'\n', Whitespace, 'root'),
613 (r'\s+', Whitespace),
614 (r':', Comment.Preproc),
615
616 # Some special cases to make functions come out nicer
617 (r'(DEF)(\s*)(FN|PROC)([A-Za-z_@][\w@]*)',
618 bygroups(Keyword.Declaration, Whitespace,
619 Keyword.Declaration, Name.Function)),
620 (r'(FN|PROC)([A-Za-z_@][\w@]*)',
621 bygroups(Keyword, Name.Function)),
622
623 (r'(GOTO|GOSUB|THEN|RESTORE)(\s*)(\d+)',
624 bygroups(Keyword, Whitespace, Name.Label)),
625
626 (r'(TRUE|FALSE)', Keyword.Constant),
627 (r'(PAGE|LOMEM|HIMEM|TIME|WIDTH|ERL|ERR|REPORT\$|POS|VPOS|VOICES)',
628 Keyword.Pseudo),
629
630 (words(base_keywords), Keyword),
631 (words(basic5_keywords), Keyword),
632
633 ('"', String.Double, 'string'),
634
635 ('%[01]{1,32}', Number.Bin),
636 ('&[0-9a-f]{1,8}', Number.Hex),
637
638 (r'[+-]?[0-9]+\.[0-9]*(E[+-]?[0-9]+)?', Number.Float),
639 (r'[+-]?\.[0-9]+(E[+-]?[0-9]+)?', Number.Float),
640 (r'[+-]?[0-9]+E[+-]?[0-9]+', Number.Float),
641 (r'[+-]?\d+', Number.Integer),
642
643 (r'([A-Za-z_@][\w@]*[%$]?)', Name.Variable),
644 (r'([+\-]=|[$!|?+\-*/%^=><();]|>=|<=|<>|<<|>>|>>>|,)', Operator),
645 ],
646 'string': [
647 (r'[^"\n]+', String.Double),
648 (r'"', String.Double, '#pop'),
649 (r'\n', Error, 'root'), # Unterminated string
650 ],
651 }
652
653 def analyse_text(text):
654 if text.startswith('10REM >') or text.startswith('REM >'):
655 return 0.9