1use crate::Span;
2use crate::source::SourceText;
3use crate::syntax::tune_classify::{classify_lines, tokenize_surface};
4
5#[derive(Debug, Clone, PartialEq, Eq, Default)]
6pub struct SurfaceMap {
7 pub line_map: LineMap,
8 pub tokens: Vec<SurfaceToken>,
9}
10
11impl SurfaceMap {
12 pub fn tokens_of_kind(&self, kind: SurfaceKind) -> impl Iterator<Item = &SurfaceToken> {
13 self.tokens.iter().filter(move |token| token.kind == kind)
14 }
15}
16
17#[derive(Debug, Clone, PartialEq, Eq, Default)]
18pub struct LineMap {
19 pub lines: Vec<ClassifiedLine>,
20 pub blocks: Vec<SourceBlock>,
21 pub tunes: Vec<TuneBlock>,
22 pub continuation_edges: Vec<ContinuationEdge>,
23 pub non_note_items: Vec<NonNoteItem>,
24}
25
26impl LineMap {
27 pub fn lines_of_kind(&self, kind: LineKind) -> impl Iterator<Item = &ClassifiedLine> {
28 self.lines.iter().filter(move |line| line.kind == kind)
29 }
30
31 pub fn blocks_of_kind(&self, kind: SourceBlockKind) -> impl Iterator<Item = &SourceBlock> {
32 self.blocks.iter().filter(move |block| block.kind == kind)
33 }
34
35 pub fn music_lines(&self) -> impl Iterator<Item = &ClassifiedLine> {
36 self.lines_of_kind(LineKind::MusicCode)
37 }
38}
39
40#[derive(Debug, Clone, PartialEq, Eq)]
41pub struct ClassifiedLine {
42 pub index: usize,
43 pub kind: LineKind,
44 pub context: LineContext,
45 pub span: Span,
46 pub text_span: Span,
47 pub content_span: Span,
48 pub marker_span: Option<Span>,
49 pub field: Option<FieldHeader>,
50 pub trailing_comment: Option<Span>,
51 pub score_line_break: ScoreLineBreak,
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum LineKind {
56 VersionLine,
57 EmptyLine,
58 Comment,
59 StylesheetDirective,
60 InformationField,
61 FieldContinuation,
62 MusicCode,
63 FreeText,
64 TypesetTextDirective,
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub enum LineContext {
69 Preamble,
70 FileHeader,
71 BetweenBlocks,
72 FreeText,
73 TypesetText,
74 TuneHeader { tune_index: usize },
75 TuneBody { tune_index: usize },
76 TuneTerminator { tune_index: usize },
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub struct FieldHeader {
81 pub code: char,
82 pub marker_span: Span,
83 pub value_span: Span,
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq)]
87pub enum ScoreLineBreak {
88 NotApplicable,
89 Physical,
90 Suppressed { marker_span: Span },
91}
92
93#[derive(Debug, Clone, PartialEq, Eq)]
94pub struct SourceBlock {
95 pub kind: SourceBlockKind,
96 pub span: Span,
97 pub line_start: usize,
98 pub line_end: usize,
99 pub tune_index: Option<usize>,
100}
101
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103pub enum SourceBlockKind {
104 FileHeader,
105 Tune,
106 FreeText,
107 TypesetText,
108}
109
110#[derive(Debug, Clone, PartialEq, Eq)]
111pub struct TuneBlock {
112 pub index: usize,
113 pub span: Span,
114 pub header_span: Span,
115 pub body_span: Span,
116 pub line_start: usize,
117 pub line_end: usize,
118 pub header_line_start: usize,
119 pub header_line_end: usize,
120 pub body_line_start: usize,
121 pub body_line_end: usize,
122 pub terminator_line: Option<usize>,
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
126pub struct ContinuationEdge {
127 pub kind: ContinuationKind,
128 pub from_line: usize,
129 pub to_line: usize,
130 pub span: Span,
131 pub marker_span: Span,
132}
133
134#[derive(Debug, Clone, Copy, PartialEq, Eq)]
135pub enum ContinuationKind {
136 FieldContinuation,
137 MusicBackslash,
138}
139
140#[derive(Debug, Clone, Copy, PartialEq, Eq)]
141pub struct NonNoteItem {
142 pub kind: NonNoteKind,
143 pub line_index: usize,
144 pub span: Span,
145}
146
147#[derive(Debug, Clone, Copy, PartialEq, Eq)]
148pub enum NonNoteKind {
149 VersionLine,
150 EmptyLine,
151 Comment,
152 InlineComment,
153 StylesheetDirective,
154 InformationField,
155 FieldContinuation,
156 FreeText,
157 TypesetTextDirective,
158}
159
160#[derive(Debug, Clone, Copy, PartialEq, Eq)]
161pub struct SurfaceToken {
162 pub kind: SurfaceKind,
163 pub span: Span,
164}
165
166#[derive(Debug, Clone, Copy, PartialEq, Eq)]
167pub enum SurfaceKind {
168 Field,
169 FieldContinuation,
170 Comment,
171 Directive,
172 FreeText,
173 Barline,
174 Note,
175 Rest,
176 Other,
177}
178
179pub fn analyze(source: &str) -> SurfaceMap {
180 analyze_source(&SourceText::new(source))
181}
182
183pub fn analyze_source(source: &SourceText) -> SurfaceMap {
184 let line_map = classify_lines(source);
185 let tokens = tokenize_surface(source, &line_map);
186
187 SurfaceMap { line_map, tokens }
188}
189
190#[cfg(test)]
191#[path = "tune_tests.rs"]
192mod tests;