~ubuntu-branches/ubuntu/vivid/frescobaldi/vivid

« back to all changes in this revision

Viewing changes to frescobaldi_app/ly/lex/lilypond.py

  • Committer: Package Import Robot
  • Author(s): Ryan Kavanagh
  • Date: 2012-01-03 16:20:11 UTC
  • mfrom: (1.4.1)
  • Revision ID: package-import@ubuntu.com-20120103162011-tsjkwl4sntwmprea
Tags: 2.0.0-1
* New upstream release 
* Drop the following uneeded patches:
  + 01_checkmodules_no_python-kde4_build-dep.diff
  + 02_no_pyc.diff
  + 04_no_binary_lilypond_upgrades.diff
* Needs new dependency python-poppler-qt4
* Update debian/watch for new download path
* Update copyright file with new holders and years

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# This file is part of the Frescobaldi project, http://www.frescobaldi.org/
 
2
#
 
3
# Copyright (c) 2008 - 2011 by Wilbert Berendsen
 
4
#
 
5
# This program is free software; you can redistribute it and/or
 
6
# modify it under the terms of the GNU General Public License
 
7
# as published by the Free Software Foundation; either version 2
 
8
# of the License, or (at your option) any later version.
 
9
#
 
10
# This program is distributed in the hope that it will be useful,
 
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
# GNU General Public License for more details.
 
14
#
 
15
# You should have received a copy of the GNU General Public License
 
16
# along with this program; if not, write to the Free Software
 
17
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
# See http://www.gnu.org/licenses/ for more information.
 
19
 
 
20
"""
 
21
Parses and tokenizes LilyPond input.
 
22
"""
 
23
 
 
24
from __future__ import unicode_literals
 
25
 
 
26
import itertools
 
27
 
 
28
from . import _token
 
29
from . import Parser, FallthroughParser
 
30
 
 
31
 
 
32
re_articulation = r"[-_^][_.>|+^-]"
 
33
re_dynamic = (
 
34
    r"\\[<!>]|"
 
35
    r"\\(f{1,5}|p{1,5}"
 
36
    r"|mf|mp|fp|spp?|sff?|sfz|rfz"
 
37
    r"|cresc|decresc|dim|cr|decr"
 
38
    r")(?![A-Za-z])")
 
39
 
 
40
re_duration = r"(\\(maxima|longa|breve)\b|(1|2|4|8|16|32|64|128|256|512|1024|2048)(?!\d))"
 
41
re_dot = r"\."
 
42
re_scaling = r"\*[\t ]*\d+(/\d+)?"
 
43
 
 
44
 
 
45
class Variable(_token.Token):
 
46
    pass
 
47
 
 
48
 
 
49
class UserVariable(_token.Token):
 
50
    pass
 
51
 
 
52
 
 
53
class Value(_token.Item, _token.Numeric):
 
54
    pass
 
55
 
 
56
 
 
57
class DecimalValue(Value):
 
58
    rx = r"-?\d+(\.\d+)?"
 
59
 
 
60
 
 
61
class Fraction(Value):
 
62
    rx = r"\d+/\d+"
 
63
    
 
64
    
 
65
class Error(_token.Error):
 
66
    pass
 
67
 
 
68
 
 
69
class Comment(_token.Comment):
 
70
    pass
 
71
 
 
72
 
 
73
class BlockCommentStart(Comment, _token.BlockCommentStart, _token.Indent):
 
74
    rx = r"%{"
 
75
    def updateState(self, state):
 
76
        state.enter(ParseBlockComment())
 
77
 
 
78
 
 
79
class BlockCommentEnd(Comment, _token.BlockCommentEnd, _token.Leaver, _token.Dedent):
 
80
    rx = r"%}"
 
81
 
 
82
 
 
83
class BlockCommentSpace(Comment, _token.BlockComment, _token.Space):
 
84
    pass
 
85
 
 
86
 
 
87
class LineComment(Comment, _token.LineComment):
 
88
    rx = r"%.*$"
 
89
    
 
90
 
 
91
class String(_token.String):
 
92
    pass
 
93
 
 
94
 
 
95
class StringQuotedStart(String, _token.StringStart):
 
96
    rx = r'"'
 
97
    def updateState(self, state):
 
98
        state.enter(ParseString())
 
99
        
 
100
 
 
101
class StringQuotedEnd(String, _token.StringEnd):
 
102
    rx = r'"'
 
103
    def updateState(self, state):
 
104
        state.leave()
 
105
        state.endArgument()
 
106
 
 
107
 
 
108
class StringQuoteEscape(_token.Character):
 
109
    rx = r'\\[\\"]'
 
110
 
 
111
 
 
112
class Skip(_token.Token):
 
113
    rx = r"s(?![A-Za-z])"
 
114
    
 
115
    
 
116
class Rest(_token.Token):
 
117
    rx = r"[Rr](?![A-Za-z])"
 
118
    
 
119
    
 
120
class Note(_token.Token):
 
121
    rx = r"[a-x]+(?![A-Za-z])"
 
122
    
 
123
 
 
124
class Octave(_token.Token):
 
125
    rx = r",+|'+"
 
126
 
 
127
 
 
128
class OctaveCheck(_token.Token):
 
129
    rx = r"=(,+|'+)?"
 
