Skip to main content

croma_core/syntax/
tune.rs

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;