@devaloop/devalang 0.0.1-alpha.15 → 0.0.1-alpha.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/.devalang +2 -0
  2. package/.github/workflows/ci.yml +92 -0
  3. package/Cargo.toml +60 -58
  4. package/README.md +1 -1
  5. package/docs/CHANGELOG.md +34 -1
  6. package/docs/CONTRIBUTING.md +101 -1
  7. package/docs/ROADMAP.md +1 -1
  8. package/docs/TODO.md +1 -1
  9. package/examples/automation.deva +1 -3
  10. package/examples/bank.deva +4 -4
  11. package/examples/events.deva +12 -0
  12. package/examples/function.deva +4 -4
  13. package/examples/index.deva +3 -5
  14. package/examples/loop.deva +5 -11
  15. package/examples/pattern.deva +8 -0
  16. package/examples/plugin.deva +12 -11
  17. package/examples/variables.deva +1 -1
  18. package/out-tsc/bin/index.js +51 -7
  19. package/out-tsc/index.js +3 -1
  20. package/out-tsc/scripts/postbuild.js +9 -10
  21. package/out-tsc/scripts/postinstall.js +49 -0
  22. package/package.json +12 -4
  23. package/project-version.json +3 -3
  24. package/rust/cli/bank.rs +462 -455
  25. package/rust/cli/build.rs +252 -199
  26. package/rust/cli/check.rs +221 -180
  27. package/rust/cli/driver.rs +297 -292
  28. package/rust/cli/generator.rs +1 -0
  29. package/rust/cli/init.rs +87 -79
  30. package/rust/cli/install.rs +35 -32
  31. package/rust/cli/login.rs +127 -134
  32. package/rust/cli/mod.rs +13 -11
  33. package/rust/cli/play.rs +1123 -218
  34. package/rust/cli/telemetry.rs +19 -0
  35. package/rust/cli/template.rs +69 -57
  36. package/rust/cli/update.rs +6 -4
  37. package/rust/common/api.rs +5 -5
  38. package/rust/common/mod.rs +3 -3
  39. package/rust/config/driver.rs +118 -94
  40. package/rust/config/loader.rs +165 -156
  41. package/rust/config/mod.rs +4 -2
  42. package/rust/config/settings.rs +91 -0
  43. package/rust/config/stats.rs +257 -0
  44. package/rust/core/audio/engine.rs +696 -659
  45. package/rust/core/audio/evaluator.rs +263 -132
  46. package/rust/core/audio/interpreter/arrow_call.rs +198 -187
  47. package/rust/core/audio/interpreter/call.rs +98 -95
  48. package/rust/core/audio/interpreter/condition.rs +70 -71
  49. package/rust/core/audio/interpreter/driver.rs +487 -231
  50. package/rust/core/audio/interpreter/function.rs +26 -21
  51. package/rust/core/audio/interpreter/let_.rs +38 -26
  52. package/rust/core/audio/interpreter/load.rs +18 -18
  53. package/rust/core/audio/interpreter/loop_.rs +113 -106
  54. package/rust/core/audio/interpreter/mod.rs +14 -14
  55. package/rust/core/audio/interpreter/sleep.rs +27 -28
  56. package/rust/core/audio/interpreter/spawn.rs +105 -102
  57. package/rust/core/audio/interpreter/tempo.rs +19 -16
  58. package/rust/core/audio/interpreter/trigger.rs +239 -210
  59. package/rust/core/audio/loader/mod.rs +1 -1
  60. package/rust/core/audio/loader/trigger.rs +100 -94
  61. package/rust/core/audio/mod.rs +7 -7
  62. package/rust/core/audio/player.rs +64 -64
  63. package/rust/core/audio/renderer.rs +56 -53
  64. package/rust/core/audio/special/easing.rs +189 -120
  65. package/rust/core/audio/special/env.rs +43 -41
  66. package/rust/core/audio/special/math.rs +102 -92
  67. package/rust/core/audio/special/mod.rs +9 -9
  68. package/rust/core/audio/special/modulator.rs +143 -120
  69. package/rust/core/builder/mod.rs +80 -85
  70. package/rust/core/debugger/lexer.rs +27 -27
  71. package/rust/core/debugger/mod.rs +24 -23
  72. package/rust/core/debugger/module.rs +55 -47
  73. package/rust/core/debugger/preprocessor.rs +27 -27
  74. package/rust/core/debugger/store.rs +40 -39
  75. package/rust/core/error/mod.rs +80 -69
  76. package/rust/core/lexer/handler/arrow.rs +82 -82
  77. package/rust/core/lexer/handler/at.rs +21 -21
  78. package/rust/core/lexer/handler/brace.rs +41 -41
  79. package/rust/core/lexer/handler/colon.rs +21 -21
  80. package/rust/core/lexer/handler/comment.rs +30 -30
  81. package/rust/core/lexer/handler/dot.rs +21 -21
  82. package/rust/core/lexer/handler/driver.rs +337 -292
  83. package/rust/core/lexer/handler/identifier.rs +46 -43
  84. package/rust/core/lexer/handler/indent.rs +66 -66
  85. package/rust/core/lexer/handler/mod.rs +16 -16
  86. package/rust/core/lexer/handler/newline.rs +23 -23
  87. package/rust/core/lexer/handler/number.rs +31 -31
  88. package/rust/core/lexer/handler/operator.rs +46 -46
  89. package/rust/core/lexer/handler/parenthesis.rs +41 -41
  90. package/rust/core/lexer/handler/slash.rs +21 -21
  91. package/rust/core/lexer/handler/string.rs +63 -63
  92. package/rust/core/lexer/mod.rs +54 -51
  93. package/rust/core/lexer/token.rs +97 -94
  94. package/rust/core/mod.rs +11 -11
  95. package/rust/core/parser/driver.rs +513 -490
  96. package/rust/core/parser/handler/arrow_call.rs +233 -227
  97. package/rust/core/parser/handler/at.rs +245 -162
  98. package/rust/core/parser/handler/bank.rs +94 -69
  99. package/rust/core/parser/handler/condition.rs +80 -74
  100. package/rust/core/parser/handler/dot.rs +143 -135
  101. package/rust/core/parser/handler/identifier/automate.rs +257 -194
  102. package/rust/core/parser/handler/identifier/call.rs +91 -88
  103. package/rust/core/parser/handler/identifier/emit.rs +66 -0
  104. package/rust/core/parser/handler/identifier/function.rs +100 -91
  105. package/rust/core/parser/handler/identifier/group.rs +85 -75
  106. package/rust/core/parser/handler/identifier/let_.rs +158 -143
  107. package/rust/core/parser/handler/identifier/mod.rs +54 -56
  108. package/rust/core/parser/handler/identifier/on.rs +98 -0
  109. package/rust/core/parser/handler/identifier/print.rs +52 -29
  110. package/rust/core/parser/handler/identifier/sleep.rs +36 -33
  111. package/rust/core/parser/handler/identifier/spawn.rs +91 -88
  112. package/rust/core/parser/handler/identifier/synth.rs +65 -63
  113. package/rust/core/parser/handler/loop_.rs +170 -89
  114. package/rust/core/parser/handler/mod.rs +8 -8
  115. package/rust/core/parser/handler/tempo.rs +53 -47
  116. package/rust/core/parser/mod.rs +4 -4
  117. package/rust/core/parser/statement.rs +142 -113
  118. package/rust/core/plugin/loader.rs +123 -48
  119. package/rust/core/plugin/mod.rs +2 -1
  120. package/rust/core/plugin/runner.rs +296 -0
  121. package/rust/core/preprocessor/loader.rs +515 -326
  122. package/rust/core/preprocessor/mod.rs +4 -4
  123. package/rust/core/preprocessor/module.rs +60 -58
  124. package/rust/core/preprocessor/processor.rs +99 -101
  125. package/rust/core/preprocessor/resolver/bank.rs +51 -48
  126. package/rust/core/preprocessor/resolver/call.rs +100 -101
  127. package/rust/core/preprocessor/resolver/condition.rs +97 -97
  128. package/rust/core/preprocessor/resolver/driver.rs +310 -280
  129. package/rust/core/preprocessor/resolver/function.rs +69 -68
  130. package/rust/core/preprocessor/resolver/group.rs +96 -91
  131. package/rust/core/preprocessor/resolver/let_.rs +32 -28
  132. package/rust/core/preprocessor/resolver/loop_.rs +320 -121
  133. package/rust/core/preprocessor/resolver/mod.rs +15 -15
  134. package/rust/core/preprocessor/resolver/spawn.rs +76 -73
  135. package/rust/core/preprocessor/resolver/synth.rs +56 -50
  136. package/rust/core/preprocessor/resolver/tempo.rs +50 -49
  137. package/rust/core/preprocessor/resolver/trigger.rs +113 -115
  138. package/rust/core/preprocessor/resolver/value.rs +81 -81
  139. package/rust/core/shared/duration.rs +9 -9
  140. package/rust/core/shared/mod.rs +3 -3
  141. package/rust/core/shared/value.rs +35 -32
  142. package/rust/core/store/function.rs +34 -34
  143. package/rust/core/store/global.rs +55 -38
  144. package/rust/core/store/mod.rs +5 -5
  145. package/rust/core/store/variable.rs +37 -34
  146. package/rust/core/utils/mod.rs +2 -2
  147. package/rust/core/utils/path.rs +37 -31
  148. package/rust/core/utils/validation.rs +35 -36
  149. package/rust/installer/addon.rs +84 -80
  150. package/rust/installer/bank.rs +62 -65
  151. package/rust/installer/mod.rs +5 -5
  152. package/rust/installer/plugin.rs +54 -55
  153. package/rust/installer/utils.rs +56 -56
  154. package/rust/lib.rs +156 -164
  155. package/rust/main.rs +250 -144
  156. package/rust/utils/error.rs +200 -51
  157. package/rust/utils/file.rs +38 -35
  158. package/rust/utils/first_usage.rs +76 -0
  159. package/rust/utils/logger.rs +195 -143
  160. package/rust/utils/mod.rs +9 -7
  161. package/rust/utils/signature.rs +19 -17
  162. package/rust/utils/spinner.rs +22 -19
  163. package/rust/utils/telemetry.rs +292 -0
  164. package/rust/utils/watcher.rs +34 -33
  165. package/templates/minimal/README.md +97 -121
  166. package/templates/welcome/README.md +97 -121
  167. package/typescript/bin/index.ts +19 -5
  168. package/typescript/index.ts +3 -1
  169. package/typescript/scripts/postbuild.ts +10 -6
  170. package/typescript/scripts/postinstall.ts +56 -0
  171. package/typescript/scripts/version/bump.ts +0 -1
  172. package/typescript/scripts/version/index.ts +0 -1
  173. package/out-tsc/bin/devalang.exe +0 -0
