@devaloop/devalang 0.0.1-alpha.9 → 0.0.1-beta.2

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 (322) hide show
  1. package/.cargo/config.toml +2 -0
  2. package/.devalang +6 -1
  3. package/.github/workflows/ci.yml +103 -0
  4. package/Cargo.toml +81 -48
  5. package/README.md +137 -154
  6. package/docs/CHANGELOG.md +428 -1
  7. package/docs/CONTRIBUTING.md +101 -0
  8. package/docs/ROADMAP.md +14 -7
  9. package/docs/TODO.md +16 -15
  10. package/examples/automation.deva +42 -0
  11. package/examples/bank.deva +7 -0
  12. package/examples/bus.deva +10 -0
  13. package/examples/duration.deva +9 -0
  14. package/examples/effect.deva +2 -0
  15. package/examples/events.deva +12 -0
  16. package/examples/filter.deva +11 -0
  17. package/examples/function.deva +15 -0
  18. package/examples/index.deva +57 -12
  19. package/examples/lfo.deva +9 -0
  20. package/examples/loop.deva +5 -12
  21. package/examples/pattern.deva +8 -0
  22. package/examples/plugin.deva +16 -0
  23. package/examples/synth.deva +11 -1
  24. package/examples/synth_types.deva +17 -0
  25. package/examples/variables.deva +1 -1
  26. package/out-tsc/bin/index.d.ts +2 -0
  27. package/out-tsc/bin/index.js +51 -7
  28. package/out-tsc/core/functions/index.d.ts +42 -0
  29. package/out-tsc/core/functions/index.js +87 -0
  30. package/out-tsc/core/index.d.ts +6 -0
  31. package/out-tsc/core/index.js +22 -0
  32. package/out-tsc/core/types/index.d.ts +4 -0
  33. package/out-tsc/core/types/index.js +20 -0
  34. package/out-tsc/core/types/plugin.d.ts +18 -0
  35. package/out-tsc/core/types/plugin.js +2 -0
  36. package/out-tsc/core/types/result.d.ts +27 -0
  37. package/out-tsc/core/types/result.js +2 -0
  38. package/out-tsc/core/types/statement.d.ts +106 -0
  39. package/out-tsc/core/types/statement.js +2 -0
  40. package/out-tsc/core/types/value.d.ts +43 -0
  41. package/out-tsc/core/types/value.js +2 -0
  42. package/out-tsc/index.d.ts +7 -0
  43. package/out-tsc/index.js +42 -1
  44. package/out-tsc/pkg/devalang_core.d.ts +15 -0
  45. package/out-tsc/pkg/devalang_core.js +65 -0
  46. package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +34 -0
  47. package/out-tsc/scripts/copy-wasm-dts.d.ts +1 -0
  48. package/out-tsc/scripts/copy-wasm-dts.js +73 -0
  49. package/out-tsc/scripts/postinstall.d.ts +1 -0
  50. package/out-tsc/scripts/postinstall.js +83 -0
  51. package/out-tsc/scripts/version/bump.d.ts +1 -0
  52. package/out-tsc/scripts/version/fetch.d.ts +1 -0
  53. package/out-tsc/scripts/version/index.d.ts +1 -0
  54. package/out-tsc/scripts/version/sync.d.ts +1 -0
  55. package/package.json +28 -7
  56. package/project-version.json +4 -4
  57. package/rust/cli/bank/api.rs +122 -0
  58. package/rust/cli/bank/commands.rs +306 -0
  59. package/rust/cli/bank/mod.rs +29 -0
  60. package/rust/cli/build/commands.rs +153 -0
  61. package/rust/cli/build/mod.rs +2 -0
  62. package/rust/cli/build/process.rs +165 -0
  63. package/rust/cli/check/mod.rs +208 -0
  64. package/rust/cli/discover/commands.rs +253 -0
  65. package/rust/cli/discover/config.rs +111 -0
  66. package/rust/cli/discover/fs.rs +19 -0
  67. package/rust/cli/discover/install.rs +103 -0
  68. package/rust/cli/discover/metadata.rs +48 -0
  69. package/rust/cli/discover/mod.rs +5 -0
  70. package/rust/cli/{init.rs → init/commands.rs} +32 -23
  71. package/rust/cli/init/mod.rs +1 -0
  72. package/rust/cli/install/addon.rs +118 -0
  73. package/rust/cli/install/bank.rs +72 -0
  74. package/rust/cli/install/commands.rs +35 -0
  75. package/rust/cli/install/mod.rs +4 -0
  76. package/rust/cli/install/plugin.rs +80 -0
  77. package/rust/cli/login/commands.rs +124 -0
  78. package/rust/cli/login/mod.rs +1 -0
  79. package/rust/cli/mod.rs +9 -202
  80. package/rust/cli/parser.rs +359 -0
  81. package/rust/cli/play/commands.rs +375 -0
  82. package/rust/cli/play/io.rs +17 -0
  83. package/rust/cli/play/mod.rs +5 -0
  84. package/rust/cli/play/process.rs +159 -0
  85. package/rust/cli/play/realtime.rs +91 -0
  86. package/rust/cli/play/utils.rs +23 -0
  87. package/rust/cli/telemetry/commands.rs +22 -0
  88. package/rust/cli/telemetry/event_creator.rs +80 -0
  89. package/rust/cli/telemetry/mod.rs +3 -0
  90. package/rust/cli/telemetry/send.rs +51 -0
  91. package/rust/cli/{template.rs → template/commands.rs} +17 -5
  92. package/rust/cli/template/mod.rs +1 -0
  93. package/rust/cli/update/commands.rs +6 -0
  94. package/rust/cli/update/mod.rs +1 -0
  95. package/rust/config/driver.rs +112 -0
  96. package/rust/config/mod.rs +3 -16
  97. package/rust/config/ops.rs +26 -0
  98. package/rust/config/settings.rs +101 -0
  99. package/rust/core/audio/engine/driver.rs +220 -0
  100. package/rust/core/audio/engine/export.rs +169 -0
  101. package/rust/core/audio/engine/helpers.rs +178 -0
  102. package/rust/core/audio/engine/mod.rs +56 -0
  103. package/rust/core/audio/engine/notes/dsp.rs +85 -0
  104. package/rust/core/audio/engine/notes/mod.rs +44 -0
  105. package/rust/core/audio/engine/notes/params.rs +294 -0
  106. package/rust/core/audio/engine/sample/insert.rs +199 -0
  107. package/rust/core/audio/engine/sample/mod.rs +40 -0
  108. package/rust/core/audio/engine/sample/padding.rs +170 -0
  109. package/rust/core/audio/evaluator/condition.rs +61 -0
  110. package/rust/core/audio/evaluator/mod.rs +9 -0
  111. package/rust/core/audio/evaluator/numeric.rs +152 -0
  112. package/rust/core/audio/evaluator/rhs.rs +16 -0
  113. package/rust/core/audio/evaluator/string_expr.rs +94 -0
  114. package/rust/core/audio/interpreter/driver.rs +574 -216
  115. package/rust/core/audio/interpreter/mod.rs +2 -12
  116. package/rust/core/audio/interpreter/statements/arrow_call/interprete.rs +175 -0
  117. package/rust/core/audio/interpreter/statements/arrow_call/methods/chord.rs +384 -0
  118. package/rust/core/audio/interpreter/statements/arrow_call/methods/mod.rs +2 -0
  119. package/rust/core/audio/interpreter/statements/arrow_call/methods/note.rs +316 -0
  120. package/rust/core/audio/interpreter/statements/arrow_call/mod.rs +3 -0
  121. package/rust/core/audio/interpreter/statements/arrow_call/types/arp.rs +192 -0
  122. package/rust/core/audio/interpreter/statements/arrow_call/types/mod.rs +24 -0
  123. package/rust/core/audio/interpreter/statements/arrow_call/types/pad.rs +116 -0
  124. package/rust/core/audio/interpreter/statements/arrow_call/types/pluck.rs +97 -0
  125. package/rust/core/audio/interpreter/statements/arrow_call/types/sub.rs +100 -0
  126. package/rust/core/audio/interpreter/statements/automate.rs +16 -0
  127. package/rust/core/audio/interpreter/statements/call.rs +295 -0
  128. package/rust/core/audio/interpreter/{condition.rs → statements/condition.rs} +72 -69
  129. package/rust/core/audio/interpreter/statements/function.rs +24 -0
  130. package/rust/core/audio/interpreter/statements/let_.rs +36 -0
  131. package/rust/core/audio/interpreter/statements/load.rs +17 -0
  132. package/rust/core/audio/interpreter/statements/loop_.rs +115 -0
  133. package/rust/core/audio/interpreter/statements/mod.rs +12 -0
  134. package/rust/core/audio/interpreter/statements/sleep.rs +28 -0
  135. package/rust/core/audio/interpreter/statements/spawn.rs +253 -0
  136. package/rust/core/audio/interpreter/statements/tempo.rs +40 -0
  137. package/rust/core/audio/interpreter/statements/trigger.rs +239 -0
  138. package/rust/core/audio/loader/mod.rs +1 -1
  139. package/rust/core/audio/loader/trigger.rs +98 -52
  140. package/rust/core/audio/mod.rs +2 -2
  141. package/rust/core/audio/player.rs +28 -12
  142. package/rust/core/audio/special/easing.rs +189 -0
  143. package/rust/core/audio/special/env.rs +45 -0
  144. package/rust/core/audio/special/math.rs +134 -0
  145. package/rust/core/audio/special/mod.rs +9 -0
  146. package/rust/core/audio/special/modulator.rs +143 -0
  147. package/rust/core/builder/mod.rs +129 -80
  148. package/rust/core/debugger/lexer.rs +4 -4
  149. package/rust/core/debugger/logs.rs +52 -0
  150. package/rust/core/debugger/mod.rs +11 -2
  151. package/rust/core/debugger/preprocessor.rs +4 -4
  152. package/rust/core/debugger/store.rs +38 -25
  153. package/rust/core/error/mod.rs +221 -12
  154. package/rust/core/lexer/driver.rs +59 -0
  155. package/rust/core/lexer/handler/arrow.rs +62 -11
  156. package/rust/core/lexer/handler/at.rs +5 -5
  157. package/rust/core/lexer/handler/brace.rs +11 -11
  158. package/rust/core/lexer/handler/colon.rs +5 -5
  159. package/rust/core/lexer/handler/comment.rs +3 -3
  160. package/rust/core/lexer/handler/dot.rs +6 -6
  161. package/rust/core/lexer/handler/driver.rs +143 -32
  162. package/rust/core/lexer/handler/identifier.rs +11 -5
  163. package/rust/core/lexer/handler/indent.rs +18 -4
  164. package/rust/core/lexer/handler/mod.rs +6 -5
  165. package/rust/core/lexer/handler/newline.rs +3 -3
  166. package/rust/core/lexer/handler/number.rs +5 -5
  167. package/rust/core/lexer/handler/operator.rs +5 -3
  168. package/rust/core/lexer/handler/parenthesis.rs +41 -0
  169. package/rust/core/lexer/handler/slash.rs +21 -0
  170. package/rust/core/lexer/handler/string.rs +3 -3
  171. package/rust/core/lexer/mod.rs +1 -49
  172. package/rust/core/lexer/token.rs +17 -12
  173. package/rust/core/mod.rs +9 -10
  174. package/rust/core/parser/driver/block.rs +111 -0
  175. package/rust/core/parser/driver/cursor.rs +82 -0
  176. package/rust/core/parser/driver/driver_impl.rs +139 -0
  177. package/rust/core/parser/driver/mod.rs +6 -0
  178. package/rust/core/parser/driver/parse_array.rs +120 -0
  179. package/rust/core/parser/driver/parse_map.rs +223 -0
  180. package/rust/core/parser/driver/parser.rs +160 -0
  181. package/rust/core/parser/handler/arrow_call.rs +277 -126
  182. package/rust/core/parser/handler/at.rs +142 -25
  183. package/rust/core/parser/handler/bank.rs +83 -20
  184. package/rust/core/parser/handler/condition.rs +14 -5
  185. package/rust/core/parser/handler/dot.rs +111 -75
  186. package/rust/core/parser/handler/identifier/automate.rs +254 -0
  187. package/rust/core/parser/handler/identifier/call.rs +74 -24
  188. package/rust/core/parser/handler/identifier/emit.rs +70 -0
  189. package/rust/core/parser/handler/identifier/function.rs +113 -0
  190. package/rust/core/parser/handler/identifier/group.rs +28 -14
  191. package/rust/core/parser/handler/identifier/let_.rs +61 -21
  192. package/rust/core/parser/handler/identifier/mod.rs +24 -20
  193. package/rust/core/parser/handler/identifier/on.rs +107 -0
  194. package/rust/core/parser/handler/identifier/print.rs +49 -0
  195. package/rust/core/parser/handler/identifier/sleep.rs +77 -14
  196. package/rust/core/parser/handler/identifier/spawn.rs +81 -31
  197. package/rust/core/parser/handler/identifier/synth.rs +102 -32
  198. package/rust/core/parser/handler/loop_.rs +144 -22
  199. package/rust/core/parser/handler/mod.rs +6 -5
  200. package/rust/core/parser/handler/pattern.rs +74 -0
  201. package/rust/core/parser/handler/tempo.rs +67 -9
  202. package/rust/core/parser/mod.rs +3 -4
  203. package/rust/core/parser/statement.rs +6 -92
  204. package/rust/core/plugin/loader.rs +137 -0
  205. package/rust/core/plugin/mod.rs +2 -0
  206. package/rust/core/plugin/runner/mod.rs +11 -0
  207. package/rust/core/plugin/runner/non_wasm.rs +297 -0
  208. package/rust/core/plugin/runner/wasm32.rs +43 -0
  209. package/rust/core/preprocessor/loader/inject.rs +278 -0
  210. package/rust/core/preprocessor/loader/loader_helpers.rs +110 -0
  211. package/rust/core/preprocessor/loader/mod.rs +235 -0
  212. package/rust/core/preprocessor/mod.rs +4 -4
  213. package/rust/core/preprocessor/module.rs +55 -50
  214. package/rust/core/preprocessor/processor/handlers.rs +107 -0
  215. package/rust/core/preprocessor/processor/mod.rs +1 -0
  216. package/rust/core/preprocessor/resolver/bank.rs +14 -12
  217. package/rust/core/preprocessor/resolver/call.rs +106 -105
  218. package/rust/core/preprocessor/resolver/condition.rs +13 -10
  219. package/rust/core/preprocessor/resolver/driver.rs +145 -48
  220. package/rust/core/preprocessor/resolver/function.rs +69 -0
  221. package/rust/core/preprocessor/resolver/group.rs +122 -61
  222. package/rust/core/preprocessor/resolver/let_.rs +13 -12
  223. package/rust/core/preprocessor/resolver/loop_.rs +240 -13
  224. package/rust/core/preprocessor/resolver/mod.rs +8 -6
  225. package/rust/core/preprocessor/resolver/pattern.rs +83 -0
  226. package/rust/core/preprocessor/resolver/spawn.rs +83 -42
  227. package/rust/core/preprocessor/resolver/synth.rs +15 -11
  228. package/rust/core/preprocessor/resolver/tempo.rs +13 -14
  229. package/rust/core/preprocessor/resolver/trigger.rs +32 -28
  230. package/rust/core/preprocessor/resolver/value.rs +111 -13
  231. package/rust/core/store/global.rs +57 -39
  232. package/rust/core/store/mod.rs +0 -3
  233. package/rust/lib.rs +323 -117
  234. package/rust/main.rs +388 -65
  235. package/rust/types/Cargo.toml +11 -0
  236. package/rust/types/src/addons.rs +55 -0
  237. package/rust/types/src/ast.rs +202 -0
  238. package/rust/types/src/config.rs +84 -0
  239. package/rust/types/src/lib.rs +15 -0
  240. package/rust/types/src/plugin.rs +20 -0
  241. package/rust/types/src/store.rs +139 -0
  242. package/rust/types/src/telemetry.rs +85 -0
  243. package/rust/utils/Cargo.toml +26 -0
  244. package/rust/utils/src/error.rs +186 -0
  245. package/rust/utils/src/file.rs +94 -0
  246. package/rust/utils/src/first_usage.rs +97 -0
  247. package/rust/utils/{mod.rs → src/lib.rs} +6 -3
  248. package/rust/utils/{logger.rs → src/logger.rs} +94 -17
  249. package/rust/utils/src/path.rs +129 -0
  250. package/rust/utils/src/signature.rs +41 -0
  251. package/rust/utils/{spinner.rs → src/spinner.rs} +7 -8
  252. package/rust/utils/src/version.rs +27 -0
  253. package/rust/utils/{watcher.rs → src/watcher.rs} +17 -4
  254. package/rust/web/api.rs +5 -0
  255. package/rust/web/cdn.rs +34 -0
  256. package/rust/web/mod.rs +3 -0
  257. package/rust/web/sso.rs +5 -0
  258. package/templates/minimal/README.md +143 -127
  259. package/templates/welcome/README.md +143 -127
  260. package/templates/welcome/src/index.deva +56 -8
  261. package/templates/welcome/src/variables.deva +2 -4
  262. package/tests/integration.rs +21 -0
  263. package/tests/rust/cli_check_build.rs +21 -0
  264. package/tests/rust/cli_help.rs +12 -0
  265. package/tests/rust/cli_template_list.rs +10 -0
  266. package/tests/rust/cli_version.rs +11 -0
  267. package/tests/typescript/index.spec.ts +136 -0
  268. package/tests/typescript/playhead.spec.ts +36 -0
  269. package/tests/typescript/render_e2e.spec.ts +77 -0
  270. package/tsconfig.json +12 -10
  271. package/typescript/bin/index.ts +19 -5
  272. package/typescript/core/functions/index.ts +94 -0
  273. package/typescript/core/index.ts +6 -0
  274. package/typescript/core/types/index.ts +4 -0
  275. package/typescript/core/types/plugin.ts +19 -0
  276. package/typescript/core/types/result.ts +29 -0
  277. package/typescript/core/types/statement.ts +47 -0
  278. package/typescript/core/types/value.ts +29 -0
  279. package/typescript/index.ts +8 -1
  280. package/typescript/pkg/devalang_core.d.ts +4 -0
  281. package/typescript/pkg/devalang_core.ts +65 -0
  282. package/typescript/scripts/copy-wasm-dts.ts +41 -0
  283. package/typescript/scripts/postinstall.ts +85 -0
  284. package/typescript/scripts/version/bump.ts +0 -1
  285. package/typescript/scripts/version/index.ts +0 -1
  286. package/docs/COMMANDS.md +0 -85
  287. package/docs/CONFIG.md +0 -30
  288. package/docs/SYNTAX.md +0 -210
  289. package/out-tsc/bin/devalang.exe +0 -0
  290. package/out-tsc/scripts/postbuild.js +0 -11
  291. package/rust/cli/build.rs +0 -137
  292. package/rust/cli/check.rs +0 -117
  293. package/rust/cli/play.rs +0 -193
  294. package/rust/config/loader.rs +0 -13
  295. package/rust/core/audio/engine.rs +0 -203
  296. package/rust/core/audio/evaluator.rs +0 -31
  297. package/rust/core/audio/interpreter/arrow_call.rs +0 -129
  298. package/rust/core/audio/interpreter/call.rs +0 -64
  299. package/rust/core/audio/interpreter/let_.rs +0 -19
  300. package/rust/core/audio/interpreter/load.rs +0 -18
  301. package/rust/core/audio/interpreter/loop_.rs +0 -67
  302. package/rust/core/audio/interpreter/sleep.rs +0 -36
  303. package/rust/core/audio/interpreter/spawn.rs +0 -66
  304. package/rust/core/audio/interpreter/tempo.rs +0 -16
  305. package/rust/core/audio/interpreter/trigger.rs +0 -69
  306. package/rust/core/audio/renderer.rs +0 -54
  307. package/rust/core/parser/driver.rs +0 -331
  308. package/rust/core/preprocessor/loader.rs +0 -193
  309. package/rust/core/preprocessor/processor.rs +0 -76
  310. package/rust/core/shared/duration.rs +0 -8
  311. package/rust/core/shared/mod.rs +0 -2
  312. package/rust/core/shared/value.rs +0 -18
  313. package/rust/core/store/export.rs +0 -28
  314. package/rust/core/store/import.rs +0 -28
  315. package/rust/core/store/variable.rs +0 -28
  316. package/rust/core/utils/mod.rs +0 -2
  317. package/rust/core/utils/path.rs +0 -31
  318. package/rust/core/utils/validation.rs +0 -37
  319. package/rust/utils/file.rs +0 -35
  320. package/rust/utils/signature.rs +0 -17
  321. package/rust/utils/version.rs +0 -15
  322. package/typescript/scripts/postbuild.ts +0 -8