130
 
 
131
 
 
132
class Accidental(_token.Token):
 
133
    pass
 
134
 
 
135
 
 
136
class AccidentalReminder(Accidental):
 
137
    rx = r"!"
 
138
 
 
139
 
 
140
class AccidentalCautionary(Accidental):
 
141
    rx = r"\?"
 
142
 
 
143
 
 
144
class Duration(_token.Token):
 
145
    pass
 
146
 
 
147
 
 
148
class Length(Duration):
 
149
    rx = re_duration
 
150
    def updateState(self, state):
 
151
        state.enter(ParseDuration())
 
152
 
 
153
 
 
154
class Dot(Duration):
 
155
    rx = re_dot
 
156
    
 
157
    
 
158
class Scaling(Duration):
 
159
    rx = re_scaling
 
160
    
 
161
    
 
162
class Delimiter(_token.Token):
 
163
    pass
 
164
 
 
165
 
 
166
class OpenBracket(Delimiter, _token.MatchStart, _token.Indent):
 
167
    """An open bracket, does not enter different parser, subclass or reimplement Parser.updateState()."""
 
168
    rx = r"\{"
 
169
    matchname = "bracket"
 
170
 
 
171
 
 
172
class CloseBracket(Delimiter, _token.MatchEnd, _token.Dedent):
 
173
    rx = r"\}"
 
174
    matchname = "bracket"
 
175
    def updateState(self, state):
 
176
        state.leave()
 
177
        state.endArgument()    
 
178
    
 
179
 
 
180
class OpenSimultaneous(Delimiter, _token.MatchStart, _token.Indent):
 
181
    """An open double French quote, does not enter different parser, subclass or reimplement Parser.updateState()."""
 
182
    rx = r"<<"
 
183
    matchname = "simultaneous"
 
184
 
 
185
 
 
186
class CloseSimultaneous(Delimiter, _token.MatchEnd, _token.Dedent):
 
187
    rx = r">>"
 
188
    matchname = "simultaneous"
 
189
    def updateState(self, state):
 
190
        state.leave()
 
191
        state.endArgument()
 
192
    
 
193
 
 
194
class SequentialStart(OpenBracket):
 
195
    def updateState(self, state):
 
196
        state.enter(ParseMusic())
 
197
 
 
198
 
 
199
class SequentialEnd(CloseBracket):
 
200
    pass
 
201
 
 
202
 
 
203
class SimultaneousStart(OpenSimultaneous):
 
204
    def updateState(self, state):
 
205
        state.enter(ParseMusic())
 
206
 
 
207
 
 
208
class SimultaneousEnd(CloseSimultaneous):
 
209
    pass
 
210
 
 
211
 
 
212
class PipeSymbol(Delimiter):
 
213
    rx = r"\|"
 
214
 
 
215
 
 
216
class IntegerValue(Value):
 
217
    rx = r"\d+"
 
218
 
 
219
 
 
220
class Articulation(_token.Token):
 
221
    @_token.patternproperty
 
222
    def rx():
 
223
        from .. import words
 
224
        return r"\\({0})(?![A-Za-z])".format("|".join(itertools.chain(
 
225
            words.articulations,
 
226
            words.ornaments,
 
227
            words.fermatas,
 
228
            words.instrument_scripts,
 
229
            words.repeat_scripts,
 
230
            words.ancient_scripts,
 
231
        )))
 
232
    
 
233
    
 
234
class Direction(Articulation):
 
235
    rx = r"[-_^]"
 
236
    def updateState(self, state):
 
237
        state.enter(ParseScriptAbbreviationOrFingering())
 
238
 
 
239
 
 
240
class ScriptAbbreviation(Articulation, _token.Leaver):
 
241
    rx = r"[+|>._^-]"
 
242
 
 
243
 
 
244
class Fingering(Articulation, _token.Leaver):
 
245
    rx = r"\d"
 
246
 
 
247
 
 
248
class StringNumber(Articulation):
 
249
    rx = r"\\\d+"
 
250
 
 
251
 
 
252
class Slur(_token.Token):
 
253
    pass
 
254
 
 
255
 
 
256
class SlurStart(Slur, _token.MatchStart):
 
257
    rx = r"\("
 
258
    matchname = "slur"
 
259
    
 
260
 
 
261
class SlurEnd(Slur, _token.MatchEnd):
 
262
    rx = r"\)"
 
263
    matchname = "slur"
 
264
    
 
265
 
 
266
class PhrasingSlurStart(SlurStart):
 
267
    rx = r"\\\("
 
268
    matchname = "phrasingslur"
 
269
    
 
270
    
 
271
class PhrasingSlurEnd(SlurEnd):
 
272
    rx = r"\\\)"
 
273
    matchname = "phrasingslur"
 
274
    
 
275
 
 
276
class Tie(Slur):
 
277
    rx = r"~"
 
278
 
 
279
 
 
280
class Beam(_token.Token):
 
281
    pass
 
282
 
 
283
 
 
284
class BeamStart(Beam, _token.MatchStart):
 
285
    rx = r"\["
 
286
    matchname = "beam"
 
287
 
 
288
 
 
289
class BeamEnd(Beam, _token.MatchEnd):
 
290
    rx = r"\]"
 
291
    matchname = "beam"
 
292
 
 
293
 
 
294
class Ligature(_token.Token):
 
