devalang_core/core/parser/handler/
dot.rs1use devalang_types::{Duration, Value};
2
3use crate::core::{
4 lexer::token::TokenKind,
5 parser::{
6 driver::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(LogLevel::Warning, &format!("Empty entity after '.' at line {}", dot_token.line));
61 String::new()
62 };
63
64 let mut duration = Duration::Auto;
66 let mut value = Value::Null;
67
68 if let Some(token) = parser.peek_clone() {
69 if token.line == current_line {
71 match token.kind {
72 TokenKind::Number => {
73 let numerator = token.lexeme.clone();
74 parser.advance();
75 if let Some(peek) = parser.peek_clone() {
76 if peek.line == current_line {
77 if let Some(TokenKind::Slash) = parser.peek_kind() {
78 parser.advance();
79 if let Some(denominator_token) = parser.peek_clone() {
80 if denominator_token.line == current_line
81 && denominator_token.kind == TokenKind::Number
82 {
83 let denominator = denominator_token.lexeme.clone();
84 parser.advance();
85 duration = Duration::Beat(format!(
86 "{}/{}",
87 numerator, denominator
88 ));
89 }
90 }
91 } else {
92 duration = parse_duration(numerator);
93 }
94 } else {
95 duration = parse_duration(numerator);
96 }
97 } else {
98 duration = parse_duration(numerator);
99 }
100 if let Some(next) = parser.peek_clone() {
101 if next.line == current_line && next.kind == TokenKind::LBrace {
102 value = parser.parse_map_value().unwrap_or(Value::Null);
103 }
104 }
105 }
106 TokenKind::Identifier => {
107 let id = token.lexeme.clone();
108 parser.advance();
109 duration = parse_duration(id);
110 if let Some(next) = parser.peek_clone() {
111 if next.line == current_line && next.kind == TokenKind::LBrace {
112 value = parser.parse_map_value().unwrap_or(Value::Null);
113 }
114 }
115 }
116 TokenKind::LBrace => {
117 value = parser.parse_map_value().unwrap_or(Value::Null);
118 }
119 _ => {}
120 }
121 }
122 }
123
124 Statement {
125 kind: StatementKind::Trigger {
126 entity,
127 duration,
128 effects: Some(value.clone()),
129 },
130 value: Value::Null,
131 indent: dot_token.indent,
132 line: dot_token.line,
133 column: dot_token.column,
134 }
135}
136
137fn parse_duration(s: String) -> Duration {
138 if s == "auto" {
139 Duration::Auto
140 } else if let Ok(num) = s.parse::<f32>() {
141 Duration::Number(num)
142 } else {
143 Duration::Identifier(s)
144 }
145}