devalang_core/core/parser/handler/
dot.rs1use devalang_types::{Duration, Value};
2
3use crate::core::{
4 lexer::token::TokenKind,
5 parser::{
6 driver::parser::Parser,
7 statement::{Statement, StatementKind},
8 },
9};
10
11pub fn parse_dot_token(
12 parser: &mut Parser,
13 _global_store: &mut crate::core::store::global::GlobalStore,
14) -> Statement {
15 parser.advance(); let logger = devalang_utils::logger::Logger::new();
17 use devalang_utils::logger::LogLevel;
18 let Some(dot_token) = parser.previous_clone() else {
19 return Statement::unknown();
20 };
21
22 let mut parts = Vec::new();
24 let current_line = dot_token.line;
25
26 while let Some(token) = parser.peek_clone() {
27 if token.line != current_line {
29 break;
30 }
31 match token.kind {
32 TokenKind::Identifier | TokenKind::Number => {
33 parts.push(token.lexeme.clone());
34 parser.advance();
35 if let Some(next) = parser.peek_clone() {
37 if next.line != current_line || next.kind != TokenKind::Dot {
38 break;
39 }
40 } else {
41 break;
42 }
43 }
44 TokenKind::Dot => {
45 parser.advance();
46 }
47 TokenKind::Newline | TokenKind::EOF | TokenKind::Indent | TokenKind::Dedent => {
48 break; }
50 _ => {
51 break;
52 }
53 }
54 }
55
56 let entity = if !parts.is_empty() {
58 parts.join(".") } else {
60 logger.log_message(
61 LogLevel::Warning,
62 &format!("Empty entity after '.' at line {}", dot_token.line),
63 );
64 String::new()
65 };
66
67 let mut duration = Duration::Auto;
69 let mut value = Value::Null;
70
71 if let Some(token) = parser.peek_clone() {
72 if token.line == current_line {
74 match token.kind {
75 TokenKind::Number => {
76 let numerator = token.lexeme.clone();
77 parser.advance();
78 if let Some(peek) = parser.peek_clone() {
79 if peek.line == current_line {
80 if let Some(TokenKind::Slash) = parser.peek_kind() {
81 parser.advance();
82 if let Some(denominator_token) = parser.peek_clone() {
83 if denominator_token.line == current_line
84 && denominator_token.kind == TokenKind::Number
85 {
86 let denominator = denominator_token.lexeme.clone();
87 parser.advance();
88 duration = Duration::Beat(format!(
89 "{}/{}",
90 numerator, denominator
91 ));
92 }
93 }
94 } else {
95 duration = parse_duration(numerator);
96 }
97 } else {
98 duration = parse_duration(numerator);
99 }
100 } else {
101 duration = parse_duration(numerator);
102 }
103 if let Some(next) = parser.peek_clone() {
104 if next.line == current_line && next.kind == TokenKind::LBrace {
105 value = parser.parse_map_value().unwrap_or(Value::Null);
106 }
107 }
108 }
109 TokenKind::Identifier => {
110 let id = token.lexeme.clone();
111 parser.advance();
112 duration = parse_duration(id);
113 if let Some(next) = parser.peek_clone() {
114 if next.line == current_line && next.kind == TokenKind::LBrace {
115 value = parser.parse_map_value().unwrap_or(Value::Null);
116 }
117 }
118 }
119 TokenKind::LBrace => {
120 value = parser.parse_map_value().unwrap_or(Value::Null);
121 }
122 _ => {}
123 }
124 }
125 }
126
127 Statement {
128 kind: StatementKind::Trigger {
129 entity,
130 duration,
131 effects: Some(value.clone()),
132 },
133 value: Value::Null,
134 indent: dot_token.indent,
135 line: dot_token.line,
136 column: dot_token.column,
137 }
138}
139
140fn parse_duration(s: String) -> Duration {
141 if s == "auto" {
142 Duration::Auto
143 } else if let Ok(num) = s.parse::<f32>() {
144 Duration::Number(num)
145 } else {
146 Duration::Identifier(s)
147 }
148}