295
    pass
 
296
 
 
297
 
 
298
class LigatureStart(Ligature, _token.MatchStart):
 
299
    rx = r"\\\["
 
300
    matchname = "ligature"
 
301
    
 
302
    
 
303
class LigatureEnd(Ligature, _token.MatchEnd):
 
304
    rx = r"\\\]"
 
305
    matchname = "ligature"
 
306
    
 
307
    
 
308
class Keyword(_token.Item):
 
309
    @_token.patternproperty
 
310
    def rx():
 
311
        from .. import words
 
312
        return r"\\({0})(?![A-Za-z])".format("|".join(words.lilypond_keywords))
 
313
 
 
314
 
 
315
class VoiceSeparator(Delimiter):
 
316
    rx = r"\\\\"
 
317
    
 
318
 
 
319
class Dynamic(_token.Token):
 
320
    rx = re_dynamic
 
321
 
 
322
 
 
323
class Command(_token.Item):
 
324
    @_token.patternproperty
 
325
    def rx():
 
326
        from .. import words
 
327
        return r"\\({0})(?![A-Za-z])".format("|".join(words.lilypond_music_commands))
 
328
    
 
329
 
 
330
class Specifier(_token.Token):
 
331
    # a specifier of a command e.g. the name of clef or repeat style.
 
332
    pass
 
333
 
 
334
 
 
335
class Score(Keyword):
 
336
    rx = r"\\score\b"
 
337
    def updateState(self, state):
 
338
        state.enter(ExpectScore())
 
339
        
 
340
 
 
341
class Book(Keyword):
 
342
    rx = r"\\book\b"
 
343
    def updateState(self, state):
 
344
        state.enter(ExpectBook())
 
345
        
 
346
        
 
347
class BookPart(Keyword):
 
348
    rx = r"\\bookpart\b"
 
349
    def updateState(self, state):
 
350
        state.enter(ExpectBookPart())
 
351
 
 
352
 
 
353
class Paper(Keyword):
 
354
    rx = r"\\paper\b"
 
355
    def updateState(self, state):
 
356
        state.enter(ExpectPaper())
 
357
 
 
358
 
 
359
class Header(Keyword):
 
360
    rx = r"\\header\b"
 
361
    def updateState(self, state):
 
362
        state.enter(ExpectHeader())
 
363
 
 
364
 
 
365
class Layout(Keyword):
 
366
    rx = r"\\layout\b"
 
367
    def updateState(self, state):
 
368
        state.enter(ExpectLayout())
 
369
 
 
370
 
 
371
class Midi(Keyword):
 
372
    rx = r"\\midi\b"
 
373
    def updateState(self, state):
 
374
        state.enter(ExpectMidi())
 
375
 
 
376
 
 
377
class With(Keyword):
 
378
    rx = r"\\with\b"
 
379
    def updateState(self, state):
 
380
        state.enter(ExpectWith())
 
381
 
 
382
 
 
383
class LayoutContext(Keyword):
 
384
    rx = r"\\context\b"
 
385
    def updateState(self, state):
 
386
        state.enter(ExpectContext())
 
387
 
 
388
 
 
389
class Markup(Command):
 
390
    rx = r"\\markup(?![A-Za-z])"
 
391
    def updateState(self, state):
 
392
        state.enter(ParseMarkup(1))
 
393
 
 
394
 
 
395
class MarkupLines(Markup):
 
396
    rx = r"\\markuplines(?![A-Za-z])"
 
397
    def updateState(self, state):
 
398
        state.enter(ParseMarkup(1))
 
399
 
 
400
 
 
401
class MarkupList(Markup):
 
402
    rx = r"\\markuplist(?![A-Za-z])"
 
403
    def updateState(self, state):
 
404
        state.enter(ParseMarkup(1))
 
405
 
 
406
 
 
407
class MarkupCommand(Markup):
 
408
    rx = r"\\[A-Za-z]+(-[A-Za-z]+)*(?![A-Za-z])"
 
409
    def updateState(self, state):
 
410
        import ly.words
 
411
        command = self[1:]
 
412
        if command in ly.words.markupcommands_nargs[0]:
 
413
            state.endArgument()
 
414
        else:
 
415
            for argcount in 2, 3, 4, 5:
 
416
                if command in ly.words.markupcommands_nargs[argcount]:
 
417
                    break
 
418
            else:
 
419
                argcount = 1
 
420
            state.enter(ParseMarkup(argcount))
 
421
 
 
422
 
 
423
class MarkupScore(Markup):
 
424
    rx = r"\\score\b"
 
425
    def updateState(self, state):
 
426
        state.enter(ExpectScore())
 
427
 
 
428
 
 
429
class MarkupWord(_token.Item):
 
430
    rx = r'[^{}"\\\s#%]+'
 
431
 
 
432
 
 
433
class OpenBracketMarkup(OpenBracket):
 
434
    def updateState(self, state):
 
435
        state.enter(ParseMarkup())
 
436
 
 
437
 
 
438
class CloseBracketMarkup(CloseBracket):
 
439
    def updateState(self, state):
 
440
        state.endArgument()    
 
441
        state.leave()
 
442
        state.endArgument()    
 
443
 
 
444
 
 
445
class Repeat(Command):
 
