@devaloop/devalang 0.0.1-alpha.8 → 0.0.1-beta.1

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 (277) hide show
  1. package/.cargo/config.toml +2 -0
  2. package/.devalang +10 -4
  3. package/.github/workflows/ci.yml +103 -0
  4. package/Cargo.toml +80 -48
  5. package/README.md +135 -158
  6. package/docs/CHANGELOG.md +413 -1
  7. package/docs/CONTRIBUTING.md +101 -0
  8. package/docs/ROADMAP.md +10 -7
  9. package/docs/TODO.md +21 -9
  10. package/examples/automation.deva +42 -0
  11. package/examples/bank.deva +7 -0
  12. package/examples/condition.deva +8 -12
  13. package/examples/duration.deva +9 -0
  14. package/examples/events.deva +12 -0
  15. package/examples/function.deva +15 -0
  16. package/examples/group.deva +3 -3
  17. package/examples/index.deva +57 -10
  18. package/examples/loop.deva +7 -12
  19. package/examples/pattern.deva +8 -0
  20. package/examples/plugin.deva +16 -0
  21. package/examples/synth.deva +14 -0
  22. package/examples/variables.deva +2 -2
  23. package/out-tsc/bin/index.d.ts +2 -0
  24. package/out-tsc/bin/index.js +51 -7
  25. package/out-tsc/core/functions/index.d.ts +37 -0
  26. package/out-tsc/core/functions/index.js +76 -0
  27. package/out-tsc/core/index.d.ts +6 -0
  28. package/out-tsc/core/index.js +22 -0
  29. package/out-tsc/core/types/index.d.ts +4 -0
  30. package/out-tsc/core/types/index.js +20 -0
  31. package/out-tsc/core/types/plugin.d.ts +18 -0
  32. package/out-tsc/core/types/plugin.js +2 -0
  33. package/out-tsc/core/types/result.d.ts +27 -0
  34. package/out-tsc/core/types/result.js +2 -0
  35. package/out-tsc/core/types/statement.d.ts +106 -0
  36. package/out-tsc/core/types/statement.js +2 -0
  37. package/out-tsc/core/types/value.d.ts +43 -0
  38. package/out-tsc/core/types/value.js +2 -0
  39. package/out-tsc/index.d.ts +7 -0
  40. package/out-tsc/index.js +42 -1
  41. package/out-tsc/pkg/devalang_core.d.ts +13 -0
  42. package/out-tsc/pkg/devalang_core.js +50 -0
  43. package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +33 -0
  44. package/out-tsc/scripts/copy-wasm-dts.d.ts +1 -0
  45. package/out-tsc/scripts/copy-wasm-dts.js +73 -0
  46. package/out-tsc/scripts/postinstall.d.ts +1 -0
  47. package/out-tsc/scripts/postinstall.js +83 -0
  48. package/out-tsc/scripts/version/bump.d.ts +1 -0
  49. package/out-tsc/scripts/version/fetch.d.ts +1 -0
  50. package/out-tsc/scripts/version/fetch.js +1 -5
  51. package/out-tsc/scripts/version/index.d.ts +1 -0
  52. package/out-tsc/scripts/version/sync.d.ts +1 -0
  53. package/package.json +28 -7
  54. package/project-version.json +4 -4
  55. package/rust/cli/bank/api.rs +122 -0
  56. package/rust/cli/bank/commands.rs +275 -0
  57. package/rust/cli/bank/mod.rs +29 -0
  58. package/rust/cli/build/commands.rs +103 -0
  59. package/rust/cli/build/mod.rs +2 -0
  60. package/rust/cli/build/process.rs +146 -0
  61. package/rust/cli/check/mod.rs +208 -0
  62. package/rust/cli/discover/commands.rs +253 -0
  63. package/rust/cli/discover/config.rs +111 -0
  64. package/rust/cli/discover/fs.rs +19 -0
  65. package/rust/cli/discover/install.rs +103 -0
  66. package/rust/cli/discover/metadata.rs +48 -0
  67. package/rust/cli/discover/mod.rs +5 -0
  68. package/rust/cli/{init.rs → init/commands.rs} +32 -23
  69. package/rust/cli/init/mod.rs +1 -0
  70. package/rust/cli/install/addon.rs +118 -0
  71. package/rust/cli/install/bank.rs +53 -0
  72. package/rust/cli/install/commands.rs +35 -0
  73. package/rust/cli/install/mod.rs +4 -0
  74. package/rust/cli/install/plugin.rs +61 -0
  75. package/rust/cli/login/commands.rs +124 -0
  76. package/rust/cli/login/mod.rs +1 -0
  77. package/rust/cli/mod.rs +12 -205
  78. package/rust/cli/parser.rs +314 -0
  79. package/rust/cli/play/commands.rs +324 -0
  80. package/rust/cli/play/io.rs +17 -0
  81. package/rust/cli/play/mod.rs +5 -0
  82. package/rust/cli/play/process.rs +150 -0
  83. package/rust/cli/play/realtime.rs +91 -0
  84. package/rust/cli/play/utils.rs +23 -0
  85. package/rust/cli/telemetry/commands.rs +22 -0
  86. package/rust/cli/telemetry/event_creator.rs +80 -0
  87. package/rust/cli/telemetry/mod.rs +3 -0
  88. package/rust/cli/telemetry/send.rs +51 -0
  89. package/rust/cli/{template.rs → template/commands.rs} +69 -57
  90. package/rust/cli/template/mod.rs +1 -0
  91. package/rust/cli/update/commands.rs +6 -0
  92. package/rust/cli/update/mod.rs +1 -0
  93. package/rust/config/driver.rs +103 -0
  94. package/rust/config/mod.rs +3 -16
  95. package/rust/config/ops.rs +26 -0
  96. package/rust/config/settings.rs +101 -0
  97. package/rust/core/audio/engine/helpers.rs +170 -0
  98. package/rust/core/audio/engine/mod.rs +7 -0
  99. package/rust/core/audio/engine/sample.rs +366 -0
  100. package/rust/core/audio/engine/synth.rs +325 -0
  101. package/rust/core/audio/evaluator.rs +310 -31
  102. package/rust/core/audio/interpreter/arrow_call.rs +311 -0
  103. package/rust/core/audio/interpreter/automate.rs +18 -0
  104. package/rust/core/audio/interpreter/call.rs +294 -42
  105. package/rust/core/audio/interpreter/condition.rs +71 -65
  106. package/rust/core/audio/interpreter/driver.rs +542 -204
  107. package/rust/core/audio/interpreter/function.rs +26 -0
  108. package/rust/core/audio/interpreter/let_.rs +38 -19
  109. package/rust/core/audio/interpreter/load.rs +19 -18
  110. package/rust/core/audio/interpreter/loop_.rs +114 -59
  111. package/rust/core/audio/interpreter/mod.rs +14 -11
  112. package/rust/core/audio/interpreter/sleep.rs +28 -36
  113. package/rust/core/audio/interpreter/spawn.rs +252 -65
  114. package/rust/core/audio/interpreter/tempo.rs +40 -16
  115. package/rust/core/audio/interpreter/trigger.rs +239 -69
  116. package/rust/core/audio/loader/mod.rs +1 -1
  117. package/rust/core/audio/loader/trigger.rs +97 -52
  118. package/rust/core/audio/mod.rs +7 -6
  119. package/rust/core/audio/player.rs +70 -54
  120. package/rust/core/audio/renderer.rs +54 -57
  121. package/rust/core/audio/special/easing.rs +189 -0
  122. package/rust/core/audio/special/env.rs +45 -0
  123. package/rust/core/audio/special/math.rs +134 -0
  124. package/rust/core/audio/special/mod.rs +9 -0
  125. package/rust/core/audio/special/modulator.rs +143 -0
  126. package/rust/core/builder/mod.rs +86 -80
  127. package/rust/core/debugger/lexer.rs +27 -27
  128. package/rust/core/debugger/mod.rs +30 -21
  129. package/rust/core/debugger/module.rs +55 -0
  130. package/rust/core/debugger/preprocessor.rs +27 -27
  131. package/rust/core/debugger/store.rs +40 -25
  132. package/rust/core/error/mod.rs +269 -60
  133. package/rust/core/lexer/driver.rs +61 -0
  134. package/rust/core/lexer/handler/arrow.rs +82 -0
  135. package/rust/core/lexer/handler/at.rs +21 -21
  136. package/rust/core/lexer/handler/brace.rs +41 -41
  137. package/rust/core/lexer/handler/colon.rs +21 -21
  138. package/rust/core/lexer/handler/comment.rs +30 -30
  139. package/rust/core/lexer/handler/dot.rs +21 -21
  140. package/rust/core/lexer/handler/driver.rs +337 -215
  141. package/rust/core/lexer/handler/identifier.rs +47 -40
  142. package/rust/core/lexer/handler/indent.rs +66 -52
  143. package/rust/core/lexer/handler/mod.rs +15 -13
  144. package/rust/core/lexer/handler/newline.rs +23 -23
  145. package/rust/core/lexer/handler/number.rs +31 -31
  146. package/rust/core/lexer/handler/operator.rs +46 -44
  147. package/rust/core/lexer/handler/parenthesis.rs +41 -0
  148. package/rust/core/lexer/handler/slash.rs +21 -0
  149. package/rust/core/lexer/handler/string.rs +63 -63
  150. package/rust/core/lexer/mod.rs +3 -30
  151. package/rust/core/lexer/token.rs +21 -12
  152. package/rust/core/mod.rs +10 -10
  153. package/rust/core/parser/driver.rs +584 -312
  154. package/rust/core/parser/handler/arrow_call.rs +253 -0
  155. package/rust/core/parser/handler/at.rs +279 -162
  156. package/rust/core/parser/handler/bank.rs +104 -41
  157. package/rust/core/parser/handler/condition.rs +83 -74
  158. package/rust/core/parser/handler/dot.rs +148 -112
  159. package/rust/core/parser/handler/identifier/automate.rs +254 -0
  160. package/rust/core/parser/handler/identifier/call.rs +91 -0
  161. package/rust/core/parser/handler/identifier/emit.rs +70 -0
  162. package/rust/core/parser/handler/identifier/function.rs +113 -0
  163. package/rust/core/parser/handler/identifier/group.rs +89 -0
  164. package/rust/core/parser/handler/identifier/let_.rs +173 -0
  165. package/rust/core/parser/handler/identifier/mod.rs +55 -0
  166. package/rust/core/parser/handler/identifier/on.rs +107 -0
  167. package/rust/core/parser/handler/identifier/print.rs +49 -0
  168. package/rust/core/parser/handler/identifier/sleep.rs +43 -0
  169. package/rust/core/parser/handler/identifier/spawn.rs +91 -0
  170. package/rust/core/parser/handler/identifier/synth.rs +135 -0
  171. package/rust/core/parser/handler/loop_.rs +194 -66
  172. package/rust/core/parser/handler/mod.rs +9 -7
  173. package/rust/core/parser/handler/pattern.rs +74 -0
  174. package/rust/core/parser/handler/tempo.rs +57 -47
  175. package/rust/core/parser/mod.rs +3 -4
  176. package/rust/core/parser/statement.rs +11 -88
  177. package/rust/core/plugin/loader.rs +137 -0
  178. package/rust/core/plugin/mod.rs +2 -0
  179. package/rust/core/plugin/runner.rs +347 -0
  180. package/rust/core/preprocessor/loader.rs +637 -179
  181. package/rust/core/preprocessor/mod.rs +4 -4
  182. package/rust/core/preprocessor/module.rs +60 -53
  183. package/rust/core/preprocessor/processor.rs +114 -67
  184. package/rust/core/preprocessor/resolver/bank.rs +49 -47
  185. package/rust/core/preprocessor/resolver/call.rs +124 -53
  186. package/rust/core/preprocessor/resolver/condition.rs +95 -66
  187. package/rust/core/preprocessor/resolver/driver.rs +324 -182
  188. package/rust/core/preprocessor/resolver/function.rs +69 -0
  189. package/rust/core/preprocessor/resolver/group.rs +94 -118
  190. package/rust/core/preprocessor/resolver/let_.rs +32 -0
  191. package/rust/core/preprocessor/resolver/loop_.rs +318 -145
  192. package/rust/core/preprocessor/resolver/mod.rs +16 -10
  193. package/rust/core/preprocessor/resolver/pattern.rs +83 -0
  194. package/rust/core/preprocessor/resolver/spawn.rs +99 -53
  195. package/rust/core/preprocessor/resolver/synth.rs +54 -0
  196. package/rust/core/preprocessor/resolver/tempo.rs +48 -49
  197. package/rust/core/preprocessor/resolver/trigger.rs +116 -111
  198. package/rust/core/preprocessor/resolver/value.rs +176 -0
  199. package/rust/core/store/export.rs +28 -28
  200. package/rust/core/store/function.rs +40 -0
  201. package/rust/core/store/global.rs +61 -39
  202. package/rust/core/store/import.rs +28 -28
  203. package/rust/core/store/mod.rs +5 -4
  204. package/rust/core/store/variable.rs +51 -28
  205. package/rust/core/utils/mod.rs +1 -2
  206. package/rust/core/utils/path.rs +37 -46
  207. package/rust/lib.rs +308 -117
  208. package/rust/main.rs +364 -65
  209. package/rust/types/Cargo.toml +11 -0
  210. package/rust/types/src/addons.rs +55 -0
  211. package/rust/types/src/ast.rs +202 -0
  212. package/rust/types/src/config.rs +74 -0
  213. package/rust/types/src/lib.rs +12 -0
  214. package/rust/types/src/telemetry.rs +85 -0
  215. package/rust/utils/Cargo.toml +26 -0
  216. package/rust/utils/src/error.rs +186 -0
  217. package/rust/utils/src/file.rs +94 -0
  218. package/rust/utils/src/first_usage.rs +97 -0
  219. package/rust/utils/{mod.rs → src/lib.rs} +9 -6
  220. package/rust/utils/{logger.rs → src/logger.rs} +200 -123
  221. package/rust/utils/src/path.rs +88 -0
  222. package/rust/utils/src/signature.rs +41 -0
  223. package/rust/utils/{spinner.rs → src/spinner.rs} +20 -21
  224. package/rust/utils/src/version.rs +27 -0
  225. package/rust/utils/{watcher.rs → src/watcher.rs} +46 -33
  226. package/rust/web/api.rs +5 -0
  227. package/rust/web/cdn.rs +34 -0
  228. package/rust/web/mod.rs +3 -0
  229. package/rust/web/sso.rs +5 -0
  230. package/templates/minimal/README.md +143 -127
  231. package/templates/welcome/README.md +143 -127
  232. package/templates/welcome/src/index.deva +56 -8
  233. package/templates/welcome/src/variables.deva +2 -4
  234. package/tests/integration.rs +21 -0
  235. package/tests/rust/cli_check_build.rs +21 -0
  236. package/tests/rust/cli_help.rs +12 -0
  237. package/tests/rust/cli_template_list.rs +10 -0
  238. package/tests/rust/cli_version.rs +11 -0
  239. package/tests/typescript/index.spec.ts +136 -0
  240. package/tests/typescript/playhead.spec.ts +36 -0
  241. package/tests/typescript/render_e2e.spec.ts +77 -0
  242. package/tsconfig.json +12 -10
  243. package/typescript/bin/index.ts +19 -5
  244. package/typescript/core/functions/index.ts +83 -0
  245. package/typescript/core/index.ts +6 -0
  246. package/typescript/core/types/index.ts +4 -0
  247. package/typescript/core/types/plugin.ts +19 -0
  248. package/typescript/core/types/result.ts +29 -0
  249. package/typescript/core/types/statement.ts +47 -0
  250. package/typescript/core/types/value.ts +29 -0
  251. package/typescript/index.ts +8 -1
  252. package/typescript/pkg/devalang_core.d.ts +4 -0
  253. package/typescript/pkg/devalang_core.ts +49 -0
  254. package/typescript/scripts/copy-wasm-dts.ts +41 -0
  255. package/typescript/scripts/postinstall.ts +85 -0
  256. package/typescript/scripts/version/bump.ts +0 -1
  257. package/typescript/scripts/version/fetch.ts +1 -6
  258. package/typescript/scripts/version/index.ts +0 -1
  259. package/docs/COMMANDS.md +0 -85
  260. package/docs/CONFIG.md +0 -30
  261. package/docs/SYNTAX.md +0 -210
  262. package/out-tsc/bin/devalang.exe +0 -0
  263. package/out-tsc/scripts/postbuild.js +0 -11
  264. package/rust/cli/build.rs +0 -137
  265. package/rust/cli/check.rs +0 -117
  266. package/rust/cli/play.rs +0 -193
  267. package/rust/config/loader.rs +0 -13
  268. package/rust/core/audio/engine.rs +0 -126
  269. package/rust/core/parser/handler/identifier.rs +0 -262
  270. package/rust/core/shared/duration.rs +0 -8
  271. package/rust/core/shared/mod.rs +0 -2
  272. package/rust/core/shared/value.rs +0 -18
  273. package/rust/core/utils/validation.rs +0 -35
  274. package/rust/utils/file.rs +0 -35
  275. package/rust/utils/signature.rs +0 -17
  276. package/rust/utils/version.rs +0 -15
  277. package/typescript/scripts/postbuild.ts +0 -8
