@devaloop/devalang 0.0.1-alpha.14 → 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 (177) hide show
  1. package/.devalang +10 -8
  2. package/.github/workflows/ci.yml +92 -0
  3. package/Cargo.toml +60 -58
  4. package/README.md +32 -15
  5. package/docs/CHANGELOG.md +93 -1
  6. package/docs/CONTRIBUTING.md +101 -1
  7. package/docs/ROADMAP.md +2 -2
  8. package/docs/TODO.md +1 -1
  9. package/examples/automation.deva +42 -0
  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 +39 -25
  14. package/examples/loop.deva +5 -11
  15. package/examples/pattern.deva +8 -0
  16. package/examples/plugin.deva +16 -0
  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 -456
  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 -8
  38. package/rust/common/cdn.rs +3 -6
  39. package/rust/common/mod.rs +3 -3
  40. package/rust/common/sso.rs +3 -6
  41. package/rust/config/driver.rs +118 -94
  42. package/rust/config/loader.rs +165 -156
  43. package/rust/config/mod.rs +4 -2
  44. package/rust/config/settings.rs +91 -0
  45. package/rust/config/stats.rs +257 -0
  46. package/rust/core/audio/engine.rs +696 -518
  47. package/rust/core/audio/evaluator.rs +263 -31
  48. package/rust/core/audio/interpreter/arrow_call.rs +198 -161
  49. package/rust/core/audio/interpreter/automate.rs +18 -0
  50. package/rust/core/audio/interpreter/call.rs +98 -95
  51. package/rust/core/audio/interpreter/condition.rs +70 -71
  52. package/rust/core/audio/interpreter/driver.rs +487 -198
  53. package/rust/core/audio/interpreter/function.rs +26 -21
  54. package/rust/core/audio/interpreter/let_.rs +38 -19
  55. package/rust/core/audio/interpreter/load.rs +18 -18
  56. package/rust/core/audio/interpreter/loop_.rs +113 -73
  57. package/rust/core/audio/interpreter/mod.rs +14 -13
  58. package/rust/core/audio/interpreter/sleep.rs +27 -30
  59. package/rust/core/audio/interpreter/spawn.rs +105 -102
  60. package/rust/core/audio/interpreter/tempo.rs +19 -16
  61. package/rust/core/audio/interpreter/trigger.rs +239 -210
  62. package/rust/core/audio/loader/mod.rs +1 -1
  63. package/rust/core/audio/loader/trigger.rs +100 -97
  64. package/rust/core/audio/mod.rs +7 -6
  65. package/rust/core/audio/player.rs +64 -64
  66. package/rust/core/audio/renderer.rs +56 -53
  67. package/rust/core/audio/special/easing.rs +189 -0
  68. package/rust/core/audio/special/env.rs +43 -0
  69. package/rust/core/audio/special/math.rs +102 -0
  70. package/rust/core/audio/special/mod.rs +9 -0
  71. package/rust/core/audio/special/modulator.rs +143 -0
  72. package/rust/core/builder/mod.rs +80 -85
  73. package/rust/core/debugger/lexer.rs +27 -27
  74. package/rust/core/debugger/mod.rs +24 -23
  75. package/rust/core/debugger/module.rs +55 -47
  76. package/rust/core/debugger/preprocessor.rs +27 -27
  77. package/rust/core/debugger/store.rs +40 -39
  78. package/rust/core/error/mod.rs +80 -66
  79. package/rust/core/lexer/handler/arrow.rs +82 -31
  80. package/rust/core/lexer/handler/at.rs +21 -21
  81. package/rust/core/lexer/handler/brace.rs +41 -41
  82. package/rust/core/lexer/handler/colon.rs +21 -21
  83. package/rust/core/lexer/handler/comment.rs +30 -30
  84. package/rust/core/lexer/handler/dot.rs +21 -21
  85. package/rust/core/lexer/handler/driver.rs +337 -263
  86. package/rust/core/lexer/handler/identifier.rs +46 -42
  87. package/rust/core/lexer/handler/indent.rs +66 -66
  88. package/rust/core/lexer/handler/mod.rs +16 -16
  89. package/rust/core/lexer/handler/newline.rs +23 -23
  90. package/rust/core/lexer/handler/number.rs +31 -31
  91. package/rust/core/lexer/handler/operator.rs +46 -44
  92. package/rust/core/lexer/handler/parenthesis.rs +41 -41
  93. package/rust/core/lexer/handler/slash.rs +21 -21
  94. package/rust/core/lexer/handler/string.rs +63 -63
  95. package/rust/core/lexer/mod.rs +54 -51
  96. package/rust/core/lexer/token.rs +97 -91
  97. package/rust/core/mod.rs +11 -11
  98. package/rust/core/parser/driver.rs +513 -408
  99. package/rust/core/parser/handler/arrow_call.rs +233 -211
  100. package/rust/core/parser/handler/at.rs +245 -162
  101. package/rust/core/parser/handler/bank.rs +94 -69
  102. package/rust/core/parser/handler/condition.rs +80 -74
  103. package/rust/core/parser/handler/dot.rs +143 -135
  104. package/rust/core/parser/handler/identifier/automate.rs +257 -0
  105. package/rust/core/parser/handler/identifier/call.rs +91 -88
  106. package/rust/core/parser/handler/identifier/emit.rs +66 -0
  107. package/rust/core/parser/handler/identifier/function.rs +100 -92
  108. package/rust/core/parser/handler/identifier/group.rs +85 -75
  109. package/rust/core/parser/handler/identifier/let_.rs +158 -127
  110. package/rust/core/parser/handler/identifier/mod.rs +54 -52
  111. package/rust/core/parser/handler/identifier/on.rs +98 -0
  112. package/rust/core/parser/handler/identifier/print.rs +52 -0
  113. package/rust/core/parser/handler/identifier/sleep.rs +36 -33
  114. package/rust/core/parser/handler/identifier/spawn.rs +91 -88
  115. package/rust/core/parser/handler/identifier/synth.rs +65 -65
  116. package/rust/core/parser/handler/loop_.rs +170 -72
  117. package/rust/core/parser/handler/mod.rs +8 -8
  118. package/rust/core/parser/handler/tempo.rs +53 -47
  119. package/rust/core/parser/mod.rs +4 -4
  120. package/rust/core/parser/statement.rs +142 -108
  121. package/rust/core/plugin/loader.rs +123 -48
  122. package/rust/core/plugin/mod.rs +2 -1
  123. package/rust/core/plugin/runner.rs +296 -0
  124. package/rust/core/preprocessor/loader.rs +515 -326
  125. package/rust/core/preprocessor/mod.rs +4 -4
  126. package/rust/core/preprocessor/module.rs +60 -58
  127. package/rust/core/preprocessor/processor.rs +99 -101
  128. package/rust/core/preprocessor/resolver/bank.rs +51 -49
  129. package/rust/core/preprocessor/resolver/call.rs +100 -100
  130. package/rust/core/preprocessor/resolver/condition.rs +97 -97
  131. package/rust/core/preprocessor/resolver/driver.rs +310 -278
  132. package/rust/core/preprocessor/resolver/function.rs +69 -78
  133. package/rust/core/preprocessor/resolver/group.rs +96 -91
  134. package/rust/core/preprocessor/resolver/let_.rs +32 -28
  135. package/rust/core/preprocessor/resolver/loop_.rs +320 -91
  136. package/rust/core/preprocessor/resolver/mod.rs +15 -15
  137. package/rust/core/preprocessor/resolver/spawn.rs +76 -92
  138. package/rust/core/preprocessor/resolver/synth.rs +56 -50
  139. package/rust/core/preprocessor/resolver/tempo.rs +50 -49
  140. package/rust/core/preprocessor/resolver/trigger.rs +113 -116
  141. package/rust/core/preprocessor/resolver/value.rs +81 -87
  142. package/rust/core/shared/bank.rs +1 -1
  143. package/rust/core/shared/duration.rs +9 -9
  144. package/rust/core/shared/mod.rs +3 -3
  145. package/rust/core/shared/value.rs +35 -32
  146. package/rust/core/store/function.rs +34 -34
  147. package/rust/core/store/global.rs +55 -38
  148. package/rust/core/store/mod.rs +5 -5
  149. package/rust/core/store/variable.rs +37 -34
  150. package/rust/core/utils/mod.rs +2 -2
  151. package/rust/core/utils/path.rs +37 -31
  152. package/rust/core/utils/validation.rs +35 -37
  153. package/rust/installer/addon.rs +84 -80
  154. package/rust/installer/bank.rs +62 -65
  155. package/rust/installer/mod.rs +5 -5
  156. package/rust/installer/plugin.rs +54 -55
  157. package/rust/installer/utils.rs +56 -56
  158. package/rust/lib.rs +156 -164
  159. package/rust/main.rs +250 -145
  160. package/rust/utils/error.rs +200 -0
  161. package/rust/utils/file.rs +38 -35
  162. package/rust/utils/first_usage.rs +76 -0
  163. package/rust/utils/logger.rs +195 -139
  164. package/rust/utils/mod.rs +9 -50
  165. package/rust/utils/signature.rs +19 -17
  166. package/rust/utils/spinner.rs +22 -19
  167. package/rust/utils/telemetry.rs +292 -0
  168. package/rust/utils/watcher.rs +34 -33
  169. package/templates/minimal/README.md +97 -121
  170. package/templates/welcome/README.md +97 -121
  171. package/typescript/bin/index.ts +19 -5
  172. package/typescript/index.ts +3 -1
  173. package/typescript/scripts/postbuild.ts +10 -6
  174. package/typescript/scripts/postinstall.ts +56 -0
  175. package/typescript/scripts/version/bump.ts +0 -1
  176. package/typescript/scripts/version/index.ts +0 -1
  177. package/out-tsc/bin/devalang.exe +0 -0
