@k-l-lambda/lilylet 0.1.49 → 0.1.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/lib/abc/abc.d.ts +102 -0
  2. package/lib/abc/abc.js +25 -0
  3. package/lib/abc/grammar.jison.js +1203 -0
  4. package/lib/abc/parser.d.ts +3 -0
  5. package/lib/abc/parser.js +6 -0
  6. package/lib/abcDecoder.d.ts +1 -0
  7. package/lib/abcDecoder.js +1 -0
  8. package/lib/grammar.jison.js +1 -1303
  9. package/lib/index.d.ts +1 -8
  10. package/lib/index.js +1 -10
  11. package/lib/lilylet/abcDecoder.d.ts +25 -0
  12. package/lib/lilylet/abcDecoder.js +1007 -0
  13. package/lib/lilylet/grammar.jison.js +1308 -0
  14. package/lib/lilylet/index.d.ts +10 -0
  15. package/lib/lilylet/index.js +10 -0
  16. package/lib/lilylet/lilypondDecoder.d.ts +29 -0
  17. package/lib/lilylet/lilypondDecoder.js +1053 -0
  18. package/lib/lilylet/lilypondEncoder.d.ts +34 -0
  19. package/lib/lilylet/lilypondEncoder.js +759 -0
  20. package/lib/lilylet/meiEncoder.d.ts +8 -0
  21. package/lib/lilylet/meiEncoder.js +1808 -0
  22. package/lib/lilylet/musicXmlDecoder.d.ts +20 -0
  23. package/lib/lilylet/musicXmlDecoder.js +1195 -0
  24. package/lib/lilylet/musicXmlEncoder.d.ts +15 -0
  25. package/lib/lilylet/musicXmlEncoder.js +701 -0
  26. package/lib/lilylet/musicXmlTypes.d.ts +199 -0
  27. package/lib/lilylet/musicXmlTypes.js +7 -0
  28. package/lib/lilylet/musicXmlUtils.d.ts +92 -0
  29. package/lib/lilylet/musicXmlUtils.js +469 -0
  30. package/lib/lilylet/parser.d.ts +3 -0
  31. package/lib/lilylet/parser.js +151 -0
  32. package/lib/lilylet/serializer.d.ts +11 -0
  33. package/lib/lilylet/serializer.js +653 -0
  34. package/lib/lilylet/types.d.ts +245 -0
  35. package/lib/lilylet/types.js +99 -0
  36. package/lib/lilypondDecoder.d.ts +1 -29
  37. package/lib/lilypondDecoder.js +1 -1006
  38. package/lib/lilypondEncoder.d.ts +1 -34
  39. package/lib/lilypondEncoder.js +1 -759
  40. package/lib/meiEncoder.d.ts +1 -8
  41. package/lib/meiEncoder.js +1 -1545
  42. package/lib/musicXmlDecoder.d.ts +1 -20
  43. package/lib/musicXmlDecoder.js +1 -1151
  44. package/lib/musicXmlEncoder.d.ts +1 -15
  45. package/lib/musicXmlEncoder.js +1 -666
  46. package/lib/musicXmlTypes.d.ts +1 -199
  47. package/lib/musicXmlTypes.js +1 -7
  48. package/lib/musicXmlUtils.d.ts +1 -81
  49. package/lib/musicXmlUtils.js +1 -435
  50. package/lib/parser.d.ts +1 -3
  51. package/lib/parser.js +1 -151
  52. package/lib/serializer.d.ts +1 -11
  53. package/lib/serializer.js +1 -650
  54. package/lib/types.d.ts +1 -244
  55. package/lib/types.js +1 -99
  56. package/package.json +2 -1
  57. package/source/abc/abc.jison +692 -0
  58. package/source/abc/abc.ts +176 -0
  59. package/source/abc/grammar.jison.js +1203 -0
  60. package/source/abc/parser.ts +12 -0
  61. package/source/lilylet/abcDecoder.ts +1121 -0
  62. package/source/lilylet/grammar.jison.js +170 -165
  63. package/source/lilylet/index.ts +4 -3
  64. package/source/lilylet/lilylet.jison +2 -0
  65. package/source/lilylet/lilypondDecoder.ts +91 -41
  66. package/source/lilylet/meiEncoder.ts +280 -0
  67. package/source/lilylet/musicXmlDecoder.ts +74 -27
  68. package/source/lilylet/musicXmlEncoder.ts +201 -146
  69. package/source/lilylet/musicXmlUtils.ts +46 -4
  70. package/source/lilylet/serializer.ts +3 -0
  71. package/source/lilylet/types.ts +1 -0