446
    rx = r"\\repeat(?![A-Za-z])"
 
447
    def updateState(self, state):
 
448
        state.enter(ParseRepeat())
 
449
    
 
450
    
 
451
class RepeatSpecifier(Specifier):
 
452
    @_token.patternproperty
 
453
    def rx():
 
454
        from .. import words
 
455
        return r"\b({0})(?![A-Za-z])".format("|".join(words.repeat_types))
 
456
    
 
457
 
 
458
class RepeatStringSpecifier(String, Specifier):
 
459
    @_token.patternproperty
 
460
    def rx():
 
461
        from .. import words
 
462
        return r'"({0})"'.format("|".join(words.repeat_types))
 
463
    
 
464
 
 
465
class RepeatCount(IntegerValue, _token.Leaver):
 
466
    pass
 
467
 
 
468
 
 
469
class Override(Keyword):
 
470
    rx = r"\\override\b"
 
471
    def updateState(self, state):
 
472
        state.enter(ParseOverride())
 
473
 
 
474
 
 
475
class Set(Override):
 
476
    rx = r"\\set\b"
 
477
    def updateState(self, state):
 
478
        state.enter(ParseSet())
 
479
    
 
480
 
 
481
class Revert(Override):
 
482
    rx = r"\\revert\b"
 
483
    def updateState(self, state):
 
484
        state.enter(ParseRevert())
 
485
    
 
486
 
 
487
class DotSetOverride(Delimiter):
 
488
    rx = r"\."
 
489
 
 
490
 
 
491
class Unset(Keyword):
 
492
    rx = r"\\unset\b"
 
493
    def updateState(self, state):
 
494
        state.enter(ParseUnset())
 
495
 
 
496
 
 
497
class New(Command):
 
498
    rx = r"\\new\b"
 
499
    def updateState(self, state):
 
500
        state.enter(ParseNewContext())
 
501
        
 
502
        
 
503
class Context(New):
 
504
    rx = r"\\context\b"
 
505
    
 
506
 
 
507
class Change(New):
 
508
    rx = r"\\change\b"
 
509
    
 
510
    
 
511
class Clef(Command):
 
512
    rx = r"\\clef\b"
 
513
    def updateState(self, state):
 
514
        state.enter(ParseClef())
 
515
 
 
516
 
 
517
class ClefSpecifier(Specifier):
 
518
    @_token.patternproperty
 
519
    def rx():
 
520
        from .. import words
 
521
        return r"\b({0})\b".format("|".join(words.clefs_plain))
 
522
    
 
523
    def updateState(self, state):
 
524
        state.leave()
 
525
 
 
526
 
 
527
class PitchCommand(Command):
 
528
    rx = r"\\(relative|transpose|transposition|key|octaveCheck)\b"
 
529
    def updateState(self, state):
 
530
        argcount = 2 if self == '\\transpose' else 1
 
531
        state.enter(ParsePitchCommand(argcount))
 
532
 
 
533
 
 
534
class Unit(Command):
 
535
    rx = r"\\(mm|cm|in|pt)\b"
 
536
    
 
537
 
 
538
class InputMode(Command):
 
539
    pass
 
540
 
 
541
 
 
542
class LyricMode(InputMode):
 
543
    rx = r"\\(lyricmode|((old)?add)?lyrics|lyricsto)\b"
 
544
    def updateState(self, state):
 
545
        state.enter(ExpectLyricMode())
 
546
 
 
547
 
 
548
class Lyric(_token.Item):
 
549
    """Base class for Lyric items."""
 
550
 
 
551
 
 
552
class LyricText(Lyric):
 
553
    rx = r"[^\\\s\d~\"]+"
 
554
 
 
555
 
 
556
class LyricHyphen(Lyric):
 
557
    rx = r"--"
 
558
    
 
559
    
 
560
class LyricExtender(Lyric):
 
561
    rx = r"__"
 
562
    
 
563
    
 
564
class LyricSkip(Lyric):
 
565
    rx = r"_"
 
566
    
 
567
 
 
568
class LyricTie(Lyric):
 
569
    rx = r"~"
 
570
 
 
571
 
 
572
class NoteMode(InputMode):
 
573
    rx = r"\\(notes|notemode)\b"
 
574
    def updateState(self, state):
 
575
        state.enter(ExpectNoteMode())
 
576
 
 
577
 
 
578
class ChordMode(InputMode):
 
579
    rx = r"\\(chords|chordmode)\b"
 
580
    def updateState(self, state):
 
581
        state.enter(ExpectChordMode())
 
582
 
 
583
 
 
584
class DrumMode(InputMode):
 
585
    rx = r"\\(drums|drummode)\b"
 
586
    def updateState(self, state):
 
587
        state.enter(ExpectDrumMode())
 
588
 
 
589
 
 
590
class FigureMode(InputMode):
 
591
    rx = r"\\(figures|figuremode)\b"
 
592
    def updateState(self, state):
 
593
        state.enter(ExpectFigureMode())
 
594
 
 
595
 
 
596
class UserCommand(_token.Token):
 
597
    rx = r"\\[A-Za-z]+(?![A-Za-z])"
 
598
    
 
599
    
 
600
class SchemeStart(_token.Item):
 
601
    rx = "[#$]"
 
602
    def updateState(self, state):
 
603
        import scheme
 
