@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,194 +1,257 @@
1
- use std::collections::HashMap;
2
-
3
- use crate::core::{
4
- lexer::token::{Token, TokenKind},
5
- parser::{driver::Parser, statement::{Statement, StatementKind}},
6
- shared::value::Value,
7
- store::global::GlobalStore,
8
- };
9
-
10
- // Grammar:
11
- // automate <identifier>:
12
- // param <name> { <percent>% = <number> ... }
13
- // Produces StatementKind::Automate with value map:
14
- // { target: Identifier, params: Map<paramName, Map<percent, Number>> }
15
- pub fn parse_automate_token(
16
- parser: &mut Parser,
17
- current_token: Token,
18
- _global_store: &mut GlobalStore,
19
- ) -> Statement {
20
- parser.advance(); // consume 'automate'
21
-
22
- // Expect target identifier
23
- let Some(target_token) = parser.peek_clone() else {
24
- return Statement::error(current_token, "Expected target after 'automate'".to_string());
25
- };
26
-
27
- if target_token.kind != TokenKind::Identifier && target_token.kind != TokenKind::String {
28
- return Statement::error(target_token, "Expected valid target after 'automate'".to_string());
29
- }
30
- parser.advance(); // consume target
31
-
32
- // Expect ':'
33
- let Some(colon_token) = parser.peek_clone() else {
34
- return Statement::error(target_token, "Expected ':' after automate target".to_string());
35
- };
36
- if colon_token.kind != TokenKind::Colon {
37
- return Statement::error(colon_token, "Expected ':' after automate target".to_string());
38
- }
39
- parser.advance(); // consume ':'
40
-
41
- let base_indent = current_token.indent;
42
-
43
- // Collect tokens inside block (indented > base_indent)
44
- let mut index = parser.token_index;
45
- let mut tokens_inside = Vec::new();
46
- while index < parser.tokens.len() {
47
- let tok = parser.tokens[index].clone();
48
- if tok.indent <= base_indent && tok.kind != TokenKind::Newline {
49
- break;
50
- }
51
- tokens_inside.push(tok);
52
- index += 1;
53
- }
54
- parser.token_index = index;
55
-
56
- // Now parse block manually to capture 'param' entries without reusing general parser kinds
57
- let mut local = Parser {
58
- resolve_modules: parser.resolve_modules,
59
- tokens: tokens_inside,
60
- token_index: 0,
61
- current_module: parser.current_module.clone(),
62
- previous: None,
63
- };
64
-
65
- let mut params: HashMap<String, Value> = HashMap::new();
66
-
67
- while let Some(tok) = local.peek_clone() {
68
- match tok.kind {
69
- TokenKind::Identifier if tok.lexeme == "param" => {
70
- local.advance(); // consume 'param'
71
- // param name
72
- let Some(name_tok) = local.peek_clone() else {
73
- return Statement::error(tok, "Expected parameter name after 'param'".to_string());
74
- };
75
- if name_tok.kind != TokenKind::Identifier && name_tok.kind != TokenKind::String {
76
- return Statement::error(name_tok, "Expected valid parameter name".to_string());
77
- }
78
- local.advance(); // consume name
79
-
80
- // Expect '{'
81
- if !local.match_token(TokenKind::LBrace) {
82
- return Statement::error(name_tok, "Expected '{' to start parameter block".to_string());
83
- }
84
-
85
- // Collect entries like: 0% = 0.0
86
- let mut envelope: HashMap<String, Value> = HashMap::new();
87
- while let Some(inner) = local.peek_clone() {
88
- if inner.kind == TokenKind::RBrace { local.advance(); break; }
89
- // Skip formatting tokens inside the param block
90
- if matches!(inner.kind, TokenKind::Newline | TokenKind::Indent | TokenKind::Dedent | TokenKind::Comma) {
91
- local.advance();
92
- continue;
93
- }
94
-
95
- // Read percentage token: could be number followed by '%' as Dot or Identifier? '%' not defined.
96
- // Our lexer has no Percent token, so accept either Number or Identifier containing e.g. '0%'.
97
- let percent_token = inner.clone();
98
- local.advance();
99
-
100
- let percent_key = percent_token.lexeme.clone();
101
-
102
- // Expect '='
103
- // Skip any stray formatting between key and '='
104
- while let Some(t) = local.peek_kind() {
105
- if matches!(t, TokenKind::Indent | TokenKind::Dedent | TokenKind::Newline) { local.advance(); continue; }
106
- break;
107
- }
108
- if !local.match_token(TokenKind::Equals) {
109
- return Statement::error(percent_token, "Expected '=' in param entry".to_string());
110
- }
111
-
112
- // Read value (number or identifier)
113
- // Skip formatting before value
114
- while let Some(t) = local.peek_kind() {
115
- if matches!(t, TokenKind::Indent | TokenKind::Dedent | TokenKind::Newline) { local.advance(); continue; }
116
- break;
117
- }
118
-
119
- let value = if let Some(vtok) = local.peek_clone() {
120
- match vtok.kind {
121
- // Handle negative numbers where '-' is lexed as Arrow
122
- TokenKind::Arrow => {
123
- // Check if next token is a number
124
- let mut num_str = String::from("-");
125
- local.advance(); // consume '-'
126
- if let Some(ntok) = local.peek_clone() {
127
- if ntok.kind == TokenKind::Number {
128
- num_str.push_str(&ntok.lexeme);
129
- local.advance(); // consume number
130
- if let Some(dot) = local.peek_clone() {
131
- if dot.kind == TokenKind::Dot {
132
- local.advance();
133
- if let Some(frac) = local.peek_clone() {
134
- if frac.kind == TokenKind::Number {
135
- num_str.push('.');
136
- num_str.push_str(&frac.lexeme);
137
- local.advance();
138
- }
139
- }
140
- }
141
- }
142
- Value::Number(num_str.parse::<f32>().unwrap_or(0.0))
143
- } else {
144
- Value::Unknown
145
- }
146
- } else {
147
- Value::Unknown
148
- }
149
- }
150
- TokenKind::Number => {
151
- // Possibly a float with dot
152
- let mut number_str = vtok.lexeme.clone();
153
- local.advance();
154
- if let Some(dot) = local.peek_clone() {
155
- if dot.kind == TokenKind::Dot {
156
- local.advance();
157
- if let Some(frac) = local.peek_clone() {
158
- if frac.kind == TokenKind::Number {
159
- number_str.push('.');
160
- number_str.push_str(&frac.lexeme);
161
- local.advance();
162
- }
163
- }
164
- }
165
- }
166
- Value::Number(number_str.parse::<f32>().unwrap_or(0.0))
167
- }
168
- TokenKind::Identifier => { local.advance(); Value::Identifier(vtok.lexeme.clone()) }
169
- TokenKind::String => { local.advance(); Value::String(vtok.lexeme.clone()) }
170
- _ => { local.advance(); Value::Unknown }
171
- }
172
- } else { Value::Null };
173
-
174
- envelope.insert(percent_key, value);
175
- }
176
-
177
- params.insert(name_tok.lexeme.clone(), Value::Map(envelope));
178
- }
179
- _ => { local.advance(); }
180
- }
181
- }
182
-
183
- let mut value_map = HashMap::new();
184
- value_map.insert("target".to_string(), Value::String(target_token.lexeme.clone()));
185
- value_map.insert("params".to_string(), Value::Map(params));
186
-
187
- Statement {
188
- kind: StatementKind::Automate { target: target_token.lexeme.clone() },
189
- value: Value::Map(value_map),
190
- indent: current_token.indent,
191
- line: current_token.line,
192
- column: current_token.column,
193
- }
194
- }
1
+ use std::collections::HashMap;
2
+
3
+ use crate::core::{
4
+ lexer::token::{Token, TokenKind},
5
+ parser::{
6
+ driver::Parser,
7
+ statement::{Statement, StatementKind},
8
+ },
9
+ shared::value::Value,
10
+ store::global::GlobalStore,
11
+ };
12
+
13
+ // Grammar:
14
+ // automate <identifier>:
15
+ // param <name> { <percent>% = <number> ... }
16
+ // Produces StatementKind::Automate with value map:
17
+ // { target: Identifier, params: Map<paramName, Map<percent, Number>> }
18
+ pub fn parse_automate_token(
19
+ parser: &mut Parser,
20
+ current_token: Token,
21
+ _global_store: &mut GlobalStore,
22
+ ) -> Statement {
23
+ parser.advance(); // consume 'automate'
24
+
25
+ // Expect target identifier
26
+ let Some(target_token) = parser.peek_clone() else {
27
+ return Statement::error(
28
+ current_token,
29
+ "Expected target after 'automate'".to_string(),
30
+ );
31
+ };
32
+
33
+ if target_token.kind != TokenKind::Identifier && target_token.kind != TokenKind::String {
34
+ return Statement::error(
35
+ target_token,
36
+ "Expected valid target after 'automate'".to_string(),
37
+ );
38
+ }
39
+ parser.advance(); // consume target
40
+
41
+ // Expect ':'
42
+ let Some(colon_token) = parser.peek_clone() else {
43
+ return Statement::error(
44
+ target_token,
45
+ "Expected ':' after automate target".to_string(),
46
+ );
47
+ };
48
+ if colon_token.kind != TokenKind::Colon {
49
+ return Statement::error(
50
+ colon_token,
51
+ "Expected ':' after automate target".to_string(),
52
+ );
53
+ }
54
+ parser.advance(); // consume ':'
55
+
56
+ let base_indent = current_token.indent;
57
+
58
+ // Collect tokens inside block (indented > base_indent)
59
+ let mut index = parser.token_index;
60
+ let mut tokens_inside = Vec::new();
61
+ while index < parser.tokens.len() {
62
+ let tok = parser.tokens[index].clone();
63
+ if tok.indent <= base_indent && tok.kind != TokenKind::Newline {
64
+ break;
65
+ }
66
+ tokens_inside.push(tok);
67
+ index += 1;
68
+ }
69
+ parser.token_index = index;
70
+
71
+ // Now parse block manually to capture 'param' entries without reusing general parser kinds
72
+ let mut local = Parser {
73
+ resolve_modules: parser.resolve_modules,
74
+ tokens: tokens_inside,
75
+ token_index: 0,
76
+ current_module: parser.current_module.clone(),
77
+ previous: None,
78
+ };
79
+
80
+ let mut params: HashMap<String, Value> = HashMap::new();
81
+
82
+ while let Some(tok) = local.peek_clone() {
83
+ match tok.kind {
84
+ TokenKind::Identifier if tok.lexeme == "param" => {
85
+ local.advance(); // consume 'param'
86
+ // param name
87
+ let Some(name_tok) = local.peek_clone() else {
88
+ return Statement::error(
89
+ tok,
90
+ "Expected parameter name after 'param'".to_string(),
91
+ );
92
+ };
93
+ if name_tok.kind != TokenKind::Identifier && name_tok.kind != TokenKind::String {
94
+ return Statement::error(name_tok, "Expected valid parameter name".to_string());
95
+ }
96
+ local.advance(); // consume name
97
+
98
+ // Expect '{'
99
+ if !local.match_token(TokenKind::LBrace) {
100
+ return Statement::error(
101
+ name_tok,
102
+ "Expected '{' to start parameter block".to_string(),
103
+ );
104
+ }
105
+
106
+ // Collect entries like: 0% = 0.0
107
+ let mut envelope: HashMap<String, Value> = HashMap::new();
108
+ while let Some(inner) = local.peek_clone() {
109
+ if inner.kind == TokenKind::RBrace {
110
+ local.advance();
111
+ break;
112
+ }
113
+ // Skip formatting tokens inside the param block
114
+ if matches!(
115
+ inner.kind,
116
+ TokenKind::Newline
117
+ | TokenKind::Indent
118
+ | TokenKind::Dedent
119
+ | TokenKind::Comma
120
+ ) {
121
+ local.advance();
122
+ continue;
123
+ }
124
+
125
+ // Read percentage token: could be number followed by '%' as Dot or Identifier? '%' not defined.
126
+ // Our lexer has no Percent token, so accept either Number or Identifier containing e.g. '0%'.
127
+ let percent_token = inner.clone();
128
+ local.advance();
129
+
130
+ let percent_key = percent_token.lexeme.clone();
131
+
132
+ // Expect '='
133
+ // Skip any stray formatting between key and '='
134
+ while let Some(t) = local.peek_kind() {
135
+ if matches!(
136
+ t,
137
+ TokenKind::Indent | TokenKind::Dedent | TokenKind::Newline
138
+ ) {
139
+ local.advance();
140
+ continue;
141
+ }
142
+ break;
143
+ }
144
+ if !local.match_token(TokenKind::Equals) {
145
+ return Statement::error(
146
+ percent_token,
147
+ "Expected '=' in param entry".to_string(),
148
+ );
149
+ }
150
+
151
+ // Read value (number or identifier)
152
+ // Skip formatting before value
153
+ while let Some(t) = local.peek_kind() {
154
+ if matches!(
155
+ t,
156
+ TokenKind::Indent | TokenKind::Dedent | TokenKind::Newline
157
+ ) {
158
+ local.advance();
159
+ continue;
160
+ }
161
+ break;
162
+ }
163
+
164
+ let value = if let Some(vtok) = local.peek_clone() {
165
+ match vtok.kind {
166
+ // Handle negative numbers where '-' is lexed as Arrow
167
+ TokenKind::Arrow => {
168
+ // Check if next token is a number
169
+ let mut num_str = String::from("-");
170
+ local.advance(); // consume '-'
171
+ if let Some(ntok) = local.peek_clone() {
172
+ if ntok.kind == TokenKind::Number {
173
+ num_str.push_str(&ntok.lexeme);
174
+ local.advance(); // consume number
175
+ if let Some(dot) = local.peek_clone() {
176
+ if dot.kind == TokenKind::Dot {
177
+ local.advance();
178
+ if let Some(frac) = local.peek_clone() {
179
+ if frac.kind == TokenKind::Number {
180
+ num_str.push('.');
181
+ num_str.push_str(&frac.lexeme);
182
+ local.advance();
183
+ }
184
+ }
185
+ }
186
+ }
187
+ Value::Number(num_str.parse::<f32>().unwrap_or(0.0))
188
+ } else {
189
+ Value::Unknown
190
+ }
191
+ } else {
192
+ Value::Unknown
193
+ }
194
+ }
195
+ TokenKind::Number => {
196
+ // Possibly a float with dot
197
+ let mut number_str = vtok.lexeme.clone();
198
+ local.advance();
199
+ if let Some(dot) = local.peek_clone() {
200
+ if dot.kind == TokenKind::Dot {
201
+ local.advance();
202
+ if let Some(frac) = local.peek_clone() {
203
+ if frac.kind == TokenKind::Number {
204
+ number_str.push('.');
205
+ number_str.push_str(&frac.lexeme);
206
+ local.advance();
207
+ }
208
+ }
209
+ }
210
+ }
211
+ Value::Number(number_str.parse::<f32>().unwrap_or(0.0))
212
+ }
213
+ TokenKind::Identifier => {
214
+ local.advance();
215
+ Value::Identifier(vtok.lexeme.clone())
216
+ }
217
+ TokenKind::String => {
218
+ local.advance();
219
+ Value::String(vtok.lexeme.clone())
220
+ }
221
+ _ => {
222
+ local.advance();
223
+ Value::Unknown
224
+ }
225
+ }
226
+ } else {
227
+ Value::Null
228
+ };
229
+
230
+ envelope.insert(percent_key, value);
231
+ }
232
+
233
+ params.insert(name_tok.lexeme.clone(), Value::Map(envelope));
234
+ }
235
+ _ => {
236
+ local.advance();
237
+ }
238
+ }
239
+ }
240
+
241
+ let mut value_map = HashMap::new();
242
+ value_map.insert(
243
+ "target".to_string(),
244
+ Value::String(target_token.lexeme.clone()),
245
+ );
246
+ value_map.insert("params".to_string(), Value::Map(params));
247
+
248
+ Statement {
249
+ kind: StatementKind::Automate {
250
+ target: target_token.lexeme.clone(),
251
+ },
252
+ value: Value::Map(value_map),
253
+ indent: current_token.indent,
254
+ line: current_token.line,
255
+ column: current_token.column,
256
+ }
257
+ }
@@ -1,88 +1,91 @@
1
- use crate::core::{
2
- lexer::token::{Token, TokenKind},
3
- parser::{statement::{Statement, StatementKind}, driver::Parser},
4
- shared::value::Value,
5
- store::global::GlobalStore,
6
- };
7
-
8
- pub fn parse_call_token(
9
- parser: &mut Parser,
10
- current_token: Token,
11
- _global_store: &mut GlobalStore
12
- ) -> Statement {
13
- parser.advance(); // consume "call"
14
-
15
- // Expect function name
16
- let name_token = match parser.peek_clone() {
17
- Some(t) => t,
18
- None => {
19
- return Statement::error(
20
- current_token,
21
- "Expected function name after 'call'".to_string()
22
- );
23
- }
24
- };
25
-
26
- if name_token.kind != TokenKind::Identifier {
27
- return Statement::error(
28
- name_token,
29
- "Expected function name to be an identifier".to_string()
30
- );
31
- }
32
-
33
- let func_name = name_token.lexeme.clone();
34
- parser.advance(); // consume function name
35
-
36
- // Expect '('
37
- let mut args: Vec<Value> = Vec::new();
38
- if let Some(open_paren) = parser.peek_clone() {
39
- if open_paren.kind == TokenKind::LParen {
40
- parser.advance(); // consume '('
41
-
42
- // Collect args until ')'
43
- while let Some(token) = parser.peek_clone() {
44
- if token.kind == TokenKind::RParen {
45
- parser.advance(); // consume ')'
46
- break;
47
- }
48
-
49
- match token.kind {
50
- TokenKind::Number => {
51
- if let Ok(num) = token.lexeme.parse::<f32>() {
52
- args.push(Value::Number(num));
53
- }
54
- parser.advance();
55
- }
56
- TokenKind::String => {
57
- args.push(Value::String(token.lexeme.clone()));
58
- parser.advance();
59
- }
60
- TokenKind::Identifier => {
61
- args.push(Value::Identifier(token.lexeme.clone()));
62
- parser.advance();
63
- }
64
- TokenKind::Comma => {
65
- parser.advance(); // skip comma
66
- }
67
- _ => {
68
- return Statement::error(
69
- token,
70
- "Unexpected token in call arguments".to_string()
71
- );
72
- }
73
- }
74
- }
75
- }
76
- }
77
-
78
- Statement {
79
- kind: StatementKind::Call {
80
- name: func_name,
81
- args,
82
- },
83
- value: Value::Null,
84
- indent: current_token.indent,
85
- line: current_token.line,
86
- column: current_token.column,
87
- }
88
- }
1
+ use crate::core::{
2
+ lexer::token::{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_call_token(
12
+ parser: &mut Parser,
13
+ current_token: Token,
14
+ _global_store: &mut GlobalStore,
15
+ ) -> Statement {
16
+ parser.advance(); // consume "call"
17
+
18
+ // Expect function name
19
+ let name_token = match parser.peek_clone() {
20
+ Some(t) => t,
21
+ None => {
22
+ return Statement::error(
23
+ current_token,
24
+ "Expected function name after 'call'".to_string(),
25
+ );
26
+ }
27
+ };
28
+
29
+ if name_token.kind != TokenKind::Identifier {
30
+ return Statement::error(
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 Statement::error(
72
+ token,
73
+ "Unexpected token in call arguments".to_string(),
74
+ );
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+
81
+ Statement {
82
+ kind: StatementKind::Call {
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
+ }