1use crate::diagnostic::Span;
5use crate::model::{Accidental, BarlineKind, Fraction, RestVisibility};
6use crate::syntax::field::{
7 InlineFieldSyntax, MalformedSyntax, MusicFieldLine, PreservedDirectiveSyntax,
8 ScoreDirectiveSyntax, UnsupportedSyntax,
9};
10use crate::syntax::lyric::{LyricLineSyntax, SymbolLineSyntax};
11
12#[derive(Debug, Clone, PartialEq, Eq, Default)]
13pub struct ParsedMusicDocument {
14 pub tunes: Vec<ParsedTuneMusic>,
15}
16
17impl ParsedMusicDocument {
18 pub fn tune(&self, tune_index: usize) -> Option<&ParsedTuneMusic> {
19 self.tunes.iter().find(|tune| tune.tune_index == tune_index)
20 }
21}
22
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct ParsedTuneMusic {
25 pub tune_index: usize,
26 pub span: Span,
27 pub lines: Vec<MusicLine>,
28 pub body_fields: Vec<MusicFieldLine>,
29 pub lyric_lines: Vec<LyricLineSyntax>,
30 pub symbol_lines: Vec<SymbolLineSyntax>,
31 pub score_directives: Vec<ScoreDirectiveSyntax>,
32 pub preserved_directives: Vec<PreservedDirectiveSyntax>,
33}
34
35#[derive(Debug, Clone, PartialEq, Eq)]
36pub struct MusicLine {
37 pub line_index: usize,
38 pub span: Span,
39 pub code_span: Span,
40 pub tokens: Vec<MusicToken>,
41 pub items: Vec<MusicItem>,
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub struct MusicToken {
46 pub kind: MusicTokenKind,
47 pub span: Span,
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51pub enum MusicTokenKind {
52 Whitespace,
53 Accidental,
54 Pitch,
55 OctaveMark,
56 Length,
57 Rest,
58 MultiMeasureRest,
59 Spacer,
60 Chord,
61 GraceGroup,
62 ChordSymbol,
63 Annotation,
64 Decoration,
65 Tuplet,
66 Slur,
67 Tie,
68 BrokenRhythm,
69 Overlay,
70 RepeatEnding,
71 Barline,
72 InlineField,
73 Unsupported,
74 Malformed,
75 Comment,
76 ScoreLineBreak,
77}
78
79#[derive(Debug, Clone, PartialEq, Eq)]
80#[allow(clippy::large_enum_variant)]
81pub enum MusicItem {
82 Note(NoteSyntax),
83 Rest(RestSyntax),
84 MultiMeasureRest(MultiMeasureRestSyntax),
85 Spacer(SpacerSyntax),
86 Chord(ChordSyntax),
87 GraceGroup(GraceGroupSyntax),
88 ChordSymbol(QuotedTextSyntax),
89 Annotation(QuotedTextSyntax),
90 Decoration(DecorationSyntax),
91 Tuplet(TupletSyntax),
92 Slur(SlurSyntax),
93 Tie(TieSyntax),
94 BrokenRhythm(BrokenRhythmSyntax),
95 Overlay(OverlaySyntax),
96 VariantEnding(VariantEndingSyntax),
97 Barline(BarlineSyntax),
98 InlineField(InlineFieldSyntax),
99 Unsupported(UnsupportedSyntax),
100 Malformed(MalformedSyntax),
101}
102
103impl MusicItem {
104 pub fn span(&self) -> Span {
105 match self {
106 Self::Note(item) => item.span,
107 Self::Rest(item) => item.span,
108 Self::MultiMeasureRest(item) => item.span,
109 Self::Spacer(item) => item.span,
110 Self::Chord(item) => item.span,
111 Self::GraceGroup(item) => item.span,
112 Self::ChordSymbol(item) | Self::Annotation(item) => item.span,
113 Self::Decoration(item) => item.span,
114 Self::Tuplet(item) => item.span,
115 Self::Slur(item) => item.span,
116 Self::Tie(item) => item.span,
117 Self::BrokenRhythm(item) => item.span,
118 Self::Overlay(item) => item.span,
119 Self::VariantEnding(item) => item.span,
120 Self::Barline(item) => item.span,
121 Self::InlineField(item) => item.span,
122 Self::Unsupported(item) => item.span,
123 Self::Malformed(item) => item.span,
124 }
125 }
126}
127
128#[derive(Debug, Clone, PartialEq, Eq)]
129pub struct NoteSyntax {
130 pub span: Span,
131 pub attachments: AttachmentBundle,
132 pub accidental: Option<AccidentalSyntax>,
133 pub pitch: PitchSyntax,
134 pub octave_marks: Vec<OctaveMarkSyntax>,
135 pub length: Option<LengthSyntax>,
136}
137
138#[derive(Debug, Clone, PartialEq, Eq, Default)]
139pub struct AttachmentBundle {
140 pub grace_groups: Vec<GraceGroupSyntax>,
141 pub chord_symbols: Vec<QuotedTextSyntax>,
142 pub annotations: Vec<QuotedTextSyntax>,
143 pub decorations: Vec<DecorationSyntax>,
144}
145
146impl AttachmentBundle {
147 pub fn is_empty(&self) -> bool {
148 self.grace_groups.is_empty()
149 && self.chord_symbols.is_empty()
150 && self.annotations.is_empty()
151 && self.decorations.is_empty()
152 }
153
154 pub(crate) fn span_start(&self) -> Option<usize> {
155 self.grace_groups
156 .iter()
157 .map(|item| item.span.start)
158 .chain(self.chord_symbols.iter().map(|item| item.span.start))
159 .chain(self.annotations.iter().map(|item| item.span.start))
160 .chain(self.decorations.iter().map(|item| item.span.start))
161 .min()
162 }
163
164 pub(crate) fn push_quoted_text(&mut self, text: QuotedTextSyntax) {
165 match text.kind {
166 QuotedTextKind::ChordSymbol => self.chord_symbols.push(text),
167 QuotedTextKind::Annotation(_) => self.annotations.push(text),
168 }
169 }
170
171 pub(crate) fn extend(&mut self, other: AttachmentBundle) {
177 self.grace_groups.extend(other.grace_groups);
178 self.chord_symbols.extend(other.chord_symbols);
179 self.annotations.extend(other.annotations);
180 self.decorations.extend(other.decorations);
181 }
182}
183
184#[derive(Debug, Clone, Copy, PartialEq, Eq)]
185pub struct PitchSyntax {
186 pub step: char,
187 pub span: Span,
188}
189
190#[derive(Debug, Clone, Copy, PartialEq, Eq)]
191pub struct AccidentalSyntax {
192 pub sign: Accidental,
193 pub span: Span,
194}
195
196#[derive(Debug, Clone, Copy, PartialEq, Eq)]
197pub struct OctaveMarkSyntax {
198 pub mark: OctaveMark,
199 pub span: Span,
200}
201
202#[derive(Debug, Clone, Copy, PartialEq, Eq)]
203pub enum OctaveMark {
204 Lower,
205 Raise,
206}
207
208#[derive(Debug, Clone, PartialEq, Eq)]
209pub struct LengthSyntax {
210 pub span: Span,
211 pub raw: String,
212 pub numerator: Option<SpannedNumber>,
213 pub slash_count: u8,
214 pub denominator: Option<SpannedNumber>,
215 pub multiplier: Fraction,
216}
217
218#[derive(Debug, Clone, Copy, PartialEq, Eq)]
219pub struct SpannedNumber {
220 pub value: u32,
221 pub span: Span,
222}
223
224#[derive(Debug, Clone, PartialEq, Eq)]
225pub struct RestSyntax {
226 pub span: Span,
227 pub attachments: AttachmentBundle,
228 pub visibility: RestVisibility,
229 pub marker_span: Span,
230 pub length: Option<LengthSyntax>,
231}
232
233#[derive(Debug, Clone, PartialEq, Eq)]
234pub struct MultiMeasureRestSyntax {
235 pub span: Span,
236 pub visibility: RestVisibility,
237 pub marker_span: Span,
238 pub count: Option<SpannedNumber>,
239}
240
241#[derive(Debug, Clone, Copy, PartialEq, Eq)]
242pub struct SpacerSyntax {
243 pub span: Span,
244}
245
246#[derive(Debug, Clone, PartialEq, Eq)]
247pub struct ChordSyntax {
248 pub span: Span,
249 pub attachments: AttachmentBundle,
250 pub open_span: Span,
251 pub close_span: Option<Span>,
252 pub members: Vec<ChordMemberSyntax>,
253 pub length: Option<LengthSyntax>,
254}
255
256#[derive(Debug, Clone, PartialEq, Eq)]
257pub struct ChordMemberSyntax {
258 pub span: Span,
259 pub note: NoteSyntax,
260 pub tie: Option<TieSyntax>,
263 pub slur_starts: Vec<SlurSyntax>,
267 pub slur_ends: Vec<SlurSyntax>,
270}
271
272#[derive(Debug, Clone, PartialEq, Eq)]
273pub struct GraceGroupSyntax {
274 pub span: Span,
275 pub slash_span: Option<Span>,
276 pub elements: Vec<GraceElementSyntax>,
277}
278
279#[derive(Debug, Clone, PartialEq, Eq)]
280pub enum GraceElementSyntax {
281 Note(NoteSyntax),
282 Chord(ChordSyntax),
283 Rest(RestSyntax),
284 Slur(SlurSyntax),
285 Malformed(MalformedSyntax),
286}
287
288#[derive(Debug, Clone, PartialEq, Eq)]
289pub struct QuotedTextSyntax {
290 pub span: Span,
291 pub content_span: Span,
292 pub text: String,
293 pub kind: QuotedTextKind,
294}
295
296#[derive(Debug, Clone, Copy, PartialEq, Eq)]
297pub enum QuotedTextKind {
298 ChordSymbol,
299 Annotation(AnnotationPlacement),
300}
301
302#[derive(Debug, Clone, Copy, PartialEq, Eq)]
303pub enum AnnotationPlacement {
304 Above,
305 Below,
306 Left,
307 Right,
308 Free,
309}
310
311#[derive(Debug, Clone, PartialEq, Eq)]
312pub struct DecorationSyntax {
313 pub span: Span,
314 pub name_span: Span,
315 pub name: String,
316 pub kind: DecorationKind,
317}
318
319#[derive(Debug, Clone, Copy, PartialEq, Eq)]
320pub enum DecorationKind {
321 Named,
322 LegacyNamed,
323 Shorthand,
324 UserDefined,
325}
326
327#[derive(Debug, Clone, PartialEq, Eq)]
328pub struct TupletSyntax {
329 pub span: Span,
330 pub p: SpannedNumber,
331 pub q: Option<SpannedNumber>,
332 pub r: Option<SpannedNumber>,
333}
334
335impl TupletSyntax {
336 pub(crate) fn r_value(&self) -> u32 {
337 self.r.map(|r| r.value).unwrap_or(self.p.value)
338 }
339}
340
341#[derive(Debug, Clone, Copy, PartialEq, Eq)]
342pub struct SlurSyntax {
343 pub span: Span,
344 pub dotted: bool,
345 pub direction: SlurDirection,
346}
347
348#[derive(Debug, Clone, Copy, PartialEq, Eq)]
349pub enum SlurDirection {
350 Start,
351 End,
352}
353
354#[derive(Debug, Clone, Copy, PartialEq, Eq)]
355pub struct TieSyntax {
356 pub span: Span,
357 pub dotted: bool,
358}
359
360#[derive(Debug, Clone, Copy, PartialEq, Eq)]
361pub struct BrokenRhythmSyntax {
362 pub span: Span,
363 pub direction: BrokenRhythmDirection,
364 pub count: u8,
365}
366
367#[derive(Debug, Clone, Copy, PartialEq, Eq)]
368pub struct OverlaySyntax {
369 pub span: Span,
370}
371
372#[derive(Debug, Clone, Copy, PartialEq, Eq)]
373pub enum BrokenRhythmDirection {
374 LeftShorter,
375 RightShorter,
376}
377
378#[derive(Debug, Clone, PartialEq, Eq)]
379pub struct VariantEndingSyntax {
380 pub span: Span,
381 pub shorthand: bool,
382 pub endings: Vec<VariantEndingPart>,
383}
384
385#[derive(Debug, Clone, PartialEq, Eq)]
386pub enum VariantEndingPart {
387 Single(SpannedNumber),
388 Range {
389 start: SpannedNumber,
390 end: SpannedNumber,
391 span: Span,
392 },
393 Text {
394 text: String,
395 span: Span,
396 },
397}
398
399#[derive(Debug, Clone, PartialEq, Eq)]
400pub struct BarlineSyntax {
401 pub span: Span,
402 pub kind: BarlineKind,
403 pub dotted: bool,
404 pub raw: String,
405}