devalang_core/core/parser/handler/
tempo.rs1use crate::core::{
2 lexer::token::TokenKind,
3 parser::{
4 driver::parser::Parser,
5 statement::{Statement, StatementKind},
6 },
7 store::global::GlobalStore,
8};
9use devalang_types::Value;
10
11pub fn parse_tempo_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
12 parser.advance(); let Some(tempo_token) = parser.previous_clone() else {
15 return Statement::unknown();
16 };
17
18 let Some(value_token) = parser.peek_clone() else {
20 return Statement::error_with_pos(
21 tempo_token.indent,
22 tempo_token.line,
23 tempo_token.column,
24 "Expected a number or identifier after 'bpm'".to_string(),
25 );
26 };
27
28 let value = match value_token.kind {
29 TokenKind::Number => {
30 let mut num = value_token.lexeme.clone();
32 parser.advance();
33 if let Some(dot) = parser.peek_clone() {
34 if dot.kind == TokenKind::Dot {
35 if let Some(next) = parser.peek_nth(1).cloned() {
36 if next.kind == TokenKind::Number {
37 parser.advance();
38 parser.advance();
39 num.push('.');
40 num.push_str(&next.lexeme);
41 }
42 }
43 }
44 }
45
46 if let Some(slash) = parser.peek_clone() {
47 if slash.kind == TokenKind::Slash {
48 parser.advance();
49 if let Some(den) = parser.peek_clone() {
50 if den.kind == TokenKind::Number || den.kind == TokenKind::Identifier {
51 let frac = format!("{}/{}", num, den.lexeme);
52 parser.advance();
53 Value::Duration(devalang_types::Duration::Beat(frac))
54 } else {
55 return Statement::error_with_pos(
56 slash.indent,
57 slash.line,
58 slash.column,
59 "Expected denominator after '/' in bpm".to_string(),
60 );
61 }
62 } else {
63 return Statement::error_with_pos(
64 slash.indent,
65 slash.line,
66 slash.column,
67 "Expected denominator after '/' in bpm".to_string(),
68 );
69 }
70 } else {
71 Value::Number(num.parse().unwrap_or(0.0))
72 }
73 } else {
74 Value::Number(num.parse().unwrap_or(0.0))
75 }
76 }
77 TokenKind::Identifier => {
78 parser.advance();
79 Value::Identifier(value_token.lexeme.clone())
80 }
81 TokenKind::String => {
82 parser.advance();
83 Value::String(value_token.lexeme.clone())
84 }
85 _ => {
86 return Statement::error_with_pos(
87 value_token.indent,
88 value_token.line,
89 value_token.column,
90 format!(
91 "Expected a number, string or identifier after 'bpm', got {:?}",
92 value_token.kind
93 ),
94 );
95 }
96 };
97
98 Statement {
99 kind: StatementKind::Tempo,
100 value,
101 indent: tempo_token.indent,
102 line: tempo_token.line,
103 column: tempo_token.column,
104 }
105}