@@ -1,72 +1,170 @@
1
- use std::collections::HashMap;
2
-
3
- use crate::core::{
4
- lexer::{ token::TokenKind },
5
- parser::{ statement::{ Statement, StatementKind }, driver::Parser },
6
- shared::value::Value,
7
- store::global::GlobalStore,
8
- };
9
-
10
- pub fn parse_loop_token(parser: &mut Parser, global_store: &mut GlobalStore) -> Statement {
11
- parser.advance(); // consume 'loop'
12
- let Some(loop_token) = parser.previous_clone() else {
13
- return Statement::unknown();
14
- };
15
-
16
- let Some(iterator_token) = parser.peek_clone() else {
17
- return Statement::error(loop_token, "Expected number or identifier after 'loop'".to_string());
18
- };
19
-
20
- let iterator_value = match iterator_token.kind {
21
- TokenKind::Number => {
22
- let val = iterator_token.lexeme.parse::<f32>().unwrap_or(1.0);
23
- parser.advance();
24
- Value::Number(val)
25
- }
26
- TokenKind::Identifier => {
27
- let val = iterator_token.lexeme.clone();
28
- parser.advance();
29
- Value::Identifier(val)
30
- }
31
- _ => {
32
- return Statement::error(
33
- iterator_token.clone(),
34
- "Expected a number or identifier as loop count".to_string()
35
- );
36
- }
37
- };
38
-
39
- // Expect colon
40
- let Some(colon_token) = parser.peek_clone() else {
41
- return Statement::error(iterator_token.clone(), "Expected ':' after loop count".to_string());
42
- };
43
-
44
- if colon_token.kind != TokenKind::Colon {
45
- let message = format!("Expected ':' after loop count, got {:?}", colon_token.kind);
46
- return Statement::error(colon_token.clone(), message);
47
- }
48
-
49
- parser.advance(); // consume ':'
50
-
51
- // Collect body
52
- let tokens = parser.collect_until(|t| t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF);
53
- let loop_body = parser.parse_block(tokens.clone(), global_store);
54
-
55
- if let Some(token) = parser.peek() {
56
- if token.kind == TokenKind::Dedent {
57
- parser.advance();
58
- }
59
- }
60
-
61
- let mut value_map = HashMap::new();
62
- value_map.insert("iterator".to_string(), iterator_value);
63
- value_map.insert("body".to_string(), Value::Block(loop_body.clone()));
64
-
65
- Statement {
66
- kind: StatementKind::Loop,
67
- value: Value::Map(value_map),
68
- indent: loop_token.indent,
69
- line: loop_token.line,
70
- column: loop_token.column,
71
- }
72
- }
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
+ pub fn parse_loop_token(parser: &mut Parser, global_store: &mut GlobalStore) -> Statement {
12
+ parser.advance(); // consume 'loop' or 'for' (aliased in lexer)
13
+ let Some(loop_token) = parser.previous_clone() else {
14
+ return Statement::unknown();
15
+ };
16
+
17
+ // Support two forms:
18
+ // 1) loop <count>:
19
+ // 2) for <ident> in [a,b,c]:
20
+
21
+ // Peek next to decide
22
+ let Some(next_token) = parser.peek_clone() else {
23
+ return Statement::error(loop_token, "Expected iterator after loop/for".to_string());
24
+ };
25
+
26
+ // Try to detect 'for <ident> in [array]:' form
27
+ let mut foreach_ident: Option<String> = None;
28
+ if let TokenKind::Identifier = next_token.kind {
29
+ // Could be either count identifier (old form) or foreach variable
30
+ // Look ahead for 'in'
31
+ let name = next_token.lexeme.clone();
32
+ // don't consume yet; we'll branch
33
+ if let Some(t2) = parser.peek_nth(1) {
34
+ if t2.kind == TokenKind::Identifier && t2.lexeme == "in" {
35
+ // foreach form
36
+ foreach_ident = Some(name);
37
+ // consume ident and 'in'
38
+ parser.advance();
39
+ parser.advance();
40
+ }
41
+ }
42
+ }
43
+
44
+ if let Some(var_name) = foreach_ident {
45
+ // Expect [array] OR number OR string OR identifier after 'in'
46
+ let array_val = if let Some(tok) = parser.peek_clone() {
47
+ match tok.kind {
48
+ TokenKind::LBracket => {
49
+ if let Some(v) = parser.parse_array_value() {
50
+ v
51
+ } else {
52
+ Value::Array(vec![])
53
+ }
54
+ }
55
+ TokenKind::Number => {
56
+ parser.advance();
57
+ let n = tok.lexeme.parse::<f32>().unwrap_or(0.0);
58
+ Value::Number(n)
59
+ }
60
+ TokenKind::String => {
61
+ parser.advance();
62
+ Value::String(tok.lexeme.clone())
63
+ }
64
+ TokenKind::Identifier => {
65
+ parser.advance();
66
+ Value::Identifier(tok.lexeme.clone())
67
+ }
68
+ _ => {
69
+ return Statement::error(
70
+ loop_token,
71
+ "Expected array, number, string or identifier after 'in'".to_string(),
72
+ );
73
+ }
74
+ }
75
+ } else {
76
+ return Statement::error(
77
+ loop_token,
78
+ "Expected array, number, string or identifier after 'in'".to_string(),
79
+ );
80
+ };
81
+
82
+ // Expect ':'
83
+ if !parser.match_token(TokenKind::Colon) {
84
+ return Statement::error(loop_token, "Expected ':' after foreach header".to_string());
85
+ }
86
+
87
+ let tokens =
88
+ parser.collect_until(|t| t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF);
89
+ let loop_body = parser.parse_block(tokens.clone(), global_store);
90
+ if let Some(token) = parser.peek() {
91
+ if token.kind == TokenKind::Dedent {
92
+ parser.advance();
93
+ }
94
+ }
95
+
96
+ let mut value_map = std::collections::HashMap::new();
97
+ value_map.insert("foreach".to_string(), Value::Identifier(var_name));
98
+ value_map.insert("array".to_string(), array_val);
99
+ value_map.insert("body".to_string(), Value::Block(loop_body.clone()));
100
+
101
+ return Statement {
102
+ kind: StatementKind::Loop,
103
+ value: Value::Map(value_map),
104
+ indent: loop_token.indent,
105
+ line: loop_token.line,
106
+ column: loop_token.column,
107
+ };
108
+ }
109
+
110
+ // Fallback to legacy: loop <count>:
111
+ let Some(iterator_token) = parser.peek_clone() else {
112
+ return Statement::error(
113
+ loop_token,
114
+ "Expected number or identifier after 'loop'".to_string(),
115
+ );
116
+ };
117
+
118
+ let iterator_value = match iterator_token.kind {
119
+ TokenKind::Number => {
120
+ let val = iterator_token.lexeme.parse::<f32>().unwrap_or(1.0);
121
+ parser.advance();
122
+ Value::Number(val)
123
+ }
124
+ TokenKind::Identifier => {
125
+ let val = iterator_token.lexeme.clone();
126
+ parser.advance();
127
+ Value::Identifier(val)
128
+ }
129
+ TokenKind::String => {
130
+ // strings that are numeric (e.g. "10")
131
+ let s = iterator_token.lexeme.clone();
132
+ parser.advance();
133
+ Value::String(s)
134
+ }
135
+ _ => {
136
+ return Statement::error(
137
+ iterator_token.clone(),
138
+ "Expected a number, string or identifier as loop count".to_string(),
139
+ );
140
+ }
141
+ };
142
+
143
+ if !parser.match_token(TokenKind::Colon) {
144
+ let message = format!(
145
+ "Expected ':' after loop count, got {:?}",
146
+ parser.peek_kind()
147
+ );
148
+ return Statement::error(loop_token.clone(), message);
149
+ }
150
+
151
+ let tokens = parser.collect_until(|t| t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF);
152
+ let loop_body = parser.parse_block(tokens.clone(), global_store);
153
+ if let Some(token) = parser.peek() {
154
+ if token.kind == TokenKind::Dedent {
155
+ parser.advance();
156
+ }
157
+ }
158
+
159
+ let mut value_map = std::collections::HashMap::new();
160
+ value_map.insert("iterator".to_string(), iterator_value);
161
+ value_map.insert("body".to_string(), Value::Block(loop_body.clone()));
162
+
163
+ Statement {
164
+ kind: StatementKind::Loop,
165
+ value: Value::Map(value_map),
166
+ indent: loop_token.indent,
167
+ line: loop_token.line,
168
+ column: loop_token.column,
169
+ }
170
+ }
@@ -1,8 +1,8 @@
1
- pub mod at;
2
- pub mod identifier;
3
- pub mod dot;
4
- pub mod tempo;
5
- pub mod bank;
6
- pub mod loop_;
7
- pub mod condition;
8
- pub mod arrow_call;
1
+ pub mod arrow_call;
2
+ pub mod at;
3
+ pub mod bank;
4
+ pub mod condition;
5
+ pub mod dot;
6
+ pub mod identifier;
7
+ pub mod loop_;
8
+ pub mod tempo;
@@ -1,47 +1,53 @@
1
- use crate::core::{
2
- lexer::token::TokenKind,
3
- parser::{ statement::{ Statement, StatementKind }, driver::Parser },
4
- shared::value::Value,
5
- store::global::GlobalStore,
6
- };
7
-
8
- pub fn parse_tempo_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
9
- parser.advance(); // consume 'bpm'
10
-
11
- let Some(tempo_token) = parser.previous_clone() else {
12
- return Statement::unknown();
13
- };
14
-
15
- // Expect a number or identifier
16
- let Some(value_token) = parser.peek_clone() else {
17
- return Statement::error(
18
- tempo_token,
19
- "Expected a number or identifier after 'bpm'".to_string()
20
- );
21
- };
22
-
23
- let value = match value_token.kind {
24
- TokenKind::Number => {
25
- parser.advance();
26
- Value::Number(value_token.lexeme.parse().unwrap_or(0.0))
27
- }
28
- TokenKind::Identifier => {
29
- parser.advance();
30
- Value::Identifier(value_token.lexeme.clone())
31
- }
32
- _ => {
33
- return Statement::error(
34
- value_token.clone(),
35
- format!("Expected a number or identifier after 'bpm', got {:?}", value_token.kind)
36
- );
37
- }
38
- };
39
-
40
- Statement {
41
- kind: StatementKind::Tempo,
42
- value,
43
- indent: tempo_token.indent,
44
- line: tempo_token.line,
45
- column: tempo_token.column,
46
- }
47
- }
1
+ use crate::core::{
2
+ lexer::token::TokenKind,
3
+ parser::{
4
+ driver::Parser,
5
+ statement::{Statement, StatementKind},
6
+ },
7
+ shared::value::Value,
8
+ store::global::GlobalStore,
9
+ };
10
+
11
+ pub fn parse_tempo_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
12
+ parser.advance(); // consume 'bpm'
13
+
14
+ let Some(tempo_token) = parser.previous_clone() else {
15
+ return Statement::unknown();
16
+ };
17
+
18
+ // Expect a number or identifier
19
+ let Some(value_token) = parser.peek_clone() else {
20
+ return Statement::error(
21
+ tempo_token,
22
+ "Expected a number or identifier after 'bpm'".to_string(),
23
+ );
24
+ };
25
+
26
+ let value = match value_token.kind {
27
+ TokenKind::Number => {
28
+ parser.advance();
29
+ Value::Number(value_token.lexeme.parse().unwrap_or(0.0))
30
+ }
31
+ TokenKind::Identifier => {
32
+ parser.advance();
33
+ Value::Identifier(value_token.lexeme.clone())
34
+ }
35
+ _ => {
36
+ return Statement::error(
37
+ value_token.clone(),
38
+ format!(
39
+ "Expected a number or identifier after 'bpm', got {:?}",
40
+ value_token.kind
41
+ ),
42
+ );
43
+ }
44
+ };
45
+
46
+ Statement {
47
+ kind: StatementKind::Tempo,
48
+ value,
49
+ indent: tempo_token.indent,
50
+ line: tempo_token.line,
51
+ column: tempo_token.column,
52
+ }
53
+ }
@@ -1,4 +1,4 @@
1
- pub mod driver;
2
-
3
- pub mod statement;
4
- pub mod handler;
1
+ pub mod driver;
2
+
3
+ pub mod handler;
4
+ pub mod statement;
@@ -1,108 +1,142 @@
1
- use serde::{ Deserialize, Serialize };
2
- use crate::core::{ lexer::token::Token, shared::{ duration::Duration, value::Value } };
3
-
4
- #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
5
- pub struct Statement {
6
- pub kind: StatementKind,
7
- pub value: Value,
8
- pub indent: usize,
9
- pub line: usize,
10
- pub column: usize,
11
- }
12
-
13
- impl Statement {
14
- pub fn unknown() -> Self {
15
- Statement {
16
- kind: StatementKind::Unknown,
17
- value: Value::Null,
18
- indent: 0,
19
- line: 0,
20
- column: 0,
21
- }
22
- }
23
-
24
- pub fn error(token: Token, message: String) -> Self {
25
- Statement {
26
- kind: StatementKind::Error { message },
27
- value: Value::Null,
28
- indent: token.indent,
29
- line: token.line,
30
- column: token.column,
31
- }
32
- }
33
- }
34
-
35
- #[derive(Debug, Serialize, Clone, Deserialize, PartialEq)]
36
- pub enum StatementKind {
37
- // ───── Core Instructions ─────
38
- Tempo,
39
- Bank,
40
- Load {
41
- source: String,
42
- alias: String,
43
- },
44
- Let {
45
- name: String,
46
- },
47
- ArrowCall {
48
- target: String,
49
- method: String,
50
- args: Vec<Value>,
51
- },
52
- Function {
53
- name: String,
54
- parameters: Vec<String>,
55
- body: Vec<Statement>,
56
- },
57
-
58
- // ───── Instruments ─────
59
- Synth,
60
-
61
- // ───── Playback / Scheduling ─────
62
- Trigger {
63
- entity: String,
64
- duration: Duration,
65
- effects: Option<Value>,
66
- },
67
- Sleep,
68
- Call {
69
- name: String,
70
- args: Vec<Value>,
71
- },
72
- Spawn {
73
- name: String,
74
- args: Vec<Value>,
75
- },
76
- Loop,
77
-
78
- // ───── Structure & Logic ─────
79
- Group,
80
-
81
- // ───── Module System ─────
82
- Include(String),
83
- Export {
84
- names: Vec<String>,
85
- source: String,
86
- },
87
- Import {
88
- names: Vec<String>,
89
- source: String,
90
- },
91
-
92
- // ───── Conditions ─────
93
- If,
94
- Else,
95
- ElseIf,
96
-
97
- // ───── Internal / Utility ─────
98
- Comment,
99
- Indent,
100
- Dedent,
101
- NewLine,
102
-
103
- // ───── Error Handling ─────
104
- Unknown,
105
- Error {
106
- message: String,
107
- },
108
- }
1
+ use crate::core::{
2
+ lexer::token::Token,
3
+ shared::{duration::Duration, value::Value},
4
+ };
5
+ use serde::{Deserialize, Serialize};
6
+
7
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
8
+ pub struct Statement {
9
+ pub kind: StatementKind,
10
+ pub value: Value,
11
+ pub indent: usize,
12
+ pub line: usize,
13
+ pub column: usize,
14
+ }
15
+
16
+ impl Statement {
17
+ pub fn unknown() -> Self {
18
+ Statement {
19
+ kind: StatementKind::Unknown,
20
+ value: Value::Null,
21
+ indent: 0,
22
+ line: 0,
23
+ column: 0,
24
+ }
25
+ }
26
+
27
+ pub fn unknown_from_token(token: &Token) -> Self {
28
+ Statement {
29
+ kind: StatementKind::Unknown,
30
+ value: Value::Null,
31
+ indent: token.indent,
32
+ line: token.line,
33
+ column: token.column,
34
+ }
35
+ }
36
+
37
+ pub fn error(token: Token, message: String) -> Self {
38
+ Statement {
39
+ kind: StatementKind::Error { message },
40
+ value: Value::Null,
41
+ indent: token.indent,
42
+ line: token.line,
43
+ column: token.column,
44
+ }
45
+ }
46
+ }
47
+
48
+ #[derive(Debug, Serialize, Clone, Deserialize, PartialEq)]
49
+ pub enum StatementKind {
50
+ // ───── Core Instructions ─────
51
+ Tempo,
52
+ Bank {
53
+ alias: Option<String>,
54
+ },
55
+ Print,
56
+ Load {
57
+ source: String,
58
+ alias: String,
59
+ },
60
+ Use {
61
+ name: String,
62
+ alias: Option<String>,
63
+ },
64
+ Let {
65
+ name: String,
66
+ },
67
+ Automate {
68
+ target: String,
69
+ },
70
+ ArrowCall {
71
+ target: String,
72
+ method: String,
73
+ args: Vec<Value>,
74
+ },
75
+ Function {
76
+ name: String,
77
+ parameters: Vec<String>,
78
+ body: Vec<Statement>,
79
+ },
80
+
81
+ // ───── Instruments ─────
82
+ Synth,
83
+
84
+ // ───── Playback / Scheduling ─────
85
+ Trigger {
86
+ entity: String,
87
+ duration: Duration,
88
+ effects: Option<Value>,
89
+ },
90
+ Sleep,
91
+ Call {
92
+ name: String,
93
+ args: Vec<Value>,
94
+ },
95
+ Spawn {
96
+ name: String,
97
+ args: Vec<Value>,
98
+ },
99
+ Loop,
100
+
101
+ // ───── Structure & Logic ─────
102
+ Group,
103
+
104
+ // ───── Module System ─────
105
+ Include(String),
106
+ Export {
107
+ names: Vec<String>,
108
+ source: String,
109
+ },
110
+ Import {
111
+ names: Vec<String>,
112
+ source: String,
113
+ },
114
+
115
+ // ───── Conditions ─────
116
+ If,
117
+ Else,
118
+ ElseIf,
119
+
120
+ // ───── Internal / Utility ─────
121
+ Comment,
122
+ Indent,
123
+ Dedent,
124
+ NewLine,
125
+
126
+ // ───── Events / Live coding ─────
127
+ On {
128
+ event: String,
129
+ args: Option<Vec<Value>>,
130
+ body: Vec<Statement>,
131
+ },
132
+ Emit {
133
+ event: String,
134
+ payload: Option<Value>,
135
+ },
136
+
137
+ // ───── Error Handling ─────
138
+ Unknown,
139
+ Error {
140
+ message: String,
141
+ },
142
+ }