604
        state.enter(scheme.ParseScheme(1))
 
605
 
 
606
 
 
607
class ContextName(_token.Token):
 
608
    @_token.patternproperty
 
609
    def rx():
 
610
        from .. import words
 
611
        return r"\b({0})\b".format("|".join(words.contexts))
 
612
    
 
613
 
 
614
class BackSlashedContextName(ContextName):
 
615
    @_token.patternproperty
 
616
    def rx():
 
617
        from .. import words
 
618
        return r"\\({0})\b".format("|".join(words.contexts))
 
619
    
 
620
    
 
621
class GrobName(_token.Token):
 
622
    @_token.patternproperty
 
623
    def rx():
 
624
        from .. import data
 
625
        return r"\b({0})\b".format("|".join(data.grobs()))
 
626
 
 
627
 
 
628
class ContextProperty(_token.Token):
 
629
    @_token.patternproperty
 
630
    def rx():
 
631
        from .. import data
 
632
        return r"\b({0})\b".format("|".join(data.context_properties()))
 
633
 
 
634
 
 
635
class PaperVariable(Variable):
 
636
    @_token.patternproperty
 
637
    def rx():
 
638
        from .. import words
 
639
        return r"\b({0})\b".format("|".join(words.papervariables))
 
640
 
 
641
 
 
642
class HeaderVariable(Variable):
 
643
    @_token.patternproperty
 
644
    def rx():
 
645
        from .. import words
 
646
        return r"\b({0})\b".format("|".join(words.headervariables))
 
647
 
 
648
 
 
649
class LayoutVariable(Variable):
 
650
    @_token.patternproperty
 
651
    def rx():
 
652
        from .. import words
 
653
        return r"\b({0})\b".format("|".join(words.layoutvariables))
 
654
 
 
655
 
 
656
class Chord(_token.Token):
 
657
    """Base class for Chord delimiters."""
 
658
    pass
 
659
 
 
660
 
 
661
class ChordStart(Chord):
 
662
    rx = r"<"
 
663
    def updateState(self, state):
 
664
        state.enter(ParseChord())
 
665
 
 
666
 
 
667
class ChordEnd(Chord, _token.Leaver):
 
668
    rx = r">"
 
669
    
 
670
 
 
671
class ErrorInChord(Error):
 
672
    rx = "|".join((
 
673
        re_articulation, # articulation
 
674
        r"<<|>>", # double french quotes
 
675
        r"\\[\\\]\[\(\)()]", # slurs beams
 
676
        re_duration, # duration
 
677
        re_scaling, # scaling
 
678
    ))
 
679
    
 
680
 
 
681
class Name(UserVariable):
 
682
    """A variable name without \\ prefix."""
 
683
    rx = r"[a-zA-Z]+(?![a-zA-Z])"
 
684
    
 
685
 
 
686
class NameLower(Name):
 
687
    """A lowercase name."""
 
688
    rx = r"[a-z]+(?![a-zA-Z])"
 
689
    
 
690
    
 
691
class NameHyphenLower(Name):
 
692
    """A lowercase name that may contain hyphens."""
 
693
    rx = r"[a-z]+(-[a-z]+)*(!?[-a-zA-Z])"
 
694
    
 
695
 
 
696
class EqualSign(_token.Token):
 
697
    rx = r"="
 
698
    
 
699
 
 
700
class EqualSignSetOverride(EqualSign):
 
701
    """An equal sign in a set/override construct."""
 
702
    def updateState(self, state):
 
703
        # wait for one more expression, then leave
 
704
        state.parser().argcount = 1
 
705
 
 
706
 
 
707
 
 
708
# Parsers
 
709
class ParseLilyPond(Parser):
 
710
    mode = 'lilypond'
 
711
 
 
712
# basic stuff that can appear everywhere
 
713
space_items = (
 
714
    _token.Space,
 
715
    BlockCommentStart,
 
716
    LineComment,
 
717
)    
 
718
 
 
719
 
 
720
base_items = space_items + (
 
721
    SchemeStart,
 
722
    StringQuotedStart,
 
723
)
 
724
 
 
725
 
 
726
# items that represent commands in both toplevel and music mode
 
727
command_items = (
 
728
    Repeat,
 
729
    PitchCommand,
 
730
    Override, Revert,
 
731
    Set, Unset,
 
732
    New, Context, Change,
 
733
    With,
 
734
    Clef,
 
735
    ChordMode, DrumMode, FigureMode, LyricMode, NoteMode,
 
736
    Markup, MarkupLines, MarkupList,
 
737
    Keyword,
 
738
    Command,
 
739
    UserCommand,
 
740
)
 
741
 
 
742
 
 
743
# items that occur in toplevel, book, bookpart or score
 
744
# no Leave-tokens!
 
745
toplevel_base_items = base_items + (
 
746
    Fraction,
 
747
    SequentialStart,
 
748
    SimultaneousStart,
 
749
) + command_items
 
750
 
 
751
 
 
752
# items that occur in music expressions
 
