Skip to main content

carmen_lang/parser/
mod.rs

1//! Parser for the Carmen language.
2//!
3//! This module provides a recursive descent parser that transforms a stream of tokens
4//! from the lexer into an Abstract Syntax Tree (AST). The parser handles:
5//!
6//! - Musical expressions (notes, chords, rhythms)
7//! - Control flow (if/else, for loops, while loops)
8//! - Function and variable declarations
9//! - Music-specific constructs (parts, staves, timelines, scores)
10//! - Comments and their positioning context
11//!
12//! The parser uses precedence climbing for binary operators and includes special
13//! handling for musical notation where context determines token interpretation.
14
15use crate::ast::*;
16use crate::errors::{AddSpan, CarmenError, ErrorSource, Result, Span};
17use crate::lexer::{Token, TokenType};
18
19/// Categorizes tokens for identifier validation during parsing.
20///
21/// Used to provide better error messages when reserved words are used
22/// as identifiers in contexts where they shouldn't be.
23#[derive(Debug, PartialEq)]
24enum TokenCategory {
25    /// Token can be used as an identifier
26    ValidIdentifier,
27    /// Token is reserved (pitch, duration, keyword, etc.)
28    Reserved(&'static str), // contains type of reserved symbol
29    /// Token cannot be used as an identifier
30    Invalid,
31}
32
33fn capitalize_first(s: &str) -> String {
34    let mut chars = s.chars();
35    match chars.next() {
36        None => String::new(),
37        Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
38    }
39}
40
41/// Creates plural form of symbol type names for error messages.
42fn pluralize_symbol_type(symbol_type: &str) -> String {
43    match symbol_type {
44        "pitch" => "Pitches".to_string(),
45        "duration" => "Durations".to_string(),
46        "dynamic" => "Dynamics".to_string(),
47        "attribute" => "Attributes".to_string(),
48        "keyword" => "Keywords".to_string(),
49        _ => format!("{}s", capitalize_first(symbol_type)),
50    }
51}
52
53/// Context for comment collection to determine appropriate positioning.
54///
55/// Comments in Carmen can be positioned relative to code elements for better
56/// formatting and semantic meaning. This enum tracks the context to determine
57/// where comments should be associated.
58#[derive(Debug, Clone)]
59enum CommentContext {
60    /// Comments that appear before the given span
61    Leading(Span),
62    /// Comments that appear after the given span
63    Trailing(Span),
64    /// Comments between list/sequence elements at the given index
65    Between(usize),
66    /// Comments not associated with any specific code element
67    Standalone,
68}
69
70/// Recursive descent parser for the Carmen language.
71///
72/// The parser consumes a stream of tokens and produces an Abstract Syntax Tree (AST).
73/// It handles operator precedence, musical notation context, and comment positioning.
74pub struct Parser {
75    /// The complete list of tokens to parse
76    tokens: Vec<Token>,
77    /// Current position in the token stream
78    current: usize,
79    /// Collected comments with positioning information
80    comments: Vec<CommentInfo>,
81}
82
83impl Parser {
84    /// Creates a new parser with the given token stream.
85    pub fn new(tokens: Vec<Token>) -> Self {
86        Self {
87            tokens,
88            current: 0,
89            comments: Vec::new(),
90        }
91    }
92
93    /// Collects comments from the current position based on the given context.
94    ///
95    /// This method determines how comments should be positioned relative to code
96    /// elements and stores them for later use in formatting or semantic analysis.
97    fn collect_comments(&mut self, context: CommentContext) -> Vec<CommentInfo> {
98        let mut collected = Vec::new();
99
100        while !self.is_at_end() {
101            if let TokenType::Comment(content) = &self.current_token().token_type {
102                let comment_span = self.current_token().span;
103                let mut comment = CommentInfo::new(content.clone(), comment_span);
104
105                comment.position = match context {
106                    CommentContext::Leading(ref target_span) => {
107                        if comment.is_same_line(target_span) {
108                            CommentPosition::Trailing
109                        } else {
110                            CommentPosition::Leading
111                        }
112                    }
113                    CommentContext::Trailing(ref target_span) => {
114                        comment.associated_span = Some(*target_span);
115                        if comment.is_same_line(target_span) {
116                            CommentPosition::Trailing
117                        } else {
118                            CommentPosition::Standalone
119                        }
120                    }
121                    CommentContext::Between(index) => CommentPosition::Between(index),
122                    CommentContext::Standalone => CommentPosition::Standalone,
123                };
124
125                collected.push(comment.clone());
126                self.comments.push(comment);
127                self.advance();
128            } else {
129                break;
130            }
131        }
132        collected
133    }
134
135    /// Skips comments while parsing and collects them for later use.
136    ///
137    /// Comments are preserved for formatting tools and semantic analysis.
138    fn skip_comments(&mut self) {
139        self.collect_comments(CommentContext::Standalone);
140    }
141
142    fn collect_leading_comments(&mut self, target_span: &Span) -> Vec<CommentInfo> {
143        self.collect_comments(CommentContext::Leading(*target_span))
144    }
145
146    fn collect_trailing_comments(&mut self, target_span: &Span) -> Vec<CommentInfo> {
147        self.collect_comments(CommentContext::Trailing(*target_span))
148    }
149
150    fn collect_between_comments(&mut self, element_index: usize) -> Vec<CommentInfo> {
151        self.collect_comments(CommentContext::Between(element_index))
152    }
153
154    fn current_token(&self) -> &Token {
155        &self.tokens[self.current]
156    }
157
158    fn previous_token(&self) -> &Token {
159        &self.tokens[self.current - 1]
160    }
161
162    fn is_at_end(&self) -> bool {
163        matches!(self.current_token().token_type, TokenType::Eof)
164    }
165
166    fn advance(&mut self) -> &Token {
167        if !self.is_at_end() {
168            self.current += 1;
169        }
170        self.previous_token()
171    }
172
173    fn check(&self, token_type: &TokenType) -> bool {
174        if self.is_at_end() {
175            false
176        } else {
177            std::mem::discriminant(&self.current_token().token_type)
178                == std::mem::discriminant(token_type)
179        }
180    }
181
182    fn match_token(&mut self, token_type: &TokenType) -> bool {
183        if self.check(token_type) {
184            self.advance();
185            true
186        } else {
187            false
188        }
189    }
190
191    /// Categorizes a token to determine if it can be used as an identifier.
192    ///
193    /// This is used, e.g., to provide helpful error messages when reserved words
194    /// are used in identifier contexts.
195    fn categorize_token(&self, token_type: &TokenType) -> TokenCategory {
196        match token_type {
197            TokenType::Identifier(_) => TokenCategory::ValidIdentifier,
198            TokenType::Pitch(_) => TokenCategory::Reserved("pitch"),
199            TokenType::Duration(_) => TokenCategory::Reserved("duration"),
200            TokenType::Dynamic(_) => TokenCategory::Reserved("dynamic"),
201            TokenType::Attribute(_) => TokenCategory::Reserved("attribute"),
202            TokenType::Let
203            | TokenType::Def
204            | TokenType::If
205            | TokenType::Else
206            | TokenType::For
207            | TokenType::While
208            | TokenType::In
209            | TokenType::Return
210            | TokenType::Part
211            | TokenType::Staff
212            | TokenType::Timeline
213            | TokenType::And
214            | TokenType::Or
215            | TokenType::Not
216            | TokenType::True
217            | TokenType::False => TokenCategory::Reserved("keyword"),
218            _ => TokenCategory::Invalid,
219        }
220    }
221
222    /// Extracts the string representation of a token for error messages.
223    fn extract_token_value(&self, token_type: &TokenType) -> String {
224        match token_type {
225            TokenType::Pitch(s)
226            | TokenType::Duration(s)
227            | TokenType::Dynamic(s)
228            | TokenType::Attribute(s)
229            | TokenType::Identifier(s) => s.clone(),
230            TokenType::Let => "let".to_string(),
231            TokenType::Def => "def".to_string(),
232            TokenType::If => "if".to_string(),
233            TokenType::Else => "else".to_string(),
234            TokenType::For => "for".to_string(),
235            TokenType::While => "while".to_string(),
236            TokenType::In => "in".to_string(),
237            TokenType::Return => "return".to_string(),
238            TokenType::Part => "part".to_string(),
239            TokenType::Staff => "staff".to_string(),
240            TokenType::Timeline => "timeline".to_string(),
241            TokenType::And => "and".to_string(),
242            TokenType::Or => "or".to_string(),
243            TokenType::Not => "not".to_string(),
244            TokenType::True => "true".to_string(),
245            TokenType::False => "false".to_string(),
246            _ => "unknown".to_string(),
247        }
248    }
249
250    /// Expects an identifier token and provides context-aware error messages.
251    ///
252    /// This method validates that the current token can be used as an identifier
253    /// in the given context and provides helpful error messages when reserved
254    /// words are used inappropriately.
255    fn expect_identifier(&self, context: &str) -> Result<String> {
256        let token = self.current_token();
257
258        match self.categorize_token(&token.token_type) {
259            TokenCategory::ValidIdentifier => {
260                if let TokenType::Identifier(name) = &token.token_type {
261                    Ok(name.clone())
262                } else {
263                    unreachable!("ValidIdentifier should only be returned for Identifier tokens")
264                }
265            }
266            TokenCategory::Reserved(symbol_type) => {
267                let symbol_value = self.extract_token_value(&token.token_type);
268                Err(ErrorSource::Parsing(format!(
269                    "Cannot use {} '{}' as {}. {} are reserved.",
270                    symbol_type,
271                    symbol_value,
272                    context,
273                    pluralize_symbol_type(symbol_type)
274                ))
275                .with_span(token.span))
276            }
277            TokenCategory::Invalid => Err(self.error(&format!("Expected {context}"))),
278        }
279    }
280
281    fn error(&self, message: &str) -> CarmenError {
282        ErrorSource::Parsing(message.to_string()).with_span(self.current_token().span)
283    }
284
285    fn consume(&mut self, token_type: TokenType, message: &str) -> Result<()> {
286        if self.check(&token_type) {
287            self.advance();
288            Ok(())
289        } else {
290            Err(self.error(message))
291        }
292    }
293
294    /// Parses an identifier with context-aware interpretation for musical notation.
295    ///
296    /// In musical contexts, some identifiers may be interpreted as musical elements
297    /// (pitches, dynamics, attributes) rather than variable names. This method
298    /// handles that context-sensitive parsing.
299    fn parse_identifier_in_musical_context(&mut self, context: &str) -> Result<SpannedExpression> {
300        let token = self.current_token().clone();
301
302        if let TokenType::Identifier(name) = &token.token_type {
303            // In musical context, single letters that could be dynamics should be treated as dynamics
304            if context == "dynamic_or_attribute" && Literal::is_dynamic(name) {
305                self.advance();
306                return Ok(Spanned {
307                    node: Expression::Literal(Literal::Dynamic(name.clone())),
308                    span: token.span,
309                });
310            }
311
312            // Check if it could be an attribute
313            if context == "dynamic_or_attribute" && Literal::is_attribute(name) {
314                self.advance();
315                return Ok(Spanned {
316                    node: Expression::Literal(Literal::Attribute(name.clone())),
317                    span: token.span,
318                });
319            }
320
321            // Check if it could be a pitch (for musical contexts)
322            if context == "pitch" && self.could_be_pitch_identifier(name) {
323                self.advance();
324                if let Some(pitch) = Literal::parse_pitch(name) {
325                    return Ok(Spanned {
326                        node: Expression::Literal(pitch),
327                        span: token.span,
328                    });
329                }
330            }
331        }
332
333        // If we reach here and context is "dynamic_or_attribute", this identifier
334        // is not a dynamic or attribute, so we should not consume it
335        if context == "dynamic_or_attribute" {
336            return Err(
337                ErrorSource::Parsing("Expected dynamic or attribute".to_string())
338                    .with_span(token.span),
339            );
340        }
341
342        // Fall back to regular identifier
343        let name = match &token.token_type {
344            TokenType::Identifier(name) => name.clone(),
345            _ => return Err(self.error(&format!("Expected identifier in {context} context"))),
346        };
347
348        self.advance();
349        Ok(Spanned {
350            node: Expression::Identifier(name),
351            span: token.span,
352        })
353    }
354
355    /// Determines if an identifier could represent a pitch in musical notation.
356    ///
357    /// Only considers it a potential pitch if it would actually parse as a valid
358    /// pitch, preventing identifiers like "ad", "add", etc. from being misinterpreted.
359    fn could_be_pitch_identifier(&self, name: &str) -> bool {
360        Literal::parse_pitch(name).is_some()
361    }
362
363    /// Determines if the current token sequence could start a musical event.
364    ///
365    /// Musical events follow the pattern: duration + pitch(es) + optional modifiers.
366    /// This method uses lookahead to distinguish musical events from other expressions.
367    fn could_be_musical_event(&self) -> bool {
368        match &self.current_token().token_type {
369            TokenType::Duration(_) => {
370                // Check if next token could be a pitch/chord/rest
371                if self.current + 1 < self.tokens.len() {
372                    match &self.tokens[self.current + 1].token_type {
373                        TokenType::Pitch(_) |
374                        TokenType::Identifier(_) | // identifier resolving to pitch
375                        TokenType::LeftParen | // chord tuple
376                        TokenType::LeftBracket | // list of pitches
377                        TokenType::Tilde => true, // rest
378                        _ => false,
379                    }
380                } else {
381                    false
382                }
383            }
384            TokenType::Number(n) if *n == 1.0 => {
385                // Special case: "1" could be duration "1/1" if followed by musical content
386                if self.current + 1 < self.tokens.len() {
387                    match &self.tokens[self.current + 1].token_type {
388                        TokenType::Pitch(_)
389                        | TokenType::Tilde
390                        | TokenType::LeftParen
391                        | TokenType::LeftBracket => true,
392                        TokenType::Identifier(name) => {
393                            // Check if identifier could be a pitch
394                            self.could_be_pitch_identifier(name)
395                        }
396                        _ => false,
397                    }
398                } else {
399                    false
400                }
401            }
402            _ => false,
403        }
404    }
405
406    fn grouping_or_tuple(&mut self) -> Result<SpannedExpression> {
407        let start = self.current_token().span.start;
408        self.consume(TokenType::LeftParen, "Expected '('")?;
409
410        self.skip_comments();
411
412        if self.check(&TokenType::RightParen) {
413            self.advance();
414            return Ok(Spanned {
415                node: Expression::Tuple {
416                    elements: Vec::new(),
417                },
418                span: Span {
419                    start,
420                    end: self.previous_token().span.end,
421                },
422            });
423        }
424
425        let mut elements = vec![self.expression()?];
426        self.collect_leading_comments(&elements[0].span);
427
428        if self.match_token(&TokenType::Comma) {
429            self.collect_between_comments(0);
430            // This is a tuple
431            while !self.check(&TokenType::RightParen) && !self.is_at_end() {
432                let element = self.expression()?;
433                self.collect_trailing_comments(&element.span);
434                elements.push(element);
435
436                if !self.match_token(&TokenType::Comma) {
437                    break;
438                }
439
440                self.collect_between_comments(elements.len() - 1);
441
442                // Allow trailing comma
443                if self.check(&TokenType::RightParen) {
444                    break;
445                }
446            }
447
448            self.skip_comments();
449            self.consume(TokenType::RightParen, "Expected ')' after tuple elements")?;
450            Ok(Spanned {
451                node: Expression::Tuple { elements },
452                span: Span {
453                    start,
454                    end: self.previous_token().span.end,
455                },
456            })
457        } else {
458            self.skip_comments();
459            // This is a grouping expression
460            self.consume(TokenType::RightParen, "Expected ')' after expression")?;
461            Ok(elements.into_iter().next().unwrap())
462        }
463    }
464
465    fn list(&mut self) -> Result<SpannedExpression> {
466        let start = self.current_token().span.start;
467        self.consume(TokenType::LeftBracket, "Expected '['")?;
468
469        let mut elements = Vec::new();
470
471        self.skip_comments(); // collect standalone comments after opening bracket
472
473        if !self.check(&TokenType::RightBracket) {
474            loop {
475                let element = self.expression()?;
476                self.collect_trailing_comments(&element.span);
477                elements.push(element);
478                if !self.match_token(&TokenType::Comma) {
479                    break;
480                }
481                // Collect comments between elements
482                self.collect_between_comments(elements.len() - 1);
483
484                // Allow trailing comma
485                if self.check(&TokenType::RightBracket) {
486                    break;
487                }
488            }
489        }
490
491        self.skip_comments(); // Collect comments before closing bracket
492        self.consume(TokenType::RightBracket, "Expected ']' after list elements")?;
493
494        Ok(Spanned {
495            node: Expression::List { elements },
496            span: Span {
497                start,
498                end: self.previous_token().span.end,
499            },
500        })
501    }
502
503    /// Checks if an expression represents a pitch class number (0-11).
504    ///
505    /// Used to determine if a set of numbers should be interpreted as a pitch class set.
506    fn is_pitch_class_number(expr: &SpannedExpression) -> bool {
507        match expr.node {
508            Expression::Literal(Literal::Number(value)) => {
509                (0.0..=11.0).contains(&value) && value.fract() == 0.0
510            }
511            _ => false,
512        }
513    }
514
515    fn extract_pitch_class_number(expr: &SpannedExpression) -> Option<u8> {
516        match expr.node {
517            Expression::Literal(Literal::Number(value)) => {
518                if (0.0..=11.0).contains(&value) && value.fract() == 0.0 {
519                    Some(value as u8)
520                } else {
521                    None
522                }
523            }
524            _ => None,
525        }
526    }
527
528    /// Checks if all elements in a collection are pitch class numbers.
529    ///
530    /// Used to determine if a set should be interpreted as a pitch class set.
531    fn is_all_pitch_class_numbers(elements: &[SpannedExpression]) -> bool {
532        !elements.is_empty() && elements.iter().all(Self::is_pitch_class_number)
533    }
534
535    /// Parses a brace-delimited construct that could be a set, pitch class set, or block.
536    ///
537    /// Uses lookahead to determine whether the content represents statements (block)
538    /// or expressions (set). If all expressions are pitch class numbers (0-11),
539    /// creates a specialized pitch class set.
540    fn set_or_block(&mut self) -> Result<SpannedExpression> {
541        let start = self.current_token().span.start;
542        self.consume(TokenType::LeftBrace, "Expected '{'")?;
543
544        self.skip_comments();
545
546        if self.check(&TokenType::RightBrace) {
547            self.advance();
548            return Ok(Spanned {
549                node: Expression::Set {
550                    elements: Vec::new(),
551                },
552                span: Span {
553                    start,
554                    end: self.previous_token().span.end,
555                },
556            });
557        }
558
559        // Try to parse as statements (block)
560        let checkpoint = self.current;
561
562        // If we can parse a statement, it's a block
563        if self.declaration().is_ok() {
564            self.current = checkpoint; // Reset position
565            let mut statements = Vec::new();
566
567            while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
568                self.skip_comments(); // Skip leading comments
569                if self.check(&TokenType::RightBrace) {
570                    break;
571                }
572
573                let stmt = self.declaration()?;
574                self.collect_trailing_comments(&stmt.span); // Collect trailing comments
575                statements.push(stmt);
576            }
577
578            self.skip_comments(); // skip any remaining comment before closing brace
579            self.consume(TokenType::RightBrace, "Expected '}' after block")?;
580
581            Ok(Spanned {
582                node: Expression::Block { statements },
583                span: Span {
584                    start,
585                    end: self.previous_token().span.end,
586                },
587            })
588        } else {
589            // Parse as set
590            self.current = checkpoint;
591            let mut elements = Vec::new();
592
593            self.skip_comments(); // Skip leading comments
594            if !self.check(&TokenType::RightBrace) {
595                loop {
596                    let expr = self.expression()?;
597                    self.collect_trailing_comments(&expr.span);
598                    elements.push(expr);
599
600                    if !self.match_token(&TokenType::Comma) {
601                        break;
602                    }
603
604                    self.collect_between_comments(elements.len() - 1);
605
606                    // Allow trailing comma
607                    if self.check(&TokenType::RightBrace) {
608                        break;
609                    }
610                }
611            }
612
613            self.skip_comments();
614            self.consume(TokenType::RightBrace, "Expected '}' after set elements")?;
615            if Self::is_all_pitch_class_numbers(&elements) {
616                let classes: Vec<u8> = elements
617                    .iter()
618                    .filter_map(Self::extract_pitch_class_number)
619                    .collect();
620
621                Ok(Spanned {
622                    node: Expression::PitchClassSet { classes },
623                    span: Span {
624                        start,
625                        end: self.previous_token().span.end,
626                    },
627                })
628            } else {
629                Ok(Spanned {
630                    node: Expression::Set { elements },
631                    span: Span {
632                        start,
633                        end: self.previous_token().span.end,
634                    },
635                })
636            }
637        }
638    }
639
640    fn if_expression(&mut self) -> Result<SpannedExpression> {
641        let start = self.current_token().span.start;
642        self.consume(TokenType::If, "Expected 'if'")?;
643
644        self.consume(TokenType::LeftParen, "Expected '(' after 'if'")?;
645        let condition = self.expression()?;
646        self.consume(TokenType::RightParen, "Expected ')' after if condition")?;
647
648        let then_branch = self.expression()?;
649
650        let else_branch = if self.match_token(&TokenType::Else) {
651            Some(Box::new(self.expression()?))
652        } else {
653            None
654        };
655
656        let end = if let Some(ref else_expr) = else_branch {
657            else_expr.span.end
658        } else {
659            then_branch.span.end
660        };
661
662        Ok(Spanned {
663            node: Expression::If {
664                condition: Box::new(condition),
665                then_branch: Box::new(then_branch),
666                else_branch,
667            },
668            span: Span { start, end },
669        })
670    }
671
672    fn for_expression(&mut self) -> Result<SpannedExpression> {
673        let start = self.current_token().span.start;
674        self.consume(TokenType::For, "Expected 'for'")?;
675
676        self.consume(TokenType::LeftParen, "Expected '(' after 'for'")?;
677
678        let variable = self.expect_identifier("a loop variable")?;
679        self.advance();
680
681        self.consume(TokenType::In, "Expected 'in' after for variable")?;
682        let iterable = self.expression()?;
683        self.consume(TokenType::RightParen, "Expected ')' after for clause")?;
684
685        let body = self.expression()?;
686
687        let end = body.span.end;
688
689        Ok(Spanned {
690            node: Expression::For {
691                variable,
692                iterable: Box::new(iterable),
693                body: Box::new(body),
694            },
695            span: Span { start, end },
696        })
697    }
698
699    fn while_expression(&mut self) -> Result<SpannedExpression> {
700        let start = self.current_token().span.start;
701        self.consume(TokenType::While, "Expected 'while'")?;
702
703        self.consume(TokenType::LeftParen, "Expected '(' after 'while'")?;
704        let condition = self.expression()?;
705        self.consume(TokenType::RightParen, "Expected ')' after while condition")?;
706
707        let body = self.expression()?;
708
709        Ok(Spanned {
710            node: Expression::While {
711                condition: Box::new(condition),
712                body: Box::new(body.clone()),
713            },
714            span: Span {
715                start,
716                end: body.span.end,
717            },
718        })
719    }
720
721    fn part_expression(&mut self) -> Result<SpannedExpression> {
722        let start = self.current_token().span.start;
723        self.consume(TokenType::Part, "Expected 'part'")?;
724
725        let name = if matches!(self.current_token().token_type, TokenType::String(_)) {
726            Some(Box::new(self.expression()?))
727        } else {
728            None
729        };
730
731        let body = self.expression()?;
732
733        Ok(Spanned {
734            node: Expression::Part {
735                name,
736                body: Box::new(body.clone()),
737            },
738            span: Span {
739                start,
740                end: body.span.end,
741            },
742        })
743    }
744
745    fn staff_expression(&mut self) -> Result<SpannedExpression> {
746        let start = self.current_token().span.start;
747        self.consume(TokenType::Staff, "Expected 'staff'")?;
748
749        let number = self.expression()?;
750        let body = self.expression()?;
751
752        Ok(Spanned {
753            node: Expression::Staff {
754                number: Box::new(number),
755                body: Box::new(body.clone()),
756            },
757            span: Span {
758                start,
759                end: body.span.end,
760            },
761        })
762    }
763
764    fn timeline_expression(&mut self) -> Result<SpannedExpression> {
765        let start = self.current_token().span.start;
766        self.consume(TokenType::Timeline, "Expected 'timeline'")?;
767
768        let body = self.expression()?;
769
770        Ok(Spanned {
771            node: Expression::Timeline {
772                body: Box::new(body.clone()),
773            },
774            span: Span {
775                start,
776                end: body.span.end,
777            },
778        })
779    }
780
781    fn movement_expression(&mut self) -> Result<SpannedExpression> {
782        let start = self.current_token().span.start;
783        self.consume(TokenType::Movement, "Expected 'movement'")?;
784
785        let name = if matches!(self.current_token().token_type, TokenType::String(_)) {
786            Some(Box::new(self.expression()?))
787        } else {
788            None
789        };
790
791        let body = self.expression()?;
792
793        Ok(Spanned {
794            node: Expression::Movement {
795                name,
796                body: Box::new(body.clone()),
797            },
798            span: Span {
799                start,
800                end: body.span.end,
801            },
802        })
803    }
804
805    fn score_expression(&mut self) -> Result<SpannedExpression> {
806        let start = self.current_token().span.start;
807        self.consume(TokenType::Score, "Expected 'score'")?;
808
809        let name = if matches!(self.current_token().token_type, TokenType::String(_)) {
810            Some(Box::new(self.expression()?))
811        } else {
812            None
813        };
814
815        let body = self.expression()?;
816
817        let end = body.span.end;
818
819        Ok(Spanned {
820            node: Expression::Score {
821                name,
822                body: Box::new(body),
823            },
824            span: Span { start, end },
825        })
826    }
827
828    /// Parses a musical event: duration + pitch(es) + optional dynamics/attributes.
829    fn musical_event(&mut self) -> Result<SpannedExpression> {
830        let start_pos = self.current_token().span.start;
831
832        // Parse duration
833        let duration = match &self.current_token().token_type {
834            TokenType::Duration(d) => {
835                let d = d.clone();
836                let span = self.current_token().span;
837                self.advance();
838                if let Some(duration) = Literal::parse_duration(&d) {
839                    Spanned {
840                        node: Expression::Literal(duration),
841                        span,
842                    }
843                } else {
844                    return Err(
845                        ErrorSource::Parsing(format!("Invalid duration: {d}")).with_span(span)
846                    );
847                }
848            }
849            TokenType::Number(n) if *n == 1.0 => {
850                // Treat "1" as whole note duration in musical context
851                let span = self.current_token().span;
852                self.advance();
853
854                Spanned {
855                    node: Expression::Literal(Literal::Duration {
856                        numerator: 1,
857                        denominator: 1,
858                        dots: 0,
859                    }),
860                    span,
861                }
862            }
863            _ => return Err(self.error("Expected duration at start of musical event")),
864        };
865
866        let pitches = self.expression()?; // parse pitche(s)
867
868        let mut dynamic = None;
869        let mut attributes = Vec::new();
870
871        while !self.check(&TokenType::Semicolon) && !self.is_at_end() {
872            // Check what kind of token we have and handle accordingly
873            match &self.current_token().token_type {
874                TokenType::Dynamic(_) => {
875                    if dynamic.is_some() {
876                        return Err(self.error("Multiple dynamics not allowed"));
877                    }
878                    dynamic = Some(Box::new(self.expression()?));
879                }
880                TokenType::Attribute(_) => {
881                    attributes.push(self.expression()?);
882                }
883                TokenType::Pitch(text) => {
884                    let text = text.clone();
885
886                    // In musical event context, prioritize dynamic/attribute interpretation
887                    if Literal::is_dynamic(&text) {
888                        if dynamic.is_some() {
889                            return Err(self.error("Multiple dynamics not allowed"));
890                        }
891                        let span = self.current_token().span;
892                        self.advance();
893                        dynamic = Some(Box::new(Spanned {
894                            node: Expression::Literal(Literal::Dynamic(text)),
895                            span,
896                        }));
897                    } else if Literal::is_attribute(&text) {
898                        let span = self.current_token().span;
899                        self.advance();
900                        attributes.push(Spanned {
901                            node: Expression::Literal(Literal::Attribute(text)),
902                            span,
903                        });
904                    } else {
905                        break; // Not a dynamic or attribute, stop parsing musical modifiers
906                    }
907                }
908                TokenType::Identifier(_) => {
909                    // Use the existing method to handle context-aware parsing
910                    match self.parse_identifier_in_musical_context("dynamic_or_attribute") {
911                        Ok(expr) => {
912                            match expr.node {
913                                Expression::Literal(Literal::Dynamic { .. }) => {
914                                    if dynamic.is_some() {
915                                        return Err(self.error("Multiple dynamics not allowed"));
916                                    }
917                                    dynamic = Some(Box::new(expr));
918                                }
919                                Expression::Literal(Literal::Attribute { .. }) => {
920                                    attributes.push(expr);
921                                }
922                                _ => unreachable!(), // parse_identifier_in_musical_context should only return dynamics/attributes in this context
923                            }
924                        }
925                        Err(_) => {
926                            // Not a dynamic or attribute, stop parsing musical modifiers
927                            break;
928                        }
929                    }
930                }
931                _ => break,
932            }
933        }
934
935        let end = if !attributes.is_empty() {
936            attributes.last().unwrap().span.end
937        } else if let Some(ref dyn_expr) = dynamic {
938            dyn_expr.span.end
939        } else {
940            pitches.span.end
941        };
942
943        Ok(Spanned {
944            node: Expression::MusicalEvent {
945                duration: Box::new(duration),
946                pitches: Box::new(pitches),
947                dynamic,
948                attributes,
949            },
950            span: Span {
951                start: start_pos,
952                end,
953            },
954        })
955    }
956
957    fn primary(&mut self) -> Result<SpannedExpression> {
958        // check if musical event
959        if self.could_be_musical_event() {
960            return self.musical_event();
961        }
962
963        let token = self.current_token().clone();
964
965        match &token.token_type {
966            TokenType::True => {
967                self.advance();
968                Ok(Spanned {
969                    node: Expression::Literal(Literal::Boolean(true)),
970                    span: token.span,
971                })
972            }
973            TokenType::False => {
974                self.advance();
975                Ok(Spanned {
976                    node: Expression::Literal(Literal::Boolean(false)),
977                    span: token.span,
978                })
979            }
980            TokenType::Number(n) => {
981                self.advance();
982                Ok(Spanned {
983                    node: Expression::Literal(Literal::Number(*n)),
984                    span: token.span,
985                })
986            }
987            TokenType::String(s) => {
988                self.advance();
989                Ok(Spanned {
990                    node: Expression::Literal(Literal::String(s.to_owned())),
991                    span: token.span,
992                })
993            }
994            TokenType::Pitch(p) => {
995                self.advance();
996                if let Some(pitch) = Literal::parse_pitch(p) {
997                    Ok(Spanned {
998                        node: Expression::Literal(pitch),
999                        span: token.span,
1000                    })
1001                } else {
1002                    Err(ErrorSource::Parsing(format!("Invalid pitch: {p}")).with_span(token.span))
1003                }
1004            }
1005            TokenType::Duration(d) => {
1006                self.advance();
1007                if let Some(duration) = Literal::parse_duration(d) {
1008                    Ok(Spanned {
1009                        node: Expression::Literal(duration),
1010                        span: token.span,
1011                    })
1012                } else {
1013                    Err(ErrorSource::Parsing(format!("Invalid duration: {d}"))
1014                        .with_span(token.span))
1015                }
1016            }
1017            TokenType::Dynamic(d) => {
1018                self.advance();
1019                Ok(Spanned {
1020                    node: Expression::Literal(Literal::Dynamic(d.to_owned())),
1021                    span: token.span,
1022                })
1023            }
1024            TokenType::Attribute(a) => {
1025                self.advance();
1026                Ok(Spanned {
1027                    node: Expression::Literal(Literal::Attribute(a.to_owned())),
1028                    span: token.span,
1029                })
1030            }
1031            TokenType::Tilde => {
1032                self.advance();
1033                Ok(Spanned {
1034                    node: Expression::Literal(Literal::Rest { duration: None }),
1035                    span: token.span,
1036                })
1037            }
1038            TokenType::Identifier(name) => {
1039                if self.could_be_pitch_identifier(name) {
1040                    self.advance();
1041                    if let Some(pitch) = Literal::parse_pitch(name) {
1042                        Ok(Spanned {
1043                            node: Expression::Literal(pitch),
1044                            span: token.span,
1045                        })
1046                    } else {
1047                        Ok(Spanned {
1048                            node: Expression::Identifier(name.to_owned()),
1049                            span: token.span,
1050                        })
1051                    }
1052                } else {
1053                    self.advance();
1054                    Ok(Spanned {
1055                        node: Expression::Identifier(name.to_owned()),
1056                        span: token.span,
1057                    })
1058                }
1059            }
1060            TokenType::LeftParen => self.grouping_or_tuple(),
1061            TokenType::LeftBracket => self.list(),
1062            TokenType::LeftBrace => self.set_or_block(),
1063            TokenType::If => self.if_expression(),
1064            TokenType::For => self.for_expression(),
1065            TokenType::While => self.while_expression(),
1066            TokenType::Part => self.part_expression(),
1067            TokenType::Staff => self.staff_expression(),
1068            TokenType::Timeline => self.timeline_expression(),
1069            TokenType::Movement => self.movement_expression(),
1070            TokenType::Score => self.score_expression(),
1071            _ => Err(self.error("Unexpected token")),
1072        }
1073    }
1074
1075    fn call(&mut self) -> Result<SpannedExpression> {
1076        let mut expr = self.primary()?;
1077
1078        while self.match_token(&TokenType::LeftParen) {
1079            let (args, kwargs) = self.parse_arguments()?;
1080            self.consume(TokenType::RightParen, "Expected ')' after arguments")?;
1081            let end = self.previous_token().span.end;
1082            expr = Spanned {
1083                node: Expression::Call {
1084                    callee: Box::new(expr.clone()),
1085                    args,
1086                    kwargs,
1087                },
1088                span: Span {
1089                    start: expr.span.start,
1090                    end,
1091                },
1092            };
1093        }
1094
1095        Ok(expr)
1096    }
1097
1098    #[allow(clippy::type_complexity)]
1099    fn parse_arguments(
1100        &mut self,
1101    ) -> Result<(Vec<SpannedExpression>, Vec<(String, SpannedExpression)>)> {
1102        let mut args = Vec::new();
1103        let mut kwargs = Vec::new();
1104        if !self.check(&TokenType::RightParen) {
1105            loop {
1106                // Check if this is a named argument (identifier = expression)
1107                if let TokenType::Identifier(name) = &self.current_token().token_type {
1108                    // Look ahead to see if next token is =
1109                    if self.current + 1 < self.tokens.len()
1110                        && matches!(self.tokens[self.current + 1].token_type, TokenType::Assign)
1111                    {
1112                        let name = name.clone();
1113                        self.advance(); // consume identifier
1114                        self.advance(); // consume =
1115                        let value = self.expression()?;
1116                        kwargs.push((name, value));
1117                    } else {
1118                        // Regular positional argument
1119                        args.push(self.expression()?);
1120                    }
1121                } else {
1122                    // Regular positional argument
1123                    args.push(self.expression()?);
1124                }
1125
1126                if !self.match_token(&TokenType::Comma) {
1127                    break;
1128                }
1129            }
1130        }
1131        Ok((args, kwargs))
1132    }
1133
1134    fn match_unary_op(&mut self) -> Option<UnaryOp> {
1135        match self.current_token().token_type {
1136            TokenType::Minus => {
1137                self.advance();
1138                Some(UnaryOp::Minus)
1139            }
1140            TokenType::Not => {
1141                self.advance();
1142                Some(UnaryOp::Not)
1143            }
1144            _ => None,
1145        }
1146    }
1147    fn unary(&mut self) -> Result<SpannedExpression> {
1148        if let Some(op) = self.match_unary_op() {
1149            let start = self.previous_token().span.start;
1150            let operand = self.unary()?;
1151            let span = Span::new(start, operand.span.end);
1152            return Ok(Spanned {
1153                node: Expression::Unary {
1154                    operator: op,
1155                    operand: Box::new(operand),
1156                },
1157                span,
1158            });
1159        }
1160        self.call()
1161    }
1162
1163    /// Parses left-associative binary operators at a given precedence level.
1164    ///
1165    /// This is a helper method for implementing precedence climbing in the
1166    /// expression parser. It handles operators like +, -, *, /, etc.
1167    fn parse_binary_left_associative<F>(
1168        &mut self,
1169        mut next_precedence: F,
1170        operators: &[TokenType],
1171    ) -> Result<SpannedExpression>
1172    where
1173        F: FnMut(&mut Self) -> Result<SpannedExpression>,
1174    {
1175        let mut expr = next_precedence(self)?;
1176
1177        while operators.iter().any(|op| self.check(op)) {
1178            let op_token_type = &self.current_token().token_type;
1179            let binary_op = match op_token_type {
1180                TokenType::Multiply => BinaryOp::Multiply,
1181                TokenType::Divide => BinaryOp::Divide,
1182                TokenType::Modulo => BinaryOp::Modulo,
1183                TokenType::Plus => BinaryOp::Add,
1184                TokenType::Minus => BinaryOp::Subtract,
1185                TokenType::Greater => BinaryOp::Greater,
1186                TokenType::GreaterEqual => BinaryOp::GreaterEqual,
1187                TokenType::Less => BinaryOp::Less,
1188                TokenType::LessEqual => BinaryOp::LessEqual,
1189                TokenType::Equal => BinaryOp::Equal,
1190                TokenType::NotEqual => BinaryOp::NotEqual,
1191                TokenType::And => BinaryOp::And,
1192                TokenType::Or => BinaryOp::Or,
1193                _ => unreachable!(),
1194            };
1195
1196            self.advance();
1197            let right = next_precedence(self)?;
1198            let span = Span::new(expr.span.start, right.span.end);
1199
1200            expr = Spanned {
1201                node: Expression::Binary {
1202                    left: Box::new(expr),
1203                    operator: binary_op,
1204                    right: Box::new(right),
1205                },
1206                span,
1207            };
1208        }
1209
1210        Ok(expr)
1211    }
1212
1213    fn factor(&mut self) -> Result<SpannedExpression> {
1214        self.parse_binary_left_associative(
1215            Self::unary,
1216            &[TokenType::Multiply, TokenType::Divide, TokenType::Modulo],
1217        )
1218    }
1219
1220    fn term(&mut self) -> Result<SpannedExpression> {
1221        self.parse_binary_left_associative(Self::factor, &[TokenType::Plus, TokenType::Minus])
1222    }
1223
1224    fn comparison(&mut self) -> Result<SpannedExpression> {
1225        self.parse_binary_left_associative(
1226            Self::term,
1227            &[
1228                TokenType::Greater,
1229                TokenType::GreaterEqual,
1230                TokenType::Less,
1231                TokenType::LessEqual,
1232            ],
1233        )
1234    }
1235
1236    fn equality(&mut self) -> Result<SpannedExpression> {
1237        self.parse_binary_left_associative(
1238            Self::comparison,
1239            &[TokenType::Equal, TokenType::NotEqual],
1240        )
1241    }
1242
1243    fn logical_and(&mut self) -> Result<SpannedExpression> {
1244        self.parse_binary_left_associative(Self::equality, &[TokenType::And])
1245    }
1246
1247    fn logical_or(&mut self) -> Result<SpannedExpression> {
1248        self.parse_binary_left_associative(Self::logical_and, &[TokenType::Or])
1249    }
1250
1251    fn pipe(&mut self) -> Result<SpannedExpression> {
1252        let mut expr = self.logical_or()?;
1253
1254        while self.match_token(&TokenType::Pipe) {
1255            let right = self.logical_or()?;
1256            let span = Span::new(expr.span.start, right.span.end);
1257            expr = Spanned {
1258                node: Expression::Pipe {
1259                    left: Box::new(expr),
1260                    right: Box::new(right),
1261                },
1262                span,
1263            };
1264        }
1265
1266        Ok(expr)
1267    }
1268
1269    fn expression(&mut self) -> Result<SpannedExpression> {
1270        self.pipe()
1271    }
1272
1273    fn variable_declaration(&mut self) -> Result<SpannedStatement> {
1274        let start = self.current_token().span.start;
1275        self.consume(TokenType::Let, "Expected 'let'")?;
1276
1277        let name = self.expect_identifier("a variable name")?;
1278        self.advance();
1279
1280        self.consume(TokenType::Assign, "Expected '=' after variable name")?;
1281        let value = self.expression()?;
1282        self.consume(
1283            TokenType::Semicolon,
1284            "Expected ';' after variable declaration",
1285        )?;
1286
1287        Ok(Spanned {
1288            node: Statement::VariableDeclaration { name, value },
1289            span: Span {
1290                start,
1291                end: self.previous_token().span.end,
1292            },
1293        })
1294    }
1295
1296    fn function_declaration(&mut self) -> Result<SpannedStatement> {
1297        let start = self.current_token().span.start;
1298        self.consume(TokenType::Def, "Expected 'def'")?;
1299
1300        let name = self.expect_identifier("a function name")?;
1301        self.advance();
1302
1303        self.consume(TokenType::LeftParen, "Expected '(' after function name")?;
1304
1305        let mut params = Vec::new();
1306        if !self.check(&TokenType::RightParen) {
1307            loop {
1308                let param = self.expect_identifier("a parameter name")?;
1309                params.push(param);
1310                self.advance();
1311
1312                if !self.match_token(&TokenType::Comma) {
1313                    break;
1314                }
1315
1316                if self.check(&TokenType::RightParen) {
1317                    break;
1318                }
1319            }
1320        }
1321
1322        self.consume(TokenType::RightParen, "Expected ')' after parameters")?;
1323        self.consume(TokenType::LeftBrace, "Expected '{' before function body")?;
1324
1325        let mut body = Vec::new();
1326        while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
1327            self.skip_comments();
1328            if self.check(&TokenType::RightBrace) {
1329                break;
1330            }
1331            let decl = self.declaration()?;
1332            self.collect_trailing_comments(&decl.span);
1333            body.push(decl);
1334        }
1335
1336        self.consume(TokenType::RightBrace, "Expected '}' after function body")?;
1337        self.consume(
1338            TokenType::Semicolon,
1339            "Expected ';' after function declaration",
1340        )?;
1341
1342        Ok(Spanned {
1343            node: Statement::FunctionDeclaration { name, params, body },
1344            span: Span {
1345                start,
1346                end: self.previous_token().span.end,
1347            },
1348        })
1349    }
1350
1351    /// Parses metadata declarations
1352    ///
1353    /// Metadata provides information about the musical composition that affects
1354    /// interpretation but isn't part of the musical content itself.
1355    fn metadata_declaration(&mut self) -> Result<SpannedStatement> {
1356        let start = self.current_token().span.start;
1357        self.consume(TokenType::At, "Expected '@'")?;
1358
1359        let key = match &self.current_token().token_type {
1360            TokenType::Identifier(key) => {
1361                let key = key.clone();
1362                self.advance();
1363                key
1364            }
1365            _ => return Err(self.error("Expected metadata key")),
1366        };
1367        // For metadata that commonly takes multiple values, parse them as a tuple
1368        let value = match key.as_str() {
1369            "time_signature" => {
1370                let expr = self.expression()?;
1371                if let Expression::Binary {
1372                    left,
1373                    operator: BinaryOp::Divide,
1374                    right,
1375                } = expr.node
1376                {
1377                    Spanned {
1378                        node: Expression::Tuple {
1379                            elements: vec![*left, *right],
1380                        },
1381                        span: expr.span,
1382                    }
1383                } else if let Expression::Literal(Literal::Duration {
1384                    numerator,
1385                    denominator,
1386                    dots: 0,
1387                }) = expr.node
1388                {
1389                    let num_expr = Spanned {
1390                        node: Expression::Literal(Literal::Number(f64::from(numerator))),
1391                        span: expr.span,
1392                    };
1393                    let den_expr = Spanned {
1394                        node: Expression::Literal(Literal::Number(f64::from(denominator))),
1395                        span: expr.span,
1396                    };
1397                    Spanned {
1398                        node: Expression::Tuple {
1399                            elements: vec![num_expr, den_expr],
1400                        },
1401                        span: expr.span,
1402                    }
1403                } else {
1404                    return Err(
1405                        self.error("Time signature must be in numerator/denominator format.")
1406                    );
1407                }
1408            }
1409            _ => self.expression()?,
1410        };
1411        self.consume(TokenType::Semicolon, "Expected ';' after metadata")?;
1412
1413        Ok(Spanned {
1414            node: Statement::Metadata { key, value },
1415            span: Span {
1416                start,
1417                end: self.previous_token().span.end,
1418            },
1419        })
1420    }
1421    fn return_statement(&mut self) -> Result<SpannedStatement> {
1422        let start = self.current_token().span.start;
1423        self.consume(TokenType::Return, "Expected 'return'")?;
1424
1425        let value = if self.check(&TokenType::Semicolon) {
1426            None
1427        } else {
1428            Some(self.expression()?)
1429        };
1430
1431        self.consume(TokenType::Semicolon, "Expected ';' after return statement")?;
1432
1433        Ok(Spanned {
1434            node: Statement::Return { value },
1435            span: Span {
1436                start,
1437                end: self.previous_token().span.end,
1438            },
1439        })
1440    }
1441
1442    fn statement(&mut self) -> Result<SpannedStatement> {
1443        match &self.current_token().token_type {
1444            TokenType::Return => self.return_statement(),
1445            _ => {
1446                let expr = self.expression()?;
1447                self.consume(TokenType::Semicolon, "Expected ';' after expression")?;
1448                Ok(Spanned {
1449                    node: Statement::Expression(expr.clone()),
1450                    span: expr.span,
1451                })
1452            }
1453        }
1454    }
1455
1456    fn declaration(&mut self) -> Result<SpannedStatement> {
1457        match &self.current_token().token_type {
1458            TokenType::Let => self.variable_declaration(),
1459            TokenType::Def => self.function_declaration(),
1460            TokenType::At => self.metadata_declaration(),
1461            _ => self.statement(),
1462        }
1463    }
1464
1465    /// Parses the entire token stream into a Carmen program.
1466    ///
1467    /// This is the main entry point for parsing. It consumes all tokens
1468    /// and produces a complete AST representing the Carmen program.
1469    ///
1470    /// # Returns
1471    /// A `Program` containing all parsed statements and collected comments.
1472    pub fn parse(mut self) -> Result<Program> {
1473        let start_span = self.current_token().span;
1474        let mut statements = Vec::new();
1475
1476        while !self.is_at_end() {
1477            self.skip_comments();
1478            if self.is_at_end() {
1479                break;
1480            }
1481
1482            let stmt = self.declaration()?;
1483            self.collect_trailing_comments(&stmt.span);
1484            statements.push(stmt);
1485
1486            self.skip_comments();
1487        }
1488
1489        let end_span = if statements.is_empty() {
1490            start_span
1491        } else {
1492            statements.last().unwrap().span
1493        };
1494
1495        Ok(Program {
1496            statements,
1497            comments: self.comments.clone(),
1498            span: Span::new(start_span.start, end_span.end),
1499        })
1500    }
1501}