@devaloop/devalang 0.0.1-alpha.7 → 0.0.1-alpha.9
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.
- package/Cargo.toml +1 -1
- package/README.md +31 -16
- package/docs/CHANGELOG.md +49 -2
- package/docs/ROADMAP.md +2 -2
- package/docs/SYNTAX.md +41 -7
- package/docs/TODO.md +3 -3
- package/examples/condition.deva +20 -0
- package/examples/group.deva +3 -3
- package/examples/index.deva +9 -8
- package/examples/loop.deva +10 -8
- package/examples/synth.deva +14 -0
- package/examples/variables.deva +2 -2
- package/out-tsc/bin/devalang.exe +0 -0
- package/out-tsc/scripts/version/fetch.js +1 -5
- package/package.json +1 -1
- package/project-version.json +3 -3
- package/rust/cli/build.rs +6 -1
- package/rust/core/audio/engine.rs +89 -12
- package/rust/core/audio/evaluator.rs +31 -0
- package/rust/core/audio/interpreter/arrow_call.rs +129 -0
- package/rust/core/audio/interpreter/call.rs +64 -0
- package/rust/core/audio/interpreter/condition.rs +69 -0
- package/rust/core/audio/interpreter/driver.rs +216 -0
- package/rust/core/audio/interpreter/let_.rs +19 -0
- package/rust/core/audio/interpreter/load.rs +18 -0
- package/rust/core/audio/interpreter/loop_.rs +67 -0
- package/rust/core/audio/interpreter/mod.rs +12 -0
- package/rust/core/audio/interpreter/sleep.rs +36 -0
- package/rust/core/audio/interpreter/spawn.rs +66 -0
- package/rust/core/audio/interpreter/tempo.rs +16 -0
- package/rust/core/audio/interpreter/trigger.rs +69 -0
- package/rust/core/audio/loader/mod.rs +1 -0
- package/rust/core/audio/{loader.rs → loader/trigger.rs} +3 -1
- package/rust/core/audio/mod.rs +2 -1
- package/rust/core/audio/renderer.rs +54 -0
- package/rust/core/builder/mod.rs +1 -1
- package/rust/core/debugger/lexer.rs +1 -1
- package/rust/core/debugger/mod.rs +1 -0
- package/rust/core/debugger/store.rs +25 -0
- package/rust/core/error/mod.rs +1 -1
- package/rust/core/lexer/handler/arrow.rs +31 -0
- package/rust/core/lexer/handler/driver.rs +226 -0
- package/rust/core/lexer/handler/identifier.rs +3 -0
- package/rust/core/lexer/handler/mod.rs +4 -227
- package/rust/core/lexer/handler/operator.rs +44 -0
- package/rust/core/lexer/mod.rs +25 -4
- package/rust/core/lexer/token.rs +40 -9
- package/rust/core/parser/driver.rs +331 -0
- package/rust/core/parser/handler/arrow_call.rs +126 -0
- package/rust/core/parser/handler/at.rs +3 -7
- package/rust/core/parser/handler/bank.rs +5 -2
- package/rust/core/parser/handler/condition.rs +74 -0
- package/rust/core/parser/handler/dot.rs +1 -1
- package/rust/core/parser/handler/identifier/call.rs +41 -0
- package/rust/core/parser/handler/identifier/group.rs +75 -0
- package/rust/core/parser/handler/identifier/let_.rs +133 -0
- package/rust/core/parser/handler/identifier/mod.rs +51 -0
- package/rust/core/parser/handler/identifier/sleep.rs +33 -0
- package/rust/core/parser/handler/identifier/spawn.rs +41 -0
- package/rust/core/parser/handler/identifier/synth.rs +65 -0
- package/rust/core/parser/handler/loop_.rs +25 -19
- package/rust/core/parser/handler/mod.rs +3 -1
- package/rust/core/parser/handler/tempo.rs +1 -1
- package/rust/core/parser/mod.rs +3 -237
- package/rust/core/parser/statement.rs +36 -35
- package/rust/core/preprocessor/loader.rs +64 -49
- package/rust/core/preprocessor/module.rs +3 -6
- package/rust/core/preprocessor/processor.rs +13 -4
- package/rust/core/preprocessor/resolver/call.rs +123 -0
- package/rust/core/preprocessor/resolver/condition.rs +92 -0
- package/rust/core/preprocessor/resolver/driver.rs +227 -0
- package/rust/core/preprocessor/resolver/group.rs +35 -87
- package/rust/core/preprocessor/resolver/let_.rs +31 -0
- package/rust/core/preprocessor/resolver/loop_.rs +62 -116
- package/rust/core/preprocessor/resolver/mod.rs +9 -153
- package/rust/core/preprocessor/resolver/spawn.rs +58 -0
- package/rust/core/preprocessor/resolver/synth.rs +50 -0
- package/rust/core/preprocessor/resolver/trigger.rs +51 -50
- package/rust/core/preprocessor/resolver/value.rs +78 -0
- package/rust/core/utils/path.rs +17 -32
- package/rust/core/utils/validation.rs +30 -28
- package/typescript/scripts/version/fetch.ts +1 -6
- package/rust/core/audio/interpreter.rs +0 -317
- package/rust/core/audio/render.rs +0 -53
- package/rust/core/lexer/handler/equal.rs +0 -32
- package/rust/core/parser/handler/identifier.rs +0 -260
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
use crate::{
|
|
3
|
+
core::{
|
|
4
|
+
parser::statement::{ Statement, StatementKind },
|
|
5
|
+
preprocessor::{
|
|
6
|
+
loader::ModuleLoader,
|
|
7
|
+
module::Module,
|
|
8
|
+
resolver::{
|
|
9
|
+
bank::resolve_bank,
|
|
10
|
+
call::resolve_call,
|
|
11
|
+
condition::resolve_condition,
|
|
12
|
+
group::resolve_group,
|
|
13
|
+
let_::resolve_let,
|
|
14
|
+
loop_::resolve_loop,
|
|
15
|
+
spawn::resolve_spawn,
|
|
16
|
+
tempo::resolve_tempo,
|
|
17
|
+
trigger::resolve_trigger,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
shared::value::Value,
|
|
21
|
+
store::global::GlobalStore,
|
|
22
|
+
},
|
|
23
|
+
utils::logger::Logger,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
pub fn resolve_all_modules(module_loader: &ModuleLoader, global_store: &mut GlobalStore) {
|
|
27
|
+
for module in global_store.clone().modules.values_mut() {
|
|
28
|
+
resolve_imports(module_loader, global_store);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
pub fn resolve_statement(
|
|
33
|
+
stmt: &Statement,
|
|
34
|
+
module: &Module,
|
|
35
|
+
path: &str,
|
|
36
|
+
global_store: &mut GlobalStore
|
|
37
|
+
) -> Statement {
|
|
38
|
+
match &stmt.kind {
|
|
39
|
+
StatementKind::Trigger { entity, duration } =>
|
|
40
|
+
resolve_trigger(stmt, entity, &mut duration.clone(), module, path, global_store),
|
|
41
|
+
StatementKind::If => resolve_condition(stmt, module, path, global_store),
|
|
42
|
+
StatementKind::Group => resolve_group(stmt, module, path, global_store),
|
|
43
|
+
StatementKind::Call => resolve_call(stmt, module, path, global_store),
|
|
44
|
+
StatementKind::Spawn => resolve_spawn(stmt, module, path, global_store),
|
|
45
|
+
StatementKind::Bank => resolve_bank(stmt, module, path, global_store),
|
|
46
|
+
StatementKind::Tempo => resolve_tempo(stmt, module, path, global_store),
|
|
47
|
+
StatementKind::Loop => resolve_loop(stmt, module, path, global_store),
|
|
48
|
+
StatementKind::Let { name, .. } => resolve_let(stmt, name, module, path, global_store),
|
|
49
|
+
|
|
50
|
+
_ => {
|
|
51
|
+
let resolved_value = resolve_value(&stmt.value, module, global_store);
|
|
52
|
+
|
|
53
|
+
Statement {
|
|
54
|
+
value: resolved_value,
|
|
55
|
+
..stmt.clone()
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
fn resolve_value(value: &Value, module: &Module, global_store: &mut GlobalStore) -> Value {
|
|
62
|
+
match value {
|
|
63
|
+
Value::Identifier(name) => {
|
|
64
|
+
if let Some(original_val) = module.variable_table.get(name) {
|
|
65
|
+
return resolve_value(original_val, module, global_store);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if let Some(export_val) = find_export_value(name, global_store) {
|
|
69
|
+
return resolve_value(&export_val, module, global_store);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
eprintln!("⚠️ Unresolved identifier '{}'", name);
|
|
73
|
+
Value::Null
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
Value::Map(map) => {
|
|
77
|
+
let mut resolved = HashMap::new();
|
|
78
|
+
for (k, v) in map {
|
|
79
|
+
resolved.insert(k.clone(), resolve_value(v, module, global_store));
|
|
80
|
+
}
|
|
81
|
+
Value::Map(resolved)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
Value::Block(stmts) => {
|
|
85
|
+
let resolved_stmts = stmts
|
|
86
|
+
.iter()
|
|
87
|
+
.map(|stmt| resolve_statement(stmt, module, &module.path, global_store))
|
|
88
|
+
.collect();
|
|
89
|
+
Value::Block(resolved_stmts)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
other => other.clone(),
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
fn find_export_value(name: &str, global_store: &GlobalStore) -> Option<Value> {
|
|
97
|
+
for (_path, module) in &global_store.modules {
|
|
98
|
+
if let Some(val) = module.export_table.get_export(name) {
|
|
99
|
+
return Some(val.clone());
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
None
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
pub fn resolve_imports(module_loader: &ModuleLoader, global_store: &mut GlobalStore) {
|
|
106
|
+
for (module_path, module) in global_store.clone().modules.iter_mut() {
|
|
107
|
+
for (name, source_path) in &module.import_table.imports {
|
|
108
|
+
match source_path {
|
|
109
|
+
Value::String(source_path) => {
|
|
110
|
+
if let Some(source_module) = global_store.modules.get(source_path) {
|
|
111
|
+
if let Some(value) = source_module.export_table.get_export(name) {
|
|
112
|
+
module.variable_table.set(name.clone(), value.clone());
|
|
113
|
+
} else {
|
|
114
|
+
println!(
|
|
115
|
+
"[warn] '{module_path}': '{name}' not found in exports of '{source_path}'"
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
} else {
|
|
119
|
+
println!(
|
|
120
|
+
"[warn] '{module_path}': cannot find source module '{source_path}'"
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
_ => {
|
|
125
|
+
println!(
|
|
126
|
+
"[warn] '{module_path}': expected string for import source, found {:?}",
|
|
127
|
+
source_path
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
pub fn resolve_and_flatten_all_modules(
|
|
136
|
+
global_store: &mut GlobalStore
|
|
137
|
+
) -> HashMap<String, Vec<Statement>> {
|
|
138
|
+
let logger = Logger::new();
|
|
139
|
+
let snapshot = global_store.clone();
|
|
140
|
+
|
|
141
|
+
// 1. Imports resolution
|
|
142
|
+
for (module_path, module) in global_store.modules.iter_mut() {
|
|
143
|
+
for (name, source_path) in &module.import_table.imports {
|
|
144
|
+
if let Value::String(source_path_str) = source_path {
|
|
145
|
+
match snapshot.modules.get(source_path_str) {
|
|
146
|
+
Some(source_module) => {
|
|
147
|
+
if let Some(value) = source_module.export_table.get_export(name) {
|
|
148
|
+
module.variable_table.set(name.clone(), value.clone());
|
|
149
|
+
} else {
|
|
150
|
+
logger.log_error_with_stacktrace(
|
|
151
|
+
&format!("'{name}' not found in exports of '{source_path_str}'"),
|
|
152
|
+
module_path
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
None => {
|
|
157
|
+
logger.log_error_with_stacktrace(
|
|
158
|
+
&format!("Cannot find source module '{source_path_str}'"),
|
|
159
|
+
module_path
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
} else {
|
|
164
|
+
logger.log_error_with_stacktrace(
|
|
165
|
+
&format!("Expected string for import source, found {:?}", source_path),
|
|
166
|
+
module_path
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// 2. Statements resolution
|
|
173
|
+
let mut resolved_map: HashMap<String, Vec<Statement>> = HashMap::new();
|
|
174
|
+
for (path, module) in global_store.modules.clone() {
|
|
175
|
+
let mut resolved = Vec::new();
|
|
176
|
+
|
|
177
|
+
for stmt in &module.statements {
|
|
178
|
+
let mut stmt = stmt.clone();
|
|
179
|
+
|
|
180
|
+
match &stmt.kind {
|
|
181
|
+
StatementKind::Trigger { entity, duration } => {
|
|
182
|
+
let resolved_stmt = resolve_trigger(
|
|
183
|
+
&stmt,
|
|
184
|
+
entity.as_str(),
|
|
185
|
+
&mut duration.clone(),
|
|
186
|
+
&module,
|
|
187
|
+
&path,
|
|
188
|
+
global_store
|
|
189
|
+
);
|
|
190
|
+
resolved.push(resolved_stmt);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
StatementKind::Loop => {
|
|
194
|
+
let resolved_stmt = resolve_loop(&stmt, &module, &path, global_store);
|
|
195
|
+
resolved.push(resolved_stmt);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
StatementKind::Bank => {
|
|
199
|
+
let resolved_stmt = resolve_bank(&stmt, &module, &path, global_store);
|
|
200
|
+
resolved.push(resolved_stmt);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
StatementKind::Tempo => {
|
|
204
|
+
let resolved_stmt = resolve_tempo(&stmt, &module, &path, global_store);
|
|
205
|
+
resolved.push(resolved_stmt);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
StatementKind::Import { .. } | StatementKind::Export { .. } => {
|
|
209
|
+
resolved.push(stmt.clone());
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
StatementKind::Group => {
|
|
213
|
+
let resolved_stmt = resolve_group(&stmt, &module, &path, global_store);
|
|
214
|
+
resolved.push(resolved_stmt);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
_ => {
|
|
218
|
+
resolved.push(stmt);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
resolved_map.insert(path.clone(), resolved);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
resolved_map
|
|
227
|
+
}
|
|
@@ -3,111 +3,59 @@ use std::collections::HashMap;
|
|
|
3
3
|
use crate::{
|
|
4
4
|
core::{
|
|
5
5
|
parser::statement::{ Statement, StatementKind },
|
|
6
|
-
preprocessor::{ module::Module, resolver::
|
|
6
|
+
preprocessor::{ module::Module, resolver::driver::resolve_statement },
|
|
7
7
|
shared::value::Value,
|
|
8
|
-
store::global::GlobalStore,
|
|
8
|
+
store::{ global::GlobalStore, variable::VariableTable },
|
|
9
9
|
},
|
|
10
|
-
utils::logger::Logger,
|
|
10
|
+
utils::logger::{ LogLevel, Logger },
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
pub fn resolve_group(
|
|
14
14
|
stmt: &Statement,
|
|
15
15
|
module: &Module,
|
|
16
16
|
path: &str,
|
|
17
|
-
global_store: &GlobalStore
|
|
17
|
+
global_store: &mut GlobalStore
|
|
18
18
|
) -> Statement {
|
|
19
19
|
let logger = Logger::new();
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
Some(other) => {
|
|
25
|
-
log_type_error(
|
|
26
|
-
&logger,
|
|
27
|
-
module,
|
|
28
|
-
stmt,
|
|
29
|
-
format!("Group name must be a string, found {:?}", other)
|
|
30
|
-
);
|
|
31
|
-
return stmt.clone();
|
|
32
|
-
}
|
|
33
|
-
None => {
|
|
34
|
-
log_type_error(&logger, module, stmt, "Group name is required".to_string());
|
|
35
|
-
return stmt.clone();
|
|
36
|
-
}
|
|
37
|
-
};
|
|
21
|
+
let Value::Map(group_map) = &stmt.value else {
|
|
22
|
+
return type_error(&logger, module, stmt, "Expected a map in group statement".to_string());
|
|
23
|
+
};
|
|
38
24
|
|
|
39
|
-
|
|
40
|
-
Some(Value::Block(block)) => {
|
|
41
|
-
let mut resolved_block = Vec::new();
|
|
42
|
-
for ref statement in block.clone() {
|
|
43
|
-
match &statement.kind {
|
|
44
|
-
StatementKind::Trigger { entity, duration } => {
|
|
45
|
-
let resolved = resolve_trigger(
|
|
46
|
-
&mut statement.clone(),
|
|
47
|
-
&entity,
|
|
48
|
-
&mut duration.clone(),
|
|
49
|
-
module,
|
|
50
|
-
path,
|
|
51
|
-
global_store
|
|
52
|
-
);
|
|
53
|
-
resolved_block.push(resolved);
|
|
54
|
-
}
|
|
55
|
-
_ => {
|
|
56
|
-
println!("Unhandled group body statement: {:?}", statement);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
Value::Block(resolved_block)
|
|
61
|
-
}
|
|
62
|
-
Some(other) => {
|
|
63
|
-
log_type_error(
|
|
64
|
-
&logger,
|
|
65
|
-
module,
|
|
66
|
-
stmt,
|
|
67
|
-
format!("Unexpected value for group body: {:?}", other)
|
|
68
|
-
);
|
|
69
|
-
Value::Null
|
|
70
|
-
}
|
|
71
|
-
None => {
|
|
72
|
-
log_type_error(
|
|
73
|
-
&logger,
|
|
74
|
-
module,
|
|
75
|
-
stmt,
|
|
76
|
-
"Missing 'body' key in group statement map".to_string()
|
|
77
|
-
);
|
|
78
|
-
Value::Null
|
|
79
|
-
}
|
|
80
|
-
};
|
|
25
|
+
let mut resolved_map = group_map.clone();
|
|
81
26
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
resolved_map.insert("
|
|
85
|
-
resolved_map.insert("body".to_string(), body_value);
|
|
86
|
-
|
|
87
|
-
return Statement {
|
|
88
|
-
kind: StatementKind::Group,
|
|
89
|
-
value: Value::Map(resolved_map),
|
|
90
|
-
..stmt.clone()
|
|
91
|
-
};
|
|
27
|
+
if let Some(Value::Block(body)) = group_map.get("body") {
|
|
28
|
+
let resolved_body = resolve_block_statements(body, module, path, global_store);
|
|
29
|
+
resolved_map.insert("body".to_string(), Value::Block(resolved_body));
|
|
92
30
|
} else {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
module,
|
|
96
|
-
stmt,
|
|
97
|
-
format!("Expected Map for group statement, found {:?}", stmt.value)
|
|
98
|
-
);
|
|
31
|
+
logger.log_message(LogLevel::Warning, "group without a body");
|
|
32
|
+
}
|
|
99
33
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
value: Value::Null,
|
|
105
|
-
..stmt.clone()
|
|
106
|
-
}
|
|
34
|
+
Statement {
|
|
35
|
+
kind: StatementKind::Group,
|
|
36
|
+
value: Value::Map(resolved_map),
|
|
37
|
+
..stmt.clone()
|
|
107
38
|
}
|
|
108
39
|
}
|
|
109
40
|
|
|
110
|
-
fn
|
|
41
|
+
fn resolve_block_statements(
|
|
42
|
+
body: &[Statement],
|
|
43
|
+
module: &Module,
|
|
44
|
+
path: &str,
|
|
45
|
+
global_store: &mut GlobalStore
|
|
46
|
+
) -> Vec<Statement> {
|
|
47
|
+
body.iter()
|
|
48
|
+
.map(|stmt| resolve_statement(stmt, module, path, global_store))
|
|
49
|
+
.collect()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fn type_error(logger: &Logger, module: &Module, stmt: &Statement, message: String) -> Statement {
|
|
111
53
|
let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
|
|
112
54
|
logger.log_error_with_stacktrace(&message, &stacktrace);
|
|
55
|
+
|
|
56
|
+
Statement {
|
|
57
|
+
kind: StatementKind::Error { message },
|
|
58
|
+
value: Value::Null,
|
|
59
|
+
..stmt.clone()
|
|
60
|
+
}
|
|
113
61
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
use crate::
|
|
2
|
+
core::{
|
|
3
|
+
parser::statement:: Statement ,
|
|
4
|
+
preprocessor::{
|
|
5
|
+
module::Module,
|
|
6
|
+
resolver:: value::resolve_value ,
|
|
7
|
+
},
|
|
8
|
+
store:: global::GlobalStore ,
|
|
9
|
+
}
|
|
10
|
+
;
|
|
11
|
+
|
|
12
|
+
pub fn resolve_let(
|
|
13
|
+
stmt: &Statement,
|
|
14
|
+
name: &str,
|
|
15
|
+
module: &Module,
|
|
16
|
+
path: &str,
|
|
17
|
+
global_store: &mut GlobalStore
|
|
18
|
+
) -> Statement {
|
|
19
|
+
let resolved_value = resolve_value(&stmt.value, module, global_store);
|
|
20
|
+
|
|
21
|
+
if let Some(current_mod) = global_store.modules.get_mut(path) {
|
|
22
|
+
current_mod.variable_table.set(name.to_string(), resolved_value.clone());
|
|
23
|
+
} else {
|
|
24
|
+
eprintln!("[resolve_statement] ❌ Module path not found: {path}");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Statement {
|
|
28
|
+
value: resolved_value,
|
|
29
|
+
..stmt.clone()
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -3,7 +3,10 @@ use std::collections::HashMap;
|
|
|
3
3
|
use crate::{
|
|
4
4
|
core::{
|
|
5
5
|
parser::statement::{ Statement, StatementKind },
|
|
6
|
-
preprocessor::{
|
|
6
|
+
preprocessor::{
|
|
7
|
+
module::Module,
|
|
8
|
+
resolver::{ driver::resolve_statement, value::resolve_value },
|
|
9
|
+
},
|
|
7
10
|
shared::value::Value,
|
|
8
11
|
store::global::GlobalStore,
|
|
9
12
|
},
|
|
@@ -14,132 +17,75 @@ pub fn resolve_loop(
|
|
|
14
17
|
stmt: &Statement,
|
|
15
18
|
module: &Module,
|
|
16
19
|
path: &str,
|
|
17
|
-
global_store: &GlobalStore
|
|
20
|
+
global_store: &mut GlobalStore
|
|
18
21
|
) -> Statement {
|
|
19
22
|
let logger = Logger::new();
|
|
20
23
|
|
|
21
|
-
|
|
22
|
-
let iterator_value = match value_map.get("iterator") {
|
|
23
|
-
Some(Value::Identifier(ident)) => {
|
|
24
|
-
match module.variable_table.get(ident) {
|
|
25
|
-
Some(Value::Number(n)) => Value::Number(*n),
|
|
26
|
-
Some(_) => {
|
|
27
|
-
log_type_error(
|
|
28
|
-
&logger,
|
|
29
|
-
module,
|
|
30
|
-
stmt,
|
|
31
|
-
format!("Loop iterator '{ident}' must resolve to a number")
|
|
32
|
-
);
|
|
33
|
-
Value::Null
|
|
34
|
-
}
|
|
35
|
-
None => {
|
|
36
|
-
// Value is not a variable so we assume it's a number
|
|
37
|
-
if let Ok(n) = ident.parse::<f32>() {
|
|
38
|
-
Value::Number(n)
|
|
39
|
-
} else {
|
|
40
|
-
log_type_error(
|
|
41
|
-
&logger,
|
|
42
|
-
module,
|
|
43
|
-
stmt,
|
|
44
|
-
format!("Loop iterator '{ident}' is not a valid number")
|
|
45
|
-
);
|
|
46
|
-
Value::Null
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
Some(Value::Number(n)) => Value::Number(*n),
|
|
52
|
-
Some(other) => {
|
|
53
|
-
log_type_error(
|
|
54
|
-
&logger,
|
|
55
|
-
module,
|
|
56
|
-
stmt,
|
|
57
|
-
format!("Unexpected value for loop iterator: {:?}", other)
|
|
58
|
-
);
|
|
59
|
-
Value::Null
|
|
60
|
-
}
|
|
61
|
-
None => {
|
|
62
|
-
log_type_error(
|
|
63
|
-
&logger,
|
|
64
|
-
module,
|
|
65
|
-
stmt,
|
|
66
|
-
"Missing 'iterator' key in loop statement map".to_string()
|
|
67
|
-
);
|
|
68
|
-
Value::Null
|
|
69
|
-
}
|
|
70
|
-
};
|
|
24
|
+
let resolved_value = resolve_value(&stmt.value, module, global_store);
|
|
71
25
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
for ref statement in block.clone() {
|
|
76
|
-
match &statement.kind {
|
|
77
|
-
StatementKind::Trigger { entity, duration } => {
|
|
78
|
-
let resolved = resolve_trigger(
|
|
79
|
-
&mut statement.clone(),
|
|
80
|
-
&entity,
|
|
81
|
-
&mut duration.clone(),
|
|
82
|
-
module,
|
|
83
|
-
path,
|
|
84
|
-
global_store
|
|
85
|
-
);
|
|
86
|
-
resolved_block.push(resolved);
|
|
87
|
-
}
|
|
88
|
-
_ => {
|
|
89
|
-
println!("Unhandled loop body statement: {:?}", statement);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
Value::Block(resolved_block)
|
|
94
|
-
}
|
|
95
|
-
Some(other) => {
|
|
96
|
-
log_type_error(
|
|
97
|
-
&logger,
|
|
98
|
-
module,
|
|
99
|
-
stmt,
|
|
100
|
-
format!("Unexpected value for loop body: {:?}", other)
|
|
101
|
-
);
|
|
102
|
-
Value::Null
|
|
103
|
-
}
|
|
104
|
-
None => {
|
|
105
|
-
log_type_error(
|
|
106
|
-
&logger,
|
|
107
|
-
module,
|
|
108
|
-
stmt,
|
|
109
|
-
"Missing 'body' key in loop statement map".to_string()
|
|
110
|
-
);
|
|
111
|
-
Value::Null
|
|
112
|
-
}
|
|
113
|
-
};
|
|
26
|
+
let Value::Map(value_map) = &resolved_value else {
|
|
27
|
+
return error_stmt(&logger, module, stmt, "Expected a map for loop value");
|
|
28
|
+
};
|
|
114
29
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
resolved_map.insert(
|
|
30
|
+
let mut resolved_map: HashMap<String, Value> = HashMap::new();
|
|
31
|
+
for (key, val) in value_map {
|
|
32
|
+
resolved_map.insert(key.clone(), resolve_value(val, module, global_store));
|
|
33
|
+
}
|
|
118
34
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
35
|
+
let iterator_value = match resolved_map.get("iterator") {
|
|
36
|
+
Some(Value::Number(n)) => Value::Number(*n),
|
|
37
|
+
Some(other) => {
|
|
38
|
+
error_value(
|
|
39
|
+
&logger,
|
|
40
|
+
module,
|
|
41
|
+
stmt,
|
|
42
|
+
&format!("Loop iterator must be a number, found: {:?}", other)
|
|
43
|
+
);
|
|
44
|
+
Value::Number(1.0)
|
|
45
|
+
}
|
|
46
|
+
None => {
|
|
47
|
+
error_value(&logger, module, stmt, "Missing 'iterator' in loop");
|
|
48
|
+
Value::Number(1.0)
|
|
123
49
|
}
|
|
124
|
-
}
|
|
125
|
-
log_type_error(
|
|
126
|
-
&logger,
|
|
127
|
-
module,
|
|
128
|
-
stmt,
|
|
129
|
-
format!("Expected a map for loop value, found {:?}", stmt.value)
|
|
130
|
-
);
|
|
50
|
+
};
|
|
131
51
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
52
|
+
let body_value = match resolved_map.remove("body") {
|
|
53
|
+
Some(Value::Block(stmts)) => {
|
|
54
|
+
let resolved = stmts
|
|
55
|
+
.iter()
|
|
56
|
+
.map(|s| resolve_statement(s, module, path, global_store))
|
|
57
|
+
.collect();
|
|
58
|
+
Value::Block(resolved)
|
|
138
59
|
}
|
|
60
|
+
_ => {
|
|
61
|
+
error_value(&logger, module, stmt, "Invalid or missing loop body");
|
|
62
|
+
Value::Block(vec![])
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
let mut final_map = HashMap::new();
|
|
67
|
+
final_map.insert("iterator".to_string(), iterator_value);
|
|
68
|
+
final_map.insert("body".to_string(), body_value);
|
|
69
|
+
|
|
70
|
+
Statement {
|
|
71
|
+
kind: StatementKind::Loop,
|
|
72
|
+
value: Value::Map(final_map),
|
|
73
|
+
..stmt.clone()
|
|
139
74
|
}
|
|
140
75
|
}
|
|
141
76
|
|
|
142
|
-
fn
|
|
77
|
+
fn error_value(logger: &Logger, module: &Module, stmt: &Statement, msg: &str) {
|
|
143
78
|
let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
|
|
144
|
-
logger.log_error_with_stacktrace(
|
|
79
|
+
logger.log_error_with_stacktrace(msg, &stacktrace);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
fn error_stmt(logger: &Logger, module: &Module, stmt: &Statement, msg: &str) -> Statement {
|
|
83
|
+
error_value(logger, module, stmt, msg);
|
|
84
|
+
Statement {
|
|
85
|
+
kind: StatementKind::Error {
|
|
86
|
+
message: msg.to_string(),
|
|
87
|
+
},
|
|
88
|
+
value: Value::Null,
|
|
89
|
+
..stmt.clone()
|
|
90
|
+
}
|
|
145
91
|
}
|