@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,162 +1,245 @@
1
- use crate::core::{
2
- lexer::token::TokenKind,
3
- parser::{ driver::Parser, statement::{ Statement, StatementKind } },
4
- shared::value::Value,
5
- store::global::GlobalStore,
6
- };
7
- pub fn parse_at_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
8
- parser.advance(); // consume '@'
9
-
10
- let Some(token) = parser.peek_clone() else {
11
- return Statement::unknown();
12
- };
13
-
14
- let keyword = token.lexeme.as_str();
15
-
16
- match keyword {
17
- "import" => {
18
- parser.advance(); // consume 'import'
19
-
20
- if !parser.match_token(TokenKind::LBrace) {
21
- return Statement::error(token, "Expected '{{' after 'import'".to_string());
22
- }
23
-
24
- let mut names = Vec::new();
25
- while let Some(token) = parser.peek() {
26
- match &token.kind {
27
- TokenKind::Identifier => {
28
- names.push(token.lexeme.clone());
29
- parser.advance();
30
- }
31
- TokenKind::Comma => {
32
- parser.advance();
33
- }
34
- TokenKind::RBrace => {
35
- parser.advance();
36
- break;
37
- }
38
- _ => {
39
- let message = format!(
40
- "Unexpected token in import list: {:?}",
41
- token.kind.clone()
42
- );
43
- return Statement::error(token.clone(), message);
44
- }
45
- }
46
- }
47
-
48
- let Some(from_token) = parser.peek_clone() else {
49
- return Statement::error(token, "Expected 'from' after import list".to_string());
50
- };
51
-
52
- if from_token.lexeme != "from" {
53
- return Statement::error(token, "Expected keyword 'from'".to_string());
54
- }
55
-
56
- parser.advance(); // consume 'from'
57
-
58
- let Some(source_token) = parser.peek() else {
59
- return Statement::error(token, "Expected string after 'from'".to_string());
60
- };
61
-
62
- if source_token.kind != TokenKind::String {
63
- return Statement::error(token, "Expected string after 'from'".to_string());
64
- }
65
-
66
- let source = source_token.lexeme.clone();
67
- parser.advance(); // consume string
68
-
69
- Statement {
70
- kind: StatementKind::Import { names, source },
71
- value: Value::Null,
72
- indent: token.indent,
73
- line: token.line,
74
- column: token.column,
75
- }
76
- }
77
-
78
- "export" => {
79
- parser.advance(); // consume 'export'
80
-
81
- parser.advance(); // consume '{'
82
-
83
- let names_tokens = parser.collect_until(|t| TokenKind::RBrace == t.kind);
84
- let mut names: Vec<String> = Vec::new();
85
-
86
- for token in names_tokens {
87
- if token.kind == TokenKind::Identifier {
88
- names.push(token.lexeme.clone());
89
- } else if token.kind == TokenKind::Comma {
90
- continue; // Ignore commas
91
- } else if token.kind == TokenKind::RBrace {
92
- break; // Stop at the closing brace
93
- } else {
94
- return Statement::error(token, "Unexpected token in export list".to_string());
95
- }
96
- }
97
-
98
- Statement {
99
- kind: StatementKind::Export {
100
- names: names.clone(),
101
- source: parser.current_module.clone(),
102
- },
103
- value: Value::Null,
104
- indent: token.indent,
105
- line: token.line,
106
- column: token.column,
107
- }
108
- }
109
-
110
- "load" => {
111
- parser.advance(); // consume 'load'
112
-
113
- // Exemple : @load "preset.mydeva"
114
- let Some(path_token) = parser.peek() else {
115
- return Statement::error(token, "Expected string after 'load'".to_string());
116
- };
117
-
118
- if path_token.kind != TokenKind::String {
119
- return Statement::error(token, "Expected string after 'load'".to_string());
120
- }
121
-
122
- let path = path_token.lexeme.clone();
123
-
124
- parser.advance(); // consume string
125
- parser.advance(); // consume 'as'
126
-
127
- let Some(as_token) = parser.peek_clone() else {
128
- return Statement::error(
129
- token,
130
- "Expected 'as' after path in load statement".to_string()
131
- );
132
- };
133
-
134
- if as_token.kind != TokenKind::Identifier {
135
- return Statement::error(
136
- token,
137
- "Expected identifier after 'as' in load statement".to_string()
138
- );
139
- }
140
-
141
- let alias = as_token.lexeme.clone();
142
-
143
- parser.advance(); // consume identifier
144
-
145
- Statement {
146
- kind: StatementKind::Load {
147
- source: path,
148
- alias,
149
- },
150
- value: Value::Null,
151
- indent: token.indent,
152
- line: token.line,
153
- column: token.column,
154
- }
155
- }
156
-
157
- _ => {
158
- let message = format!("Unknown keyword after '@' : {}", keyword);
159
- Statement::error(token, message)
160
- }
161
- }
162
- }
1
+ use crate::core::{
2
+ lexer::token::TokenKind,
3
+ parser::{
4
+ driver::Parser,
5
+ statement::{Statement, StatementKind},
6
+ },
7
+ shared::value::Value,
8
+ store::global::GlobalStore,
9
+ };
10
+ pub fn parse_at_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
11
+ parser.advance(); // consume '@'
12
+
13
+ let Some(token) = parser.peek_clone() else {
14
+ return Statement::unknown();
15
+ };
16
+
17
+ let keyword = token.lexeme.as_str();
18
+
19
+ match keyword {
20
+ "use" => {
21
+ parser.advance(); // consume 'use'
22
+ let Some(use_token) = parser.previous_clone() else {
23
+ return Statement::unknown();
24
+ };
25
+
26
+ // Expect plugin author
27
+ let Some(author_token) = parser.peek_clone() else {
28
+ return Statement::error(use_token, "Expected plugin author".to_string());
29
+ };
30
+ if author_token.kind != TokenKind::Identifier {
31
+ return Statement::error(
32
+ author_token,
33
+ "Expected identifier for plugin author".to_string(),
34
+ );
35
+ }
36
+ parser.advance(); // consume author
37
+
38
+ // Expect '.'
39
+ if !parser.match_token(TokenKind::Dot) {
40
+ return Statement::error(
41
+ author_token,
42
+ "Expected '.' after plugin author".to_string(),
43
+ );
44
+ }
45
+
46
+ // Expect plugin name
47
+ let Some(plugin_token) = parser.peek_clone() else {
48
+ return Statement::error(author_token, "Expected plugin name".to_string());
49
+ };
50
+
51
+ let name = match plugin_token.kind {
52
+ TokenKind::Identifier | TokenKind::Number => {
53
+ parser.advance();
54
+ format!("{}.{}", author_token.lexeme, plugin_token.lexeme)
55
+ }
56
+ _ => {
57
+ return Statement::error(
58
+ plugin_token,
59
+ "Expected identifier or number for plugin name".to_string(),
60
+ );
61
+ }
62
+ };
63
+
64
+ // Optional alias
65
+ let alias = if parser.match_token(TokenKind::As) {
66
+ let Some(alias_token) = parser.peek_clone() else {
67
+ return Statement::error(
68
+ use_token,
69
+ "Expected identifier after 'as'".to_string(),
70
+ );
71
+ };
72
+ if alias_token.kind != TokenKind::Identifier {
73
+ return Statement::error(
74
+ alias_token,
75
+ "Expected identifier after 'as'".to_string(),
76
+ );
77
+ }
78
+ parser.advance();
79
+ Some(alias_token.lexeme.clone())
80
+ } else {
81
+ None
82
+ };
83
+
84
+ Statement {
85
+ kind: StatementKind::Use {
86
+ name: name.clone(),
87
+ alias,
88
+ },
89
+ value: Value::Null,
90
+ indent: use_token.indent,
91
+ line: use_token.line,
92
+ column: use_token.column,
93
+ }
94
+ }
95
+
96
+ "import" => {
97
+ parser.advance(); // consume 'import'
98
+
99
+ if !parser.match_token(TokenKind::LBrace) {
100
+ return Statement::error(token, "Expected '{{' after 'import'".to_string());
101
+ }
102
+
103
+ let mut names = Vec::new();
104
+ while let Some(token) = parser.peek() {
105
+ match &token.kind {
106
+ TokenKind::Identifier => {
107
+ names.push(token.lexeme.clone());
108
+ parser.advance();
109
+ }
110
+ TokenKind::Comma => {
111
+ parser.advance();
112
+ }
113
+ TokenKind::RBrace => {
114
+ parser.advance();
115
+ break;
116
+ }
117
+ _ => {
118
+ let message =
119
+ format!("Unexpected token in import list: {:?}", token.kind.clone());
120
+ return Statement::error(token.clone(), message);
121
+ }
122
+ }
123
+ }
124
+
125
+ let Some(from_token) = parser.peek_clone() else {
126
+ return Statement::error(token, "Expected 'from' after import list".to_string());
127
+ };
128
+
129
+ if from_token.lexeme != "from" {
130
+ return Statement::error(token, "Expected keyword 'from'".to_string());
131
+ }
132
+
133
+ parser.advance(); // consume 'from'
134
+
135
+ let Some(source_token) = parser.peek() else {
136
+ return Statement::error(token, "Expected string after 'from'".to_string());
137
+ };
138
+
139
+ if source_token.kind != TokenKind::String {
140
+ return Statement::error(token, "Expected string after 'from'".to_string());
141
+ }
142
+
143
+ let source = source_token.lexeme.clone();
144
+ parser.advance(); // consume string
145
+
146
+ Statement {
147
+ kind: StatementKind::Import { names, source },
148
+ value: Value::Null,
149
+ indent: token.indent,
150
+ line: token.line,
151
+ column: token.column,
152
+ }
153
+ }
154
+
155
+ "export" => {
156
+ parser.advance(); // consume 'export'
157
+
158
+ parser.advance(); // consume '{'
159
+
160
+ let names_tokens = parser.collect_until(|t| TokenKind::RBrace == t.kind);
161
+ let mut names: Vec<String> = Vec::new();
162
+
163
+ for token in names_tokens {
164
+ if token.kind == TokenKind::Identifier {
165
+ names.push(token.lexeme.clone());
166
+ } else if token.kind == TokenKind::Comma {
167
+ continue; // Ignore commas
168
+ } else if token.kind == TokenKind::RBrace {
169
+ break; // Stop at the closing brace
170
+ } else {
171
+ return Statement::error(token, "Unexpected token in export list".to_string());
172
+ }
173
+ }
174
+
175
+ Statement {
176
+ kind: StatementKind::Export {
177
+ names: names.clone(),
178
+ source: parser.current_module.clone(),
179
+ },
180
+ value: Value::Null,
181
+ indent: token.indent,
182
+ line: token.line,
183
+ column: token.column,
184
+ }
185
+ }
186
+
187
+ "load" => {
188
+ parser.advance(); // consume 'load'
189
+
190
+ // Example: @load "preset.mydeva"
191
+ let Some(path_token) = parser.peek() else {
192
+ return Statement::error(token, "Expected string after 'load'".to_string());
193
+ };
194
+
195
+ if path_token.kind != TokenKind::String {
196
+ return Statement::error(token, "Expected string after 'load'".to_string());
197
+ }
198
+
199
+ let path = path_token.lexeme.clone();
200
+
201
+ parser.advance(); // consume string
202
+
203
+ if !parser.match_token(TokenKind::As) {
204
+ return Statement::error(
205
+ token,
206
+ "Expected 'as' after path in load statement".to_string(),
207
+ );
208
+ }
209
+
210
+ let Some(alias_token) = parser.peek_clone() else {
211
+ return Statement::error(
212
+ token,
213
+ "Expected identifier after 'as' in load statement".to_string(),
214
+ );
215
+ };
216
+
217
+ if alias_token.kind != TokenKind::Identifier {
218
+ return Statement::error(
219
+ token,
220
+ "Expected identifier after 'as' in load statement".to_string(),
221
+ );
222
+ }
223
+
224
+ let alias = alias_token.lexeme.clone();
225
+
226
+ parser.advance(); // consume identifier
227
+
228
+ Statement {
229
+ kind: StatementKind::Load {
230
+ source: path,
231
+ alias,
232
+ },
233
+ value: Value::Null,
234
+ indent: token.indent,
235
+ line: token.line,
236
+ column: token.column,
237
+ }
238
+ }
239
+
240
+ _ => {
241
+ let message = format!("Unknown keyword after '@' : {}", keyword);
242
+ Statement::error(token, message)
243
+ }
244
+ }
245
+ }
@@ -1,69 +1,94 @@
1
- use crate::core::{
2
- lexer::token::TokenKind,
3
- parser::{ statement::{ Statement, StatementKind }, driver::Parser },
4
- shared::value::Value,
5
- store::global::GlobalStore,
6
- };
7
-
8
- pub fn parse_bank_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
9
- parser.advance(); // consume 'bank'
10
-
11
- let Some(bank_token) = parser.previous_clone() else {
12
- return Statement::unknown();
13
- };
14
-
15
- let bank_value = if let Some(token) = parser.peek_clone() {
16
- match token.kind {
17
- TokenKind::Identifier | TokenKind::Number => {
18
- parser.advance(); // consume identifier or number
19
-
20
- let mut value = token.lexeme.clone();
21
-
22
- // Support namespaced banks: <author>.<bank_name>
23
- if let Some(next) = parser.peek_clone() {
24
- if next.kind == TokenKind::Dot {
25
- parser.advance(); // consume '.'
26
- if let Some(last) = parser.peek_clone() {
27
- match last.kind {
28
- TokenKind::Identifier | TokenKind::Number => {
29
- parser.advance();
30
- value = format!("{}.{}", value, last.lexeme);
31
- Value::String(value)
32
- }
33
- _ => Value::Unknown,
34
- }
35
- } else {
36
- Value::Unknown
37
- }
38
- } else {
39
- match token.kind {
40
- TokenKind::Identifier => Value::Identifier(value),
41
- TokenKind::Number => Value::Number(value.parse::<f32>().unwrap_or(0.0)),
42
- _ => Value::Unknown,
43
- }
44
- }
45
- } else {
46
- match token.kind {
47
- TokenKind::Identifier => Value::Identifier(value),
48
- TokenKind::Number => Value::Number(value.parse::<f32>().unwrap_or(0.0)),
49
- _ => Value::Unknown,
50
- }
51
- }
52
- }
53
- _ => Value::Unknown,
54
- }
55
- } else {
56
- return Statement::error(
57
- bank_token,
58
- "Expected identifier or number after 'bank'".to_string()
59
- );
60
- };
61
-
62
- Statement {
63
- kind: StatementKind::Bank,
64
- value: bank_value,
65
- indent: bank_token.indent,
66
- line: bank_token.line,
67
- column: bank_token.column,
68
- }
69
- }
1
+ use crate::core::{
2
+ lexer::token::TokenKind,
3
+ parser::{
4
+ driver::Parser,
5
+ statement::{Statement, StatementKind},
6
+ },
7
+ shared::value::Value,
8
+ store::global::GlobalStore,
9
+ };
10
+
11
+ pub fn parse_bank_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
12
+ // consume 'bank'
13
+ parser.advance();
14
+
15
+ let Some(bank_tok) = parser.previous_clone() else {
16
+ return Statement::unknown();
17
+ };
18
+
19
+ // Parse bank name
20
+ let bank_value: Value = match parser.peek_clone() {
21
+ Some(tok) => match tok.kind {
22
+ TokenKind::Identifier | TokenKind::Number => {
23
+ // base name
24
+ parser.advance();
25
+ let mut base = tok.lexeme.clone();
26
+ // optional .suffix (identifier or number)
27
+ if let Some(dot) = parser.peek_clone() {
28
+ if dot.kind == TokenKind::Dot {
29
+ // consume '.' and the following ident/number
30
+ parser.advance();
31
+ if let Some(suffix) = parser.peek_clone() {
32
+ match suffix.kind {
33
+ TokenKind::Identifier | TokenKind::Number => {
34
+ parser.advance();
35
+ base.push('.');
36
+ base.push_str(&suffix.lexeme);
37
+ Value::String(base)
38
+ }
39
+ _ => Value::Identifier(base),
40
+ }
41
+ } else {
42
+ Value::Identifier(base)
43
+ }
44
+ } else {
45
+ match tok.kind {
46
+ TokenKind::Identifier => Value::String(base),
47
+ TokenKind::Number => Value::Number(base.parse::<f32>().unwrap_or(0.0)),
48
+ _ => Value::Unknown,
49
+ }
50
+ }
51
+ } else {
52
+ match tok.kind {
53
+ TokenKind::Identifier => Value::String(base),
54
+ TokenKind::Number => Value::Number(base.parse::<f32>().unwrap_or(0.0)),
55
+ _ => Value::Unknown,
56
+ }
57
+ }
58
+ }
59
+ TokenKind::String => {
60
+ parser.advance();
61
+ Value::String(tok.lexeme.clone())
62
+ }
63
+ _ => Value::Unknown,
64
+ },
65
+ None => Value::Unknown,
66
+ };
67
+
68
+ if matches!(bank_value, Value::Unknown | Value::Null) {
69
+ return Statement::error(bank_tok, "Expected a bank name".to_string());
70
+ }
71
+
72
+ // Optional alias: as <identifier>
73
+ let mut alias: Option<String> = None;
74
+ if parser.peek_is("as") {
75
+ // consume 'as'
76
+ parser.advance();
77
+ let Some(next) = parser.peek_clone() else {
78
+ return Statement::error(bank_tok, "Expected identifier after 'as'".to_string());
79
+ };
80
+ if next.kind != TokenKind::Identifier {
81
+ return Statement::error(next, "Expected identifier after 'as'".to_string());
82
+ }
83
+ parser.advance();
84
+ alias = Some(next.lexeme.clone());
85
+ }
86
+
87
+ Statement {
88
+ kind: StatementKind::Bank { alias },
89
+ value: bank_value,
90
+ indent: bank_tok.indent,
91
+ line: bank_tok.line,
92
+ column: bank_tok.column,
93
+ }
94
+ }