@@ -1,143 +1,158 @@
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
- shared::value::Value,
11
- store::global::GlobalStore,
12
- };
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 Statement::error(token, "Expected identifier after 'let'".to_string());
27
- }
28
- } else {
29
- return Statement::error(current_token, "Expected identifier after 'let'".to_string());
30
- };
31
-
32
- if !parser.match_token(TokenKind::Equals) {
33
- return Statement::error(current_token, "Expected '=' after identifier".to_string());
34
- }
35
-
36
- // If RHS begins with '$' or contains expression tokens ('+', '-', '*', '/', '(', '['),
37
- // collect the rest of the line as a raw expression string.
38
- if let Some(tok) = parser.peek_clone() {
39
- let line = tok.line;
40
- if tok.lexeme.starts_with('$') || matches!(tok.kind, TokenKind::Identifier | TokenKind::Number | TokenKind::LParen | TokenKind::LBracket) {
41
- // Collect tokens until end of the current line
42
- let collected = parser.collect_until(|t| t.line != line || matches!(t.kind, TokenKind::Newline | TokenKind::EOF));
43
- let mut text = String::new();
44
- for t in collected.iter() {
45
- if matches!(t.kind, TokenKind::Newline | TokenKind::EOF) { break; }
46
- text.push_str(&t.lexeme);
47
- }
48
- return Statement { kind: StatementKind::Let { name: identifier }, value: Value::String(text.trim().to_string()), indent: current_token.indent, line: current_token.line, column: current_token.column };
49
- }
50
- }
51
-
52
- let value = match parser.peek_clone() {
53
- Some(token) if token.kind == TokenKind::Dot => {
54
- let dot_stmt = parse_dot_token(parser, global_store);
55
- Value::Statement(Box::new(dot_stmt))
56
- }
57
- Some(token) if token.kind == TokenKind::Synth => {
58
- let synth_stmt = parse_synth_token(parser, token.clone(), global_store);
59
- Value::Statement(Box::new(synth_stmt))
60
- }
61
- Some(token) if token.kind == TokenKind::Identifier => {
62
- parser.advance();
63
- Value::Identifier(token.lexeme.clone())
64
- }
65
- Some(token) if token.kind == TokenKind::String => {
66
- parser.advance();
67
- Value::String(token.lexeme.clone())
68
- }
69
- Some(token) if token.kind == TokenKind::Number => {
70
- parser.advance();
71
- Value::Number(token.lexeme.parse().unwrap_or(0.0))
72
- }
73
- Some(token) if token.kind == TokenKind::Boolean => {
74
- parser.advance();
75
- Value::Boolean(token.lexeme.parse().unwrap_or(false))
76
- }
77
- Some(token) if token.kind == TokenKind::LBrace => {
78
- parser.advance();
79
-
80
- let mut map = HashMap::new();
81
-
82
- while let Some(key_token) = parser.peek_clone() {
83
- if key_token.kind == TokenKind::RBrace {
84
- parser.advance(); // consume '}'
85
- break;
86
- }
87
-
88
- if key_token.kind != TokenKind::Identifier {
89
- return Statement::error(token, "Expected key identifier in map".to_string());
90
- }
91
- parser.advance();
92
- let key = key_token.lexeme.clone();
93
-
94
- if !parser.match_token(TokenKind::Colon) {
95
- let message = format!("Expected ':' after key '{}'", key);
96
- return Statement::error(token, message);
97
- }
98
-
99
- let val = match parser.peek_clone() {
100
- Some(t) if t.kind == TokenKind::Number => {
101
- parser.advance();
102
- Value::Number(t.lexeme.parse().unwrap_or(0.0))
103
- }
104
- Some(t) if t.kind == TokenKind::String => {
105
- parser.advance();
106
- Value::String(t.lexeme.clone())
107
- }
108
- Some(t) if t.kind == TokenKind::Identifier => {
109
- parser.advance();
110
- Value::Identifier(t.lexeme.clone())
111
- }
112
- _ => Value::Null,
113
- };
114
-
115
- if val == Value::Null {
116
- let message = format!("Invalid value for key '{}'", key);
117
- return Statement::error(token, message);
118
- }
119
-
120
- map.insert(key, val);
121
-
122
- if let Some(t) = parser.peek() {
123
- if t.kind == TokenKind::Comma {
124
- parser.advance(); // skip comma
125
- }
126
- }
127
- }
128
-
129
- Value::Map(map)
130
- }
131
- _ => {
132
- return Statement::error(current_token, "Unhandled value type after '='".to_string());
133
- }
134
- };
135
-
136
- Statement {
137
- kind: StatementKind::Let { name: identifier },
138
- value: value,
139
- indent: current_token.indent,
140
- line: current_token.line,
141
- column: current_token.column,
142
- }
143
- }
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
+ shared::value::Value,
11
+ store::global::GlobalStore,
12
+ };
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 Statement::error(token, "Expected identifier after 'let'".to_string());
27
+ }
28
+ } else {
29
+ return Statement::error(current_token, "Expected identifier after 'let'".to_string());
30
+ };
31
+
32
+ if !parser.match_token(TokenKind::Equals) {
33
+ return Statement::error(current_token, "Expected '=' after identifier".to_string());
34
+ }
35
+
36
+ // If RHS begins with '$' or contains expression tokens ('+', '-', '*', '/', '(', '['),
37
+ // collect the rest of the line as a raw expression string.
38
+ if let Some(tok) = parser.peek_clone() {
39
+ let line = tok.line;
40
+ if tok.lexeme.starts_with('$')
41
+ || matches!(
42
+ tok.kind,
43
+ TokenKind::Identifier | TokenKind::Number | TokenKind::LParen | TokenKind::LBracket
44
+ )
45
+ {
46
+ // Collect tokens until end of the current line
47
+ let collected = parser.collect_until(|t| {
48
+ t.line != line || matches!(t.kind, TokenKind::Newline | TokenKind::EOF)
49
+ });
50
+ let mut text = String::new();
51
+ for t in collected.iter() {
52
+ if matches!(t.kind, TokenKind::Newline | TokenKind::EOF) {
53
+ break;
54
+ }
55
+ text.push_str(&t.lexeme);
56
+ }
57
+ return Statement {
58
+ kind: StatementKind::Let { name: identifier },
59
+ value: Value::String(text.trim().to_string()),
60
+ indent: current_token.indent,
61
+ line: current_token.line,
62
+ column: current_token.column,
63
+ };
64
+ }
65
+ }
66
+
67
+ let value = match parser.peek_clone() {
68
+ Some(token) if token.kind == TokenKind::Dot => {
69
+ let dot_stmt = parse_dot_token(parser, global_store);
70
+ Value::Statement(Box::new(dot_stmt))
71
+ }
72
+ Some(token) if token.kind == TokenKind::Synth => {
73
+ let synth_stmt = parse_synth_token(parser, token.clone(), global_store);
74
+ Value::Statement(Box::new(synth_stmt))
75
+ }
76
+ Some(token) if token.kind == TokenKind::Identifier => {
77
+ parser.advance();
78
+ Value::Identifier(token.lexeme.clone())
79
+ }
80
+ Some(token) if token.kind == TokenKind::String => {
81
+ parser.advance();
82
+ Value::String(token.lexeme.clone())
83
+ }
84
+ Some(token) if token.kind == TokenKind::Number => {
85
+ parser.advance();
86
+ Value::Number(token.lexeme.parse().unwrap_or(0.0))
87
+ }
88
+ Some(token) if token.kind == TokenKind::Boolean => {
89
+ parser.advance();
90
+ Value::Boolean(token.lexeme.parse().unwrap_or(false))
91
+ }
92
+ Some(token) if token.kind == TokenKind::LBrace => {
93
+ parser.advance();
94
+
95
+ let mut map = HashMap::new();
96
+
97
+ while let Some(key_token) = parser.peek_clone() {
98
+ if key_token.kind == TokenKind::RBrace {
99
+ parser.advance(); // consume '}'
100
+ break;
101
+ }
102
+
103
+ if key_token.kind != TokenKind::Identifier {
104
+ return Statement::error(token, "Expected key identifier in map".to_string());
105
+ }
106
+ parser.advance();
107
+ let key = key_token.lexeme.clone();
108
+
109
+ if !parser.match_token(TokenKind::Colon) {
110
+ let message = format!("Expected ':' after key '{}'", key);
111
+ return Statement::error(token, message);
112
+ }
113
+
114
+ let val = match parser.peek_clone() {
115
+ Some(t) if t.kind == TokenKind::Number => {
116
+ parser.advance();
117
+ Value::Number(t.lexeme.parse().unwrap_or(0.0))
118
+ }
119
+ Some(t) if t.kind == TokenKind::String => {
120
+ parser.advance();
121
+ Value::String(t.lexeme.clone())
122
+ }
123
+ Some(t) if t.kind == TokenKind::Identifier => {
124
+ parser.advance();
125
+ Value::Identifier(t.lexeme.clone())
126
+ }
127
+ _ => Value::Null,
128
+ };
129
+
130
+ if val == Value::Null {
131
+ let message = format!("Invalid value for key '{}'", key);
132
+ return Statement::error(token, message);
133
+ }
134
+
135
+ map.insert(key, val);
136
+
137
+ if let Some(t) = parser.peek() {
138
+ if t.kind == TokenKind::Comma {
139
+ parser.advance(); // skip comma
140
+ }
141
+ }
142
+ }
143
+
144
+ Value::Map(map)
145
+ }
146
+ _ => {
147
+ return Statement::error(current_token, "Unhandled value type after '='".to_string());
148
+ }
149
+ };
150
+
151
+ Statement {
152
+ kind: StatementKind::Let { name: identifier },
153
+ value: value,
154
+ indent: current_token.indent,
155
+ line: current_token.line,
156
+ column: current_token.column,
157
+ }
158
+ }
@@ -1,56 +1,54 @@
1
- pub mod let_;
2
- pub mod group;
3
- pub mod call;
4
- pub mod spawn;
5
- pub mod sleep;
6
- pub mod synth;
7
- pub mod function;
8
- pub mod automate;
9
- pub mod print;
10
-
11
- use crate::core::{
12
- parser::{
13
- driver::Parser,
14
- handler::identifier::{
15
- automate::parse_automate_token,
16
- call::parse_call_token,
17
- group::parse_group_token,
18
- let_::parse_let_token,
19
- print::parse_print_token,
20
- sleep::parse_sleep_token,
21
- spawn::parse_spawn_token,
22
- synth::parse_synth_token,
23
- },
24
- statement::{ Statement },
25
- },
26
- store::global::GlobalStore,
27
- };
28
-
29
- pub fn parse_identifier_token(parser: &mut Parser, global_store: &mut GlobalStore) -> Statement {
30
- let Some(current_token) = parser.peek_clone() else {
31
- return Statement::unknown();
32
- };
33
-
34
- let current_token_clone = current_token.clone();
35
- let current_token_lexeme = current_token_clone.lexeme.clone();
36
-
37
- let statement = match current_token_lexeme.as_str() {
38
- "let" => parse_let_token(parser, current_token_clone, global_store),
39
- "group" => parse_group_token(parser, current_token_clone, global_store),
40
- "call" => parse_call_token(parser, current_token_clone, global_store),
41
- "spawn" => parse_spawn_token(parser, current_token_clone, global_store),
42
- "sleep" => parse_sleep_token(parser, current_token_clone, global_store),
43
- "synth" => parse_synth_token(parser, current_token_clone, global_store),
44
- "automate" => parse_automate_token(parser, current_token_clone, global_store),
45
- "print" => parse_print_token(parser, current_token_clone, global_store),
46
- _ => {
47
- parser.advance(); // consume identifier
48
-
49
- println!("Unrecognized identifier: {}", current_token_lexeme);
50
-
51
- return Statement::error(current_token_clone, "Unexpected identifier".to_string());
52
- }
53
- };
54
-
55
- return statement;
56
- }
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
+ let statement = 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
+ return Statement::error(current_token_clone, "Unexpected identifier".to_string());
50
+ }
51
+ };
52
+
53
+ return statement;
54
+ }
@@ -0,0 +1,98 @@
1
+ use crate::core::{
2
+ lexer::token::TokenKind,
3
+ parser::{
4
+ driver::Parser,
5
+ statement::{Statement, StatementKind},
6
+ },
7
+ shared::value::Value,
8
+ store::global::GlobalStore,
9
+ };
10
+
11
+ // Syntax:
12
+ // on <identifier>:
13
+ // <indented block>
14
+ pub fn parse_on_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
15
+ // consume 'on'
16
+ let on_tok = match parser.peek_clone() {
17
+ Some(tok) => tok,
18
+ None => return Statement::unknown(),
19
+ };
20
+ parser.advance();
21
+
22
+ // Expect event name identifier
23
+ let event_tok = match parser.peek_clone() {
24
+ Some(tok) if tok.kind == TokenKind::Identifier => tok,
25
+ Some(other) => {
26
+ return Statement::error(other, "Expected event name after 'on'".to_string());
27
+ }
28
+ None => return Statement::error(on_tok, "Expected event name after 'on'".to_string()),
29
+ };
30
+ let event_name = event_tok.lexeme.clone();
31
+ parser.advance();
32
+
33
+ // Optional parenthesized args on same line
34
+ let mut args: Option<Vec<Value>> = None;
35
+ if parser.peek_kind() == Some(TokenKind::LParen) {
36
+ parser.advance(); // '('
37
+ let mut collected: Vec<Value> = Vec::new();
38
+ // Collect tokens until ')', supporting numbers and identifiers separated by comma
39
+ while let Some(tok) = parser.peek_clone() {
40
+ match tok.kind {
41
+ TokenKind::RParen => {
42
+ parser.advance();
43
+ break;
44
+ }
45
+ TokenKind::Number => {
46
+ parser.advance();
47
+ collected.push(Value::Number(tok.lexeme.parse().unwrap_or(0.0)));
48
+ }
49
+ TokenKind::Identifier => {
50
+ parser.advance();
51
+ collected.push(Value::Identifier(tok.lexeme));
52
+ }
53
+ TokenKind::Comma => {
54
+ parser.advance();
55
+ }
56
+ TokenKind::Whitespace | TokenKind::Newline => {
57
+ parser.advance();
58
+ }
59
+ _ => {
60
+ break;
61
+ }
62
+ }
63
+ }
64
+ if !collected.is_empty() {
65
+ args = Some(collected);
66
+ }
67
+ }
68
+
69
+ // Expect ':' then block
70
+ if parser.peek_kind() != Some(TokenKind::Colon) {
71
+ return Statement::error(event_tok, "Expected ':' after event name".to_string());
72
+ }
73
+ parser.advance(); // consume ':'
74
+
75
+ let base_indent = on_tok.indent;
76
+ let block_tokens = parser.collect_block_tokens(base_indent);
77
+ // Parse body within current store context
78
+ let body = parser.parse_block(block_tokens, _global_store);
79
+
80
+ let stmt = Statement {
81
+ kind: StatementKind::On {
82
+ event: event_name,
83
+ args,
84
+ body,
85
+ },
86
+ value: Value::Null,
87
+ indent: on_tok.indent,
88
+ line: on_tok.line,
89
+ column: on_tok.column,
90
+ };
91
+
92
+ // Register in global store for later emission
93
+ if let StatementKind::On { event, .. } = &stmt.kind {
94
+ _global_store.register_event_handler(event, stmt.clone());
95
+ }
96
+
97
+ stmt
98
+ }
@@ -1,29 +1,52 @@
1
- use crate::core::{
2
- lexer::token::{ Token, TokenKind },
3
- parser::{ driver::Parser, statement::{ Statement, StatementKind } },
4
- store::global::GlobalStore,
5
- };
6
-
7
- pub fn parse_print_token(
8
- parser: &mut Parser,
9
- current_token: Token,
10
- _global_store: &mut GlobalStore
11
- ) -> Statement {
12
- // consume 'print'
13
- parser.advance();
14
-
15
- let collected = parser.collect_until(|t| matches!(t.kind, TokenKind::Newline | TokenKind::EOF));
16
- // If single identifier, store as Identifier; else store as String of concatenated lexemes
17
- let value = if collected.len() == 1 && collected[0].kind == TokenKind::Identifier {
18
- crate::core::shared::value::Value::Identifier(collected[0].lexeme.clone())
19
- } else {
20
- let mut text = String::new();
21
- for t in collected.iter() {
22
- if matches!(t.kind, TokenKind::Newline | TokenKind::EOF) { break; }
23
- text.push_str(&t.lexeme);
24
- }
25
- crate::core::shared::value::Value::String(text.trim().to_string())
26
- };
27
-
28
- Statement { kind: StatementKind::Print, value, indent: current_token.indent, line: current_token.line, column: current_token.column }
29
- }
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
+
10
+ pub fn parse_print_token(
11
+ parser: &mut Parser,
12
+ current_token: Token,
13
+ _global_store: &mut GlobalStore,
14
+ ) -> Statement {
15
+ // consume 'print'
16
+ parser.advance();
17
+
18
+ let collected = parser.collect_until(|t| matches!(t.kind, TokenKind::Newline | TokenKind::EOF));
19
+ // Accept: print <identifier|string|number|expression>
20
+ let value = if collected.len() == 1 {
21
+ 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
+ }
28
+ TokenKind::Number => {
29
+ let n = collected[0].lexeme.parse::<f32>().unwrap_or(0.0);
30
+ crate::core::shared::value::Value::Number(n)
31
+ }
32
+ _ => crate::core::shared::value::Value::String(collected[0].lexeme.clone()),
33
+ }
34
+ } else {
35
+ // Join tokens with spaces to preserve readability for expressions/text
36
+ let text = collected
37
+ .iter()
38
+ .filter(|t| !matches!(t.kind, TokenKind::Newline | TokenKind::EOF))
39
+ .map(|t| t.lexeme.clone())
40
+ .collect::<Vec<_>>()
41
+ .join(" ");
42
+ crate::core::shared::value::Value::String(text.trim().to_string())
43
+ };
44
+
45
+ Statement {
46
+ kind: StatementKind::Print,
47
+ value,
48
+ indent: current_token.indent,
49
+ line: current_token.line,
50
+ column: current_token.column,
51
+ }
52
+ }