@@ -1,66 +1,194 @@
1
- use std::collections::HashMap;
2
-
3
- use crate::core::{
4
- lexer::{ token::TokenKind },
5
- parser::{ statement::{ Statement, StatementKind }, driver::Parser },
6
- shared::value::Value,
7
- store::global::GlobalStore,
8
- };
9
-
10
- pub fn parse_loop_token(parser: &mut Parser, global_store: &mut GlobalStore) -> Statement {
11
- parser.advance(); // consume 'loop'
12
-
13
- let Some(loop_token) = parser.previous_clone() else {
14
- return Statement::unknown();
15
- };
16
-
17
- // Expect an identifier (iterator)
18
- let Some(iterator_token) = parser.peek_clone() else {
19
- return Statement::error(loop_token, "Expected identifier after 'loop'".to_string());
20
- };
21
-
22
- let iterator_name = iterator_token.lexeme.clone();
23
- parser.advance(); // consume iterator
24
-
25
- // Expect colon
26
- let Some(colon_token) = parser.peek_clone() else {
27
- return Statement::error(iterator_token.clone(), "Expected ':' after iterator".to_string());
28
- };
29
-
30
- if colon_token.kind != TokenKind::Colon {
31
- let message = format!("Expected ':' after iterator, got {:?}", colon_token.kind);
32
- return Statement::error(colon_token.clone(), message);
33
- }
34
-
35
- parser.advance(); // consume ':'
36
-
37
- // Collect all indented statements
38
- let tokens = parser.collect_until(
39
- |t| (t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF)
40
- );
41
- let loop_body = parser.parse_block(tokens.clone(), global_store);
42
-
43
- // Peek for dedent
44
- if let Some(token) = parser.peek() {
45
- if token.kind == TokenKind::Dedent {
46
- parser.advance();
47
- } else {
48
- // Unexpected token after loop body
49
- }
50
- } else {
51
- // EOF or unexpected end of input
52
- }
53
-
54
- let mut value_map = HashMap::new();
55
-
56
- value_map.insert("iterator".to_string(), Value::Identifier(iterator_name));
57
- value_map.insert("body".to_string(), Value::Block(loop_body.clone()));
58
-
59
- Statement {
60
- kind: StatementKind::Loop,
61
- value: Value::Map(value_map),
62
- indent: loop_token.indent,
63
- line: loop_token.line,
64
- column: loop_token.column,
65
- }
66
- }
1
+ use devalang_types::Value;
2
+
3
+ use crate::core::{
4
+ lexer::token::TokenKind,
5
+ parser::{
6
+ driver::Parser,
7
+ statement::{Statement, StatementKind},
8
+ },
9
+ store::global::GlobalStore,
10
+ };
11
+
12
+ pub fn parse_loop_token(parser: &mut Parser, global_store: &mut GlobalStore) -> Statement {
13
+ parser.advance(); // consume 'loop' or 'for' (aliased in lexer)
14
+ let Some(loop_token) = parser.previous_clone() else {
15
+ return Statement::unknown();
16
+ };
17
+
18
+ // Support two forms:
19
+ // 1) loop <count>:
20
+ // 2) for <ident> in [a,b,c]:
21
+
22
+ // Peek next to decide
23
+ let Some(next_token) = parser.peek_clone() else {
24
+ return Statement::error_with_pos(
25
+ loop_token.indent,
26
+ loop_token.line,
27
+ loop_token.column,
28
+ "Expected iterator after loop/for".to_string(),
29
+ );
30
+ };
31
+
32
+ // Try to detect 'for <ident> in [array]:' form
33
+ let mut foreach_ident: Option<String> = None;
34
+ if let TokenKind::Identifier = next_token.kind {
35
+ // Could be either count identifier (old form) or foreach variable
36
+ // Look ahead for 'in'
37
+ let name = next_token.lexeme.clone();
38
+ // don't consume yet; we'll branch
39
+ if let Some(t2) = parser.peek_nth(1) {
40
+ if t2.kind == TokenKind::Identifier && t2.lexeme == "in" {
41
+ // foreach form
42
+ foreach_ident = Some(name);
43
+ // consume ident and 'in'
44
+ parser.advance();
45
+ parser.advance();
46
+ }
47
+ }
48
+ }
49
+
50
+ if let Some(var_name) = foreach_ident {
51
+ // Expect [array] OR number OR string OR identifier after 'in'
52
+ let array_val = if let Some(tok) = parser.peek_clone() {
53
+ match tok.kind {
54
+ TokenKind::LBracket => {
55
+ if let Some(v) = parser.parse_array_value() {
56
+ v
57
+ } else {
58
+ Value::Array(vec![])
59
+ }
60
+ }
61
+ TokenKind::Number => {
62
+ parser.advance();
63
+ let n = tok.lexeme.parse::<f32>().unwrap_or(0.0);
64
+ Value::Number(n)
65
+ }
66
+ TokenKind::String => {
67
+ parser.advance();
68
+ Value::String(tok.lexeme.clone())
69
+ }
70
+ TokenKind::Identifier => {
71
+ parser.advance();
72
+ Value::Identifier(tok.lexeme.clone())
73
+ }
74
+ _ => {
75
+ return Statement::error_with_pos(
76
+ loop_token.indent,
77
+ loop_token.line,
78
+ loop_token.column,
79
+ "Expected array, number, string or identifier after 'in'".to_string(),
80
+ );
81
+ }
82
+ }
83
+ } else {
84
+ return Statement::error_with_pos(
85
+ loop_token.indent,
86
+ loop_token.line,
87
+ loop_token.column,
88
+ "Expected array, number, string or identifier after 'in'".to_string(),
89
+ );
90
+ };
91
+
92
+ // Expect ':'
93
+ if !parser.match_token(TokenKind::Colon) {
94
+ return Statement::error_with_pos(
95
+ loop_token.indent,
96
+ loop_token.line,
97
+ loop_token.column,
98
+ "Expected ':' after foreach header".to_string(),
99
+ );
100
+ }
101
+
102
+ let tokens =
103
+ parser.collect_until(|t| t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF);
104
+ let loop_body = parser.parse_block(tokens.clone(), global_store);
105
+ if let Some(token) = parser.peek() {
106
+ if token.kind == TokenKind::Dedent {
107
+ parser.advance();
108
+ }
109
+ }
110
+
111
+ let mut value_map = std::collections::HashMap::new();
112
+ value_map.insert("foreach".to_string(), Value::Identifier(var_name));
113
+ value_map.insert("array".to_string(), array_val);
114
+ value_map.insert("body".to_string(), Value::Block(loop_body.clone()));
115
+
116
+ return Statement {
117
+ kind: StatementKind::Loop,
118
+ value: Value::Map(value_map),
119
+ indent: loop_token.indent,
120
+ line: loop_token.line,
121
+ column: loop_token.column,
122
+ };
123
+ }
124
+
125
+ // Fallback to legacy: loop <count>:
126
+ let Some(iterator_token) = parser.peek_clone() else {
127
+ return Statement::error_with_pos(
128
+ loop_token.indent,
129
+ loop_token.line,
130
+ loop_token.column,
131
+ "Expected number or identifier after 'loop'".to_string(),
132
+ );
133
+ };
134
+
135
+ let iterator_value = match iterator_token.kind {
136
+ TokenKind::Number => {
137
+ let val = iterator_token.lexeme.parse::<f32>().unwrap_or(1.0);
138
+ parser.advance();
139
+ Value::Number(val)
140
+ }
141
+ TokenKind::Identifier => {
142
+ let val = iterator_token.lexeme.clone();
143
+ parser.advance();
144
+ Value::Identifier(val)
145
+ }
146
+ TokenKind::String => {
147
+ // strings that are numeric (e.g. "10")
148
+ let s = iterator_token.lexeme.clone();
149
+ parser.advance();
150
+ Value::String(s)
151
+ }
152
+ _ => {
153
+ return Statement::error_with_pos(
154
+ iterator_token.clone().indent,
155
+ iterator_token.clone().line,
156
+ iterator_token.clone().column,
157
+ "Expected a number, string or identifier as loop count".to_string(),
158
+ );
159
+ }
160
+ };
161
+
162
+ if !parser.match_token(TokenKind::Colon) {
163
+ let message = format!(
164
+ "Expected ':' after loop count, got {:?}",
165
+ parser.peek_kind()
166
+ );
167
+ return Statement::error_with_pos(
168
+ loop_token.clone().indent,
169
+ loop_token.clone().line,
170
+ loop_token.clone().column,
171
+ message,
172
+ );
173
+ }
174
+
175
+ let tokens = parser.collect_until(|t| t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF);
176
+ let loop_body = parser.parse_block(tokens.clone(), global_store);
177
+ if let Some(token) = parser.peek() {
178
+ if token.kind == TokenKind::Dedent {
179
+ parser.advance();
180
+ }
181
+ }
182
+
183
+ let mut value_map = std::collections::HashMap::new();
184
+ value_map.insert("iterator".to_string(), iterator_value);
185
+ value_map.insert("body".to_string(), Value::Block(loop_body.clone()));
186
+
187
+ Statement {
188
+ kind: StatementKind::Loop,
189
+ value: Value::Map(value_map),
190
+ indent: loop_token.indent,
191
+ line: loop_token.line,
192
+ column: loop_token.column,
193
+ }
194
+ }
@@ -1,7 +1,9 @@
1
- pub mod at;
2
- pub mod identifier;
3
- pub mod dot;
4
- pub mod tempo;
5
- pub mod bank;
6
- pub mod loop_;
7
- pub mod condition;
1
+ pub mod arrow_call;
2
+ pub mod at;
3
+ pub mod bank;
4
+ pub mod condition;
5
+ pub mod dot;
6
+ pub mod identifier;
7
+ pub mod loop_;
8
+ pub mod pattern;
9
+ pub mod tempo;
@@ -0,0 +1,74 @@
1
+ use devalang_types::Value;
2
+
3
+ use crate::core::{
4
+ lexer::token::TokenKind,
5
+ parser::{
6
+ driver::Parser,
7
+ statement::{Statement, StatementKind},
8
+ },
9
+ store::global::GlobalStore,
10
+ };
11
+
12
+ pub fn parse_pattern_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
13
+ // consume 'pattern'
14
+ parser.advance();
15
+
16
+ let Some(tok) = parser.previous_clone() else {
17
+ return Statement::unknown();
18
+ };
19
+
20
+ // Parse pattern name
21
+ let mut name = String::new();
22
+ if let Some(next) = parser.peek_clone() {
23
+ if next.kind == TokenKind::Identifier {
24
+ parser.advance();
25
+ name = next.lexeme.clone();
26
+ }
27
+ }
28
+
29
+ // optional 'with <target>' sequence
30
+ let mut target: Option<String> = None;
31
+ if parser.peek_is("with") {
32
+ parser.advance(); // consume 'with'
33
+ if let Some(tok2) = parser.peek_clone() {
34
+ // target can be identifier or dotted identifier
35
+ if tok2.kind == TokenKind::Identifier {
36
+ parser.advance();
37
+ let mut base = tok2.lexeme.clone();
38
+ if let Some(dot) = parser.peek_clone() {
39
+ if dot.kind == TokenKind::Dot {
40
+ parser.advance();
41
+ if let Some(suf) = parser.peek_clone() {
42
+ if suf.kind == TokenKind::Identifier || suf.kind == TokenKind::Number {
43
+ parser.advance();
44
+ base.push('.');
45
+ base.push_str(&suf.lexeme);
46
+ }
47
+ }
48
+ }
49
+ }
50
+ target = Some(base);
51
+ }
52
+ }
53
+ }
54
+
55
+ // optional '=' and pattern string
56
+ let mut value: Value = Value::Null;
57
+ if parser.peek_is("=") {
58
+ parser.advance();
59
+ if let Some(tok3) = parser.peek_clone() {
60
+ if tok3.kind == TokenKind::String {
61
+ parser.advance();
62
+ value = Value::String(tok3.lexeme.clone());
63
+ }
64
+ }
65
+ }
66
+
67
+ Statement {
68
+ kind: StatementKind::Pattern { name, target },
69
+ value,
70
+ indent: tok.indent,
71
+ line: tok.line,
72
+ column: tok.column,
73
+ }
74
+ }
@@ -1,47 +1,57 @@
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_tempo_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
9
- parser.advance(); // consume 'bpm'
10
-
11
- let Some(tempo_token) = parser.previous_clone() else {
12
- return Statement::unknown();
13
- };
14
-
15
- // Expect a number or identifier
16
- let Some(value_token) = parser.peek_clone() else {
17
- return Statement::error(
18
- tempo_token,
19
- "Expected a number or identifier after 'bpm'".to_string()
20
- );
21
- };
22
-
23
- let value = match value_token.kind {
24
- TokenKind::Number => {
25
- parser.advance();
26
- Value::Number(value_token.lexeme.parse().unwrap_or(0.0))
27
- }
28
- TokenKind::Identifier => {
29
- parser.advance();
30
- Value::Identifier(value_token.lexeme.clone())
31
- }
32
- _ => {
33
- return Statement::error(
34
- value_token.clone(),
35
- format!("Expected a number or identifier after 'bpm', got {:?}", value_token.kind)
36
- );
37
- }
38
- };
39
-
40
- Statement {
41
- kind: StatementKind::Tempo,
42
- value,
43
- indent: tempo_token.indent,
44
- line: tempo_token.line,
45
- column: tempo_token.column,
46
- }
47
- }
1
+ use crate::core::{
2
+ lexer::token::TokenKind,
3
+ parser::{
4
+ driver::Parser,
5
+ statement::{Statement, StatementKind},
6
+ },
7
+ store::global::GlobalStore,
8
+ };
9
+ use devalang_types::Value;
10
+
11
+ pub fn parse_tempo_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
12
+ parser.advance(); // consume 'bpm'
13
+
14
+ let Some(tempo_token) = parser.previous_clone() else {
15
+ return Statement::unknown();
16
+ };
17
+
18
+ // Expect a number or identifier
19
+ let Some(value_token) = parser.peek_clone() else {
20
+ return Statement::error_with_pos(
21
+ tempo_token.indent,
22
+ tempo_token.line,
23
+ tempo_token.column,
24
+ "Expected a number or identifier after 'bpm'".to_string(),
25
+ );
26
+ };
27
+
28
+ let value = match value_token.kind {
29
+ TokenKind::Number => {
30
+ parser.advance();
31
+ Value::Number(value_token.lexeme.parse().unwrap_or(0.0))
32
+ }
33
+ TokenKind::Identifier => {
34
+ parser.advance();
35
+ Value::Identifier(value_token.lexeme.clone())
36
+ }
37
+ _ => {
38
+ return Statement::error_with_pos(
39
+ value_token.indent,
40
+ value_token.line,
41
+ value_token.column,
42
+ format!(
43
+ "Expected a number or identifier after 'bpm', got {:?}",
44
+ value_token.kind
45
+ ),
46
+ );
47
+ }
48
+ };
49
+
50
+ Statement {
51
+ kind: StatementKind::Tempo,
52
+ value,
53
+ indent: tempo_token.indent,
54
+ line: tempo_token.line,
55
+ column: tempo_token.column,
56
+ }
57
+ }
@@ -1,4 +1,3 @@
1
- pub mod driver;
2
-
3
- pub mod statement;
4
- pub mod handler;
1
+ pub mod driver;
2
+ pub mod handler;
3
+ pub mod statement;
@@ -1,88 +1,11 @@
1
- use serde::{ Deserialize, Serialize };
2
- use crate::core::{ lexer::token::Token, shared::{ duration::Duration, value::Value } };
3
-
4
- #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
5
- pub struct Statement {
6
- pub kind: StatementKind,
7
- pub value: Value,
8
- pub indent: usize,
9
- pub line: usize,
10
- pub column: usize,
11
- }
12
-
13
- impl Statement {
14
- pub fn unknown() -> Self {
15
- Statement {
16
- kind: StatementKind::Unknown,
17
- value: Value::Null,
18
- indent: 0,
19
- line: 0,
20
- column: 0,
21
- }
22
- }
23
-
24
- pub fn error(token: Token, message: String) -> Self {
25
- Statement {
26
- kind: StatementKind::Error { message },
27
- value: Value::Null,
28
- indent: token.indent,
29
- line: token.line,
30
- column: token.column,
31
- }
32
- }
33
- }
34
-
35
- #[derive(Debug, Serialize, Clone, Deserialize, PartialEq)]
36
- pub enum StatementKind {
37
- // ───── Core Instructions ─────
38
- Tempo,
39
- Bank,
40
- Load {
41
- source: String,
42
- alias: String,
43
- },
44
- Let {
45
- name: String,
46
- },
47
-
48
- // ───── Playback / Scheduling ─────
49
- Trigger {
50
- entity: String,
51
- duration: Duration,
52
- },
53
- Sleep,
54
- Call,
55
- Spawn,
56
- Loop,
57
-
58
- // ───── Structure & Logic ─────
59
- Group,
60
-
61
- // ───── Module System ─────
62
- Include(String),
63
- Export {
64
- names: Vec<String>,
65
- source: String,
66
- },
67
- Import {
68
- names: Vec<String>,
69
- source: String,
70
- },
71
-
72
- // ───── Conditions ─────
73
- If,
74
- Else,
75
- ElseIf,
76
-
77
- // ───── Internal / Utility ─────
78
- Comment,
79
- Indent,
80
- Dedent,
81
- NewLine,
82
-
83
- // ───── Error Handling ─────
84
- Unknown,
85
- Error {
86
- message: String,
87
- },
88
- }
1
+ use crate::core::lexer::token::Token;
2
+
3
+ pub use devalang_types::{Duration, Statement, StatementKind, Value};
4
+
5
+ pub fn unknown_from_token(token: &Token) -> Statement {
6
+ Statement::unknown_with_pos(token.indent, token.line, token.column)
7
+ }
8
+
9
+ pub fn error_from_token(token: Token, message: String) -> Statement {
10
+ Statement::error_with_pos(token.indent, token.line, token.column, message)
11
+ }