753
music_items = base_items + (
 
754
    Dynamic,
 
755
    Skip,
 
756
    Rest,
 
757
    Note,
 
758
    Fraction,
 
759
    Length,
 
760
    Octave,
 
761
    OctaveCheck,
 
762
    AccidentalCautionary,
 
763
    AccidentalReminder,
 
764
    PipeSymbol,
 
765
    VoiceSeparator,
 
766
    SequentialStart, SequentialEnd,
 
767
    SimultaneousStart, SimultaneousEnd,
 
768
    ChordStart,
 
769
    ContextName,
 
770
    GrobName,
 
771
    SlurStart, SlurEnd,
 
772
    PhrasingSlurStart, PhrasingSlurEnd,
 
773
    Tie,
 
774
    BeamStart, BeamEnd,
 
775
    LigatureStart, LigatureEnd,
 
776
    Direction,
 
777
    Articulation,
 
778
    IntegerValue,
 
779
) + command_items
 
780
    
 
781
 
 
782
# items that occur inside chords
 
783
music_chord_items = (
 
784
    ErrorInChord,
 
785
    ChordEnd,
 
786
    StringNumber,
 
787
) + music_items
 
788
 
 
789
 
 
790
 
 
791
class ParseGlobal(ParseLilyPond):
 
792
    """Parses LilyPond from the toplevel of a file."""
 
793
    # TODO: implement assignments
 
794
    items = (
 
795
        Book,
 
796
        BookPart,
 
797
        Score,
 
798
        Markup, MarkupLines, MarkupList,
 
799
        Paper, Header, Layout,
 
800
    ) + toplevel_base_items + (
 
801
        Name,
 
802
        EqualSign,
 
803
    )
 
804
 
 
805
 
 
806
class ExpectOpenBracket(ParseLilyPond):
 
807
    """Waits for an OpenBracket and then replaces the parser with the class set in the replace attribute.
 
808
    
 
809
    Subclass this to set the destination for the OpenBracket.
 
810
    
 
811
    """
 
812
    default = Error
 
813
    items = space_items + (
 
814
        OpenBracket,
 
815
    )
 
816
    def updateState(self, state, token):
 
817
        if isinstance(token, OpenBracket):
 
818
            state.replace(self.replace())
 
819
        
 
820
 
 
821
class ExpectOpenBrackedOrSimultaneous(ParseLilyPond):
 
822
    """Waits for an OpenBracket or << and then replaces the parser with the class set in the replace attribute.
 
823
    
 
824
    Subclass this to set the destination for the OpenBracket.
 
825
    
 
826
    """
 
827
    default = Error
 
828
    items = space_items + (
 
829
        OpenBracket,
 
830
        OpenSimultaneous,
 
831
    )
 
832
    def updateState(self, state, token):
 
833
        if isinstance(token, (OpenBracket, OpenSimultaneous)):
 
834
            state.replace(self.replace())
 
835
        
 
836
 
 
837
class ParseScore(ParseLilyPond):
 
838
    """Parses the expression after \score {, leaving at } """
 
839
    items = (
 
840
        CloseBracket,
 
841
        Header, Layout, Midi, With,
 
842
    ) + toplevel_base_items
 
843
 
 
844
 
 
845
class ExpectScore(ExpectOpenBracket):
 
846
    replace = ParseScore
 
847
            
 
848
 
 
849
class ParseBook(ParseLilyPond):
 
850
    """Parses the expression after \book {, leaving at } """
 
851
    items = (
 
852
        CloseBracket,
 
853
        Markup, MarkupLines, MarkupList,
 
854
        BookPart,
 
855
        Score,
 
856
        Paper, Header, Layout,
 
857
    ) + toplevel_base_items
 
858
 
 
859
 
 
860
 
 
861
class ExpectBook(ExpectOpenBracket):
 
862
    replace = ParseBook
 
863
 
 
864
 
 
865
class ParseBookPart(ParseLilyPond):
 
866
    """Parses the expression after \score {, leaving at } """
 
867
    items = (
 
868
        CloseBracket,
 
869
        Markup, MarkupLines, MarkupList,
 
870
        Score,
 
871
        Paper, Header, Layout,
 
872
    ) + toplevel_base_items
 
873
 
 
874
 
 
875
class ExpectBookPart(ExpectOpenBracket):
 
876
    replace = ParseBookPart
 
877
 
 
878
 
 
879
class ParsePaper(ParseLilyPond):
 
880
    """Parses the expression after \score {, leaving at } """
 
881
    items = base_items + (
 
882
        CloseBracket,
 
883
        Markup, MarkupLines, MarkupList,
 
884
        PaperVariable,
 
885
        EqualSign,
 
886
        DecimalValue,
 
887
        Unit,
 
888
    )
 
889
 
 
890
 
 
891
class ExpectPaper(ExpectOpenBracket):
 
892
    replace = ParsePaper
 
893
 
 
894
 
 
895
class ParseHeader(ParseLilyPond):
 
896
    """Parses the expression after \score {, leaving at } """
 
897
    items = (
 
898
        CloseBracket,
 
899
        Markup, MarkupLines, MarkupList,
 
900
        HeaderVariable,
 
901
        EqualSign,
 
902
    ) + toplevel_base_items
 
903
 
 
904
 
 
905
class ExpectHeader(ExpectOpenBracket):
 
906
    replace = ParseHeader
 
907
        
 
908
 
 
909
class ParseLayout(ParseLilyPond):
 
910
    """Parses the expression after \score {, leaving at } """
 