@@ -0,0 +1,692 @@
1
+
2
+ %{
3
+ const header = (name, value) => {
4
+ switch (name) {
5
+ case "K":
6
+ if (typeof value === "string") {
7
+ return {
8
+ name,
9
+ value: key(value),
10
+ };
11
+ }
12
+ }
13
+
14
+ return {
15
+ name,
16
+ value,
17
+ };
18
+ };
19
+
20
+
21
+ const event = (chord, duration) => {
22
+ return {
23
+ chord,
24
+ duration,
25
+ };
26
+ };
27
+
28
+
29
+ const pitch = (acc, phonet, quotes) => {
30
+ return {
31
+ acc,
32
+ phonet,
33
+ quotes,
34
+ };
35
+ };
36
+
37
+
38
+ const patch = (terms, bar) => {
39
+ const control = {};
40
+ terms.forEach(term => {
41
+ if (term.control)
42
+ control[term.control.name] = term.control.value;
43
+ });
44
+
45
+ return {
46
+ control,
47
+ terms,
48
+ bar,
49
+ };
50
+ };
51
+
52
+
53
+ const voice = (name, clef, properties) => ({
54
+ name,
55
+ clef,
56
+ properties,
57
+ });
58
+
59
+
60
+ const assign = (name, value) => {
61
+ return {
62
+ [name]: value,
63
+ };
64
+ };
65
+
66
+
67
+ const frac = (numerator, denominator) => {
68
+ return {
69
+ numerator,
70
+ denominator,
71
+ };
72
+ };
73
+
74
+
75
+ const articulation = (content, scope) => ({
76
+ articulation: content,
77
+ scope,
78
+ });
79
+
80
+
81
+ const tune = (header, body) => {
82
+ const {patches} = body;
83
+ const measures = [];
84
+ let measure = null;
85
+ let lastVoice = 1;
86
+ patches.forEach(patch => {
87
+ const voice = patch.control.V || 1;
88
+ if (voice <= lastVoice) {
89
+ if (measure)
90
+ measures.push(measure);
91
+ measure = {voices: []};
92
+ }
93
+ measure.voices.push(patch);
94
+ });
95
+
96
+ measures.push(measure);
97
+
98
+ measures.forEach((measure, index) => measure.index = index + 1);
99
+
100
+ return {
101
+ header,
102
+ body: {
103
+ measures,
104
+ },
105
+ };
106
+ };
107
+
108
+
109
+ const grace = (events, acciaccatura) => ({
110
+ grace: true,
111
+ acciaccatura,
112
+ events,
113
+ });
114
+
115
+
116
+ const chord = (pitches, tie) => ({
117
+ pitches,
118
+ tie,
119
+ });
120
+
121
+
122
+ const staffShift = (shift) => ({
123
+ staffShift: shift,
124
+ });
125
+
126
+
127
+ const comment = (text) => ({
128
+ comment: text,
129
+ });
130
+
131
+
132
+ const staffGroup = (items, bound) => ({
133
+ items,
134
+ bound,
135
+ });
136
+
137
+
138
+ const tempo = (note, bpm) => ({
139
+ note,
140
+ bpm,
141
+ });
142
+
143
+
144
+ const key = (root, mode) => ({
145
+ root,
146
+ mode,
147
+ });
148
+
149
+
150
+ const clef = clef => ({clef});
151
+
152
+
153
+ const octaveShift = shift => ({octaveShift: shift});
154
+ %}
155
+
156
+
157
+ %lex
158
+
159
+ %option flex unicode
160
+
161
+ %x string
162
+ %x comment
163
+ %x spec_comment
164
+ %x title_string
165
+ %x key_signature
166
+ %x exclamation_exp
167
+
168
+
169
+ H \b[A-Z](?=\:[^|])
170
+ A \b[A-G](?=[\W\d\sA-Ga-g_zHJLMOPRSTuv]*\b)
171
+ Am \b[A-G](?=[m][a][j]|[m][i][n]\b)
172
+ a \b[a-g](?=[\W\d\sA-Ga-g_zHJLMOPRSTuv]*\b)
173
+ z \b[z]
174
+ Z \b[Z]
175
+ x \b[x](?=[\W\d\s])
176
+ N [0-9]
177
+ P \b[HJLMOPRSTuv](?=[A-Ga-g][A-Ga-g0-9]*\b)
178
+ PP \b[HJLMOPRSTuv](?=[xz!\[^_=\s"])
179
+
180
+ SPECIAL [:!^_,'/<>={}()\[\]|.\-+~]
181
+
182
+
183
+ %%
184
+
185
+ \" { this.pushState('string'); return 'STR_START'; }
186
+ <string>\" { this.popState(); return 'STR_END'; }
187
+ <string>\\\" return 'STR_CONTENT'
188
+ <string>[^"]+ return 'STR_CONTENT'
189
+
190
+ ^[T][:][\s]* { this.pushState('title_string'); return 'T:'; }
191
+ ^[C][:][\s]* { this.pushState('title_string'); return 'C:'; }
192
+ <title_string>\n { this.popState(); }
193
+ <title_string>[^\n]+ return 'STR_CONTENT'
194
+
195
+ ^[K][:][\s]* { this.pushState('key_signature'); return 'K:'; }
196
+ <key_signature>"treble" return 'TREBLE';
197
+ <key_signature>"bass" return 'BASS';
198
+ <key_signature>"tenor" return 'TENOR';
199
+ <key_signature>[A-G] return 'A';
200
+ <key_signature>[b] return 'FLAT';
201
+ <key_signature>[#] return 'SHARP';
202
+ <key_signature>[m][a-z]* return 'NAME';
203
+ <key_signature>[a-z]+ return 'NAME';
204
+ <key_signature>[ \t]+ {}
205
+ <key_signature>[+\-] return yytext;
206
+ <key_signature>[0-9] return 'N';
207
+ <key_signature>\n { this.popState(); }
208
+ <key_signature>\] { this.popState(); return ']'; }
209
+
210
+ ^[%] { this.pushState('comment'); }
211
+ <comment>[%] { this.pushState('spec_comment'); }
212
+ <comment>[^\n]+ { return 'COMMENT'; }
213
+ <spec_comment>\n { this.popState(); this.popState(); }
214
+ <comment>\n { this.popState(); }
215
+ <spec_comment>\s {}
216
+ <spec_comment>"score" return 'SCORE'
217
+ <spec_comment>[\w]+ return 'NN'
218
+ <spec_comment>[(){}\[\]|] return yytext
219
+
220
+ [!] { this.pushState('exclamation_exp'); return '!'; }
221
+ <exclamation_exp>[!] { this.popState(); return '!'; }
222
+ <exclamation_exp>{SPECIAL} return yytext
223
+ <exclamation_exp>"D.C." return yytext
224
+ <exclamation_exp>"D.S." return yytext
225
+ <exclamation_exp>"alcoda" return yytext
226
+ <exclamation_exp>"alfine" return yytext
227
+ <exclamation_exp>[8][v][ab] return yytext
228
+ <exclamation_exp>[1][5][m][ab] return yytext
229
+ <exclamation_exp>\b[ms]?[pf]+[z]?\b return 'DYNAMIC'
230
+ <exclamation_exp>{a} return 'a'
231
+ <exclamation_exp>{N} return 'N'
232
+ <exclamation_exp>[a-zA-Z][\w-]* return 'NAME'
233
+
234
+ \s+ {}
235
+
236
+ {SPECIAL} return yytext
237
+
238
+ {H} return 'H'
239
+ {A} return 'A'
240
+ {Am} return 'A'
241
+ {a} return 'a'
242
+ {z} return 'z'
243
+ {Z} return 'Z'
244
+ {P} return yytext
245
+ {PP} return yytext
246
+ {x} return 'x'
247
+ {N} return 'N'
248
+ \b[ms]?[pf]+[z]?\b return 'DYNAMIC'
249
+
250
+ "staff" return 'STAFF'
251
+ "maj" return 'MAJ'
252
+ "min" return 'MIN'
253
+ [a-zA-Z][\w-]* return 'NAME'
254
+
255
+ <<EOF>> return 'EOF'
256
+
257
+
258
+ /lex
259
+
260
+ %start start_symbol
261
+
262
+ %%
263
+
264
+ start_symbol
265
+ : tunes EOF { return $1; }
266
+ ;
267
+
268
+ tunes
269
+ : tune -> [$1]
270
+ | tunes tune -> [...$1, $2]
271
+ ;
272
+
273
+ tune
274
+ : header body -> tune($1, $2)
275
+ ;
276
+
277
+ header
278
+ : head_lines
279
+ ;
280
+
281
+ head_lines
282
+ : head_line -> [$1]
283
+ | comment -> [$1]
284
+ | head_lines head_line -> [...$1, $2]
285
+ | head_lines comment -> [...$1, $2]
286
+ | head_lines staff_layout_statement -> [...$1, $2]
287
+ | head_lines ']' -> $1
288
+ | head_lines '}' -> $1
289
+ | head_lines ')' -> $1
290
+ ;
291
+
292
+ comment
293
+ : COMMENT -> comment($1)
294
+ ;
295
+
296
+ staff_layout_statement
297
+ : 'SCORE' staff_layout -> $2
298
+ ;
299
+
300
+ staff_layout
301
+ : staff_layout_items -> ({staffLayout: $1})
302
+ ;
303
+
304
+ staff_layout_items
305
+ : staff_layout_item -> [$1]
306
+ | staff_layout_items staff_layout_item -> [...$1, $2]
307
+ | staff_layout_items '|' -> $1
308
+ ;
309
+
310
+ staff_layout_item
311
+ : NN -> staffGroup([$1])
312
+ | '(' staff_layout_items ')' -> staffGroup($2, 'arc')
313
+ | '[' staff_layout_items ']' -> staffGroup($2, 'square')
314
+ | '{' staff_layout_items '}' -> staffGroup($2, 'curly')
315
+ | '[' staff_layout_items '}' -> staffGroup($2, 'square')
316
+ | '{' staff_layout_items ']' -> staffGroup($2, 'curly')
317
+ ;
318
+
319
+ head_line
320
+ : 'T:' string_content -> header('T', $2)
321
+ | 'C:' string_content -> header('C', $2)
322
+ | 'K:' key_signature -> header('K', $2)
323
+ | H ':' header_value -> header($1, $3)
324
+ ;
325
+
326
+ header_value
327
+ : string
328
+ | number
329
+ | frac
330
+ | numeric_tempo
331
+ | upper_phonet
332
+ | voice_exp
333
+ | staff_shift
334
+ | NAME
335
+ | key_signature
336
+ | clef
337
+ ;
338
+
339
+ staff_shift
340
+ : 'STAFF' plus_minus_number -> staffShift($2)
341
+ | NAME plus_minus_number -> staffShift($2)
342
+ ;
343
+
344
+ key_signature
345
+ : A -> key($1, null)
346
+ | A sharp_or_flat -> key($1 + $2, null)
347
+ | A key_mode -> key($1, $2)
348
+ | A sharp_or_flat key_mode -> key($1 + $2, $3)
349
+ ;
350
+
351
+ clef
352
+ : TREBLE -> clef($1)
353
+ | BASS -> clef($1)
354
+ | TENOR -> clef($1)
355
+ ;
356
+
357
+ sharp_or_flat
358
+ : SHARP -> '#'
359
+ | FLAT -> 'b'
360
+ ;
361
+
362
+ key_mode
363
+ : MAJ -> 'major'
364
+ | MIN -> 'minor'
365
+ | NAME -> $1.startsWith("ma") ? "major" : "minor"
366
+ ;
367
+
368
+ plus_minus_number
369
+ : '+' number -> Number($2)
370
+ | '-' number -> -Number($2)
371
+ ;
372
+
373
+ string
374
+ : STR_START string_content STR_END -> $2
375
+ ;
376
+
377
+ string_content
378
+ : %empty -> ""
379
+ | string_content STR_CONTENT -> $1 ? $1 + $2 : $2
380
+ ;
381
+
382
+ body
383
+ : patches -> ({patches: $1})
384
+ ;
385
+
386
+ frac
387
+ : number '/' number -> frac($1, $3)
388
+ ;
389
+
390
+ number
391
+ : N -> Number($1)
392
+ | number N -> $1 * 10 + Number($2)
393
+ ;
394
+
395
+ numeric_tempo
396
+ : frac '=' number -> tempo($1, $3)
397
+ ;
398
+
399
+ voice_exp
400
+ : number -> voice($1)
401
+ | number NAME -> voice($1, $2)
402
+ | number NAME assigns -> voice($1, $2, $3)
403
+ | NAME -> voice(1, $1)
404
+ | NAME assigns -> voice(1, $1, $2)
405
+ ;
406
+
407
+ assigns
408
+ : assign -> $1
409
+ | assigns assign -> ({...$1, ...$2})
410
+ ;
411
+
412
+ assign
413
+ : NAME '=' assign_value -> assign($1, $3)
414
+ ;
415
+
416
+ assign_value
417
+ : string
418
+ | number
419
+ | plus_minus_number
420
+ | NAME
421
+ ;
422
+
423
+ upper_phonet
424
+ : A
425
+ ;
426
+
427
+ lower_phonet
428
+ : a
429
+ ;
430
+
431
+ patches
432
+ : patch -> [$1]
433
+ | bar patch -> [$2]
434
+ | patches patch -> [...$1, $2]
435
+ | patches comment -> $1
436
+ | tailless_patch -> [$1]
437
+ | patches tailless_patch -> [...$1, $2]
438
+ | patches ']' -> $1
439
+ | patches '}' -> $1
440
+ ;
441
+
442
+ patch
443
+ : music bar -> patch($1, $2)
444
+ ;
445
+
446
+ tailless_patch
447
+ : music -> patch($1, null)
448
+ ;
449
+
450
+ bar
451
+ : '|' -> '|'
452
+ | '|' ':' -> '|:'
453
+ | ':' '|' -> ':|'
454
+ | ':' ':' -> ':|:'
455
+ | ':' '|' ':' -> ':|:'
456
+ | ':' '|' '|' ':' -> ':|:'
457
+ | '|' '|' -> '||'
458
+ | '|' ']' -> '|]'
459
+ | ':' '|' ']' -> ':|]'
460
+ | '|' N -> '|' + $2
461
+ | ':' '|' N -> ':|' + $2
462
+ ;
463
+
464
+ music
465
+ : %empty
466
+ | music expressive_mark -> $1 ? [...$1, $2] : [$2]
467
+ | music text -> $1 ? [...$1, $2] : [$2]
468
+ | music event -> $1 ? [...$1, $2] : [$2]
469
+ | music grace_events -> $1 ? [...$1, $2] : [$2]
470
+ | music control -> $1 ? [...$1, $2] : [$2]
471
+ | music broken_rhythm { Object.assign($1.at(-1), $2); $$ = $1; }
472
+ | music triplet -> $1 ? [...$1, $2] : [$2]
473
+ | music N -> $1
474
+ | music NAME -> $1
475
+ | music '^' NAME -> $1
476
+ | music '^' -> $1
477
+ ;
478
+
479
+ control
480
+ : '[' H ':' header_value ']' -> ({control: header($2, $4)})
481
+ | '[' 'K:' header_value ']' -> ({control: header("K", $3)})
482
+ | '[' NAME ':' header_value ']' -> ({control: header($2, $4)})
483
+ ;
484
+
485
+ expressive_mark
486
+ : articulation
487
+ | '(' -> ({express: $1})
488
+ | ')' -> ({express: $1})
489
+ | '.' -> ({express: $1})
490
+ | '-' -> ({express: $1})
491
+ | 'O' -> ({express: "coda"})
492
+ | 'S' -> ({express: "segno"})
493
+ ;
494
+
495
+ articulation
496
+ : '!' articulation_content '!' -> $2
497
+ | '!' directive_text '!' -> $2
498
+ | 'P' -> articulation("prall")
499
+ | 'T' -> articulation("trill")
500
+ | 'H' -> articulation("fermata")
501
+ | 'J' -> articulation("slide")
502
+ | 'L' -> articulation("accent")
503
+ | 'M' -> articulation("mordent")
504
+ | 'R' -> articulation("roll")
505
+ | 'u' -> articulation("upbow")
506
+ | 'v' -> articulation("downbow")
507
+ | '~' -> articulation("mordent")
508
+ ;
509
+
510
+ articulation_content
511
+ : scope_articulation -> articulation($1)
512
+ | scope_articulation parenthese -> articulation($1, $2)
513
+ | DYNAMIC -> articulation($1)
514
+ | a -> articulation($1)
515
+ | "^" -> articulation($1)
516
+ | fingering_numbers -> ({fingering: Number($1)})
517
+ | tremolo -> ({tremolo: $1})
518
+ | tremolo '-' -> ({tremolo: $1}) // unknown meaning of '-'?
519
+ ;
520
+
521
+ fingering_numbers
522
+ : N -> String($1)
523
+ | fingering_numbers N -> $1 + $2
524
+ ;
525
+
526
+ tremolo
527
+ : '/' -> 1
528
+ | tremolo '/' -> $1 + 1
529
+ ;
530
+
531
+ directive_text
532
+ : dc -> ({directive: $1})
533
+ | dc al -> ({directive: `${$1} ${$2}`})
534
+ | octave_shift "(" -> octaveShift($1)
535
+ | octave_shift ")" -> octaveShift(0)
536
+ ;
537
+
538
+ octave_shift
539
+ : "8va" -> -1
540
+ | "8vb" -> 1
541
+ | "15ma" -> -2
542
+ | "15mb" -> 2
543
+ ;
544
+
545
+ dc
546
+ : "D.C."
547
+ | "D.S."
548
+ ;
549
+
550
+ al
551
+ : "alcoda" -> "al coda"
552
+ | "alfine" -> "al fine"
553
+ ;
554
+
555
+ scope_articulation
556
+ : '<'
557
+ | '>'
558
+ | NAME
559
+ ;
560
+
561
+ parenthese
562
+ : '('
563
+ | ')'
564
+ ;
565
+
566
+ text
567
+ : string -> ({text: $1})
568
+ ;
569
+
570
+ pitch_or_chord
571
+ : pitch -> chord([$1])
572
+ | chord
573
+ | accidentals chord -> $2
574
+ ;
575
+
576
+ chord
577
+ : '[' pitches ']' -> chord($2)
578
+ | '[' ')' ']' -> chord([])
579
+ | '[' ')' -> chord([])
580
+ ;
581
+
582
+ pitches
583
+ : pitch -> [$1]
584
+ | pitches pitch -> [...$1, $2]
585
+ | '.' pitch -> [$2]
586
+ | pitches '.' pitch -> [...$1, $3]
587
+ | '[' pitch -> [$2]
588
+ | pitches '[' pitch -> [...$1, $3]
589
+ | pitches '.' '[' pitch -> [...$1, $4]
590
+ | '.' '[' pitch -> [$3]
591
+ | pitches ')' -> $1
592
+ ;
593
+
594
+ quotes
595
+ : sub_quotes
596
+ | sup_quotes
597
+ ;
598
+
599
+ sub_quotes
600
+ : ',' -> -1
601
+ | sub_quotes ',' -> $1 - 1
602
+ ;
603
+
604
+ sup_quotes
605
+ : "'" -> 1
606
+ | sup_quotes "'" -> $1 + 1
607
+ ;
608
+
609
+ accidentals
610
+ : '^' -> 1
611
+ | '_' -> -1
612
+ | '=' -> 0
613
+ | '^' '^' -> 2
614
+ | '_' '_' -> -2
615
+ | '=' '=' -> 0
616
+ ;
617
+
618
+ pitch
619
+ : acc_pitch
620
+ | acc_pitch '-' { $1.tie = true; $$ = $1; }
621
+ | rest_phonet -> pitch(null, $1, 0)
622
+ ;
623
+
624
+ acc_pitch
625
+ : phonet -> pitch(null, $1, 0)
626
+ | phonet quotes -> pitch(null, $1, $2)
627
+ | accidentals phonet -> pitch($1, $2, 0)
628
+ | accidentals phonet quotes -> pitch($1, $2, $3)
629
+ ;
630
+
631
+ phonet
632
+ : upper_phonet
633
+ | lower_phonet
634
+ ;
635
+
636
+ rest_phonet
637
+ : z
638
+ | Z
639
+ | x
640
+ ;
641
+
642
+ event
643
+ : pitch_or_chord -> ({event: event($1)})
644
+ | pitch_or_chord duration -> ({event: event($1, $2)})
645
+ ;
646
+
647
+ events
648
+ : event -> [$1]
649
+ | events event -> [...$1, $2]
650
+ ;
651
+
652
+ grace_events
653
+ : '{' grace_music '}' -> grace($2)
654
+ | '{' '/' grace_music '}' -> grace($3, true)
655
+ ;
656
+
657
+ grace_music
658
+ : event -> [$1]
659
+ | expressive_mark event -> [$1, $2]
660
+ | grace_music event -> [...$1, $2]
661
+ | grace_music expressive_mark -> [...$1, $2]
662
+ | grace_music control -> [...$1, $2]
663
+ | control event -> [$1, $2]
664
+ ;
665
+
666
+ duration
667
+ : number '/' number -> frac(Number($1), Number($3))
668
+ | '/' number -> frac(1, Number($2))
669
+ | number -> frac(Number($1))
670
+ | '/' -> frac(1, 2)
671
+ ;
672
+
673
+ broken_rhythm
674
+ : broken_right -> ({broken: $1})
675
+ | broken_left -> ({broken: $1})
676
+ ;
677
+
678
+ broken_right
679
+ : '>' -> 1
680
+ | broken_right '>' -> $1 + 1
681
+ ;
682
+
683
+ broken_left
684
+ : '<' -> -1
685
+ | broken_left '<' -> $1 - 1
686
+ ;
687
+
688
+ triplet
689
+ : '(' number ':' number ':' number -> ({triplet: $2, multiplier: $4, n: $6})
690
+ | '(' number ':' number -> ({triplet: $2, multiplier: $4})
691
+ | '(' number -> ({triplet: $2})
692
+ ;