@devaloop/devalang 0.0.1-alpha.16-hotfix.3 → 0.0.1-alpha.18

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 (239) hide show
  1. package/.cargo/config.toml +2 -0
  2. package/.devalang +10 -10
  3. package/.github/workflows/ci.yml +0 -1
  4. package/Cargo.toml +18 -2
  5. package/README.md +82 -34
  6. package/docs/CHANGELOG.md +91 -0
  7. package/docs/ROADMAP.md +7 -4
  8. package/docs/TODO.md +1 -1
  9. package/examples/index.deva +55 -35
  10. package/examples/pattern.deva +5 -5
  11. package/out-tsc/bin/index.d.ts +2 -0
  12. package/out-tsc/core/functions/index.d.ts +37 -0
  13. package/out-tsc/core/functions/index.js +76 -0
  14. package/out-tsc/core/index.d.ts +6 -0
  15. package/out-tsc/core/index.js +22 -0
  16. package/out-tsc/core/types/index.d.ts +4 -0
  17. package/out-tsc/core/types/index.js +20 -0
  18. package/out-tsc/core/types/plugin.d.ts +18 -0
  19. package/out-tsc/core/types/plugin.js +2 -0
  20. package/out-tsc/core/types/result.d.ts +27 -0
  21. package/out-tsc/core/types/result.js +2 -0
  22. package/out-tsc/core/types/statement.d.ts +106 -0
  23. package/out-tsc/core/types/statement.js +2 -0
  24. package/out-tsc/core/types/value.d.ts +43 -0
  25. package/out-tsc/core/types/value.js +2 -0
  26. package/out-tsc/index.d.ts +7 -0
  27. package/out-tsc/index.js +41 -2
  28. package/out-tsc/pkg/devalang_core.d.ts +7 -0
  29. package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +33 -0
  30. package/out-tsc/scripts/copy-wasm-dts.d.ts +1 -0
  31. package/out-tsc/scripts/copy-wasm-dts.js +73 -0
  32. package/out-tsc/scripts/postinstall.d.ts +1 -0
  33. package/out-tsc/scripts/postinstall.js +33 -23
  34. package/out-tsc/scripts/version/bump.d.ts +1 -0
  35. package/out-tsc/scripts/version/fetch.d.ts +1 -0
  36. package/out-tsc/scripts/version/index.d.ts +1 -0
  37. package/out-tsc/scripts/version/sync.d.ts +1 -0
  38. package/package.json +16 -4
  39. package/project-version.json +3 -3
  40. package/rust/cli/bank/api.rs +122 -0
  41. package/rust/cli/bank/commands.rs +275 -0
  42. package/rust/cli/bank/mod.rs +29 -0
  43. package/rust/cli/build/commands.rs +107 -0
  44. package/rust/cli/build/mod.rs +2 -0
  45. package/rust/cli/build/process.rs +146 -0
  46. package/rust/cli/{check.rs → check/mod.rs} +18 -31
  47. package/rust/cli/discover/commands.rs +253 -0
  48. package/rust/cli/discover/config.rs +111 -0
  49. package/rust/cli/discover/fs.rs +19 -0
  50. package/rust/cli/discover/install.rs +103 -0
  51. package/rust/cli/discover/metadata.rs +48 -0
  52. package/rust/cli/discover/mod.rs +5 -0
  53. package/rust/cli/{init.rs → init/commands.rs} +88 -87
  54. package/rust/cli/init/mod.rs +1 -0
  55. package/rust/cli/install/addon.rs +126 -0
  56. package/rust/cli/install/bank.rs +53 -0
  57. package/rust/cli/{install.rs → install/commands.rs} +9 -9
  58. package/rust/{installer → cli/install}/mod.rs +2 -3
  59. package/rust/cli/install/plugin.rs +61 -0
  60. package/rust/cli/{login.rs → login/commands.rs} +8 -11
  61. package/rust/cli/login/mod.rs +1 -0
  62. package/rust/cli/mod.rs +2 -2
  63. package/rust/cli/{driver.rs → parser.rs} +7 -2
  64. package/rust/cli/play/commands.rs +324 -0
  65. package/rust/cli/play/io.rs +17 -0
  66. package/rust/cli/play/mod.rs +5 -0
  67. package/rust/cli/play/process.rs +150 -0
  68. package/rust/cli/play/realtime.rs +91 -0
  69. package/rust/cli/play/utils.rs +23 -0
  70. package/rust/cli/{telemetry.rs → telemetry/commands.rs} +4 -4
  71. package/rust/cli/telemetry/event_creator.rs +80 -0
  72. package/rust/cli/telemetry/mod.rs +3 -0
  73. package/rust/cli/telemetry/send.rs +51 -0
  74. package/rust/cli/{template.rs → template/commands.rs} +1 -1
  75. package/rust/cli/template/mod.rs +1 -0
  76. package/rust/cli/{update.rs → update/commands.rs} +6 -6
  77. package/rust/cli/update/mod.rs +1 -0
  78. package/rust/config/driver.rs +57 -72
  79. package/rust/config/mod.rs +1 -2
  80. package/rust/config/ops.rs +26 -0
  81. package/rust/config/settings.rs +40 -42
  82. package/rust/core/audio/engine/helpers.rs +158 -0
  83. package/rust/core/audio/engine/mod.rs +7 -0
  84. package/rust/core/audio/engine/sample.rs +359 -0
  85. package/rust/core/audio/engine/synth.rs +325 -0
  86. package/rust/core/audio/evaluator.rs +68 -27
  87. package/rust/core/audio/interpreter/arrow_call.rs +113 -33
  88. package/rust/core/audio/interpreter/call.rs +232 -56
  89. package/rust/core/audio/interpreter/condition.rs +3 -2
  90. package/rust/core/audio/interpreter/driver.rs +206 -151
  91. package/rust/core/audio/interpreter/let_.rs +1 -1
  92. package/rust/core/audio/interpreter/load.rs +2 -1
  93. package/rust/core/audio/interpreter/loop_.rs +7 -6
  94. package/rust/core/audio/interpreter/sleep.rs +2 -1
  95. package/rust/core/audio/interpreter/spawn.rs +186 -54
  96. package/rust/core/audio/interpreter/tempo.rs +31 -10
  97. package/rust/core/audio/interpreter/trigger.rs +2 -2
  98. package/rust/core/audio/loader/trigger.rs +4 -7
  99. package/rust/core/audio/player.rs +6 -0
  100. package/rust/core/audio/renderer.rs +5 -7
  101. package/rust/core/audio/special/env.rs +3 -1
  102. package/rust/core/audio/special/math.rs +26 -6
  103. package/rust/core/audio/special/modulator.rs +2 -2
  104. package/rust/core/builder/mod.rs +9 -3
  105. package/rust/core/debugger/lexer.rs +1 -1
  106. package/rust/core/debugger/mod.rs +6 -0
  107. package/rust/core/debugger/module.rs +4 -4
  108. package/rust/core/debugger/preprocessor.rs +1 -1
  109. package/rust/core/debugger/store.rs +2 -2
  110. package/rust/core/error/mod.rs +189 -0
  111. package/rust/core/lexer/driver.rs +61 -0
  112. package/rust/core/lexer/handler/arrow.rs +1 -1
  113. package/rust/core/lexer/handler/at.rs +1 -1
  114. package/rust/core/lexer/handler/brace.rs +2 -2
  115. package/rust/core/lexer/handler/colon.rs +1 -1
  116. package/rust/core/lexer/handler/comment.rs +1 -1
  117. package/rust/core/lexer/handler/dot.rs +1 -1
  118. package/rust/core/lexer/handler/driver.rs +1 -1
  119. package/rust/core/lexer/handler/identifier.rs +4 -3
  120. package/rust/core/lexer/handler/mod.rs +1 -2
  121. package/rust/core/lexer/handler/number.rs +1 -1
  122. package/rust/core/lexer/handler/operator.rs +1 -1
  123. package/rust/core/lexer/handler/parenthesis.rs +2 -2
  124. package/rust/core/lexer/handler/slash.rs +1 -1
  125. package/rust/core/lexer/handler/string.rs +1 -1
  126. package/rust/core/lexer/mod.rs +1 -52
  127. package/rust/core/lexer/token.rs +91 -97
  128. package/rust/core/mod.rs +0 -1
  129. package/rust/core/parser/driver.rs +78 -22
  130. package/rust/core/parser/handler/arrow_call.rs +28 -8
  131. package/rust/core/parser/handler/at.rs +55 -21
  132. package/rust/core/parser/handler/bank.rs +14 -4
  133. package/rust/core/parser/handler/condition.rs +6 -3
  134. package/rust/core/parser/handler/dot.rs +5 -3
  135. package/rust/core/parser/handler/identifier/automate.rs +13 -16
  136. package/rust/core/parser/handler/identifier/call.rs +4 -4
  137. package/rust/core/parser/handler/identifier/emit.rs +9 -5
  138. package/rust/core/parser/handler/identifier/function.rs +20 -7
  139. package/rust/core/parser/handler/identifier/group.rs +11 -7
  140. package/rust/core/parser/handler/identifier/let_.rs +24 -9
  141. package/rust/core/parser/handler/identifier/mod.rs +6 -5
  142. package/rust/core/parser/handler/identifier/on.rs +16 -7
  143. package/rust/core/parser/handler/identifier/print.rs +6 -9
  144. package/rust/core/parser/handler/identifier/sleep.rs +12 -5
  145. package/rust/core/parser/handler/identifier/spawn.rs +4 -4
  146. package/rust/core/parser/handler/identifier/synth.rs +79 -9
  147. package/rust/core/parser/handler/loop_.rs +38 -13
  148. package/rust/core/parser/handler/mod.rs +1 -0
  149. package/rust/core/parser/handler/pattern.rs +74 -0
  150. package/rust/core/parser/handler/tempo.rs +9 -5
  151. package/rust/core/parser/mod.rs +0 -1
  152. package/rust/core/parser/statement.rs +6 -137
  153. package/rust/core/plugin/loader.rs +41 -27
  154. package/rust/core/plugin/runner.rs +68 -17
  155. package/rust/core/preprocessor/loader.rs +181 -99
  156. package/rust/core/preprocessor/processor.rs +9 -9
  157. package/rust/core/preprocessor/resolver/bank.rs +6 -8
  158. package/rust/core/preprocessor/resolver/call.rs +47 -23
  159. package/rust/core/preprocessor/resolver/condition.rs +6 -8
  160. package/rust/core/preprocessor/resolver/driver.rs +28 -28
  161. package/rust/core/preprocessor/resolver/function.rs +6 -6
  162. package/rust/core/preprocessor/resolver/group.rs +6 -8
  163. package/rust/core/preprocessor/resolver/loop_.rs +8 -10
  164. package/rust/core/preprocessor/resolver/mod.rs +1 -0
  165. package/rust/core/preprocessor/resolver/pattern.rs +75 -0
  166. package/rust/core/preprocessor/resolver/spawn.rs +45 -22
  167. package/rust/core/preprocessor/resolver/synth.rs +6 -8
  168. package/rust/core/preprocessor/resolver/tempo.rs +6 -8
  169. package/rust/core/preprocessor/resolver/trigger.rs +22 -19
  170. package/rust/core/preprocessor/resolver/value.rs +99 -4
  171. package/rust/core/store/export.rs +28 -28
  172. package/rust/core/store/function.rs +6 -0
  173. package/rust/core/store/global.rs +7 -1
  174. package/rust/core/store/import.rs +28 -28
  175. package/rust/core/store/variable.rs +16 -2
  176. package/rust/core/utils/mod.rs +0 -1
  177. package/rust/lib.rs +102 -9
  178. package/rust/main.rs +159 -45
  179. package/rust/types/Cargo.toml +11 -0
  180. package/rust/types/src/addons.rs +55 -0
  181. package/rust/types/src/ast.rs +202 -0
  182. package/rust/types/src/config.rs +74 -0
  183. package/rust/types/src/lib.rs +12 -0
  184. package/rust/types/src/telemetry.rs +85 -0
  185. package/rust/utils/Cargo.toml +26 -0
  186. package/rust/utils/{error.rs → src/error.rs} +186 -200
  187. package/rust/utils/src/file.rs +94 -0
  188. package/rust/utils/src/first_usage.rs +97 -0
  189. package/rust/utils/{mod.rs → src/lib.rs} +1 -1
  190. package/rust/utils/{logger.rs → src/logger.rs} +17 -12
  191. package/rust/utils/src/path.rs +88 -0
  192. package/rust/utils/src/signature.rs +41 -0
  193. package/rust/utils/{spinner.rs → src/spinner.rs} +3 -5
  194. package/rust/utils/src/version.rs +27 -0
  195. package/rust/utils/{watcher.rs → src/watcher.rs} +13 -1
  196. package/rust/web/cdn.rs +34 -0
  197. package/templates/minimal/README.md +98 -54
  198. package/templates/welcome/README.md +98 -54
  199. package/templates/welcome/src/index.deva +56 -8
  200. package/templates/welcome/src/variables.deva +2 -4
  201. package/tests/rust/TODO.md +0 -0
  202. package/tests/typescript/index.spec.ts +136 -0
  203. package/tests/typescript/playhead.spec.ts +36 -0
  204. package/tests/typescript/render_e2e.spec.ts +77 -0
  205. package/tsconfig.json +1 -1
  206. package/typescript/core/functions/index.ts +83 -0
  207. package/typescript/core/index.ts +6 -0
  208. package/typescript/core/types/index.ts +4 -0
  209. package/typescript/core/types/plugin.ts +19 -0
  210. package/typescript/core/types/result.ts +29 -0
  211. package/typescript/core/types/statement.ts +47 -0
  212. package/typescript/core/types/value.ts +29 -0
  213. package/typescript/index.ts +7 -2
  214. package/typescript/pkg/devalang_core.d.ts +4 -0
  215. package/typescript/scripts/copy-wasm-dts.ts +41 -0
  216. package/rust/cli/bank.rs +0 -462
  217. package/rust/cli/build.rs +0 -252
  218. package/rust/cli/play.rs +0 -1123
  219. package/rust/common/cdn.rs +0 -5
  220. package/rust/config/loader.rs +0 -165
  221. package/rust/config/stats.rs +0 -257
  222. package/rust/core/audio/engine.rs +0 -696
  223. package/rust/core/shared/bank.rs +0 -21
  224. package/rust/core/shared/duration.rs +0 -9
  225. package/rust/core/shared/mod.rs +0 -3
  226. package/rust/core/shared/value.rs +0 -35
  227. package/rust/core/utils/validation.rs +0 -35
  228. package/rust/installer/addon.rs +0 -84
  229. package/rust/installer/bank.rs +0 -62
  230. package/rust/installer/plugin.rs +0 -54
  231. package/rust/installer/utils.rs +0 -56
  232. package/rust/utils/file.rs +0 -38
  233. package/rust/utils/first_usage.rs +0 -83
  234. package/rust/utils/signature.rs +0 -19
  235. package/rust/utils/telemetry.rs +0 -292
  236. package/rust/utils/version.rs +0 -15
  237. /package/rust/{common → web}/api.rs +0 -0
  238. /package/rust/{common → web}/mod.rs +0 -0
  239. /package/rust/{common → web}/sso.rs +0 -0