911
    items = base_items + (
 
912
        CloseBracket,
 
913
        LayoutContext,
 
914
        LayoutVariable,
 
915
        EqualSign,
 
916
        DecimalValue,
 
917
        Unit,
 
918
    )
 
919
 
 
920
 
 
921
class ExpectLayout(ExpectOpenBracket):
 
922
    replace = ParseLayout
 
923
        
 
924
 
 
925
class ParseMidi(ParseLilyPond):
 
926
    """Parses the expression after \score {, leaving at } """
 
927
    items = base_items + (
 
928
        CloseBracket,
 
929
        LayoutContext,
 
930
        LayoutVariable,
 
931
        EqualSign,
 
932
        DecimalValue,
 
933
        Unit,
 
934
    )
 
935
 
 
936
 
 
937
class ExpectMidi(ExpectOpenBracket):
 
938
    replace = ParseMidi
 
939
 
 
940
 
 
941
class ParseWith(ParseLilyPond):
 
942
    """Parses the expression after \score {, leaving at } """
 
943
    items = (
 
944
        CloseBracket,
 
945
        ContextProperty,
 
946
        EqualSign,
 
947
    ) + toplevel_base_items
 
948
 
 
949
 
 
950
class ExpectWith(ExpectOpenBracket):
 
951
    replace = ParseWith
 
952
        
 
953
 
 
954
class ParseContext(ParseLilyPond):
 
955
    """Parses the expression after \score {, leaving at } """
 
956
    items = (
 
957
        CloseBracket,
 
958
        BackSlashedContextName,
 
959
        ContextProperty,
 
960
        EqualSign,
 
961
    ) + toplevel_base_items
 
962
 
 
963
 
 
964
class ExpectContext(ExpectOpenBracket):
 
965
    replace = ParseContext
 
966
        
 
967
 
 
968
class ParseMusic(ParseLilyPond):
 
969
    """Parses LilyPond music expressions."""
 
970
    items = music_items
 
971
    
 
972
 
 
973
class ParseChord(ParseMusic):
 
974
    """LilyPond inside chords < >"""
 
975
    items = music_chord_items
 
976
 
 
977
 
 
978
class ParseString(Parser):
 
979
    default = String
 
980
    items = (
 
981
        StringQuotedEnd,
 
982
        StringQuoteEscape,
 
983
    )
 
984
    
 
985
 
 
986
class ParseBlockComment(Parser):
 
987
    default = Comment
 
988
    items = (
 
989
        BlockCommentSpace,
 
990
        BlockCommentEnd,
 
991
    )
 
992
 
 
993
 
 
994
class ParseMarkup(Parser):
 
995
    items =  (
 
996
        MarkupScore,
 
997
        MarkupCommand,
 
998
        OpenBracketMarkup,
 
999
        CloseBracketMarkup,
 
1000
        MarkupWord,
 
1001
    ) + base_items
 
1002
 
 
1003
 
 
1004
class ParseRepeat(FallthroughParser):
 
1005
    items = space_items + (
 
1006
        RepeatSpecifier,
 
1007
        RepeatStringSpecifier,
 
1008
        RepeatCount,
 
1009
    )
 
1010
 
 
1011
 
 
1012
class ParseDuration(FallthroughParser):
 
1013
    items = space_items + (
 
1014
        Dot,
 
1015
    )
 
1016
    def fallthrough(self, state):
 
1017
        state.replace(ParseDurationScaling())
 
1018
        
 
1019
        
 
1020
class ParseDurationScaling(ParseDuration):
 
1021
    items = space_items + (
 
1022
        Scaling,
 
1023
    )
 
1024
    def fallthrough(self, state):
 
1025
        state.leave()
 
1026
 
 
1027
 
 
1028
class ParseOverride(ParseLilyPond):
 
1029
    argcount = 0
 
1030
    items = (
 
1031
        ContextName,
 
1032
        DotSetOverride,
 
1033
        GrobName,
 
1034
        EqualSignSetOverride,
 
1035
        Name,
 
1036
        Markup, MarkupLines, MarkupList,
 
1037
    ) + base_items
 
1038
    
 
1039
 
 
1040
class ParseRevert(FallthroughParser):
 
1041
    items = space_items + (
 
1042
        ContextName,
 
1043
        DotSetOverride,
 
1044
        GrobName,
 
1045
        Name,
 
1046
        SchemeStart,
 
1047
    )
 
1048
 
 
1049
    
 
1050
class ParseSet(ParseLilyPond):
 
1051
    argcount = 0
 
1052
    items = (
 
1053
        ContextName,
 
1054
        DotSetOverride,
 
1055
        ContextProperty,
 
1056
        EqualSignSetOverride,
 
1057
        Name,
 
1058
        Markup, MarkupLines, MarkupList,
 
1059
    ) + base_items
 
1060
    
 
1061
    
 
1062
class ParseUnset(FallthroughParser):
 
1063
    items = space_items + (
 
1064
        ContextName,
 
1065
        DotSetOverride,
 
1066
        ContextProperty,
 
1067
        Name,
 
1068
    )
 
1069
 
 
1070
 
 
1071
class ParseNewContext(FallthroughParser):
 
1072
    items = space_items + (
 
1073
        ContextName,
 
1074
        Name,
 
1075
        EqualSign,
 
1076
        StringQuotedStart,
 
1077
    )
 
