@devaloop/devalang 0.0.1-alpha.14 → 0.0.1-alpha.16

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 (177) hide show
  1. package/.devalang +10 -8
  2. package/.github/workflows/ci.yml +92 -0
  3. package/Cargo.toml +60 -58
  4. package/README.md +32 -15
  5. package/docs/CHANGELOG.md +93 -1
  6. package/docs/CONTRIBUTING.md +101 -1
  7. package/docs/ROADMAP.md +2 -2
  8. package/docs/TODO.md +1 -1
  9. package/examples/automation.deva +42 -0
  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 +39 -25
  14. package/examples/loop.deva +5 -11
  15. package/examples/pattern.deva +8 -0
  16. package/examples/plugin.deva +16 -0
  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 -456
  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 -8
  38. package/rust/common/cdn.rs +3 -6
  39. package/rust/common/mod.rs +3 -3
  40. package/rust/common/sso.rs +3 -6
  41. package/rust/config/driver.rs +118 -94
  42. package/rust/config/loader.rs +165 -156
  43. package/rust/config/mod.rs +4 -2
  44. package/rust/config/settings.rs +91 -0
  45. package/rust/config/stats.rs +257 -0
  46. package/rust/core/audio/engine.rs +696 -518
  47. package/rust/core/audio/evaluator.rs +263 -31
  48. package/rust/core/audio/interpreter/arrow_call.rs +198 -161
  49. package/rust/core/audio/interpreter/automate.rs +18 -0
  50. package/rust/core/audio/interpreter/call.rs +98 -95
  51. package/rust/core/audio/interpreter/condition.rs +70 -71
  52. package/rust/core/audio/interpreter/driver.rs +487 -198
  53. package/rust/core/audio/interpreter/function.rs +26 -21
  54. package/rust/core/audio/interpreter/let_.rs +38 -19
  55. package/rust/core/audio/interpreter/load.rs +18 -18
  56. package/rust/core/audio/interpreter/loop_.rs +113 -73
  57. package/rust/core/audio/interpreter/mod.rs +14 -13
  58. package/rust/core/audio/interpreter/sleep.rs +27 -30
  59. package/rust/core/audio/interpreter/spawn.rs +105 -102
  60. package/rust/core/audio/interpreter/tempo.rs +19 -16
  61. package/rust/core/audio/interpreter/trigger.rs +239 -210
  62. package/rust/core/audio/loader/mod.rs +1 -1
  63. package/rust/core/audio/loader/trigger.rs +100 -97
  64. package/rust/core/audio/mod.rs +7 -6
  65. package/rust/core/audio/player.rs +64 -64
  66. package/rust/core/audio/renderer.rs +56 -53
  67. package/rust/core/audio/special/easing.rs +189 -0
  68. package/rust/core/audio/special/env.rs +43 -0
  69. package/rust/core/audio/special/math.rs +102 -0
  70. package/rust/core/audio/special/mod.rs +9 -0
  71. package/rust/core/audio/special/modulator.rs +143 -0
  72. package/rust/core/builder/mod.rs +80 -85
  73. package/rust/core/debugger/lexer.rs +27 -27
  74. package/rust/core/debugger/mod.rs +24 -23
  75. package/rust/core/debugger/module.rs +55 -47
  76. package/rust/core/debugger/preprocessor.rs +27 -27
  77. package/rust/core/debugger/store.rs +40 -39
  78. package/rust/core/error/mod.rs +80 -66
  79. package/rust/core/lexer/handler/arrow.rs +82 -31
  80. package/rust/core/lexer/handler/at.rs +21 -21
  81. package/rust/core/lexer/handler/brace.rs +41 -41
  82. package/rust/core/lexer/handler/colon.rs +21 -21
  83. package/rust/core/lexer/handler/comment.rs +30 -30
  84. package/rust/core/lexer/handler/dot.rs +21 -21
  85. package/rust/core/lexer/handler/driver.rs +337 -263
  86. package/rust/core/lexer/handler/identifier.rs +46 -42
  87. package/rust/core/lexer/handler/indent.rs +66 -66
  88. package/rust/core/lexer/handler/mod.rs +16 -16
  89. package/rust/core/lexer/handler/newline.rs +23 -23
  90. package/rust/core/lexer/handler/number.rs +31 -31
  91. package/rust/core/lexer/handler/operator.rs +46 -44
  92. package/rust/core/lexer/handler/parenthesis.rs +41 -41
  93. package/rust/core/lexer/handler/slash.rs +21 -21
  94. package/rust/core/lexer/handler/string.rs +63 -63
  95. package/rust/core/lexer/mod.rs +54 -51
  96. package/rust/core/lexer/token.rs +97 -91
  97. package/rust/core/mod.rs +11 -11
  98. package/rust/core/parser/driver.rs +513 -408
  99. package/rust/core/parser/handler/arrow_call.rs +233 -211
  100. package/rust/core/parser/handler/at.rs +245 -162
  101. package/rust/core/parser/handler/bank.rs +94 -69
  102. package/rust/core/parser/handler/condition.rs +80 -74
  103. package/rust/core/parser/handler/dot.rs +143 -135
  104. package/rust/core/parser/handler/identifier/automate.rs +257 -0
  105. package/rust/core/parser/handler/identifier/call.rs +91 -88
  106. package/rust/core/parser/handler/identifier/emit.rs +66 -0
  107. package/rust/core/parser/handler/identifier/function.rs +100 -92
  108. package/rust/core/parser/handler/identifier/group.rs +85 -75
  109. package/rust/core/parser/handler/identifier/let_.rs +158 -127
  110. package/rust/core/parser/handler/identifier/mod.rs +54 -52
  111. package/rust/core/parser/handler/identifier/on.rs +98 -0
  112. package/rust/core/parser/handler/identifier/print.rs +52 -0
  113. package/rust/core/parser/handler/identifier/sleep.rs +36 -33
  114. package/rust/core/parser/handler/identifier/spawn.rs +91 -88
  115. package/rust/core/parser/handler/identifier/synth.rs +65 -65
  116. package/rust/core/parser/handler/loop_.rs +170 -72
  117. package/rust/core/parser/handler/mod.rs +8 -8
  118. package/rust/core/parser/handler/tempo.rs +53 -47
  119. package/rust/core/parser/mod.rs +4 -4
  120. package/rust/core/parser/statement.rs +142 -108
  121. package/rust/core/plugin/loader.rs +123 -48
  122. package/rust/core/plugin/mod.rs +2 -1
  123. package/rust/core/plugin/runner.rs +296 -0
  124. package/rust/core/preprocessor/loader.rs +515 -326
  125. package/rust/core/preprocessor/mod.rs +4 -4
  126. package/rust/core/preprocessor/module.rs +60 -58
  127. package/rust/core/preprocessor/processor.rs +99 -101
  128. package/rust/core/preprocessor/resolver/bank.rs +51 -49
  129. package/rust/core/preprocessor/resolver/call.rs +100 -100
  130. package/rust/core/preprocessor/resolver/condition.rs +97 -97
  131. package/rust/core/preprocessor/resolver/driver.rs +310 -278
  132. package/rust/core/preprocessor/resolver/function.rs +69 -78
  133. package/rust/core/preprocessor/resolver/group.rs +96 -91
  134. package/rust/core/preprocessor/resolver/let_.rs +32 -28
  135. package/rust/core/preprocessor/resolver/loop_.rs +320 -91
  136. package/rust/core/preprocessor/resolver/mod.rs +15 -15
  137. package/rust/core/preprocessor/resolver/spawn.rs +76 -92
  138. package/rust/core/preprocessor/resolver/synth.rs +56 -50
  139. package/rust/core/preprocessor/resolver/tempo.rs +50 -49
  140. package/rust/core/preprocessor/resolver/trigger.rs +113 -116
  141. package/rust/core/preprocessor/resolver/value.rs +81 -87
  142. package/rust/core/shared/bank.rs +1 -1
  143. package/rust/core/shared/duration.rs +9 -9
  144. package/rust/core/shared/mod.rs +3 -3
  145. package/rust/core/shared/value.rs +35 -32
  146. package/rust/core/store/function.rs +34 -34
  147. package/rust/core/store/global.rs +55 -38
  148. package/rust/core/store/mod.rs +5 -5
  149. package/rust/core/store/variable.rs +37 -34
  150. package/rust/core/utils/mod.rs +2 -2
  151. package/rust/core/utils/path.rs +37 -31
  152. package/rust/core/utils/validation.rs +35 -37
  153. package/rust/installer/addon.rs +84 -80
  154. package/rust/installer/bank.rs +62 -65
  155. package/rust/installer/mod.rs +5 -5
  156. package/rust/installer/plugin.rs +54 -55
  157. package/rust/installer/utils.rs +56 -56
  158. package/rust/lib.rs +156 -164
  159. package/rust/main.rs +250 -145
  160. package/rust/utils/error.rs +200 -0
  161. package/rust/utils/file.rs +38 -35
  162. package/rust/utils/first_usage.rs +76 -0
  163. package/rust/utils/logger.rs +195 -139
  164. package/rust/utils/mod.rs +9 -50
  165. package/rust/utils/signature.rs +19 -17
  166. package/rust/utils/spinner.rs +22 -19
  167. package/rust/utils/telemetry.rs +292 -0
  168. package/rust/utils/watcher.rs +34 -33
  169. package/templates/minimal/README.md +97 -121
  170. package/templates/welcome/README.md +97 -121
  171. package/typescript/bin/index.ts +19 -5
  172. package/typescript/index.ts +3 -1
  173. package/typescript/scripts/postbuild.ts +10 -6
  174. package/typescript/scripts/postinstall.ts +56 -0
  175. package/typescript/scripts/version/bump.ts +0 -1
  176. package/typescript/scripts/version/index.ts +0 -1
  177. package/out-tsc/bin/devalang.exe +0 -0
