eric6/ThirdParty/Pygments/pygments/lexers/csound.py

changeset 6942
2602857055c5
parent 6651
e8f3b5568b21
child 7547
21b0534faebc
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 # -*- coding: utf-8 -*-
2 """
3 pygments.lexers.csound
4 ~~~~~~~~~~~~~~~~~~~~~~
5
6 Lexers for Csound languages.
7
8 :copyright: Copyright 2006-2017 by the Pygments team, see AUTHORS.
9 :license: BSD, see LICENSE for details.
10 """
11
12 import re
13
14 from pygments.lexer import RegexLexer, bygroups, default, include, using, words
15 from pygments.token import Comment, Error, Keyword, Name, Number, Operator, Punctuation, \
16 String, Text, Whitespace
17 from pygments.lexers._csound_builtins import OPCODES, DEPRECATED_OPCODES
18 from pygments.lexers.html import HtmlLexer
19 from pygments.lexers.python import PythonLexer
20 from pygments.lexers.scripting import LuaLexer
21
22 __all__ = ['CsoundScoreLexer', 'CsoundOrchestraLexer', 'CsoundDocumentLexer']
23
24 newline = (r'((?:(?:;|//).*)*)(\n)', bygroups(Comment.Single, Text))
25
26
27 class CsoundLexer(RegexLexer):
28 tokens = {
29 'whitespace': [
30 (r'[ \t]+', Text),
31 (r'/[*](?:.|\n)*?[*]/', Comment.Multiline),
32 (r'(?:;|//).*$', Comment.Single),
33 (r'(\\)(\n)', bygroups(Whitespace, Text))
34 ],
35
36 'preprocessor directives': [
37 (r'#(?:e(?:nd(?:if)?|lse)\b|##)|@@?[ \t]*\d+', Comment.Preproc),
38 (r'#include', Comment.Preproc, 'include directive'),
39 (r'#[ \t]*define', Comment.Preproc, 'define directive'),
40 (r'#(?:ifn?def|undef)\b', Comment.Preproc, 'macro directive')
41 ],
42
43 'include directive': [
44 include('whitespace'),
45 (r'([^ \t]).*?\1', String, '#pop')
46 ],
47
48 'define directive': [
49 (r'\n', Text),
50 include('whitespace'),
51 (r'([A-Z_a-z]\w*)(\()', bygroups(Comment.Preproc, Punctuation),
52 ('#pop', 'macro parameter name list')),
53 (r'[A-Z_a-z]\w*', Comment.Preproc, ('#pop', 'before macro body'))
54 ],
55 'macro parameter name list': [
56 include('whitespace'),
57 (r'[A-Z_a-z]\w*', Comment.Preproc),
58 (r"['#]", Punctuation),
59 (r'\)', Punctuation, ('#pop', 'before macro body'))
60 ],
61 'before macro body': [
62 (r'\n', Text),
63 include('whitespace'),
64 (r'#', Punctuation, ('#pop', 'macro body'))
65 ],
66 'macro body': [
67 (r'(?:\\(?!#)|[^#\\]|\n)+', Comment.Preproc),
68 (r'\\#', Comment.Preproc),
69 (r'(?<!\\)#', Punctuation, '#pop')
70 ],
71
72 'macro directive': [
73 include('whitespace'),
74 (r'[A-Z_a-z]\w*', Comment.Preproc, '#pop')
75 ],
76
77 'macro uses': [
78 (r'(\$[A-Z_a-z]\w*\.?)(\()', bygroups(Comment.Preproc, Punctuation),
79 'macro parameter value list'),
80 (r'\$[A-Z_a-z]\w*(?:\.|\b)', Comment.Preproc)
81 ],
82 'macro parameter value list': [
83 (r'(?:[^\'#"{()]|\{(?!\{))+', Comment.Preproc),
84 (r"['#]", Punctuation),
85 (r'"', String, 'macro parameter value quoted string'),
86 (r'\{\{', String, 'macro parameter value braced string'),
87 (r'\(', Comment.Preproc, 'macro parameter value parenthetical'),
88 (r'\)', Punctuation, '#pop')
89 ],
90 'macro parameter value quoted string': [
91 (r"\\[#'()]", Comment.Preproc),
92 (r"[#'()]", Error),
93 include('quoted string')
94 ],
95 'macro parameter value braced string': [
96 (r"\\[#'()]", Comment.Preproc),
97 (r"[#'()]", Error),
98 include('braced string')
99 ],
100 'macro parameter value parenthetical': [
101 (r'(?:[^\\()]|\\\))+', Comment.Preproc),
102 (r'\(', Comment.Preproc, '#push'),
103 (r'\)', Comment.Preproc, '#pop')
104 ],
105
106 'whitespace and macro uses': [
107 include('whitespace'),
108 include('macro uses')
109 ],
110
111 'numbers': [
112 (r'\d+[Ee][+-]?\d+|(\d+\.\d*|\d*\.\d+)([Ee][+-]?\d+)?', Number.Float),
113 (r'(0[Xx])([0-9A-Fa-f]+)', bygroups(Keyword.Type, Number.Hex)),
114 (r'\d+', Number.Integer)
115 ],
116
117 'braced string': [
118 # Do nothing. This must be defined in subclasses.
119 ]
120 }
121
122
123 class CsoundScoreLexer(CsoundLexer):
124 """
125 For `Csound <https://csound.github.io>`_ scores.
126
127 .. versionadded:: 2.1
128 """
129
130 name = 'Csound Score'
131 aliases = ['csound-score', 'csound-sco']
132 filenames = ['*.sco']
133
134 tokens = {
135 'root': [
136 (r'\n', Text),
137 include('whitespace and macro uses'),
138 include('preprocessor directives'),
139
140 (r'[abCdefiqstvxy]', Keyword),
141 # There is also a w statement that is generated internally and should not be
142 # used; see https://github.com/csound/csound/issues/750.
143
144 (r'z', Keyword.Constant),
145 # z is a constant equal to 800,000,000,000. 800 billion seconds is about
146 # 25,367.8 years. See also
147 # https://csound.github.io/docs/manual/ScoreTop.html and
148 # https://github.com/csound/csound/search?q=stof+path%3AEngine+filename%3Asread.c.
149
150 (r'([nNpP][pP])(\d+)', bygroups(Keyword, Number.Integer)),
151
152 (r'[mn]', Keyword, 'mark statement'),
153
154 include('numbers'),
155 (r'[!+\-*/^%&|<>#~.]', Operator),
156 (r'[()\[\]]', Punctuation),
157 (r'"', String, 'quoted string'),
158 (r'\{', Comment.Preproc, 'loop after left brace'),
159 ],
160
161 'mark statement': [
162 include('whitespace and macro uses'),
163 (r'[A-Z_a-z]\w*', Name.Label),
164 (r'\n', Text, '#pop')
165 ],
166
167 'quoted string': [
168 (r'"', String, '#pop'),
169 (r'[^"$]+', String),
170 include('macro uses'),
171 (r'[$]', String)
172 ],
173
174 'loop after left brace': [
175 include('whitespace and macro uses'),
176 (r'\d+', Number.Integer, ('#pop', 'loop after repeat count')),
177 ],
178 'loop after repeat count': [
179 include('whitespace and macro uses'),
180 (r'[A-Z_a-z]\w*', Comment.Preproc, ('#pop', 'loop'))
181 ],
182 'loop': [
183 (r'\}', Comment.Preproc, '#pop'),
184 include('root')
185 ],
186
187 # Braced strings are not allowed in Csound scores, but this is needed
188 # because the superclass includes it.
189 'braced string': [
190 (r'\}\}', String, '#pop'),
191 (r'[^}]|\}(?!\})', String)
192 ]
193 }
194
195
196 class CsoundOrchestraLexer(CsoundLexer):
197 """
198 For `Csound <https://csound.github.io>`_ orchestras.
199
200 .. versionadded:: 2.1
201 """
202
203 name = 'Csound Orchestra'
204 aliases = ['csound', 'csound-orc']
205 filenames = ['*.orc', '*.udo']
206
207 user_defined_opcodes = set()
208
209 def opcode_name_callback(lexer, match):
210 opcode = match.group(0)
211 lexer.user_defined_opcodes.add(opcode)
212 yield match.start(), Name.Function, opcode
213
214 def name_callback(lexer, match):
215 name = match.group(1)
216 if name in OPCODES or name in DEPRECATED_OPCODES:
217 yield match.start(), Name.Builtin, name
218 if match.group(2):
219 yield match.start(2), Punctuation, match.group(2)
220 yield match.start(3), Keyword.Type, match.group(3)
221 elif name in lexer.user_defined_opcodes:
222 yield match.start(), Name.Function, name
223 else:
224 nameMatch = re.search(r'^(g?[afikSw])(\w+)', name)
225 if nameMatch:
226 yield nameMatch.start(1), Keyword.Type, nameMatch.group(1)
227 yield nameMatch.start(2), Name, nameMatch.group(2)
228 else:
229 yield match.start(), Name, name
230 if match.group(2):
231 yield match.start(2), Punctuation, match.group(2)
232 yield match.start(3), Name, match.group(3)
233
234 tokens = {
235 'root': [
236 (r'\n', Text),
237
238 (r'^([ \t]*)(\w+)(:)(?:[ \t]+|$)', bygroups(Text, Name.Label, Punctuation)),
239
240 include('whitespace and macro uses'),
241 include('preprocessor directives'),
242
243 (r'\binstr\b', Keyword.Declaration, 'instrument numbers and identifiers'),
244 (r'\bopcode\b', Keyword.Declaration, 'after opcode keyword'),
245 (r'\b(?:end(?:in|op))\b', Keyword.Declaration),
246
247 include('partial statements')
248 ],
249
250 'partial statements': [
251 (r'\b(?:0dbfs|A4|k(?:r|smps)|nchnls(?:_i)?|sr)\b', Name.Variable.Global),
252
253 include('numbers'),
254
255 (r'\+=|-=|\*=|/=|<<|>>|<=|>=|==|!=|&&|\|\||[~¬]|[=!+\-*/^%&|<>#?:]', Operator),
256 (r'[(),\[\]]', Punctuation),
257
258 (r'"', String, 'quoted string'),
259 (r'\{\{', String, 'braced string'),
260
261 (words((
262 'do', 'else', 'elseif', 'endif', 'enduntil', 'fi', 'if', 'ithen', 'kthen',
263 'od', 'then', 'until', 'while',
264 ), prefix=r'\b', suffix=r'\b'), Keyword),
265 (words(('return', 'rireturn'), prefix=r'\b', suffix=r'\b'), Keyword.Pseudo),
266
267 (r'\b[ik]?goto\b', Keyword, 'goto label'),
268 (r'\b(r(?:einit|igoto)|tigoto)(\(|\b)', bygroups(Keyword.Pseudo, Punctuation),
269 'goto label'),
270 (r'\b(c(?:g|in?|k|nk?)goto)(\(|\b)', bygroups(Keyword.Pseudo, Punctuation),
271 ('goto label', 'goto argument')),
272 (r'\b(timout)(\(|\b)', bygroups(Keyword.Pseudo, Punctuation),
273 ('goto label', 'goto argument', 'goto argument')),
274 (r'\b(loop_[gl][et])(\(|\b)', bygroups(Keyword.Pseudo, Punctuation),
275 ('goto label', 'goto argument', 'goto argument', 'goto argument')),
276
277 (r'\bprintk?s\b', Name.Builtin, 'prints opcode'),
278 (r'\b(?:readscore|scoreline(?:_i)?)\b', Name.Builtin, 'Csound score opcode'),
279 (r'\bpyl?run[it]?\b', Name.Builtin, 'Python opcode'),
280 (r'\blua_(?:exec|opdef)\b', Name.Builtin, 'Lua opcode'),
281 (r'\bp\d+\b', Name.Variable.Instance),
282 (r'\b([A-Z_a-z]\w*)(?:(:)([A-Za-z]))?\b', name_callback)
283 ],
284
285 'instrument numbers and identifiers': [
286 include('whitespace and macro uses'),
287 (r'\d+|[A-Z_a-z]\w*', Name.Function),
288 (r'[+,]', Punctuation),
289 (r'\n', Text, '#pop')
290 ],
291
292 'after opcode keyword': [
293 include('whitespace and macro uses'),
294 (r'[A-Z_a-z]\w*', opcode_name_callback, ('#pop', 'opcode type signatures')),
295 (r'\n', Text, '#pop')
296 ],
297 'opcode type signatures': [
298 include('whitespace and macro uses'),
299
300 # https://github.com/csound/csound/search?q=XIDENT+path%3AEngine+filename%3Acsound_orc.lex
301 (r'0|[afijkKoOpPStV\[\]]+', Keyword.Type),
302
303 (r',', Punctuation),
304 (r'\n', Text, '#pop')
305 ],
306
307 'quoted string': [
308 (r'"', String, '#pop'),
309 (r'[^\\"$%)]+', String),
310 include('macro uses'),
311 include('escape sequences'),
312 include('format specifiers'),
313 (r'[\\$%)]', String)
314 ],
315 'braced string': [
316 (r'\}\}', String, '#pop'),
317 (r'(?:[^\\%)}]|\}(?!\}))+', String),
318 include('escape sequences'),
319 include('format specifiers'),
320 (r'[\\%)]', String)
321 ],
322 'escape sequences': [
323 # https://github.com/csound/csound/search?q=unquote_string+path%3AEngine+filename%3Acsound_orc_compile.c
324 (r'\\(?:[\\abnrt"]|[0-7]{1,3})', String.Escape)
325 ],
326 # Format specifiers are highlighted in all strings, even though only
327 # fprintks https://csound.github.io/docs/manual/fprintks.html
328 # fprints https://csound.github.io/docs/manual/fprints.html
329 # printf/printf_i https://csound.github.io/docs/manual/printf.html
330 # printks https://csound.github.io/docs/manual/printks.html
331 # prints https://csound.github.io/docs/manual/prints.html
332 # sprintf https://csound.github.io/docs/manual/sprintf.html
333 # sprintfk https://csound.github.io/docs/manual/sprintfk.html
334 # work with strings that contain format specifiers. In addition, these
335 # opcodes’ handling of format specifiers is inconsistent:
336 # - fprintks, fprints, printks, and prints do accept %a and %A
337 # specifiers, but can’t accept %s specifiers.
338 # - printf, printf_i, sprintf, and sprintfk don’t accept %a and %A
339 # specifiers, but can accept %s specifiers.
340 # See https://github.com/csound/csound/issues/747 for more information.
341 'format specifiers': [
342 (r'%[#0\- +]*\d*(?:\.\d+)?[diuoxXfFeEgGaAcs]', String.Interpol),
343 (r'%%', String.Escape)
344 ],
345
346 'goto argument': [
347 include('whitespace and macro uses'),
348 (r',', Punctuation, '#pop'),
349 include('partial statements')
350 ],
351 'goto label': [
352 include('whitespace and macro uses'),
353 (r'\w+', Name.Label, '#pop'),
354 default('#pop')
355 ],
356
357 'prints opcode': [
358 include('whitespace and macro uses'),
359 (r'"', String, 'prints quoted string'),
360 default('#pop')
361 ],
362 'prints quoted string': [
363 (r'\\\\[aAbBnNrRtT]', String.Escape),
364 (r'%[!nNrRtT]|[~^]{1,2}', String.Escape),
365 include('quoted string')
366 ],
367
368 'Csound score opcode': [
369 include('whitespace and macro uses'),
370 (r'\{\{', String, 'Csound score'),
371 (r'\n', Text, '#pop')
372 ],
373 'Csound score': [
374 (r'\}\}', String, '#pop'),
375 (r'([^}]+)|\}(?!\})', using(CsoundScoreLexer))
376 ],
377
378 'Python opcode': [
379 include('whitespace and macro uses'),
380 (r'\{\{', String, 'Python'),
381 (r'\n', Text, '#pop')
382 ],
383 'Python': [
384 (r'\}\}', String, '#pop'),
385 (r'([^}]+)|\}(?!\})', using(PythonLexer))
386 ],
387
388 'Lua opcode': [
389 include('whitespace and macro uses'),
390 (r'\{\{', String, 'Lua'),
391 (r'\n', Text, '#pop')
392 ],
393 'Lua': [
394 (r'\}\}', String, '#pop'),
395 (r'([^}]+)|\}(?!\})', using(LuaLexer))
396 ]
397 }
398
399
400 class CsoundDocumentLexer(RegexLexer):
401 """
402 For `Csound <https://csound.github.io>`_ documents.
403
404 .. versionadded:: 2.1
405 """
406
407 name = 'Csound Document'
408 aliases = ['csound-document', 'csound-csd']
409 filenames = ['*.csd']
410
411 # These tokens are based on those in XmlLexer in pygments/lexers/html.py. Making
412 # CsoundDocumentLexer a subclass of XmlLexer rather than RegexLexer may seem like a
413 # better idea, since Csound Document files look like XML files. However, Csound
414 # Documents can contain Csound comments (preceded by //, for example) before and
415 # after the root element, unescaped bitwise AND & and less than < operators, etc. In
416 # other words, while Csound Document files look like XML files, they may not actually
417 # be XML files.
418 tokens = {
419 'root': [
420 (r'/[*](.|\n)*?[*]/', Comment.Multiline),
421 (r'(?:;|//).*$', Comment.Single),
422 (r'[^/;<]+|/(?!/)', Text),
423
424 (r'<\s*CsInstruments', Name.Tag, ('orchestra', 'tag')),
425 (r'<\s*CsScore', Name.Tag, ('score', 'tag')),
426 (r'<\s*[Hh][Tt][Mm][Ll]', Name.Tag, ('HTML', 'tag')),
427
428 (r'<\s*[\w:.-]+', Name.Tag, 'tag'),
429 (r'<\s*/\s*[\w:.-]+\s*>', Name.Tag)
430 ],
431
432 'orchestra': [
433 (r'<\s*/\s*CsInstruments\s*>', Name.Tag, '#pop'),
434 (r'(.|\n)+?(?=<\s*/\s*CsInstruments\s*>)', using(CsoundOrchestraLexer))
435 ],
436 'score': [
437 (r'<\s*/\s*CsScore\s*>', Name.Tag, '#pop'),
438 (r'(.|\n)+?(?=<\s*/\s*CsScore\s*>)', using(CsoundScoreLexer))
439 ],
440 'HTML': [
441 (r'<\s*/\s*[Hh][Tt][Mm][Ll]\s*>', Name.Tag, '#pop'),
442 (r'(.|\n)+?(?=<\s*/\s*[Hh][Tt][Mm][Ll]\s*>)', using(HtmlLexer))
443 ],
444
445 'tag': [
446 (r'\s+', Text),
447 (r'[\w.:-]+\s*=', Name.Attribute, 'attr'),
448 (r'/?\s*>', Name.Tag, '#pop')
449 ],
450 'attr': [
451 (r'\s+', Text),
452 (r'".*?"', String, '#pop'),
453 (r"'.*?'", String, '#pop'),
454 (r'[^\s>]+', String, '#pop')
455 ]
456 }

eric ide

mercurial