@@ -1,20 +1,20 @@
1
1
  use std::collections::HashMap;
2
2
 
3
3
  use crate::core::{
4
- lexer::token::{ Token, TokenKind },
4
+ lexer::token::{Token, TokenKind},
5
5
  parser::{
6
- driver::Parser,
7
- handler::identifier::synth::parse_synth_token,
8
- statement::{ Statement, StatementKind },
6
+ driver::parser::Parser,
7
+ handler::{dot::parse_dot_token, identifier::synth::parse_synth_token},
8
+ statement::{Statement, StatementKind},
9
9
  },
10
- shared::value::Value,
11
10
  store::global::GlobalStore,
12
11
  };
12
+ use devalang_types::Value;
13
13
 
14
14
  pub fn parse_let_token(
15
15
  parser: &mut Parser,
16
16
  current_token: Token,
17
- global_store: &mut GlobalStore
17
+ global_store: &mut GlobalStore,
18
18
  ) -> Statement {
19
19
  parser.advance(); // consume "let"
20
20
 
@@ -23,23 +23,49 @@ pub fn parse_let_token(
23
23
  parser.advance();
24
24
  token.lexeme.clone()
25
25
  } else {
26
- return Statement::error(token, "Expected identifier after 'let'".to_string());
26
+ return crate::core::parser::statement::error_from_token(
27
+ token,
28
+ "Expected identifier after 'let'".to_string(),
29
+ );
27
30
  }
28
31
  } else {
29
- return Statement::error(current_token, "Expected identifier after 'let'".to_string());
32
+ return crate::core::parser::statement::error_from_token(
33
+ current_token,
34
+ "Expected identifier after 'let'".to_string(),
35
+ );
30
36
  };
