@devaloop/devalang 0.0.1-alpha.15 → 0.0.1-alpha.16-hotfix.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/.devalang +2 -0
  2. package/.github/workflows/ci.yml +92 -0
  3. package/Cargo.toml +60 -58
  4. package/README.md +1 -1
  5. package/docs/CHANGELOG.md +34 -1
  6. package/docs/CONTRIBUTING.md +101 -1
  7. package/docs/ROADMAP.md +1 -1
  8. package/docs/TODO.md +1 -1
  9. package/examples/automation.deva +1 -3
  10. package/examples/bank.deva +4 -4
  11. package/examples/events.deva +12 -0
  12. package/examples/function.deva +4 -4
  13. package/examples/index.deva +3 -5
  14. package/examples/loop.deva +5 -11
  15. package/examples/pattern.deva +8 -0
  16. package/examples/plugin.deva +12 -11
  17. package/examples/variables.deva +1 -1
  18. package/out-tsc/bin/index.js +51 -7
  19. package/out-tsc/index.js +3 -1
  20. package/out-tsc/scripts/postbuild.js +9 -10
  21. package/out-tsc/scripts/postinstall.js +49 -0
  22. package/package.json +12 -4
  23. package/project-version.json +3 -3
  24. package/rust/cli/bank.rs +462 -455
  25. package/rust/cli/build.rs +252 -199
  26. package/rust/cli/check.rs +221 -180
  27. package/rust/cli/driver.rs +297 -292
  28. package/rust/cli/generator.rs +1 -0
  29. package/rust/cli/init.rs +87 -79
  30. package/rust/cli/install.rs +35 -32
  31. package/rust/cli/login.rs +127 -134
  32. package/rust/cli/mod.rs +13 -11
  33. package/rust/cli/play.rs +1123 -218
  34. package/rust/cli/telemetry.rs +19 -0
  35. package/rust/cli/template.rs +69 -57
  36. package/rust/cli/update.rs +6 -4
  37. package/rust/common/api.rs +5 -5
  38. package/rust/common/mod.rs +3 -3
  39. package/rust/config/driver.rs +118 -94
  40. package/rust/config/loader.rs +165 -156
  41. package/rust/config/mod.rs +4 -2
  42. package/rust/config/settings.rs +91 -0
  43. package/rust/config/stats.rs +257 -0
  44. package/rust/core/audio/engine.rs +696 -659
  45. package/rust/core/audio/evaluator.rs +263 -132
  46. package/rust/core/audio/interpreter/arrow_call.rs +198 -187
  47. package/rust/core/audio/interpreter/call.rs +98 -95
  48. package/rust/core/audio/interpreter/condition.rs +70 -71
  49. package/rust/core/audio/interpreter/driver.rs +487 -231
  50. package/rust/core/audio/interpreter/function.rs +26 -21
  51. package/rust/core/audio/interpreter/let_.rs +38 -26
  52. package/rust/core/audio/interpreter/load.rs +18 -18
  53. package/rust/core/audio/interpreter/loop_.rs +113 -106
  54. package/rust/core/audio/interpreter/mod.rs +14 -14
  55. package/rust/core/audio/interpreter/sleep.rs +27 -28
  56. package/rust/core/audio/interpreter/spawn.rs +105 -102
  57. package/rust/core/audio/interpreter/tempo.rs +19 -16
  58. package/rust/core/audio/interpreter/trigger.rs +239 -210
  59. package/rust/core/audio/loader/mod.rs +1 -1
  60. package/rust/core/audio/loader/trigger.rs +100 -94
  61. package/rust/core/audio/mod.rs +7 -7
  62. package/rust/core/audio/player.rs +64 -64
  63. package/rust/core/audio/renderer.rs +56 -53
  64. package/rust/core/audio/special/easing.rs +189 -120
  65. package/rust/core/audio/special/env.rs +43 -41
  66. package/rust/core/audio/special/math.rs +102 -92
  67. package/rust/core/audio/special/mod.rs +9 -9
  68. package/rust/core/audio/special/modulator.rs +143 -120
  69. package/rust/core/builder/mod.rs +80 -85
  70. package/rust/core/debugger/lexer.rs +27 -27
  71. package/rust/core/debugger/mod.rs +24 -23
  72. package/rust/core/debugger/module.rs +55 -47
  73. package/rust/core/debugger/preprocessor.rs +27 -27
  74. package/rust/core/debugger/store.rs +40 -39
  75. package/rust/core/error/mod.rs +80 -69
  76. package/rust/core/lexer/handler/arrow.rs +82 -82
  77. package/rust/core/lexer/handler/at.rs +21 -21
  78. package/rust/core/lexer/handler/brace.rs +41 -41
  79. package/rust/core/lexer/handler/colon.rs +21 -21
  80. package/rust/core/lexer/handler/comment.rs +30 -30
  81. package/rust/core/lexer/handler/dot.rs +21 -21
  82. package/rust/core/lexer/handler/driver.rs +337 -292
  83. package/rust/core/lexer/handler/identifier.rs +46 -43
  84. package/rust/core/lexer/handler/indent.rs +66 -66
  85. package/rust/core/lexer/handler/mod.rs +16 -16
  86. package/rust/core/lexer/handler/newline.rs +23 -23
  87. package/rust/core/lexer/handler/number.rs +31 -31
  88. package/rust/core/lexer/handler/operator.rs +46 -46
  89. package/rust/core/lexer/handler/parenthesis.rs +41 -41
  90. package/rust/core/lexer/handler/slash.rs +21 -21
  91. package/rust/core/lexer/handler/string.rs +63 -63
  92. package/rust/core/lexer/mod.rs +54 -51
  93. package/rust/core/lexer/token.rs +97 -94
  94. package/rust/core/mod.rs +11 -11
  95. package/rust/core/parser/driver.rs +513 -490
  96. package/rust/core/parser/handler/arrow_call.rs +233 -227
  97. package/rust/core/parser/handler/at.rs +245 -162
  98. package/rust/core/parser/handler/bank.rs +94 -69
  99. package/rust/core/parser/handler/condition.rs +80 -74
  100. package/rust/core/parser/handler/dot.rs +143 -135
  101. package/rust/core/parser/handler/identifier/automate.rs +257 -194
  102. package/rust/core/parser/handler/identifier/call.rs +91 -88
  103. package/rust/core/parser/handler/identifier/emit.rs +66 -0
  104. package/rust/core/parser/handler/identifier/function.rs +100 -91
  105. package/rust/core/parser/handler/identifier/group.rs +85 -75
  106. package/rust/core/parser/handler/identifier/let_.rs +158 -143
  107. package/rust/core/parser/handler/identifier/mod.rs +54 -56
  108. package/rust/core/parser/handler/identifier/on.rs +98 -0
  109. package/rust/core/parser/handler/identifier/print.rs +52 -29
  110. package/rust/core/parser/handler/identifier/sleep.rs +36 -33
  111. package/rust/core/parser/handler/identifier/spawn.rs +91 -88
  112. package/rust/core/parser/handler/identifier/synth.rs +65 -63
  113. package/rust/core/parser/handler/loop_.rs +170 -89
  114. package/rust/core/parser/handler/mod.rs +8 -8
  115. package/rust/core/parser/handler/tempo.rs +53 -47
  116. package/rust/core/parser/mod.rs +4 -4
  117. package/rust/core/parser/statement.rs +142 -113
  118. package/rust/core/plugin/loader.rs +123 -48
  119. package/rust/core/plugin/mod.rs +2 -1
  120. package/rust/core/plugin/runner.rs +296 -0
  121. package/rust/core/preprocessor/loader.rs +515 -326
  122. package/rust/core/preprocessor/mod.rs +4 -4
  123. package/rust/core/preprocessor/module.rs +60 -58
  124. package/rust/core/preprocessor/processor.rs +99 -101
  125. package/rust/core/preprocessor/resolver/bank.rs +51 -48
  126. package/rust/core/preprocessor/resolver/call.rs +100 -101
  127. package/rust/core/preprocessor/resolver/condition.rs +97 -97
  128. package/rust/core/preprocessor/resolver/driver.rs +310 -280
  129. package/rust/core/preprocessor/resolver/function.rs +69 -68
  130. package/rust/core/preprocessor/resolver/group.rs +96 -91
  131. package/rust/core/preprocessor/resolver/let_.rs +32 -28
  132. package/rust/core/preprocessor/resolver/loop_.rs +320 -121
  133. package/rust/core/preprocessor/resolver/mod.rs +15 -15
  134. package/rust/core/preprocessor/resolver/spawn.rs +76 -73
  135. package/rust/core/preprocessor/resolver/synth.rs +56 -50
  136. package/rust/core/preprocessor/resolver/tempo.rs +50 -49
  137. package/rust/core/preprocessor/resolver/trigger.rs +113 -115
  138. package/rust/core/preprocessor/resolver/value.rs +81 -81
  139. package/rust/core/shared/duration.rs +9 -9
  140. package/rust/core/shared/mod.rs +3 -3
  141. package/rust/core/shared/value.rs +35 -32
  142. package/rust/core/store/function.rs +34 -34
  143. package/rust/core/store/global.rs +55 -38
  144. package/rust/core/store/mod.rs +5 -5
  145. package/rust/core/store/variable.rs +37 -34
  146. package/rust/core/utils/mod.rs +2 -2
  147. package/rust/core/utils/path.rs +37 -31
  148. package/rust/core/utils/validation.rs +35 -36
  149. package/rust/installer/addon.rs +84 -80
  150. package/rust/installer/bank.rs +62 -65
  151. package/rust/installer/mod.rs +5 -5
  152. package/rust/installer/plugin.rs +54 -55
  153. package/rust/installer/utils.rs +56 -56
  154. package/rust/lib.rs +156 -164
  155. package/rust/main.rs +250 -144
  156. package/rust/utils/error.rs +200 -51
  157. package/rust/utils/file.rs +38 -35
  158. package/rust/utils/first_usage.rs +76 -0
  159. package/rust/utils/logger.rs +195 -143
  160. package/rust/utils/mod.rs +9 -7
  161. package/rust/utils/signature.rs +19 -17
  162. package/rust/utils/spinner.rs +22 -19
  163. package/rust/utils/telemetry.rs +292 -0
  164. package/rust/utils/watcher.rs +34 -33
  165. package/templates/minimal/README.md +97 -121
  166. package/templates/welcome/README.md +97 -121
  167. package/typescript/bin/index.ts +19 -5
  168. package/typescript/index.ts +3 -1
  169. package/typescript/scripts/postbuild.ts +10 -6
  170. package/typescript/scripts/postinstall.ts +56 -0
  171. package/typescript/scripts/version/bump.ts +0 -1
  172. package/typescript/scripts/version/index.ts +0 -1
  173. package/out-tsc/bin/devalang.exe +0 -0