@@ -1,408 +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 les tokens Whitespace et Newline avant parsing
111
- self.tokens = tokens
112
- .into_iter()
113
- .filter(|t| t.kind != TokenKind::Whitespace && t.kind != TokenKind::Newline)
114
- .collect();
115
- self.token_index = 0;
116
-
117
- let mut statements = Vec::new();
118
-
119
- while !self.is_eof() {
120
- let token = match self.peek() {
121
- Some(t) => t.clone(),
122
- None => {
123
- break;
124
- }
125
- };
126
-
127
- if token.kind == TokenKind::Newline {
128
- self.advance();
129
- continue;
130
- }
131
-
132
- let statement = match &token.kind {
133
- TokenKind::At => parse_at_token(self, global_store),
134
- TokenKind::Identifier => {
135
- if let Some(next) = self.peek_nth(1).cloned() {
136
- if next.kind == TokenKind::Arrow {
137
- parse_arrow_call(self, global_store)
138
- } else {
139
- parse_identifier_token(self, global_store)
140
- }
141
- } else {
142
- parse_identifier_token(self, global_store)
143
- }
144
- }
145
- TokenKind::Dot => parse_dot_token(self, global_store),
146
- TokenKind::Tempo => parse_tempo_token(self, global_store),
147
- TokenKind::Bank => parse_bank_token(self, global_store),
148
- TokenKind::Loop => parse_loop_token(self, global_store),
149
- TokenKind::If => parse_condition_token(self, global_store),
150
- TokenKind::Function => parse_function_token(self, global_store),
151
-
152
- | TokenKind::Else // Ignore else, already handled in `parse_condition_token`
153
- | TokenKind::Comment
154
- | TokenKind::Equals
155
- | TokenKind::Colon
156
- | TokenKind::Number
157
- | TokenKind::String
158
- | TokenKind::LBrace
159
- | TokenKind::RBrace
160
- | TokenKind::Comma
161
- | TokenKind::Dedent
162
- | TokenKind::Indent => {
163
- self.advance();
164
- continue;
165
- }
166
-
167
- TokenKind::EOF => {
168
- break;
169
- }
170
-
171
- _ => {
172
- println!("Unhandled token: {:?}", token);
173
- self.advance();
174
- Statement::unknown()
175
- }
176
- };
177
-
178
- statements.push(statement);
179
- }
180
-
181
- statements
182
- }
183
-
184
- pub fn check_token(&self, kind: TokenKind) -> bool {
185
- self.peek().map_or(false, |t| t.kind == kind)
186
- }
187
-
188
- pub fn peek_kind(&self) -> Option<TokenKind> {
189
- self.peek().map(|t| t.kind.clone())
190
- }
191
-
192
- pub fn parse_map_value(&mut self) -> Option<Value> {
193
- if !self.match_token(TokenKind::LBrace) {
194
- return None;
195
- }
196
-
197
- let mut map = std::collections::HashMap::new();
198
-
199
- while !self.check_token(TokenKind::RBrace) && !self.is_eof() {
200
- // Skip newlines, whitespace, indent, dedent before the key
201
- while
202
- self.check_token(TokenKind::Newline) ||
203
- self.check_token(TokenKind::Whitespace) ||
204
- self.check_token(TokenKind::Indent) ||
205
- self.check_token(TokenKind::Dedent)
206
- {
207
- self.advance();
208
- }
209
-
210
- // Check if we are at the closing brace of the map
211
- if self.check_token(TokenKind::RBrace) {
212
- break;
213
- }
214
-
215
- let key = if let Some(token) = self.advance() {
216
- match token.kind {
217
- | TokenKind::Whitespace
218
- | TokenKind::Indent
219
- | TokenKind::Dedent
220
- | TokenKind::Newline => {
221
- continue;
222
- }
223
- _ => token.lexeme.clone(),
224
- }
225
- } else {
226
- break;
227
- };
228
-
229
- // Skip newlines and whitespace before colon
230
- while self.check_token(TokenKind::Newline) || self.check_token(TokenKind::Whitespace) {
231
- self.advance();
232
- }
233
-
234
- if !self.match_token(TokenKind::Colon) {
235
- println!("Expected ':' after map key '{}'", key);
236
- break;
237
- }
238
-
239
- // Skip newlines and whitespace before value
240
- while self.check_token(TokenKind::Newline) || self.check_token(TokenKind::Whitespace) {
241
- self.advance();
242
- }
243
-
244
- let value = if let Some(token) = self.peek_clone() {
245
- match token.kind {
246
- TokenKind::String => {
247
- self.advance();
248
- Value::String(token.lexeme.clone())
249
- }
250
- TokenKind::Number => {
251
- let mut number_str = token.lexeme.clone();
252
- self.advance(); // consume the first number
253
-
254
- if let Some(dot_token) = self.peek_clone() {
255
- if dot_token.kind == TokenKind::Dot {
256
- self.advance(); // consume the dot
257
-
258
- if let Some(decimal_token) = self.peek_clone() {
259
- if decimal_token.kind == TokenKind::Number {
260
- self.advance(); // consume the number after the dot
261
- number_str.push('.');
262
- number_str.push_str(&decimal_token.lexeme);
263
- } else {
264
- println!(
265
- "Expected number after dot, got {:?}",
266
- decimal_token
267
- );
268
- return Some(Value::Null);
269
- }
270
- } else {
271
- println!("Expected number after dot, but reached EOF");
272
- return Some(Value::Null);
273
- }
274
- }
275
- }
276
-
277
- Value::Number(number_str.parse::<f32>().unwrap_or(0.0))
278
- }
279
-
280
- TokenKind::Identifier => {
281
- self.advance();
282
- Value::Identifier(token.lexeme.clone())
283
- }
284
- _ => {
285
- println!("Unexpected token in map value: {:?}", token);
286
- Value::Null
287
- }
288
- }
289
- } else {
290
- Value::Null
291
- };
292
-
293
- map.insert(key, value);
294
- }
295
-
296
- if !self.match_token(TokenKind::RBrace) {
297
- println!("Expected '}}' at end of map");
298
- }
299
-
300
- Some(Value::Map(map))
301
- }
302
-
303
- pub fn peek(&self) -> Option<&Token> {
304
- self.tokens.get(self.token_index)
305
- }
306
-
307
- pub fn peek_clone(&self) -> Option<Token> {
308
- self.tokens.get(self.token_index).cloned()
309
- }
310
-
311
- pub fn expect(&mut self, kind: TokenKind) -> Result<&Token, String> {
312
- let tok = self.advance().ok_or("Unexpected end of input")?;
313
- if tok.kind == kind {
314
- Ok(tok)
315
- } else {
316
- Err(format!("Expected {:?}, got {:?}", kind, tok.kind))
317
- }
318
- }
319
-
320
- pub fn collect_block_tokens(&mut self, base_indent: usize) -> Vec<Token> {
321
- let mut tokens = Vec::new();
322
-
323
- while let Some(tok) = self.peek() {
324
- if tok.indent <= base_indent && tok.kind != TokenKind::Newline {
325
- break;
326
- }
327
- tokens.push(self.advance().unwrap().clone());
328
- }
329
-
330
- tokens
331
- }
332
-
333
- pub fn collect_until<F>(&mut self, condition: F) -> Vec<Token> where F: Fn(&Token) -> bool {
334
- let mut collected = Vec::new();
335
- while let Some(token) = self.peek() {
336
- if token.kind == TokenKind::Newline || token.kind == TokenKind::Indent {
337
- self.advance(); // Skip newlines and indents
338
- continue;
339
- }
340
- if token.kind == TokenKind::EOF {
341
- break;
342
- }
343
- if condition(token) {
344
- break;
345
- }
346
- collected.push(self.advance().unwrap().clone());
347
- }
348
-
349
- collected
350
- }
351
-
352
- pub fn is_eof(&self) -> bool {
353
- self.token_index >= self.tokens.len()
354
- }
355
-
356
- pub fn parse_block_until_next_else(
357
- &mut self,
358
- base_indent: usize,
359
- global_store: &mut GlobalStore
360
- ) -> Vec<Statement> {
361
- let mut block_tokens = Vec::new();
362
-
363
- while let Some(tok) = self.peek() {
364
- // Stop if we encounter an 'else' at same indent level
365
- if tok.lexeme == "else" && tok.indent == base_indent {
366
- break;
367
- }
368
- block_tokens.push(self.advance().unwrap().clone());
369
- }
370
-
371
- self.parse_block(block_tokens, global_store)
372
- }
373
-
374
- pub fn parse_condition_until_colon(&mut self) -> Option<Value> {
375
- let tokens = self.collect_until(|t| t.kind == TokenKind::Colon);
376
- if tokens.is_empty() {
377
- return None;
378
- }
379
-
380
- let condition = tokens
381
- .iter()
382
- .map(|t| t.lexeme.clone())
383
- .collect::<Vec<_>>()
384
- .join(" ");
385
-
386
- Some(Value::String(condition))
387
- }
388
-
389
- pub fn parse_block_until_else_or_dedent(
390
- &mut self,
391
- base_indent: usize,
392
- global_store: &mut GlobalStore
393
- ) -> Vec<Statement> {
394
- let mut tokens = Vec::new();
395
-
396
- while let Some(tok) = self.peek() {
397
- if tok.lexeme == "else" && tok.indent == base_indent {
398
- break;
399
- }
400
- if tok.indent < base_indent && tok.kind != TokenKind::Newline {
401
- break;
402
- }
403
- tokens.push(self.advance().unwrap().clone());
404
- }
405
-
406
- self.parse_block(tokens, global_store)
407
- }
408
- }
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
+ }