31
37
 
32
38
  if !parser.match_token(TokenKind::Equals) {
33
- return Statement::error(current_token, "Expected '=' after identifier".to_string());
39
+ return crate::core::parser::statement::error_from_token(
40
+ current_token,
41
+ "Expected '=' after identifier".to_string(),
42
+ );
34
43
  }
35
44
 
36
- if let Some(token) = parser.peek_clone() {
37
- if token.kind == TokenKind::Synth {
38
- let synth_stmt = parse_synth_token(parser, token.clone(), global_store);
39
-
45
+ // If RHS begins with '$' or contains expression tokens ('+', '-', '*', '/', '(', '['),
46
+ // collect the rest of the line as a raw expression string.
47
+ if let Some(tok) = parser.peek_clone() {
48
+ let line = tok.line;
49
+ if tok.lexeme.starts_with('$')
50
+ || matches!(
51
+ tok.kind,
52
+ TokenKind::Identifier | TokenKind::Number | TokenKind::LParen | TokenKind::LBracket
53
+ )
54
+ {
55
+ // Collect tokens until end of the current line
56
+ let collected = parser.collect_until(|t| {
57
+ t.line != line || matches!(t.kind, TokenKind::Newline | TokenKind::EOF)
58
+ });
59
+ let mut text = String::new();
60
+ for t in collected.iter() {
61
+ if matches!(t.kind, TokenKind::Newline | TokenKind::EOF) {
62
+ break;
63
+ }
64
+ text.push_str(&t.lexeme);
65
+ }
40
66
  return Statement {
41
67
  kind: StatementKind::Let { name: identifier },
42
- value: synth_stmt.value,
68
+ value: Value::String(text.trim().to_string()),
43
69
  indent: current_token.indent,
44
70
  line: current_token.line,
45
71
  column: current_token.column,
@@ -48,6 +74,14 @@ pub fn parse_let_token(
48
74
  }
49
75
 
50
76
  let value = match parser.peek_clone() {
77
+ Some(token) if token.kind == TokenKind::Dot => {
78
+ let dot_stmt = parse_dot_token(parser, global_store);
79
+ Value::Statement(Box::new(dot_stmt))
80
+ }
81
+ Some(token) if token.kind == TokenKind::Synth => {
82
+ let synth_stmt = parse_synth_token(parser, token.clone(), global_store);
83
+ Value::Statement(Box::new(synth_stmt))
84
+ }
51
85
  Some(token) if token.kind == TokenKind::Identifier => {
52
86
  parser.advance();
53
87
  Value::Identifier(token.lexeme.clone())
@@ -65,7 +99,8 @@ pub fn parse_let_token(
65
99
  Value::Boolean(token.lexeme.parse().unwrap_or(false))
66
100
  }
67
101
  Some(token) if token.kind == TokenKind::LBrace => {
68
- parser.advance(); // consume '{'
102
+ parser.advance();
103
+
69
104
  let mut map = HashMap::new();
70
105
 
71
106
  while let Some(key_token) = parser.peek_clone() {
@@ -75,14 +110,17 @@ pub fn parse_let_token(
75
110
  }
76
111
 
77
112
  if key_token.kind != TokenKind::Identifier {
78
- return Statement::error(token, "Expected key identifier in map".to_string());
113
+ return crate::core::parser::statement::error_from_token(
114
+ token,
115
+ "Expected key identifier in map".to_string(),
116
+ );
79
117
  }
80
118
  parser.advance();
81
119
  let key = key_token.lexeme.clone();
82
120
 
83
121
  if !parser.match_token(TokenKind::Colon) {
84
122
  let message = format!("Expected ':' after key '{}'", key);
85
- return Statement::error(token, message);
123
+ return crate::core::parser::statement::error_from_token(token, message);
86
124
  }
87
125
 
88
126
  let val = match parser.peek_clone() {
@@ -103,7 +141,7 @@ pub fn parse_let_token(
103
141
 
104
142
  if val == Value::Null {
105
143
  let message = format!("Invalid value for key '{}'", key);
106
- return Statement::error(token, message);
144
+ return crate::core::parser::statement::error_from_token(token, message);
107
145
  }
108
146
 
109
147
  map.insert(key, val);
@@ -117,9 +155,11 @@ pub fn parse_let_token(
117
155
 
118
156
  Value::Map(map)
119
157
  }
120
- other => {
121
- let message = format!("Unexpected value token in let: {:?}", other);
122
- return Statement::error(current_token, message);
158
+ _ => {
159
+ return crate::core::parser::statement::error_from_token(
160
+ current_token,
161
+ "Unhandled value type after '='".to_string(),
162
+ );
123
163
  }
124
164
  };
125
165
 
@@ -1,22 +1,23 @@
1
- pub mod let_;
2
- pub mod group;
1
+ pub mod automate;
3
2
  pub mod call;
4
- pub mod spawn;
3
+ pub mod emit;
4
+ pub mod function;
5
+ pub mod group;
6
+ pub mod let_;
7
+ pub mod on;
8
+ pub mod print;
5
9
  pub mod sleep;
10
+ pub mod spawn;
6
11
  pub mod synth;
7
12
 
8
13
  use crate::core::{
9
14
  parser::{
10
- driver::Parser,
11
- handler::{
12
- identifier::{
13
- call::parse_call_token,
14
- group::parse_group_token,
15
- let_::parse_let_token,
16
- sleep::parse_sleep_token,
17
- spawn::parse_spawn_token,
18
- synth::parse_synth_token
19
- },
15
+ driver::parser::Parser,
16
+ handler::identifier::{
17
+ automate::parse_automate_token, call::parse_call_token, emit::parse_emit_token,
18
+ group::parse_group_token, let_::parse_let_token, on::parse_on_token,
19
+ print::parse_print_token, sleep::parse_sleep_token, spawn::parse_spawn_token,
20
+ synth::parse_synth_token,
20
21
  },
21
22
  statement::Statement,
22
23
  },
@@ -31,21 +32,24 @@ pub fn parse_identifier_token(parser: &mut Parser, global_store: &mut GlobalStor
31
32
  let current_token_clone = current_token.clone();
32
33
  let current_token_lexeme = current_token_clone.lexeme.clone();
33
34
 
34
- let statement = match current_token_lexeme.as_str() {
35
+ match current_token_lexeme.as_str() {
35
36
  "let" => parse_let_token(parser, current_token_clone, global_store),
36
37
  "group" => parse_group_token(parser, current_token_clone, global_store),
37
38
  "call" => parse_call_token(parser, current_token_clone, global_store),
38
39
  "spawn" => parse_spawn_token(parser, current_token_clone, global_store),
39
40
  "sleep" => parse_sleep_token(parser, current_token_clone, global_store),
40
41
  "synth" => parse_synth_token(parser, current_token_clone, global_store),
42
+ "automate" => parse_automate_token(parser, current_token_clone, global_store),
43
+ "print" => parse_print_token(parser, current_token_clone, global_store),
44
+ "on" => parse_on_token(parser, global_store),
45
+ "emit" => parse_emit_token(parser, current_token_clone, global_store),
41
46
  _ => {
42
47
  parser.advance(); // consume identifier
43
48
 
44
- println!("Unrecognized identifier: {}", current_token_lexeme);
45
-
46
- return Statement::error(current_token_clone, "Unexpected identifier".to_string());
49
+ crate::core::parser::statement::error_from_token(
50
+ current_token_clone,
51
+ "Unexpected identifier".to_string(),
52
+ )
47
53
  }
48
- };
49
-
50
- return statement;
54
+ }
51
55
  }
@@ -0,0 +1,107 @@
1
+ use devalang_types::Value;
2
+
3
+ use crate::core::{
4
+ lexer::token::TokenKind,
5
+ parser::{
6
+ driver::parser::Parser,
7
+ statement::{Statement, StatementKind},
8
+ },
9
+ store::global::GlobalStore,
10
+ };
11
+
12
+ pub fn parse_on_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
13
+ // consume 'on'
14
+ let on_tok = match parser.peek_clone() {
15
+ Some(tok) => tok,
16
+ None => return Statement::unknown(),
17
+ };
18
+ parser.advance();
19
+
20
+ // Expect event name identifier
21
+ let event_tok = match parser.peek_clone() {
22
+ Some(tok) if tok.kind == TokenKind::Identifier => tok,
23
+ Some(other) => {
24
+ return crate::core::parser::statement::error_from_token(
25
+ other,
26
+ "Expected event name after 'on'".to_string(),
27
+ );
28
+ }
29
+ None => {
30
+ return crate::core::parser::statement::error_from_token(
31
+ on_tok,
32
+ "Expected event name after 'on'".to_string(),
33
+ );
34
+ }
35
+ };
36
+ let event_name = event_tok.lexeme.clone();
37
+ parser.advance();
38
+
39
+ // Optional parenthesized args on same line
40
+ let mut args: Option<Vec<Value>> = None;
41
+ if parser.peek_kind() == Some(TokenKind::LParen) {
42
+ parser.advance(); // '('
43
+ let mut collected: Vec<Value> = Vec::new();
44
+ // Collect tokens until ')', supporting numbers and identifiers separated by comma
45
+ while let Some(tok) = parser.peek_clone() {
46
+ match tok.kind {
47
+ TokenKind::RParen => {
48
+ parser.advance();
49
+ break;
50
+ }
51
+ TokenKind::Number => {
52
+ parser.advance();
53
+ collected.push(Value::Number(tok.lexeme.parse().unwrap_or(0.0)));
54
+ }
55
+ TokenKind::Identifier => {
56
+ parser.advance();
57
+ collected.push(Value::Identifier(tok.lexeme));
58
+ }
59
+ TokenKind::Comma => {
60
+ parser.advance();
61
+ }
62
+ TokenKind::Whitespace | TokenKind::Newline => {
63
+ parser.advance();
64
+ }
65
+ _ => {
66
+ break;
67
+ }
68
+ }
69
+ }
70
+ if !collected.is_empty() {
71
+ args = Some(collected);
72
+ }
73
+ }
74
+
75
+ // Expect ':' then block
76
+ if parser.peek_kind() != Some(TokenKind::Colon) {
77
+ return crate::core::parser::statement::error_from_token(
78
+ event_tok,
79
+ "Expected ':' after event name".to_string(),
80
+ );
81
+ }
82
+ parser.advance(); // consume ':'
83
+
84
+ let base_indent = on_tok.indent;
85
+ let block_tokens = parser.collect_block_tokens(base_indent);
86
+ // Parse body within current store context
87
+ let body = parser.parse_block(block_tokens, _global_store);
88
+
89
+ let stmt = Statement {
90
+ kind: StatementKind::On {
91
+ event: event_name,
92
+ args,
93
+ body,
94
+ },
95
+ value: Value::Null,
96
+ indent: on_tok.indent,
97
+ line: on_tok.line,
98
+ column: on_tok.column,
99
+ };
100
+
101
+ // Register in global store for later emission
102
+ if let StatementKind::On { event, .. } = &stmt.kind {
103
+ _global_store.register_event_handler(event, stmt.clone());
104
+ }
105
+
106
+ stmt
107
+ }
@@ -0,0 +1,49 @@
1
+ use crate::core::{
2
+ lexer::token::{Token, TokenKind},
3
+ parser::{
4
+ driver::parser::Parser,
5
+ statement::{Statement, StatementKind},
6
+ },
7
+ store::global::GlobalStore,
8
+ };
9
+ use devalang_types::Value;
10
+
11
+ pub fn parse_print_token(
12
+ parser: &mut Parser,
13
+ current_token: Token,
14
+ _global_store: &mut GlobalStore,
15
+ ) -> Statement {
16
+ // consume 'print'
17
+ parser.advance();
18
+
19
+ let collected = parser.collect_until(|t| matches!(t.kind, TokenKind::Newline | TokenKind::EOF));
20
+ // Accept: print <identifier|string|number|expression>
21
+ let value = if collected.len() == 1 {
22
+ match collected[0].kind {
23
+ TokenKind::Identifier => Value::Identifier(collected[0].lexeme.clone()),
24
+ TokenKind::String => Value::String(collected[0].lexeme.clone()),
25
+ TokenKind::Number => {
26
+ let n = collected[0].lexeme.parse::<f32>().unwrap_or(0.0);
27
+ Value::Number(n)
28
+ }
29
+ _ => Value::String(collected[0].lexeme.clone()),
30
+ }
31
+ } else {
32
+ // Join tokens with spaces to preserve readability for expressions/text
33
+ let text = collected
34
+ .iter()
35
+ .filter(|t| !matches!(t.kind, TokenKind::Newline | TokenKind::EOF))
36
+ .map(|t| t.lexeme.clone())
37
+ .collect::<Vec<_>>()
38
+ .join(" ");
39
+ Value::String(text.trim().to_string())
40
+ };
41
+
42
+ Statement {
43
+ kind: StatementKind::Print,
44
+ value,
45
+ indent: current_token.indent,
46
+ line: current_token.line,
47
+ column: current_token.column,
48
+ }
49
+ }
@@ -1,33 +1,96 @@
1
+ use devalang_types::Value;
2
+
1
3
  use crate::core::{
2
- lexer::token::{ Token, TokenKind },
3
- parser::{ statement::{ Statement, StatementKind }, driver::Parser },
4
- shared::value::Value,
4
+ lexer::token::{Token, TokenKind},
5
+ parser::{
6
+ driver::parser::Parser,
7
+ statement::{Statement, StatementKind},
8
+ },
5
9
  store::global::GlobalStore,
6
10
  };
7
11
 
8
12
  pub fn parse_sleep_token(
9
13
  parser: &mut Parser,
10
14
  current_token: Token,
11
- global_store: &mut GlobalStore
15
+ _global_store: &mut GlobalStore,
12
16
  ) -> Statement {
13
17
  parser.advance(); // consume "sleep"
14
18
 
15
- let duration = if let Some(token) = parser.peek_clone() {
16
- if token.kind == TokenKind::Number {
17
- parser.advance();
18
- token.lexeme.parse().unwrap_or(0.0)
19
- } else {
20
- return Statement::error(token, "Expected number after 'sleep'".to_string());
19
+ // Accept number, decimal, fraction like 1/4 (-> Duration::Beat), string, or identifier
20
+ let duration_value = if let Some(token) = parser.peek_clone() {
21
+ match token.kind {
22
+ TokenKind::Number => {
23
+ let mut num = token.lexeme.clone();
24
+ parser.advance();
25
+ // decimal part
26
+ if let Some(dot) = parser.peek_clone() {
27
+ if dot.kind == TokenKind::Dot {
28
+ if let Some(next) = parser.peek_nth(1).cloned() {
29
+ if next.kind == TokenKind::Number {
30
+ parser.advance(); // consume dot
31
+ parser.advance(); // consume next number
32
+ num.push('.');
33
+ num.push_str(&next.lexeme);
34
+ }
35
+ }
36
+ }
37
+ }
38
+
39
+ // fraction form 1/4 -> Duration::Beat("1/4")
40
+ if let Some(slash) = parser.peek_clone() {
41
+ if slash.kind == TokenKind::Slash {
42
+ parser.advance();
43
+ if let Some(den) = parser.peek_clone() {
44
+ if den.kind == TokenKind::Number || den.kind == TokenKind::Identifier {
45
+ let frac = format!("{}/{}", num, den.lexeme);
46
+ parser.advance();
47
+ Value::Duration(devalang_types::Duration::Beat(frac))
48
+ } else {
49
+ return crate::core::parser::statement::error_from_token(
50
+ slash,
51
+ "Expected denominator after '/' in sleep".to_string(),
52
+ );
53
+ }
54
+ } else {
55
+ return crate::core::parser::statement::error_from_token(
56
+ slash,
57
+ "Expected denominator after '/' in sleep".to_string(),
58
+ );
59
+ }
60
+ } else {
61
+ Value::Number(num.parse().unwrap_or(0.0))
62
+ }
63
+ } else {
64
+ Value::Number(num.parse().unwrap_or(0.0))
65
+ }
66
+ }
67
+ TokenKind::String => {
68
+ parser.advance();
69
+ Value::String(token.lexeme.clone())
70
+ }
71
+ TokenKind::Identifier => {
72
+ parser.advance();
73
+ Value::Identifier(token.lexeme.clone())
74
+ }
75
+ _ => {
76
+ return crate::core::parser::statement::error_from_token(
77
+ token,
78
+ "Expected duration after 'sleep'".to_string(),
79
+ );
80
+ }
21
81
  }
22
82
  } else {
23
- return Statement::error(current_token, "Expected number after 'sleep'".to_string());
83
+ return crate::core::parser::statement::error_from_token(
84
+ current_token,
85
+ "Expected duration after 'sleep'".to_string(),
86
+ );
24
87
  };
25
88
 
26
- return Statement {
89
+ Statement {
27
90
  kind: StatementKind::Sleep,
28
- value: Value::Number(duration),
91
+ value: duration_value,
29
92
  indent: current_token.indent,
30
93
  line: current_token.line,
31
94
  column: current_token.column,
32
- };
95
+ }
33
96
  }
@@ -1,41 +1,91 @@
1
1
  use crate::core::{
2
- lexer::token::{ Token, TokenKind },
3
- parser::{ statement::{ Statement, StatementKind }, driver::Parser },
4
- shared::value::Value,
2
+ lexer::token::{Token, TokenKind},
3
+ parser::{
4
+ driver::parser::Parser,
5
+ statement::{Statement, StatementKind},
6
+ },
5
7
  store::global::GlobalStore,
6
8
  };
9
+ use devalang_types::Value;
7
10
 
8
11
  pub fn parse_spawn_token(
9
12
  parser: &mut Parser,
10
13
  current_token: Token,
11
- global_store: &mut GlobalStore
14
+ _global_store: &mut GlobalStore,
12
15
  ) -> Statement {
13
- parser.advance(); // consume "spawn"
14
-
15
- let value = if let Some(token) = parser.peek_clone() {
16
- parser.advance();
17
- match token.kind {
18
- TokenKind::Identifier => Value::Identifier(token.lexeme.clone()),
19
- TokenKind::String => Value::String(token.lexeme.clone()),
20
- _ => {
21
- return Statement::error(
22
- token,
23
- "Expected identifier or string after 'spawn'".to_string()
24
- );
25
- }
26
- }
27
- } else {
28
- return Statement::error(
16
+ parser.advance(); // consume "spawn"
17
+
18
+ // Expect function name
19
+ let name_token = match parser.peek_clone() {
20
+ Some(t) => t,
21
+ None => {
22
+ return crate::core::parser::statement::error_from_token(
29
23
  current_token,
30
- "Expected identifier or string after 'spawn'".to_string()
24
+ "Expected function name after 'spawn'".to_string(),
31
25
  );
32
- };
33
-
34
- return Statement {
35
- kind: StatementKind::Spawn,
36
- value,
37
- indent: current_token.indent,
38
- line: current_token.line,
39
- column: current_token.column,
40
- };
41
- }
26
+ }
27
+ };
28
+
29
+ if name_token.kind != TokenKind::Identifier {
30
+ return crate::core::parser::statement::error_from_token(
31
+ name_token,
32
+ "Expected function name to be an identifier".to_string(),
33
+ );
34
+ }
35
+
36
+ let func_name = name_token.lexeme.clone();
37
+ parser.advance(); // consume function name
38
+
39
+ // Expect '('
40
+ let mut args: Vec<Value> = Vec::new();
41
+ if let Some(open_paren) = parser.peek_clone() {
42
+ if open_paren.kind == TokenKind::LParen {
43
+ parser.advance(); // consume '('
44
+
45
+ // Collect args until ')'
46
+ while let Some(token) = parser.peek_clone() {
47
+ if token.kind == TokenKind::RParen {
48
+ parser.advance(); // consume ')'
49
+ break;
50
+ }
51
+
52
+ match token.kind {
53
+ TokenKind::Number => {
54
+ if let Ok(num) = token.lexeme.parse::<f32>() {
55
+ args.push(Value::Number(num));
56
+ }
57
+ parser.advance();
58
+ }
59
+ TokenKind::String => {
60
+ args.push(Value::String(token.lexeme.clone()));
61
+ parser.advance();
62
+ }
63
+ TokenKind::Identifier => {
64
+ args.push(Value::Identifier(token.lexeme.clone()));
65
+ parser.advance();
66
+ }
67
+ TokenKind::Comma => {
68
+ parser.advance(); // skip comma
69
+ }
70
+ _ => {
71
+ return crate::core::parser::statement::error_from_token(
72
+ token,
73
+ "Unexpected token in spawn arguments".to_string(),
74
+ );
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+
81
+ Statement {
82
+ kind: StatementKind::Spawn {
83
+ name: func_name,
84
+ args,
85
+ },
86
+ value: Value::Null,
87
+ indent: current_token.indent,
88
+ line: current_token.line,
89
+ column: current_token.column,
90
+ }
91
+ }