@@ -1,490 +1,513 @@
1
- use crate::core::{
2
- lexer::token::{ Token, TokenKind },
3
- parser::{
4
- handler::{
5
- arrow_call::parse_arrow_call,
6
- at::parse_at_token,
7
- bank::parse_bank_token,
8
- condition::parse_condition_token,
9
- dot::parse_dot_token,
10
- identifier::{ function::parse_function_token, parse_identifier_token },
11
- loop_::parse_loop_token,
12
- tempo::parse_tempo_token,
13
- },
14
- statement::Statement,
15
- },
16
- shared::value::Value,
17
- store::global::GlobalStore,
18
- };
19
-
20
- #[derive(Debug, Clone, PartialEq)]
21
- pub struct Parser {
22
- pub resolve_modules: bool,
23
- pub tokens: Vec<Token>,
24
- pub token_index: usize,
25
- pub current_module: String,
26
- pub previous: Option<Token>,
27
- }
28
-
29
- impl Parser {
30
- pub fn new() -> Self {
31
- Parser {
32
- resolve_modules: false,
33
- tokens: Vec::new(),
34
- token_index: 0,
35
- current_module: String::new(),
36
- previous: None,
37
- }
38
- }
39
-
40
- pub fn set_current_module(&mut self, module_path: String) {
41
- self.current_module = module_path;
42
- }
43
-
44
- pub fn advance(&mut self) -> Option<&Token> {
45
- if self.is_eof() {
46
- return None;
47
- }
48
-
49
- self.previous = self.tokens.get(self.token_index).cloned();
50
- self.token_index += 1;
51
-
52
- self.tokens.get(self.token_index - 1)
53
- }
54
-
55
- pub fn peek_is(&self, expected: &str) -> bool {
56
- self.peek().map_or(false, |t| t.lexeme == expected)
57
- }
58
-
59
- pub fn peek_nth(&self, n: usize) -> Option<&Token> {
60
- if self.token_index + n < self.tokens.len() {
61
- self.tokens.get(self.token_index + n)
62
- } else {
63
- None
64
- }
65
- }
66
-
67
- pub fn peek_nth_kind(&self, n: usize) -> Option<TokenKind> {
68
- self.peek_nth(n).map(|t| t.kind.clone())
69
- }
70
-
71
- pub fn advance_if(&mut self, kind: TokenKind) -> bool {
72
- if self.match_token(kind) { true } else { false }
73
- }
74
-
75
- pub fn match_token(&mut self, kind: TokenKind) -> bool {
76
- if let Some(tok) = self.peek() {
77
- if tok.kind == kind {
78
- self.advance();
79
- return true;
80
- }
81
- }
82
- false
83
- }
84
-
85
- pub fn previous_clone(&self) -> Option<Token> {
86
- self.previous.clone()
87
- }
88
-
89
- pub fn parse_block(
90
- &self,
91
- tokens: Vec<Token>,
92
- global_store: &mut GlobalStore
93
- ) -> Vec<Statement> {
94
- let mut inner_parser = Parser {
95
- resolve_modules: self.resolve_modules,
96
- tokens,
97
- token_index: 0,
98
- current_module: self.current_module.clone(),
99
- previous: None,
100
- };
101
-
102
- inner_parser.parse_tokens(inner_parser.tokens.clone(), global_store)
103
- }
104
-
105
- pub fn parse_tokens(
106
- &mut self,
107
- tokens: Vec<Token>,
108
- global_store: &mut GlobalStore
109
- ) -> Vec<Statement> {
110
- // Filtrer uniquement les espaces, mais conserver les Newline car
111
- // certaines constructions (ex: print ...) s'appuient sur la fin de ligne.
112
- self.tokens = tokens
113
- .into_iter()
114
- .filter(|t| t.kind != TokenKind::Whitespace)
115
- .collect();
116
- self.token_index = 0;
117
-
118
- let mut statements = Vec::new();
119
-
120
- while !self.is_eof() {
121
- let token = match self.peek() {
122
- Some(t) => t.clone(),
123
- None => {
124
- break;
125
- }
126
- };
127
-
128
- if token.kind == TokenKind::Newline {
129
- self.advance();
130
- continue;
131
- }
132
-
133
- let statement = match &token.kind {
134
- TokenKind::At => parse_at_token(self, global_store),
135
- TokenKind::Identifier => {
136
- if let Some(next) = self.peek_nth(1).cloned() {
137
- if next.kind == TokenKind::Arrow {
138
- parse_arrow_call(self, global_store)
139
- } else {
140
- parse_identifier_token(self, global_store)
141
- }
142
- } else {
143
- parse_identifier_token(self, global_store)
144
- }
145
- }
146
- TokenKind::Dot => parse_dot_token(self, global_store),
147
- TokenKind::Tempo => parse_tempo_token(self, global_store),
148
- TokenKind::Bank => parse_bank_token(self, global_store),
149
- TokenKind::Loop => parse_loop_token(self, global_store),
150
- TokenKind::If => parse_condition_token(self, global_store),
151
- TokenKind::Function => parse_function_token(self, global_store),
152
-
153
- | TokenKind::Else // Ignore else, already handled in `parse_condition_token`
154
- | TokenKind::Comment
155
- | TokenKind::Equals
156
- | TokenKind::Colon
157
- | TokenKind::Number
158
- | TokenKind::String
159
- | TokenKind::LBrace
160
- | TokenKind::RBrace
161
- | TokenKind::Comma
162
- | TokenKind::Dedent
163
- | TokenKind::Indent => {
164
- self.advance();
165
- continue;
166
- }
167
-
168
- TokenKind::EOF => {
169
- break;
170
- }
171
-
172
- _ => {
173
- println!("Unhandled token: {:?}", token);
174
- self.advance();
175
- Statement::unknown()
176
- }
177
- };
178
-
179
- statements.push(statement);
180
- }
181
-
182
- statements
183
- }
184
-
185
- pub fn check_token(&self, kind: TokenKind) -> bool {
186
- self.peek().map_or(false, |t| t.kind == kind)
187
- }
188
-
189
- pub fn peek_kind(&self) -> Option<TokenKind> {
190
- self.peek().map(|t| t.kind.clone())
191
- }
192
-
193
- pub fn parse_map_value(&mut self) -> Option<Value> {
194
- if !self.match_token(TokenKind::LBrace) {
195
- return None;
196
- }
197
-
198
- let mut map = std::collections::HashMap::new();
199
-
200
- while !self.check_token(TokenKind::RBrace) && !self.is_eof() {
201
- // Skip separators and formatting before the key
202
- while
203
- self.check_token(TokenKind::Newline) ||
204
- self.check_token(TokenKind::Whitespace) ||
205
- self.check_token(TokenKind::Indent) ||
206
- self.check_token(TokenKind::Dedent) ||
207
- self.check_token(TokenKind::Comma)
208
- {
209
- self.advance();
210
- }
211
-
212
- // Check if we are at the closing brace of the map
213
- if self.check_token(TokenKind::RBrace) {
214
- break;
215
- }
216
-
217
- let key = if let Some(token) = self.advance() {
218
- match token.kind {
219
- | TokenKind::Whitespace
220
- | TokenKind::Indent
221
- | TokenKind::Dedent
222
- | TokenKind::Newline => {
223
- continue;
224
- }
225
- _ => token.lexeme.clone(),
226
- }
227
- } else {
228
- break;
229
- };
230
-
231
- // Skip newlines and whitespace before colon
232
- while self.check_token(TokenKind::Newline) || self.check_token(TokenKind::Whitespace) {
233
- self.advance();
234
- }
235
-
236
- if !self.match_token(TokenKind::Colon) {
237
- println!("Expected ':' after map key '{}'", key);
238
- break;
239
- }
240
-
241
- // Skip separators and formatting before value
242
- while
243
- self.check_token(TokenKind::Newline) ||
244
- self.check_token(TokenKind::Whitespace) ||
245
- self.check_token(TokenKind::Indent) ||
246
- self.check_token(TokenKind::Dedent) ||
247
- self.check_token(TokenKind::Comma)
248
- {
249
- self.advance();
250
- }
251
-
252
- let value = if let Some(token) = self.peek_clone() {
253
- match token.kind {
254
- TokenKind::String => {
255
- self.advance();
256
- Value::String(token.lexeme.clone())
257
- }
258
- TokenKind::Number => {
259
- let mut number_str = token.lexeme.clone();
260
- self.advance(); // consume the first number
261
-
262
- if let Some(dot_token) = self.peek_clone() {
263
- if dot_token.kind == TokenKind::Dot {
264
- self.advance(); // consume the dot
265
-
266
- if let Some(decimal_token) = self.peek_clone() {
267
- if decimal_token.kind == TokenKind::Number {
268
- self.advance(); // consume the number after the dot
269
- number_str.push('.');
270
- number_str.push_str(&decimal_token.lexeme);
271
- } else {
272
- println!(
273
- "Expected number after dot, got {:?}",
274
- decimal_token
275
- );
276
- return Some(Value::Null);
277
- }
278
- } else {
279
- println!("Expected number after dot, but reached EOF");
280
- return Some(Value::Null);
281
- }
282
- }
283
- }
284
-
285
- Value::Number(number_str.parse::<f32>().unwrap_or(0.0))
286
- }
287
-
288
- TokenKind::Identifier => {
289
- self.advance();
290
- Value::Identifier(token.lexeme.clone())
291
- }
292
- _ => {
293
- println!("Unexpected token in map value: {:?}", token);
294
- Value::Null
295
- }
296
- }
297
- } else {
298
- Value::Null
299
- };
300
-
301
- map.insert(key, value);
302
-
303
- // Optionally skip a trailing comma after the value
304
- while self.check_token(TokenKind::Comma) || self.check_token(TokenKind::Whitespace) || self.check_token(TokenKind::Newline) {
305
- self.advance();
306
- }
307
- }
308
-
309
- if !self.match_token(TokenKind::RBrace) {
310
- println!("Expected '}}' at end of map");
311
- }
312
-
313
- Some(Value::Map(map))
314
- }
315
-
316
- // Parse an array value like [1, 2, 3] or ["a", b]
317
- pub fn parse_array_value(&mut self) -> Option<Value> {
318
- if !self.match_token(TokenKind::LBracket) {
319
- return None;
320
- }
321
-
322
- let mut arr: Vec<Value> = Vec::new();
323
-
324
- while !self.check_token(TokenKind::RBracket) && !self.is_eof() {
325
- // Skip formatting tokens
326
- while
327
- self.check_token(TokenKind::Newline) ||
328
- self.check_token(TokenKind::Whitespace) ||
329
- self.check_token(TokenKind::Indent) ||
330
- self.check_token(TokenKind::Dedent) ||
331
- self.check_token(TokenKind::Comma)
332
- {
333
- self.advance();
334
- }
335
-
336
- if self.check_token(TokenKind::RBracket) {
337
- break;
338
- }
339
-
340
- if let Some(token) = self.peek_clone() {
341
- let value = match token.kind {
342
- TokenKind::String => { self.advance(); Value::String(token.lexeme.clone()) }
343
- TokenKind::Number => {
344
- // Support simple decimals split as number '.' number
345
- let mut number_str = token.lexeme.clone();
346
- self.advance();
347
- if let Some(dot) = self.peek_clone() {
348
- if dot.kind == TokenKind::Dot {
349
- if let Some(next) = self.peek_nth(1).cloned() {
350
- if next.kind == TokenKind::Number {
351
- self.advance(); // consume dot
352
- self.advance(); // consume next number
353
- number_str.push('.');
354
- number_str.push_str(&next.lexeme);
355
- }
356
- }
357
- }
358
- }
359
- Value::Number(number_str.parse::<f32>().unwrap_or(0.0))
360
- }
361
- TokenKind::Identifier => { self.advance(); Value::Identifier(token.lexeme.clone()) }
362
- TokenKind::LBrace => {
363
- // Allow inline maps inside arrays
364
- if let Some(v) = self.parse_map_value() { v } else { Value::Null }
365
- }
366
- TokenKind::LBracket => {
367
- // Nested arrays
368
- if let Some(v) = self.parse_array_value() { v } else { Value::Null }
369
- }
370
- _ => { self.advance(); Value::Null }
371
- };
372
-
373
- // Only push non-null (retain alignment with permissive parsing)
374
- if value != Value::Null { arr.push(value); }
375
-
376
- // Optional trailing comma handled by the skipper at loop start
377
- } else {
378
- break;
379
- }
380
- }
381
-
382
- if !self.match_token(TokenKind::RBracket) {
383
- println!("Expected ']' at end of array");
384
- }
385
-
386
- Some(Value::Array(arr))
387
- }
388
-
389
- pub fn peek(&self) -> Option<&Token> {
390
- self.tokens.get(self.token_index)
391
- }
392
-
393
- pub fn peek_clone(&self) -> Option<Token> {
394
- self.tokens.get(self.token_index).cloned()
395
- }
396
-
397
- pub fn expect(&mut self, kind: TokenKind) -> Result<&Token, String> {
398
- let tok = self.advance().ok_or("Unexpected end of input")?;
399
- if tok.kind == kind {
400
- Ok(tok)
401
- } else {
402
- Err(format!("Expected {:?}, got {:?}", kind, tok.kind))
403
- }
404
- }
405
-
406
- pub fn collect_block_tokens(&mut self, base_indent: usize) -> Vec<Token> {
407
- let mut tokens = Vec::new();
408
-
409
- while let Some(tok) = self.peek() {
410
- if tok.indent <= base_indent && tok.kind != TokenKind::Newline {
411
- break;
412
- }
413
- tokens.push(self.advance().unwrap().clone());
414
- }
415
-
416
- tokens
417
- }
418
-
419
- pub fn collect_until<F>(&mut self, condition: F) -> Vec<Token> where F: Fn(&Token) -> bool {
420
- let mut collected = Vec::new();
421
- while let Some(token) = self.peek() {
422
- if condition(token) {
423
- break;
424
- }
425
- if token.kind == TokenKind::EOF {
426
- break;
427
- }
428
- collected.push(self.advance().unwrap().clone());
429
- }
430
-
431
- collected
432
- }
433
-
434
- pub fn is_eof(&self) -> bool {
435
- self.token_index >= self.tokens.len()
436
- }
437
-
438
- pub fn parse_block_until_next_else(
439
- &mut self,
440
- base_indent: usize,
441
- global_store: &mut GlobalStore
442
- ) -> Vec<Statement> {
443
- let mut block_tokens = Vec::new();
444
-
445
- while let Some(tok) = self.peek() {
446
- // Stop if we encounter an 'else' at same indent level
447
- if tok.lexeme == "else" && tok.indent == base_indent {
448
- break;
449
- }
450
- block_tokens.push(self.advance().unwrap().clone());
451
- }
452
-
453
- self.parse_block(block_tokens, global_store)
454
- }
455
-
456
- pub fn parse_condition_until_colon(&mut self) -> Option<Value> {
457
- let tokens = self.collect_until(|t| t.kind == TokenKind::Colon);
458
- if tokens.is_empty() {
459
- return None;
460
- }
461
-
462
- let condition = tokens
463
- .iter()
464
- .map(|t| t.lexeme.clone())
465
- .collect::<Vec<_>>()
466
- .join(" ");
467
-
468
- Some(Value::String(condition))
469
- }
470
-
471
- pub fn parse_block_until_else_or_dedent(
472
- &mut self,
473
- base_indent: usize,
474
- global_store: &mut GlobalStore
475
- ) -> Vec<Statement> {
476
- let mut tokens = Vec::new();
477
-
478
- while let Some(tok) = self.peek() {
479
- if tok.lexeme == "else" && tok.indent == base_indent {
480
- break;
481
- }
482
- if tok.indent < base_indent && tok.kind != TokenKind::Newline {
483
- break;
484
- }
485
- tokens.push(self.advance().unwrap().clone());
486
- }
487
-
488
- self.parse_block(tokens, global_store)
489
- }
490
- }
1
+ use crate::core::{
2
+ lexer::token::{Token, TokenKind},
3
+ parser::{
4
+ handler::{
5
+ arrow_call::parse_arrow_call,
6
+ at::parse_at_token,
7
+ bank::parse_bank_token,
8
+ condition::parse_condition_token,
9
+ dot::parse_dot_token,
10
+ identifier::{function::parse_function_token, parse_identifier_token},
11
+ loop_::parse_loop_token,
12
+ tempo::parse_tempo_token,
13
+ },
14
+ statement::Statement,
15
+ },
16
+ shared::value::Value,
17
+ store::global::GlobalStore,
18
+ };
19
+
20
+ #[derive(Debug, Clone, PartialEq)]
21
+ pub struct Parser {
22
+ pub resolve_modules: bool,
23
+ pub tokens: Vec<Token>,
24
+ pub token_index: usize,
25
+ pub current_module: String,
26
+ pub previous: Option<Token>,
27
+ }
28
+
29
+ impl Parser {
30
+ pub fn new() -> Self {
31
+ Parser {
32
+ resolve_modules: false,
33
+ tokens: Vec::new(),
34
+ token_index: 0,
35
+ current_module: String::new(),
36
+ previous: None,
37
+ }
38
+ }
39
+
40
+ pub fn set_current_module(&mut self, module_path: String) {
41
+ self.current_module = module_path;
42
+ }
43
+
44
+ pub fn advance(&mut self) -> Option<&Token> {
45
+ if self.is_eof() {
46
+ return None;
47
+ }
48
+
49
+ self.previous = self.tokens.get(self.token_index).cloned();
50
+ self.token_index += 1;
51
+
52
+ self.tokens.get(self.token_index - 1)
53
+ }
54
+
55
+ pub fn peek_is(&self, expected: &str) -> bool {
56
+ self.peek().map_or(false, |t| t.lexeme == expected)
57
+ }
58
+
59
+ pub fn peek_nth(&self, n: usize) -> Option<&Token> {
60
+ if self.token_index + n < self.tokens.len() {
61
+ self.tokens.get(self.token_index + n)
62
+ } else {
63
+ None
64
+ }
65
+ }
66
+
67
+ pub fn peek_nth_kind(&self, n: usize) -> Option<TokenKind> {
68
+ self.peek_nth(n).map(|t| t.kind.clone())
69
+ }
70
+
71
+ pub fn advance_if(&mut self, kind: TokenKind) -> bool {
72
+ if self.match_token(kind) { true } else { false }
73
+ }
74
+
75
+ pub fn match_token(&mut self, kind: TokenKind) -> bool {
76
+ if let Some(tok) = self.peek() {
77
+ if tok.kind == kind {
78
+ self.advance();
79
+ return true;
80
+ }
81
+ }
82
+ false
83
+ }
84
+
85
+ pub fn previous_clone(&self) -> Option<Token> {
86
+ self.previous.clone()
87
+ }
88
+
89
+ pub fn parse_block(
90
+ &self,
91
+ tokens: Vec<Token>,
92
+ global_store: &mut GlobalStore,
93
+ ) -> Vec<Statement> {
94
+ let mut inner_parser = Parser {
95
+ resolve_modules: self.resolve_modules,
96
+ tokens,
97
+ token_index: 0,
98
+ current_module: self.current_module.clone(),
99
+ previous: None,
100
+ };
101
+
102
+ inner_parser.parse_tokens(inner_parser.tokens.clone(), global_store)
103
+ }
104
+
105
+ pub fn parse_tokens(
106
+ &mut self,
107
+ tokens: Vec<Token>,
108
+ global_store: &mut GlobalStore,
109
+ ) -> Vec<Statement> {
110
+ // Filter out Whitespace tokens but keep Newline tokens because some constructs (e.g., print ...)
111
+ // rely on end-of-line semantics.
112
+ self.tokens = tokens
113
+ .into_iter()
114
+ .filter(|t| t.kind != TokenKind::Whitespace)
115
+ .collect();
116
+ self.token_index = 0;
117
+
118
+ let mut statements = Vec::new();
119
+
120
+ while !self.is_eof() {
121
+ let token = match self.peek() {
122
+ Some(t) => t.clone(),
123
+ None => {
124
+ break;
125
+ }
126
+ };
127
+
128
+ if token.kind == TokenKind::Newline {
129
+ self.advance();
130
+ continue;
131
+ }
132
+
133
+ let statement = match &token.kind {
134
+ TokenKind::At => parse_at_token(self, global_store),
135
+ TokenKind::Identifier => {
136
+ if let Some(next) = self.peek_nth(1).cloned() {
137
+ if next.kind == TokenKind::Arrow {
138
+ parse_arrow_call(self, global_store)
139
+ } else {
140
+ parse_identifier_token(self, global_store)
141
+ }
142
+ } else {
143
+ parse_identifier_token(self, global_store)
144
+ }
145
+ }
146
+ TokenKind::Dot => parse_dot_token(self, global_store),
147
+ TokenKind::Tempo => parse_tempo_token(self, global_store),
148
+ TokenKind::Bank => parse_bank_token(self, global_store),
149
+ TokenKind::Loop => parse_loop_token(self, global_store),
150
+ TokenKind::If => parse_condition_token(self, global_store),
151
+ TokenKind::Function => parse_function_token(self, global_store),
152
+ TokenKind::On => crate::core::parser::handler::identifier::on::parse_on_token(self, global_store),
153
+ TokenKind::Emit => crate::core::parser::handler::identifier::emit::parse_emit_token(self, token.clone(), global_store),
154
+
155
+ | TokenKind::Else // Ignore else, already handled in `parse_condition_token`
156
+ | TokenKind::Comment
157
+ | TokenKind::Equals
158
+ | TokenKind::Colon
159
+ | TokenKind::Number
160
+ | TokenKind::String
161
+ | TokenKind::LBrace
162
+ | TokenKind::RBrace
163
+ | TokenKind::Comma
164
+ | TokenKind::Dedent
165
+ | TokenKind::Indent => {
166
+ self.advance();
167
+ continue;
168
+ }
169
+
170
+ TokenKind::EOF => {
171
+ break;
172
+ }
173
+
174
+ _ => {
175
+ self.advance();
176
+ Statement::unknown_from_token(&token)
177
+ }
178
+ };
179
+
180
+ statements.push(statement);
181
+ }
182
+
183
+ statements
184
+ }
185
+
186
+ pub fn check_token(&self, kind: TokenKind) -> bool {
187
+ self.peek().map_or(false, |t| t.kind == kind)
188
+ }
189
+
190
+ pub fn peek_kind(&self) -> Option<TokenKind> {
191
+ self.peek().map(|t| t.kind.clone())
192
+ }
193
+
194
+ pub fn parse_map_value(&mut self) -> Option<Value> {
195
+ if !self.match_token(TokenKind::LBrace) {
196
+ return None;
197
+ }
198
+
199
+ let mut map = std::collections::HashMap::new();
200
+
201
+ while !self.check_token(TokenKind::RBrace) && !self.is_eof() {
202
+ // Skip separators and formatting before the key
203
+ while self.check_token(TokenKind::Newline)
204
+ || self.check_token(TokenKind::Whitespace)
205
+ || self.check_token(TokenKind::Indent)
206
+ || self.check_token(TokenKind::Dedent)
207
+ || self.check_token(TokenKind::Comma)
208
+ {
209
+ self.advance();
210
+ }
211
+
212
+ // Check if we are at the closing brace of the map
213
+ if self.check_token(TokenKind::RBrace) {
214
+ break;
215
+ }
216
+
217
+ let key = if let Some(token) = self.advance() {
218
+ match token.kind {
219
+ TokenKind::Whitespace
220
+ | TokenKind::Indent
221
+ | TokenKind::Dedent
222
+ | TokenKind::Newline => {
223
+ continue;
224
+ }
225
+ _ => token.lexeme.clone(),
226
+ }
227
+ } else {
228
+ break;
229
+ };
230
+
231
+ // Skip newlines and whitespace before colon
232
+ while self.check_token(TokenKind::Newline) || self.check_token(TokenKind::Whitespace) {
233
+ self.advance();
234
+ }
235
+
236
+ if !self.match_token(TokenKind::Colon) {
237
+ println!("Expected ':' after map key '{}'", key);
238
+ break;
239
+ }
240
+
241
+ // Skip separators and formatting before value
242
+ while self.check_token(TokenKind::Newline)
243
+ || self.check_token(TokenKind::Whitespace)
244
+ || self.check_token(TokenKind::Indent)
245
+ || self.check_token(TokenKind::Dedent)
246
+ || self.check_token(TokenKind::Comma)
247
+ {
248
+ self.advance();
249
+ }
250
+
251
+ let value = if let Some(token) = self.peek_clone() {
252
+ match token.kind {
253
+ TokenKind::String => {
254
+ self.advance();
255
+ Value::String(token.lexeme.clone())
256
+ }
257
+ TokenKind::Number => {
258
+ let mut number_str = token.lexeme.clone();
259
+ self.advance(); // consume the first number
260
+
261
+ if let Some(dot_token) = self.peek_clone() {
262
+ if dot_token.kind == TokenKind::Dot {
263
+ self.advance(); // consume the dot
264
+
265
+ if let Some(decimal_token) = self.peek_clone() {
266
+ if decimal_token.kind == TokenKind::Number {
267
+ self.advance(); // consume the number after the dot
268
+ number_str.push('.');
269
+ number_str.push_str(&decimal_token.lexeme);
270
+ } else {
271
+ println!(
272
+ "Expected number after dot, got {:?}",
273
+ decimal_token
274
+ );
275
+ return Some(Value::Null);
276
+ }
277
+ } else {
278
+ println!("Expected number after dot, but reached EOF");
279
+ return Some(Value::Null);
280
+ }
281
+ }
282
+ }
283
+
284
+ Value::Number(number_str.parse::<f32>().unwrap_or(0.0))
285
+ }
286
+
287
+ TokenKind::Identifier => {
288
+ self.advance();
289
+ Value::Identifier(token.lexeme.clone())
290
+ }
291
+ _ => {
292
+ println!("Unexpected token in map value: {:?}", token);
293
+ Value::Null
294
+ }
295
+ }
296
+ } else {
297
+ Value::Null
298
+ };
299
+
300
+ map.insert(key, value);
301
+
302
+ // Optionally skip a trailing comma after the value
303
+ while self.check_token(TokenKind::Comma)
304
+ || self.check_token(TokenKind::Whitespace)
305
+ || self.check_token(TokenKind::Newline)
306
+ {
307
+ self.advance();
308
+ }
309
+ }
310
+
311
+ if !self.match_token(TokenKind::RBrace) {
312
+ println!("Expected '}}' at end of map");
313
+ }
314
+
315
+ Some(Value::Map(map))
316
+ }
317
+
318
+ // Parse an array value like [1, 2, 3] or ["a", b]
319
+ pub fn parse_array_value(&mut self) -> Option<Value> {
320
+ if !self.match_token(TokenKind::LBracket) {
321
+ return None;
322
+ }
323
+
324
+ let mut arr: Vec<Value> = Vec::new();
325
+
326
+ while !self.check_token(TokenKind::RBracket) && !self.is_eof() {
327
+ // Skip formatting tokens
328
+ while self.check_token(TokenKind::Newline)
329
+ || self.check_token(TokenKind::Whitespace)
330
+ || self.check_token(TokenKind::Indent)
331
+ || self.check_token(TokenKind::Dedent)
332
+ || self.check_token(TokenKind::Comma)
333
+ {
334
+ self.advance();
335
+ }
336
+
337
+ if self.check_token(TokenKind::RBracket) {
338
+ break;
339
+ }
340
+
341
+ if let Some(token) = self.peek_clone() {
342
+ let value = match token.kind {
343
+ TokenKind::String => {
344
+ self.advance();
345
+ Value::String(token.lexeme.clone())
346
+ }
347
+ TokenKind::Number => {
348
+ // Support simple decimals split as number '.' number
349
+ let mut number_str = token.lexeme.clone();
350
+ self.advance();
351
+ if let Some(dot) = self.peek_clone() {
352
+ if dot.kind == TokenKind::Dot {
353
+ if let Some(next) = self.peek_nth(1).cloned() {
354
+ if next.kind == TokenKind::Number {
355
+ self.advance(); // consume dot
356
+ self.advance(); // consume next number
357
+ number_str.push('.');
358
+ number_str.push_str(&next.lexeme);
359
+ }
360
+ }
361
+ }
362
+ }
363
+ Value::Number(number_str.parse::<f32>().unwrap_or(0.0))
364
+ }
365
+ TokenKind::Identifier => {
366
+ self.advance();
367
+ Value::Identifier(token.lexeme.clone())
368
+ }
369
+ TokenKind::LBrace => {
370
+ // Allow inline maps inside arrays
371
+ if let Some(v) = self.parse_map_value() {
372
+ v
373
+ } else {
374
+ Value::Null
375
+ }
376
+ }
377
+ TokenKind::LBracket => {
378
+ // Nested arrays
379
+ if let Some(v) = self.parse_array_value() {
380
+ v
381
+ } else {
382
+ Value::Null
383
+ }
384
+ }
385
+ _ => {
386
+ self.advance();
387
+ Value::Null
388
+ }
389
+ };
390
+
391
+ // Only push non-null (retain alignment with permissive parsing)
392
+ if value != Value::Null {
393
+ arr.push(value);
394
+ }
395
+
396
+ // Optional trailing comma handled by the skipper at loop start
397
+ } else {
398
+ break;
399
+ }
400
+ }
401
+
402
+ if !self.match_token(TokenKind::RBracket) {
403
+ println!("Expected ']' at end of array");
404
+ }
405
+
406
+ Some(Value::Array(arr))
407
+ }
408
+
409
+ pub fn peek(&self) -> Option<&Token> {
410
+ self.tokens.get(self.token_index)
411
+ }
412
+
413
+ pub fn peek_clone(&self) -> Option<Token> {
414
+ self.tokens.get(self.token_index).cloned()
415
+ }
416
+
417
+ pub fn expect(&mut self, kind: TokenKind) -> Result<&Token, String> {
418
+ let tok = self.advance().ok_or("Unexpected end of input")?;
419
+ if tok.kind == kind {
420
+ Ok(tok)
421
+ } else {
422
+ Err(format!("Expected {:?}, got {:?}", kind, tok.kind))
423
+ }
424
+ }
425
+
426
+ pub fn collect_block_tokens(&mut self, base_indent: usize) -> Vec<Token> {
427
+ let mut tokens = Vec::new();
428
+
429
+ while let Some(tok) = self.peek() {
430
+ if tok.indent <= base_indent && tok.kind != TokenKind::Newline {
431
+ break;
432
+ }
433
+ tokens.push(self.advance().unwrap().clone());
434
+ }
435
+
436
+ tokens
437
+ }
438
+
439
+ pub fn collect_until<F>(&mut self, condition: F) -> Vec<Token>
440
+ where
441
+ F: Fn(&Token) -> bool,
442
+ {
443
+ let mut collected = Vec::new();
444
+ while let Some(token) = self.peek() {
445
+ if condition(token) {
446
+ break;
447
+ }
448
+ if token.kind == TokenKind::EOF {
449
+ break;
450
+ }
451
+ collected.push(self.advance().unwrap().clone());
452
+ }
453
+
454
+ collected
455
+ }
456
+
457
+ pub fn is_eof(&self) -> bool {
458
+ self.token_index >= self.tokens.len()
459
+ }
460
+
461
+ pub fn parse_block_until_next_else(
462
+ &mut self,
463
+ base_indent: usize,
464
+ global_store: &mut GlobalStore,
465
+ ) -> Vec<Statement> {
466
+ let mut block_tokens = Vec::new();
467
+
468
+ while let Some(tok) = self.peek() {
469
+ // Stop if we encounter an 'else' at same indent level
470
+ if tok.lexeme == "else" && tok.indent == base_indent {
471
+ break;
472
+ }
473
+ block_tokens.push(self.advance().unwrap().clone());
474
+ }
475
+
476
+ self.parse_block(block_tokens, global_store)
477
+ }
478
+
479
+ pub fn parse_condition_until_colon(&mut self) -> Option<Value> {
480
+ let tokens = self.collect_until(|t| t.kind == TokenKind::Colon);
481
+ if tokens.is_empty() {
482
+ return None;
483
+ }
484
+
485
+ let condition = tokens
486
+ .iter()
487
+ .map(|t| t.lexeme.clone())
488
+ .collect::<Vec<_>>()
489
+ .join(" ");
490
+
491
+ Some(Value::String(condition))
492
+ }
493
+
494
+ pub fn parse_block_until_else_or_dedent(
495
+ &mut self,
496
+ base_indent: usize,
497
+ global_store: &mut GlobalStore,
498
+ ) -> Vec<Statement> {
499
+ let mut tokens = Vec::new();
500
+
501
+ while let Some(tok) = self.peek() {
502
+ if tok.lexeme == "else" && tok.indent == base_indent {
503
+ break;
504
+ }
505
+ if tok.indent < base_indent && tok.kind != TokenKind::Newline {
506
+ break;
507
+ }
508
+ tokens.push(self.advance().unwrap().clone());
509
+ }
510
+
511
+ self.parse_block(tokens, global_store)
512
+ }
513
+ }