@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
@@ -0,0 +1,173 @@
1
+ use std::collections::HashMap;
2
+
3
+ use crate::core::{
4
+ lexer::token::{Token, TokenKind},
5
+ parser::{
6
+ driver::Parser,
7
+ handler::{dot::parse_dot_token, identifier::synth::parse_synth_token},
8
+ statement::{Statement, StatementKind},
9
+ },
10
+ store::global::GlobalStore,
11
+ };
12
+ use devalang_types::Value;
13
+
14
+ pub fn parse_let_token(
15
+ parser: &mut Parser,
16
+ current_token: Token,
17
+ global_store: &mut GlobalStore,
18
+ ) -> Statement {
19
+ parser.advance(); // consume "let"
20
+
21
+ let identifier = if let Some(token) = parser.peek_clone() {
22
+ if token.kind == TokenKind::Identifier {
23
+ parser.advance();
24
+ token.lexeme.clone()
25
+ } else {
26
+ return crate::core::parser::statement::error_from_token(
27
+ token,
28
+ "Expected identifier after 'let'".to_string(),
29
+ );
30
+ }
31
+ } else {
32
+ return crate::core::parser::statement::error_from_token(
33
+ current_token,
34
+ "Expected identifier after 'let'".to_string(),
35
+ );
36
+ };
37
+
38
+ if !parser.match_token(TokenKind::Equals) {
39
+ return crate::core::parser::statement::error_from_token(
40
+ current_token,
41
+ "Expected '=' after identifier".to_string(),
42
+ );
43
+ }
44
+
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
+ }
66
+ return Statement {
67
+ kind: StatementKind::Let { name: identifier },
68
+ value: Value::String(text.trim().to_string()),
69
+ indent: current_token.indent,
70
+ line: current_token.line,
71
+ column: current_token.column,
72
+ };
73
+ }
74
+ }
75
+
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
+ }
85
+ Some(token) if token.kind == TokenKind::Identifier => {
86
+ parser.advance();
87
+ Value::Identifier(token.lexeme.clone())
88
+ }
89
+ Some(token) if token.kind == TokenKind::String => {
90
+ parser.advance();
91
+ Value::String(token.lexeme.clone())
92
+ }
93
+ Some(token) if token.kind == TokenKind::Number => {
94
+ parser.advance();
95
+ Value::Number(token.lexeme.parse().unwrap_or(0.0))
96
+ }
97
+ Some(token) if token.kind == TokenKind::Boolean => {
98
+ parser.advance();
99
+ Value::Boolean(token.lexeme.parse().unwrap_or(false))
100
+ }
101
+ Some(token) if token.kind == TokenKind::LBrace => {
102
+ parser.advance();
103
+
104
+ let mut map = HashMap::new();
105
+
106
+ while let Some(key_token) = parser.peek_clone() {
107
+ if key_token.kind == TokenKind::RBrace {
108
+ parser.advance(); // consume '}'
109
+ break;
110
+ }
111
+
112
+ if key_token.kind != TokenKind::Identifier {
113
+ return crate::core::parser::statement::error_from_token(
114
+ token,
115
+ "Expected key identifier in map".to_string(),
116
+ );
117
+ }
118
+ parser.advance();
119
+ let key = key_token.lexeme.clone();
120
+
121
+ if !parser.match_token(TokenKind::Colon) {
122
+ let message = format!("Expected ':' after key '{}'", key);
123
+ return crate::core::parser::statement::error_from_token(token, message);
124
+ }
125
+
126
+ let val = match parser.peek_clone() {
127
+ Some(t) if t.kind == TokenKind::Number => {
128
+ parser.advance();
129
+ Value::Number(t.lexeme.parse().unwrap_or(0.0))
130
+ }
131
+ Some(t) if t.kind == TokenKind::String => {
132
+ parser.advance();
133
+ Value::String(t.lexeme.clone())
134
+ }
135
+ Some(t) if t.kind == TokenKind::Identifier => {
136
+ parser.advance();
137
+ Value::Identifier(t.lexeme.clone())
138
+ }
139
+ _ => Value::Null,
140
+ };
141
+
142
+ if val == Value::Null {
143
+ let message = format!("Invalid value for key '{}'", key);
144
+ return crate::core::parser::statement::error_from_token(token, message);
145
+ }
146
+
147
+ map.insert(key, val);
148
+
149
+ if let Some(t) = parser.peek() {
150
+ if t.kind == TokenKind::Comma {
151
+ parser.advance(); // skip comma
152
+ }
153
+ }
154
+ }
155
+
156
+ Value::Map(map)
157
+ }
158
+ _ => {
159
+ return crate::core::parser::statement::error_from_token(
160
+ current_token,
161
+ "Unhandled value type after '='".to_string(),
162
+ );
163
+ }
164
+ };
165
+
166
+ Statement {
167
+ kind: StatementKind::Let { name: identifier },
168
+ value,
169
+ indent: current_token.indent,
170
+ line: current_token.line,
171
+ column: current_token.column,
172
+ }
173
+ }
@@ -0,0 +1,55 @@
1
+ pub mod automate;
2
+ pub mod call;
3
+ pub mod emit;
4
+ pub mod function;
5
+ pub mod group;
6
+ pub mod let_;
7
+ pub mod on;
8
+ pub mod print;
9
+ pub mod sleep;
10
+ pub mod spawn;
11
+ pub mod synth;
12
+
13
+ use crate::core::{
14
+ parser::{
15
+ driver::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,
21
+ },
22
+ statement::Statement,
23
+ },
24
+ store::global::GlobalStore,
25
+ };
26
+
27
+ pub fn parse_identifier_token(parser: &mut Parser, global_store: &mut GlobalStore) -> Statement {
28
+ let Some(current_token) = parser.peek_clone() else {
29
+ return Statement::unknown();
30
+ };
31
+
32
+ let current_token_clone = current_token.clone();
33
+ let current_token_lexeme = current_token_clone.lexeme.clone();
34
+
35
+ match current_token_lexeme.as_str() {
36
+ "let" => parse_let_token(parser, current_token_clone, global_store),
37
+ "group" => parse_group_token(parser, current_token_clone, global_store),
38
+ "call" => parse_call_token(parser, current_token_clone, global_store),
39
+ "spawn" => parse_spawn_token(parser, current_token_clone, global_store),
40
+ "sleep" => parse_sleep_token(parser, current_token_clone, global_store),
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),
46
+ _ => {
47
+ parser.advance(); // consume identifier
48
+
49
+ crate::core::parser::statement::error_from_token(
50
+ current_token_clone,
51
+ "Unexpected identifier".to_string(),
52
+ )
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,107 @@
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_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,
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
+ }
@@ -0,0 +1,43 @@
1
+ use devalang_types::Value;
2
+
3
+ use crate::core::{
4
+ lexer::token::{Token, TokenKind},
5
+ parser::{
6
+ driver::Parser,
7
+ statement::{Statement, StatementKind},
8
+ },
9
+ store::global::GlobalStore,
10
+ };
11
+
12
+ pub fn parse_sleep_token(
13
+ parser: &mut Parser,
14
+ current_token: Token,
15
+ _global_store: &mut GlobalStore,
16
+ ) -> Statement {
17
+ parser.advance(); // consume "sleep"
18
+
19
+ let duration = if let Some(token) = parser.peek_clone() {
20
+ if token.kind == TokenKind::Number {
21
+ parser.advance();
22
+ token.lexeme.parse().unwrap_or(0.0)
23
+ } else {
24
+ return crate::core::parser::statement::error_from_token(
25
+ token,
26
+ "Expected number after 'sleep'".to_string(),
27
+ );
28
+ }
29
+ } else {
30
+ return crate::core::parser::statement::error_from_token(
31
+ current_token,
32
+ "Expected number after 'sleep'".to_string(),
33
+ );
34
+ };
35
+
36
+ Statement {
37
+ kind: StatementKind::Sleep,
38
+ value: Value::Number(duration),
39
+ indent: current_token.indent,
40
+ line: current_token.line,
41
+ column: current_token.column,
42
+ }
43
+ }
@@ -0,0 +1,91 @@
1
+ use crate::core::{
2
+ lexer::token::{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_spawn_token(
12
+ parser: &mut Parser,
13
+ current_token: Token,
14
+ _global_store: &mut GlobalStore,
15
+ ) -> Statement {
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(
23
+ current_token,
24
+ "Expected function name after 'spawn'".to_string(),
25
+ );
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
+ }
@@ -0,0 +1,135 @@
1
+ use std::collections::HashMap;
2
+
3
+ use devalang_types::Value;
4
+
5
+ use crate::core::{
6
+ lexer::token::Token,
7
+ parser::{
8
+ driver::Parser,
9
+ handler::dot::parse_dot_token,
10
+ statement::{Statement, StatementKind},
11
+ },
12
+ store::global::GlobalStore,
13
+ };
14
+
15
+ pub fn parse_synth_token(
16
+ parser: &mut Parser,
17
+ _current_token: Token,
18
+ _global_store: &mut GlobalStore,
19
+ ) -> Statement {
20
+ parser.advance(); // consume 'synth'
21
+
22
+ let Some(synth_token) = parser.previous_clone() else {
23
+ return Statement::unknown();
24
+ };
25
+
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;
30
+
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
+ }
49
+
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
+ }
101
+
102
+ // Expect synth optional parameters map
103
+ let parameters = if let Some(params) = parser.parse_map_value() {
104
+ // If parameters are provided, we expect a map
105
+ if let Value::Map(map) = params {
106
+ map
107
+ } else {
108
+ return crate::core::parser::statement::error_from_token(
109
+ synth_token,
110
+ "Expected a map for synth parameters".to_string(),
111
+ );
112
+ }
113
+ } else {
114
+ // If no parameters are provided, we can still create the statement with an empty map
115
+ HashMap::new()
116
+ };
117
+
118
+ Statement {
119
+ kind: StatementKind::Synth,
120
+ value: Value::Map(HashMap::from([
121
+ ("entity".to_string(), Value::String("synth".to_string())),
122
+ (
123
+ "value".to_string(),
124
+ Value::Map(HashMap::from([
125
+ // Store waveform as identifier to allow resolution from variables/exports
126
+ ("waveform".to_string(), Value::Identifier(synth_waveform)),
127
+ ("parameters".to_string(), Value::Map(parameters)),
128
+ ])),
129
+ ),
130
+ ])),
131
+ indent: synth_token.indent,
132
+ line: synth_token.line,
133
+ column: synth_token.column,
134
+ }
135
+ }