@@ -7,9 +7,9 @@ use crate::core::{
7
7
  handler::{dot::parse_dot_token, identifier::synth::parse_synth_token},
8
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,
@@ -23,14 +23,23 @@ 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
45
  // If RHS begins with '$' or contains expression tokens ('+', '-', '*', '/', '(', '['),
@@ -101,14 +110,17 @@ pub fn parse_let_token(
101
110
  }
102
111
 
103
112
  if key_token.kind != TokenKind::Identifier {
104
- 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
+ );
105
117
  }
106
118
  parser.advance();
107
119
  let key = key_token.lexeme.clone();
108
120
 
109
121
  if !parser.match_token(TokenKind::Colon) {
110
122
  let message = format!("Expected ':' after key '{}'", key);
111
- return Statement::error(token, message);
123
+ return crate::core::parser::statement::error_from_token(token, message);
112
124
  }
113
125
 
114
126
  let val = match parser.peek_clone() {
@@ -129,7 +141,7 @@ pub fn parse_let_token(
129
141
 
130
142
  if val == Value::Null {
131
143
  let message = format!("Invalid value for key '{}'", key);
132
- return Statement::error(token, message);
144
+ return crate::core::parser::statement::error_from_token(token, message);
133
145
  }
134
146
 
135
147
  map.insert(key, val);
@@ -144,13 +156,16 @@ pub fn parse_let_token(
144
156
  Value::Map(map)
145
157
  }
146
158
  _ => {
147
- return Statement::error(current_token, "Unhandled value type after '='".to_string());
159
+ return crate::core::parser::statement::error_from_token(
160
+ current_token,
161
+ "Unhandled value type after '='".to_string(),
162
+ );
148
163
  }
149
164
  };
150
165
 
151
166
  Statement {
152
167
  kind: StatementKind::Let { name: identifier },
153
- value: value,
168
+ value,
154
169
  indent: current_token.indent,
155
170
  line: current_token.line,
156
171
  column: current_token.column,
@@ -32,7 +32,7 @@ pub fn parse_identifier_token(parser: &mut Parser, global_store: &mut GlobalStor
32
32
  let current_token_clone = current_token.clone();
33
33
  let current_token_lexeme = current_token_clone.lexeme.clone();
34
34
 
35
- let statement = match current_token_lexeme.as_str() {
35
+ match current_token_lexeme.as_str() {
36
36
  "let" => parse_let_token(parser, current_token_clone, global_store),
37
37
  "group" => parse_group_token(parser, current_token_clone, global_store),
38
38
  "call" => parse_call_token(parser, current_token_clone, global_store),
@@ -46,9 +46,10 @@ pub fn parse_identifier_token(parser: &mut Parser, global_store: &mut GlobalStor
46
46
  _ => {
47
47
  parser.advance(); // consume identifier
48
48
 
49
- 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
+ )
50
53
  }
51
- };
52
-
53
- return statement;
54
+ }
54
55
  }
@@ -1,16 +1,14 @@
1
+ use devalang_types::Value;
2
+
1
3
  use crate::core::{
2
4
  lexer::token::TokenKind,
3
5
  parser::{
4
6
  driver::Parser,
5
7
  statement::{Statement, StatementKind},
6
8
  },
7
- shared::value::Value,
8
9
  store::global::GlobalStore,
9
10
  };
10
11
 
11
- // Syntax:
12
- // on <identifier>:
13
- // <indented block>
14
12
  pub fn parse_on_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
15
13
  // consume 'on'
16
14
  let on_tok = match parser.peek_clone() {
@@ -23,9 +21,17 @@ pub fn parse_on_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> S
23
21
  let event_tok = match parser.peek_clone() {
24
22
  Some(tok) if tok.kind == TokenKind::Identifier => tok,
25
23
  Some(other) => {
26
- return Statement::error(other, "Expected event name after 'on'".to_string());
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
+ );
27
34
  }
28
- None => return Statement::error(on_tok, "Expected event name after 'on'".to_string()),
29
35
  };
30
36
  let event_name = event_tok.lexeme.clone();
31
37
  parser.advance();
@@ -68,7 +74,10 @@ pub fn parse_on_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> S
68
74
 
69
75
  // Expect ':' then block
70
76
  if parser.peek_kind() != Some(TokenKind::Colon) {
71
- return Statement::error(event_tok, "Expected ':' after event name".to_string());
77
+ return crate::core::parser::statement::error_from_token(
78
+ event_tok,
79
+ "Expected ':' after event name".to_string(),
80
+ );
72
81
  }
73
82
  parser.advance(); // consume ':'
74
83
 
@@ -6,6 +6,7 @@ use crate::core::{
6
6
  },
7
7
  store::global::GlobalStore,
8
8
  };
9
+ use devalang_types::Value;
9
10
 
10
11
  pub fn parse_print_token(
11
12
  parser: &mut Parser,
@@ -19,17 +20,13 @@ pub fn parse_print_token(
19
20
  // Accept: print <identifier|string|number|expression>
20
21
  let value = if collected.len() == 1 {
21
22
  match collected[0].kind {
22
- TokenKind::Identifier => {
23
- crate::core::shared::value::Value::Identifier(collected[0].lexeme.clone())
24
- }
25
- TokenKind::String => {
26
- crate::core::shared::value::Value::String(collected[0].lexeme.clone())
27
- }
23
+ TokenKind::Identifier => Value::Identifier(collected[0].lexeme.clone()),
24
+ TokenKind::String => Value::String(collected[0].lexeme.clone()),
28
25
  TokenKind::Number => {
29
26
  let n = collected[0].lexeme.parse::<f32>().unwrap_or(0.0);
30
- crate::core::shared::value::Value::Number(n)
27
+ Value::Number(n)
31
28
  }
32
- _ => crate::core::shared::value::Value::String(collected[0].lexeme.clone()),
29
+ _ => Value::String(collected[0].lexeme.clone()),
33
30
  }
34
31
  } else {
35
32
  // Join tokens with spaces to preserve readability for expressions/text
@@ -39,7 +36,7 @@ pub fn parse_print_token(
39
36
  .map(|t| t.lexeme.clone())
40
37
  .collect::<Vec<_>>()
41
38
  .join(" ");
42
- crate::core::shared::value::Value::String(text.trim().to_string())
39
+ Value::String(text.trim().to_string())
43
40
  };
44
41
 
45
42
  Statement {
@@ -1,10 +1,11 @@
1
+ use devalang_types::Value;
2
+
1
3
  use crate::core::{
2
4
  lexer::token::{Token, TokenKind},
3
5
  parser::{
4
6
  driver::Parser,
5
7
  statement::{Statement, StatementKind},
6
8
  },
7
- shared::value::Value,
8
9
  store::global::GlobalStore,
9
10
  };
10
11
 
@@ -20,17 +21,23 @@ pub fn parse_sleep_token(
20
21
  parser.advance();
21
22
  token.lexeme.parse().unwrap_or(0.0)
22
23
  } else {
23
- return Statement::error(token, "Expected number after 'sleep'".to_string());
24
+ return crate::core::parser::statement::error_from_token(
25
+ token,
26
+ "Expected number after 'sleep'".to_string(),
27
+ );
24
28
  }
25
29
  } else {
26
- return Statement::error(current_token, "Expected number after 'sleep'".to_string());
30
+ return crate::core::parser::statement::error_from_token(
31
+ current_token,
32
+ "Expected number after 'sleep'".to_string(),
33
+ );
27
34
  };
28
35
 
29
- return Statement {
36
+ Statement {
30
37
  kind: StatementKind::Sleep,
31
38
  value: Value::Number(duration),
32
39
  indent: current_token.indent,
33
40
  line: current_token.line,
34
41
  column: current_token.column,
35
- };
42
+ }
36
43
  }
@@ -4,9 +4,9 @@ use crate::core::{
4
4
  driver::Parser,
5
5
  statement::{Statement, StatementKind},
6
6
  },
7
- shared::value::Value,
8
7
  store::global::GlobalStore,
9
8
  };
9
+ use devalang_types::Value;
10
10
 
11
11
  pub fn parse_spawn_token(
12
12
  parser: &mut Parser,
@@ -19,7 +19,7 @@ pub fn parse_spawn_token(
19
19
  let name_token = match parser.peek_clone() {
20
20
  Some(t) => t,
21
21
  None => {
22
- return Statement::error(
22
+ return crate::core::parser::statement::error_from_token(
23
23
  current_token,
24
24
  "Expected function name after 'spawn'".to_string(),
25
25
  );
@@ -27,7 +27,7 @@ pub fn parse_spawn_token(
27
27
  };
28
28
 
29
29
  if name_token.kind != TokenKind::Identifier {
30
- return Statement::error(
30
+ return crate::core::parser::statement::error_from_token(
31
31
  name_token,
32
32
  "Expected function name to be an identifier".to_string(),
33
33
  );
@@ -68,7 +68,7 @@ pub fn parse_spawn_token(
68
68
  parser.advance(); // skip comma
69
69
  }
70
70
  _ => {
71
- return Statement::error(
71
+ return crate::core::parser::statement::error_from_token(
72
72
  token,
73
73
  "Unexpected token in spawn arguments".to_string(),
74
74
  );
@@ -1,12 +1,14 @@
1
1
  use std::collections::HashMap;
2
2
 
3
+ use devalang_types::Value;
4
+
3
5
  use crate::core::{
4
6
  lexer::token::Token,
5
7
  parser::{
6
8
  driver::Parser,
9
+ handler::dot::parse_dot_token,
7
10
  statement::{Statement, StatementKind},
8
11
  },
9
- shared::value::Value,
10
12
  store::global::GlobalStore,
11
13
  };
12
14
 
@@ -21,14 +23,81 @@ pub fn parse_synth_token(
21
23
  return Statement::unknown();
22
24
  };
23
25
 
24
- // Expect an identifier (synth waveform)
25
- let Some(identifier_token) = parser.peek_clone() else {
26
- return Statement::error(synth_token, "Expected identifier after 'synth'".to_string());
27
- };
26
+ // Expect a provider/waveform identifier (can be dotted: alias.synth)
27
+ // Also accept a dot-led entity by delegating to the dot parser (e.g. .module.export)
28
+ let synth_waveform = if let Some(first_token) = parser.peek_clone() {
29
+ use crate::core::lexer::token::TokenKind;
28
30
 
29
- let synth_waveform = identifier_token.lexeme.clone();
31
+ if first_token.kind == TokenKind::Dot {
32
+ // Parse dot-entity and extract its entity string
33
+ let dot_stmt = parse_dot_token(parser, _global_store);
34
+ // Extract entity if the parsed statement is a Trigger
35
+ match dot_stmt.kind {
36
+ StatementKind::Trigger { entity, .. } => entity,
37
+ _ => String::new(),
38
+ }
39
+ } else {
40
+ if first_token.kind != crate::core::lexer::token::TokenKind::Identifier
41
+ && first_token.kind != crate::core::lexer::token::TokenKind::Number
42
+ && first_token.kind != crate::core::lexer::token::TokenKind::Synth
43
+ {
44
+ return crate::core::parser::statement::error_from_token(
45
+ first_token.clone(),
46
+ "Expected identifier after 'synth'".to_string(),
47
+ );
48
+ }
30
49
 
31
- parser.advance(); // consume identifier
50
+ // Collect dotted parts on the same line
51
+ let mut parts: Vec<String> = Vec::new();
52
+ let current_line = first_token.line;
53
+ loop {
54
+ let Some(tok) = parser.peek_clone() else {
55
+ break;
56
+ };
57
+ if tok.line != current_line {
58
+ break;
59
+ }
60
+ match tok.kind {
61
+ crate::core::lexer::token::TokenKind::Identifier
62
+ | crate::core::lexer::token::TokenKind::Number
63
+ | crate::core::lexer::token::TokenKind::Synth => {
64
+ parts.push(tok.lexeme.clone());
65
+ parser.advance();
66
+ // If next isn't a dot on same line, stop
67
+ if let Some(next) = parser.peek_clone() {
68
+ if !(next.line == current_line
69
+ && next.kind == crate::core::lexer::token::TokenKind::Dot)
70
+ {
71
+ break;
72
+ }
73
+ } else {
74
+ break;
75
+ }
76
+ }
77
+ crate::core::lexer::token::TokenKind::Dot => {
78
+ parser.advance();
79
+ }
80
+ _ => break,
81
+ }
82
+ }
83
+
84
+ parts.join(".")
85
+ }
86
+ } else {
87
+ return crate::core::parser::statement::error_from_token(
88
+ synth_token,
89
+ "Expected identifier after 'synth'".to_string(),
90
+ );
91
+ };
92
+
93
+ // Skip formatting before optional parameters map
94
+ while parser.check_token(crate::core::lexer::token::TokenKind::Newline)
95
+ || parser.check_token(crate::core::lexer::token::TokenKind::Indent)
96
+ || parser.check_token(crate::core::lexer::token::TokenKind::Dedent)
97
+ || parser.check_token(crate::core::lexer::token::TokenKind::Whitespace)
98
+ {
99
+ parser.advance();
100
+ }
32
101
 
33
102
  // Expect synth optional parameters map
34
103
  let parameters = if let Some(params) = parser.parse_map_value() {
@@ -36,7 +105,7 @@ pub fn parse_synth_token(
36
105
  if let Value::Map(map) = params {
37
106
  map
38
107
  } else {
39
- return Statement::error(
108
+ return crate::core::parser::statement::error_from_token(
40
109
  synth_token,
41
110
  "Expected a map for synth parameters".to_string(),
42
111
  );
@@ -53,7 +122,8 @@ pub fn parse_synth_token(
53
122
  (
54
123
  "value".to_string(),
55
124
  Value::Map(HashMap::from([
56
- ("waveform".to_string(), Value::String(synth_waveform)),
125
+ // Store waveform as identifier to allow resolution from variables/exports
126
+ ("waveform".to_string(), Value::Identifier(synth_waveform)),
57
127
  ("parameters".to_string(), Value::Map(parameters)),
58
128
  ])),
59
129
  ),
@@ -1,10 +1,11 @@
1
+ use devalang_types::Value;
2
+
1
3
  use crate::core::{
2
4
  lexer::token::TokenKind,
3
5
  parser::{
4
6
  driver::Parser,
5
7
  statement::{Statement, StatementKind},
6
8
  },
7
- shared::value::Value,
8
9
  store::global::GlobalStore,
9
10
  };
10
11
 
@@ -20,7 +21,12 @@ pub fn parse_loop_token(parser: &mut Parser, global_store: &mut GlobalStore) ->
20
21
 
21
22
  // Peek next to decide
22
23
  let Some(next_token) = parser.peek_clone() else {
23
- return Statement::error(loop_token, "Expected iterator after loop/for".to_string());
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
+ );
24
30
  };
25
31
 
26
32
  // Try to detect 'for <ident> in [array]:' form
@@ -66,22 +72,31 @@ pub fn parse_loop_token(parser: &mut Parser, global_store: &mut GlobalStore) ->
66
72
  Value::Identifier(tok.lexeme.clone())
67
73
  }
68
74
  _ => {
69
- return Statement::error(
70
- loop_token,
75
+ return Statement::error_with_pos(
76
+ loop_token.indent,
77
+ loop_token.line,
78
+ loop_token.column,
71
79
  "Expected array, number, string or identifier after 'in'".to_string(),
72
80
  );
73
81
  }
74
82
  }
75
83
  } else {
76
- return Statement::error(
77
- loop_token,
84
+ return Statement::error_with_pos(
85
+ loop_token.indent,
86
+ loop_token.line,
87
+ loop_token.column,
78
88
  "Expected array, number, string or identifier after 'in'".to_string(),
79
89
  );
80
90
  };
81
91
 
82
92
  // Expect ':'
83
93
  if !parser.match_token(TokenKind::Colon) {
84
- return Statement::error(loop_token, "Expected ':' after foreach header".to_string());
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
+ );
85
100
  }
86
101
 
87
102
  let tokens =
@@ -109,8 +124,10 @@ pub fn parse_loop_token(parser: &mut Parser, global_store: &mut GlobalStore) ->
109
124
 
110
125
  // Fallback to legacy: loop <count>:
111
126
  let Some(iterator_token) = parser.peek_clone() else {
112
- return Statement::error(
113
- loop_token,
127
+ return Statement::error_with_pos(
128
+ loop_token.indent,
129
+ loop_token.line,
130
+ loop_token.column,
114
131
  "Expected number or identifier after 'loop'".to_string(),
115
132
  );
116
133
  };
@@ -133,8 +150,10 @@ pub fn parse_loop_token(parser: &mut Parser, global_store: &mut GlobalStore) ->
133
150
  Value::String(s)
134
151
  }
135
152
  _ => {
136
- return Statement::error(
137
- iterator_token.clone(),
153
+ return Statement::error_with_pos(
154
+ iterator_token.clone().indent,
155
+ iterator_token.clone().line,
156
+ iterator_token.clone().column,
138
157
  "Expected a number, string or identifier as loop count".to_string(),
139
158
  );
140
159
  }
@@ -145,10 +164,16 @@ pub fn parse_loop_token(parser: &mut Parser, global_store: &mut GlobalStore) ->
145
164
  "Expected ':' after loop count, got {:?}",
146
165
  parser.peek_kind()
147
166
  );
148
- return Statement::error(loop_token.clone(), message);
167
+ return Statement::error_with_pos(
168
+ loop_token.clone().indent,
169
+ loop_token.clone().line,
170
+ loop_token.clone().column,
171
+ message,
172
+ );
149
173
  }
150
174
 
151
- let tokens = parser.collect_until(|t| t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF);
175
+ let tokens =
176
+ parser.collect_until(|t| t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF);
152
177
  let loop_body = parser.parse_block(tokens.clone(), global_store);
153
178
  if let Some(token) = parser.peek() {
154
179
  if token.kind == TokenKind::Dedent {
@@ -1,6 +1,7 @@
1
1
  pub mod arrow_call;
2
2
  pub mod at;
3
3
  pub mod bank;
4
+ pub mod pattern;
4
5
  pub mod condition;
5
6
  pub mod dot;
6
7
  pub mod identifier;
@@ -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
+ }
@@ -4,9 +4,9 @@ use crate::core::{
4
4
  driver::Parser,
5
5
  statement::{Statement, StatementKind},
6
6
  },
7
- shared::value::Value,
8
7
  store::global::GlobalStore,
9
8
  };
9
+ use devalang_types::Value;
10
10
 
11
11
  pub fn parse_tempo_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
12
12
  parser.advance(); // consume 'bpm'
@@ -17,8 +17,10 @@ pub fn parse_tempo_token(parser: &mut Parser, _global_store: &mut GlobalStore) -
17
17
 
18
18
  // Expect a number or identifier
19
19
  let Some(value_token) = parser.peek_clone() else {
20
- return Statement::error(
21
- tempo_token,
20
+ return Statement::error_with_pos(
21
+ tempo_token.indent,
22
+ tempo_token.line,
23
+ tempo_token.column,
22
24
  "Expected a number or identifier after 'bpm'".to_string(),
23
25
  );
24
26
  };
@@ -33,8 +35,10 @@ pub fn parse_tempo_token(parser: &mut Parser, _global_store: &mut GlobalStore) -
33
35
  Value::Identifier(value_token.lexeme.clone())
34
36
  }
35
37
  _ => {
36
- return Statement::error(
37
- value_token.clone(),
38
+ return Statement::error_with_pos(
39
+ value_token.indent,
40
+ value_token.line,
41
+ value_token.column,
38
42
  format!(
39
43
  "Expected a number or identifier after 'bpm', got {:?}",
40
44
  value_token.kind
@@ -1,4 +1,3 @@
1
1
  pub mod driver;
2
-
3
2
  pub mod handler;
4
3
  pub mod statement;