1078
 
 
1079
 
 
1080
class ParseClef(FallthroughParser):
 
1081
    argcount = 1
 
1082
    items = space_items + (
 
1083
        ClefSpecifier,
 
1084
        StringQuotedStart,
 
1085
    )
 
1086
 
 
1087
 
 
1088
class ParseScriptAbbreviationOrFingering(FallthroughParser):
 
1089
    argcount = 1
 
1090
    items = space_items + (
 
1091
        ScriptAbbreviation,
 
1092
        Fingering,
 
1093
    )
 
1094
 
 
1095
 
 
1096
class ParseInputMode(ParseLilyPond):
 
1097
    """Base class for parser for mode-changing music commands."""
 
1098
    
 
1099
    
 
1100
class ExpectLyricMode(FallthroughParser):
 
1101
    items = space_items + (
 
1102
        OpenBracket,
 
1103
        OpenSimultaneous,
 
1104
        SchemeStart,
 
1105
        StringQuotedStart,
 
1106
        Name,
 
1107
    )
 
1108
    
 
1109
    def updateState(self, state, token):
 
1110
        if isinstance(token, (OpenBracket, OpenSimultaneous)):
 
1111
            state.replace(ParseLyricMode())
 
1112
        
 
1113
 
 
1114
class ParseLyricMode(ParseInputMode):
 
1115
    """Parser for \\lyrics, \\lyricmode, \\addlyrics, etc."""
 
1116
    items = base_items + (
 
1117
        CloseBracket,
 
1118
        CloseSimultaneous,
 
1119
        OpenBracket,
 
1120
        OpenSimultaneous,
 
1121
        PipeSymbol,
 
1122
        LyricHyphen,
 
1123
        LyricExtender,
 
1124
        LyricSkip,
 
1125
        LyricTie,
 
1126
        LyricText,
 
1127
        Dynamic,
 
1128
        Skip,
 
1129
        Length,
 
1130
        Markup, MarkupLines, MarkupList,
 
1131
    ) + command_items
 
1132
    
 
1133
    def updateState(self, state, token):
 
1134
        if isinstance(token, (OpenSimultaneous, OpenBracket)):
 
1135
            state.replace(ParseLyricMode())
 
1136
 
 
1137
 
 
1138
class ExpectChordMode(FallthroughParser):
 
1139
    items = space_items + (
 
1140
        OpenBracket,
 
1141
        OpenSimultaneous,
 
1142
    )
 
1143
    
 
1144
    def updateState(self, state, token):
 
1145
        if isinstance(token, (OpenBracket, OpenSimultaneous)):
 
1146
            state.replace(ParseChordMode())
 
1147
        
 
1148
 
 
1149
class ParseChordMode(ParseInputMode, ParseMusic):
 
1150
    """Parser for \\chords and \\chordmode."""
 
1151
    pass # TODO: implement
 
1152
 
 
1153
 
 
1154
class ExpectNoteMode(FallthroughParser):
 
1155
    items = space_items + (
 
1156
        OpenBracket,
 
1157
        OpenSimultaneous,
 
1158
    )
 
1159
    
 
1160
    def updateState(self, state, token):
 
1161
        if isinstance(token, (OpenBracket, OpenSimultaneous)):
 
1162
            state.replace(ParseNoteMode())
 
1163
        
 
1164
 
 
1165
class ParseNoteMode(ParseInputMode, ParseMusic):
 
1166
    """Parser for \\notes and \\notemode. Same as Music itself."""
 
1167
 
 
1168
 
 
1169
class ExpectDrumMode(FallthroughParser):
 
1170
    items = space_items + (
 
1171
        OpenBracket,
 
1172
        OpenSimultaneous,
 
1173
    )
 
1174
    
 
1175
    def updateState(self, state, token):
 
1176
        if isinstance(token, (OpenBracket, OpenSimultaneous)):
 
1177
            state.replace(ParseDrumMode())
 
1178
        
 
1179
 
 
1180
class ParseDrumMode(ParseInputMode, ParseMusic):
 
1181
    """Parser for \\drums and \\drummode."""
 
1182
    pass # TODO: implement
 
1183
 
 
1184
 
 
1185
class ExpectFigureMode(FallthroughParser):
 
1186
    items = space_items + (
 
1187
        OpenBracket,
 
1188
        OpenSimultaneous,
 
1189
    )
 
1190
    
 
1191
    def updateState(self, state, token):
 
1192
        if isinstance(token, (OpenBracket, OpenSimultaneous)):
 
1193
            state.replace(ParseFigureMode())
 
1194
        
 
1195
 
 
1196
class ParseFigureMode(ParseInputMode, ParseMusic):
 
1197
    """Parser for \\figures and \\figuremode."""
 
1198
    pass # TODO: implement
 
1199
    
 
1200
 
 
1201
class ParsePitchCommand(FallthroughParser):
 
1202
    argcount = 1
 
1203
    items = space_items + (
 
1204
        Note,
 
1205
        Octave,
 
1206
    )
 
1207
    def updateState(self, state, token):
 
1208
        if isinstance(token, Note):
 
1209
            self.argcount -= 1
 
1210
        elif isinstance(token, _token.Space) and self.argcount <= 0:
 
1211
            state.leave()
 
1212
 
 
1213
 
 
1214