@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
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
use serde::{ Deserialize, Serialize };
|
|
2
|
-
|
|
3
2
|
use crate::core::{ lexer::token::Token, shared::{ duration::Duration, value::Value } };
|
|
4
3
|
|
|
5
4
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
@@ -34,39 +33,40 @@ impl Statement {
|
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
#[derive(Debug, Serialize, Clone, Deserialize, PartialEq)]
|
|
37
|
-
/// Represents the kind of a statement
|
|
38
36
|
pub enum StatementKind {
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
// ───── Core Instructions ─────
|
|
38
|
+
Tempo,
|
|
39
|
+
Bank,
|
|
40
|
+
Load {
|
|
41
|
+
source: String,
|
|
42
|
+
alias: String,
|
|
44
43
|
},
|
|
45
|
-
|
|
46
|
-
// Variable statements
|
|
47
44
|
Let {
|
|
48
45
|
name: String,
|
|
49
46
|
},
|
|
47
|
+
ArrowCall {
|
|
48
|
+
target: String,
|
|
49
|
+
method: String,
|
|
50
|
+
args: Vec<Value>,
|
|
51
|
+
},
|
|
50
52
|
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
+
// ───── Instruments ─────
|
|
54
|
+
Synth,
|
|
53
55
|
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
// ───── Playback / Scheduling ─────
|
|
57
|
+
Trigger {
|
|
58
|
+
entity: String,
|
|
59
|
+
duration: Duration,
|
|
60
|
+
},
|
|
61
|
+
Sleep,
|
|
58
62
|
Call,
|
|
59
63
|
Spawn,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// Keyword statements
|
|
66
|
-
Tempo,
|
|
67
|
-
Bank,
|
|
64
|
+
Loop,
|
|
65
|
+
|
|
66
|
+
// ───── Structure & Logic ─────
|
|
67
|
+
Group,
|
|
68
68
|
|
|
69
|
-
//
|
|
69
|
+
// ───── Module System ─────
|
|
70
70
|
Include(String),
|
|
71
71
|
Export {
|
|
72
72
|
names: Vec<String>,
|
|
@@ -76,20 +76,21 @@ pub enum StatementKind {
|
|
|
76
76
|
names: Vec<String>,
|
|
77
77
|
source: String,
|
|
78
78
|
},
|
|
79
|
-
Load {
|
|
80
|
-
source: String,
|
|
81
|
-
alias: String,
|
|
82
|
-
},
|
|
83
79
|
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
},
|
|
80
|
+
// ───── Conditions ─────
|
|
81
|
+
If,
|
|
82
|
+
Else,
|
|
83
|
+
ElseIf,
|
|
89
84
|
|
|
90
|
-
//
|
|
85
|
+
// ───── Internal / Utility ─────
|
|
91
86
|
Comment,
|
|
92
87
|
Indent,
|
|
93
88
|
Dedent,
|
|
94
89
|
NewLine,
|
|
95
|
-
|
|
90
|
+
|
|
91
|
+
// ───── Error Handling ─────
|
|
92
|
+
Unknown,
|
|
93
|
+
Error {
|
|
94
|
+
message: String,
|
|
95
|
+
},
|
|
96
|
+
}
|
|
@@ -1,30 +1,39 @@
|
|
|
1
|
-
use std::collections::HashMap;
|
|
1
|
+
use std::{ collections::HashMap, path::Path };
|
|
2
2
|
use crate::{
|
|
3
3
|
core::{
|
|
4
4
|
error::ErrorHandler,
|
|
5
5
|
lexer::{ token::Token, Lexer },
|
|
6
|
-
parser::{ statement::{ Statement, StatementKind }, Parser },
|
|
7
|
-
preprocessor::{
|
|
8
|
-
module::Module,
|
|
9
|
-
processor::process_modules,
|
|
10
|
-
resolver::{ resolve_all_modules, resolve_and_flatten_all_modules },
|
|
11
|
-
},
|
|
6
|
+
parser::{ statement::{ Statement, StatementKind }, driver::Parser },
|
|
7
|
+
preprocessor::{ module::Module, processor::process_modules },
|
|
12
8
|
store::global::GlobalStore,
|
|
13
9
|
utils::path::normalize_path,
|
|
14
10
|
},
|
|
15
11
|
utils::logger::Logger,
|
|
16
12
|
};
|
|
13
|
+
use crate::core::preprocessor::resolver::driver::{
|
|
14
|
+
resolve_all_modules,
|
|
15
|
+
resolve_and_flatten_all_modules,
|
|
16
|
+
};
|
|
17
|
+
use crate::core::utils::path::resolve_relative_path;
|
|
17
18
|
|
|
18
19
|
pub struct ModuleLoader {
|
|
19
20
|
pub entry: String,
|
|
20
21
|
pub output: String,
|
|
22
|
+
pub base_dir: String,
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
impl ModuleLoader {
|
|
24
26
|
pub fn new(entry: &str, output: &str) -> Self {
|
|
27
|
+
let base_dir = Path::new(entry)
|
|
28
|
+
.parent()
|
|
29
|
+
.unwrap_or(Path::new(""))
|
|
30
|
+
.to_string_lossy()
|
|
31
|
+
.replace('\\', "/");
|
|
32
|
+
|
|
25
33
|
Self {
|
|
26
34
|
entry: entry.to_string(),
|
|
27
35
|
output: output.to_string(),
|
|
36
|
+
base_dir: base_dir,
|
|
28
37
|
}
|
|
29
38
|
}
|
|
30
39
|
|
|
@@ -39,13 +48,12 @@ impl ModuleLoader {
|
|
|
39
48
|
let mut module = Module::new(&entry_path);
|
|
40
49
|
module.content = content.to_string();
|
|
41
50
|
|
|
42
|
-
println!("Loading module from raw source: {}", normalized_entry_path);
|
|
43
|
-
|
|
44
51
|
global_store.insert_module(normalized_entry_path.to_string(), module);
|
|
45
52
|
|
|
46
53
|
Self {
|
|
47
54
|
entry: normalized_entry_path.to_string(),
|
|
48
55
|
output: output_path.to_string(),
|
|
56
|
+
base_dir: "".to_string(),
|
|
49
57
|
}
|
|
50
58
|
}
|
|
51
59
|
|
|
@@ -93,6 +101,7 @@ impl ModuleLoader {
|
|
|
93
101
|
global_store: &mut GlobalStore
|
|
94
102
|
) -> (HashMap<String, Vec<Token>>, HashMap<String, Vec<Statement>>) {
|
|
95
103
|
// SECTION Load the entry module and its dependencies
|
|
104
|
+
|
|
96
105
|
let tokens_by_module = self.load_module_recursively(&self.entry, global_store);
|
|
97
106
|
|
|
98
107
|
// SECTION Process and resolve modules
|
|
@@ -107,72 +116,78 @@ impl ModuleLoader {
|
|
|
107
116
|
#[cfg(feature = "cli")]
|
|
108
117
|
fn load_module_recursively(
|
|
109
118
|
&self,
|
|
110
|
-
|
|
119
|
+
raw_path: &str,
|
|
111
120
|
global_store: &mut GlobalStore
|
|
112
121
|
) -> HashMap<String, Vec<Token>> {
|
|
113
|
-
|
|
122
|
+
let path = normalize_path(raw_path);
|
|
123
|
+
|
|
124
|
+
// Check if already loaded
|
|
125
|
+
if global_store.modules.contains_key(&path) {
|
|
114
126
|
return HashMap::new();
|
|
115
127
|
}
|
|
116
128
|
|
|
117
129
|
let lexer = Lexer::new();
|
|
118
|
-
let tokens = lexer.lex_tokens(path);
|
|
130
|
+
let tokens = lexer.lex_tokens(&path);
|
|
119
131
|
|
|
120
132
|
let mut parser = Parser::new();
|
|
121
|
-
parser.set_current_module(path.
|
|
133
|
+
parser.set_current_module(path.clone());
|
|
122
134
|
|
|
123
135
|
let statements = parser.parse_tokens(tokens.clone(), global_store);
|
|
124
136
|
|
|
125
|
-
//
|
|
137
|
+
// Error handling
|
|
126
138
|
let mut error_handler = ErrorHandler::new();
|
|
127
139
|
error_handler.detect_from_statements(&mut parser, &statements);
|
|
128
140
|
|
|
129
|
-
error_handler.has_errors()
|
|
141
|
+
if error_handler.has_errors() {
|
|
130
142
|
let logger = Logger::new();
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
let stacktrace = format!("{}:{}:{}", path, error.line, error.column);
|
|
135
|
-
logger.log_error_with_stacktrace(&error.message, &stacktrace);
|
|
143
|
+
for error in error_handler.get_errors() {
|
|
144
|
+
let trace = format!("{}:{}:{}", path, error.line, error.column);
|
|
145
|
+
logger.log_error_with_stacktrace(&error.message, &trace);
|
|
136
146
|
}
|
|
137
|
-
}
|
|
147
|
+
}
|
|
138
148
|
|
|
139
|
-
//
|
|
140
|
-
let mut module = Module::new(path);
|
|
149
|
+
// Insert module into store
|
|
150
|
+
let mut module = Module::new(&path);
|
|
141
151
|
module.tokens = tokens.clone();
|
|
142
152
|
module.statements = statements.clone();
|
|
153
|
+
global_store.insert_module(path.clone(), module);
|
|
143
154
|
|
|
144
|
-
|
|
155
|
+
// Load dependencies
|
|
156
|
+
self.load_module_imports(&path, global_store);
|
|
145
157
|
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
global_store.modules.iter().for_each(|(path, module)| {
|
|
153
|
-
tokens_by_module.insert(path.clone(), module.tokens.clone());
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
tokens_by_module
|
|
158
|
+
// Return tokens per module
|
|
159
|
+
global_store.modules
|
|
160
|
+
.iter()
|
|
161
|
+
.map(|(p, m)| (p.clone(), m.tokens.clone()))
|
|
162
|
+
.collect()
|
|
157
163
|
}
|
|
158
164
|
|
|
159
165
|
#[cfg(feature = "cli")]
|
|
160
166
|
fn load_module_imports(&self, path: &String, global_store: &mut GlobalStore) {
|
|
161
|
-
let
|
|
162
|
-
.get(path)
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
Some(source.clone())
|
|
168
|
-
} else {
|
|
169
|
-
None
|
|
167
|
+
let import_paths: Vec<String> = {
|
|
168
|
+
let current_module = match global_store.modules.get(path) {
|
|
169
|
+
Some(module) => module,
|
|
170
|
+
None => {
|
|
171
|
+
eprintln!("[warn] Cannot resolve imports: module '{}' not found in store", path);
|
|
172
|
+
return;
|
|
170
173
|
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
current_module.statements
|
|
177
|
+
.iter()
|
|
178
|
+
.filter_map(|stmt| {
|
|
179
|
+
if let StatementKind::Import { source, .. } = &stmt.kind {
|
|
180
|
+
Some(source.clone())
|
|
181
|
+
} else {
|
|
182
|
+
None
|
|
183
|
+
}
|
|
184
|
+
})
|
|
185
|
+
.collect()
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
for import_path in import_paths {
|
|
189
|
+
let resolved = resolve_relative_path(path, &import_path);
|
|
190
|
+
self.load_module_recursively(&resolved, global_store);
|
|
176
191
|
}
|
|
177
192
|
}
|
|
178
193
|
}
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
use crate::core::{
|
|
2
2
|
lexer::token::Token,
|
|
3
3
|
parser::statement::Statement,
|
|
4
|
-
store::{
|
|
5
|
-
export::ExportTable,
|
|
6
|
-
global::GlobalStore,
|
|
7
|
-
import::ImportTable,
|
|
8
|
-
variable::VariableTable,
|
|
9
|
-
},
|
|
4
|
+
store::{ export::ExportTable, import::ImportTable, variable::VariableTable },
|
|
10
5
|
};
|
|
11
6
|
|
|
12
7
|
#[derive(Debug, Clone)]
|
|
@@ -19,6 +14,7 @@ pub struct Module {
|
|
|
19
14
|
pub export_table: ExportTable,
|
|
20
15
|
pub import_table: ImportTable,
|
|
21
16
|
pub content: String,
|
|
17
|
+
pub current_dir: String,
|
|
22
18
|
}
|
|
23
19
|
|
|
24
20
|
impl Module {
|
|
@@ -32,6 +28,7 @@ impl Module {
|
|
|
32
28
|
import_table: ImportTable::new(),
|
|
33
29
|
resolved: false,
|
|
34
30
|
content: String::new(),
|
|
31
|
+
current_dir: String::new(),
|
|
35
32
|
}
|
|
36
33
|
}
|
|
37
34
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
use std::collections::HashMap;
|
|
1
|
+
use std::{ collections::HashMap, path::Path };
|
|
2
2
|
|
|
3
3
|
use crate::core::{
|
|
4
|
-
parser::{ statement::StatementKind
|
|
4
|
+
parser::{ driver::Parser, statement::StatementKind },
|
|
5
5
|
preprocessor::{ loader::ModuleLoader, resolver::group },
|
|
6
6
|
shared::value::Value,
|
|
7
7
|
store::global::GlobalStore,
|
|
8
|
+
utils::path::{normalize_path, resolve_relative_path},
|
|
8
9
|
};
|
|
9
10
|
|
|
10
11
|
pub fn process_modules(module_loader: &ModuleLoader, global_store: &mut GlobalStore) {
|
|
@@ -16,9 +17,13 @@ pub fn process_modules(module_loader: &ModuleLoader, global_store: &mut GlobalSt
|
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
StatementKind::Load { source, alias } => {
|
|
20
|
+
let module_dir = Path::new(&module.path).parent().unwrap_or(Path::new(""));
|
|
21
|
+
|
|
22
|
+
let resolved_path = normalize_path(&module_dir.join(source));
|
|
23
|
+
|
|
19
24
|
module.variable_table.variables.insert(
|
|
20
25
|
alias.clone(),
|
|
21
|
-
Value::Sample(
|
|
26
|
+
Value::Sample(resolved_path)
|
|
22
27
|
);
|
|
23
28
|
}
|
|
24
29
|
|
|
@@ -31,8 +36,12 @@ pub fn process_modules(module_loader: &ModuleLoader, global_store: &mut GlobalSt
|
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
StatementKind::Import { names, source } => {
|
|
39
|
+
let resolved = resolve_relative_path(&module.path, source);
|
|
34
40
|
for name in names {
|
|
35
|
-
module.import_table.add_import(
|
|
41
|
+
module.import_table.add_import(
|
|
42
|
+
name.clone(),
|
|
43
|
+
Value::String(resolved.clone())
|
|
44
|
+
);
|
|
36
45
|
}
|
|
37
46
|
}
|
|
38
47
|
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
use crate::{
|
|
2
|
+
core::{
|
|
3
|
+
parser::statement::{ Statement, StatementKind },
|
|
4
|
+
preprocessor::{ module::Module, resolver::driver::resolve_statement },
|
|
5
|
+
shared::value::Value,
|
|
6
|
+
store::global::GlobalStore,
|
|
7
|
+
},
|
|
8
|
+
utils::logger::{ Logger, LogLevel },
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
pub fn resolve_call(
|
|
12
|
+
stmt: &Statement,
|
|
13
|
+
module: &Module,
|
|
14
|
+
path: &str,
|
|
15
|
+
global_store: &mut GlobalStore
|
|
16
|
+
) -> Statement {
|
|
17
|
+
let logger = Logger::new();
|
|
18
|
+
|
|
19
|
+
match &stmt.value {
|
|
20
|
+
Value::Identifier(ident) => {
|
|
21
|
+
match module.variable_table.get(ident) {
|
|
22
|
+
Some(Value::String(group_name)) =>
|
|
23
|
+
resolve_group_by_name(group_name, stmt, module, path, global_store, &logger),
|
|
24
|
+
Some(Value::Map(group_map)) =>
|
|
25
|
+
resolved_call(stmt, group_map, module, path, global_store),
|
|
26
|
+
Some(other) =>
|
|
27
|
+
error_stmt(
|
|
28
|
+
&logger,
|
|
29
|
+
module,
|
|
30
|
+
stmt,
|
|
31
|
+
&format!(
|
|
32
|
+
"Identifier '{ident}' must resolve to a group name or map, found {:?}",
|
|
33
|
+
other
|
|
34
|
+
)
|
|
35
|
+
),
|
|
36
|
+
None =>
|
|
37
|
+
error_stmt(
|
|
38
|
+
&logger,
|
|
39
|
+
module,
|
|
40
|
+
stmt,
|
|
41
|
+
&format!("Identifier '{ident}' not found in variable table")
|
|
42
|
+
),
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
Value::String(name) =>
|
|
47
|
+
resolve_group_by_name(name, stmt, module, path, global_store, &logger),
|
|
48
|
+
|
|
49
|
+
Value::Map(group_map) => resolved_call(stmt, group_map, module, path, global_store),
|
|
50
|
+
|
|
51
|
+
other =>
|
|
52
|
+
error_stmt(
|
|
53
|
+
&logger,
|
|
54
|
+
module,
|
|
55
|
+
stmt,
|
|
56
|
+
&format!("Call expects a group name as string or identifier, found {:?}", other)
|
|
57
|
+
),
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
fn resolve_group_by_name(
|
|
62
|
+
name: &str,
|
|
63
|
+
stmt: &Statement,
|
|
64
|
+
module: &Module,
|
|
65
|
+
path: &str,
|
|
66
|
+
global_store: &mut GlobalStore,
|
|
67
|
+
logger: &Logger
|
|
68
|
+
) -> Statement {
|
|
69
|
+
match module.variable_table.get(name) {
|
|
70
|
+
Some(Value::Map(group_map)) => resolved_call(stmt, group_map, module, path, global_store),
|
|
71
|
+
Some(other) =>
|
|
72
|
+
error_stmt(
|
|
73
|
+
logger,
|
|
74
|
+
module,
|
|
75
|
+
stmt,
|
|
76
|
+
&format!("Expected a group for '{}', but found {:?}", name, other)
|
|
77
|
+
),
|
|
78
|
+
None =>
|
|
79
|
+
error_stmt(
|
|
80
|
+
logger,
|
|
81
|
+
module,
|
|
82
|
+
stmt,
|
|
83
|
+
&format!("Group '{}' not found in module '{}'", name, module.path)
|
|
84
|
+
),
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
fn resolved_call(
|
|
89
|
+
stmt: &Statement,
|
|
90
|
+
group_map: &std::collections::HashMap<String, Value>,
|
|
91
|
+
module: &Module,
|
|
92
|
+
path: &str,
|
|
93
|
+
global_store: &mut GlobalStore
|
|
94
|
+
) -> Statement {
|
|
95
|
+
let mut cloned_map = group_map.clone();
|
|
96
|
+
|
|
97
|
+
if let Some(Value::Block(stmts)) = group_map.get("body") {
|
|
98
|
+
let resolved = stmts
|
|
99
|
+
.iter()
|
|
100
|
+
.map(|s| resolve_statement(s, module, path, global_store))
|
|
101
|
+
.collect();
|
|
102
|
+
cloned_map.insert("body".to_string(), Value::Block(resolved));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
Statement {
|
|
106
|
+
kind: StatementKind::Call,
|
|
107
|
+
value: Value::Map(cloned_map),
|
|
108
|
+
..stmt.clone()
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
fn error_stmt(logger: &Logger, module: &Module, stmt: &Statement, message: &str) -> Statement {
|
|
113
|
+
let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
|
|
114
|
+
logger.log_message(LogLevel::Error, &format!("{message}\n → at {stacktrace}"));
|
|
115
|
+
|
|
116
|
+
Statement {
|
|
117
|
+
kind: StatementKind::Error {
|
|
118
|
+
message: message.to_string(),
|
|
119
|
+
},
|
|
120
|
+
value: Value::Null,
|
|
121
|
+
..stmt.clone()
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
use crate::{
|
|
2
|
+
core::{
|
|
3
|
+
parser::statement::{Statement, StatementKind},
|
|
4
|
+
preprocessor::{module::Module, resolver::driver::resolve_statement},
|
|
5
|
+
shared::value::Value,
|
|
6
|
+
store::global::GlobalStore,
|
|
7
|
+
},
|
|
8
|
+
utils::logger::Logger,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
pub fn resolve_condition(
|
|
12
|
+
stmt: &Statement,
|
|
13
|
+
module: &Module,
|
|
14
|
+
path: &str,
|
|
15
|
+
global_store: &mut GlobalStore,
|
|
16
|
+
) -> Statement {
|
|
17
|
+
let logger = Logger::new();
|
|
18
|
+
|
|
19
|
+
let Value::Map(condition_map) = &stmt.value else {
|
|
20
|
+
return type_error(&logger, module, stmt, "Expected a map in condition statement".to_string());
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
let mut resolved_map = condition_map.clone();
|
|
24
|
+
|
|
25
|
+
// Main body resolution
|
|
26
|
+
if let Some(Value::Block(body)) = condition_map.get("body") {
|
|
27
|
+
let resolved_body = resolve_block_statements(body, module, path, global_store);
|
|
28
|
+
resolved_map.insert("body".to_string(), Value::Block(resolved_body));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Recursive resolution of next condition
|
|
32
|
+
if let Some(Value::Map(next_map)) = condition_map.get("next") {
|
|
33
|
+
let next_stmt = Statement {
|
|
34
|
+
kind: StatementKind::If,
|
|
35
|
+
value: Value::Map(next_map.clone()),
|
|
36
|
+
..stmt.clone()
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
let resolved_next = resolve_condition(&next_stmt, module, path, global_store);
|
|
40
|
+
|
|
41
|
+
if let Value::Map(mut resolved_next_map) = resolved_next.value {
|
|
42
|
+
// Body next resolution
|
|
43
|
+
if let Some(Value::Block(body)) = resolved_next_map.get("body") {
|
|
44
|
+
let resolved_body = resolve_block_statements(body, module, path, global_store);
|
|
45
|
+
resolved_next_map.insert("body".to_string(), Value::Block(resolved_body));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
resolved_map.insert("next".to_string(), Value::Map(resolved_next_map));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
Statement {
|
|
53
|
+
kind: StatementKind::If,
|
|
54
|
+
value: Value::Map(resolved_map),
|
|
55
|
+
..stmt.clone()
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
fn resolve_block_statements(
|
|
60
|
+
body: &[Statement],
|
|
61
|
+
module: &Module,
|
|
62
|
+
path: &str,
|
|
63
|
+
global_store: &mut GlobalStore,
|
|
64
|
+
) -> Vec<Statement> {
|
|
65
|
+
body.iter()
|
|
66
|
+
.flat_map(|stmt| {
|
|
67
|
+
let resolved = resolve_statement(stmt, module, path, global_store);
|
|
68
|
+
|
|
69
|
+
if let StatementKind::Call = resolved.kind {
|
|
70
|
+
if let Value::Block(inner) = &resolved.value {
|
|
71
|
+
return inner
|
|
72
|
+
.iter()
|
|
73
|
+
.map(|s| resolve_statement(s, module, path, global_store))
|
|
74
|
+
.collect();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
vec![resolved]
|
|
79
|
+
})
|
|
80
|
+
.collect()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
fn type_error(logger: &Logger, module: &Module, stmt: &Statement, message: String) -> Statement {
|
|
84
|
+
let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
|
|
85
|
+
logger.log_error_with_stacktrace(&message, &stacktrace);
|
|
86
|
+
|
|
87
|
+
Statement {
|
|
88
|
+
kind: StatementKind::Error { message },
|
|
89
|
+
value: Value::Null,
|
|
90
|
+
..stmt.clone()
|
|
91
|
+
}
|
|
92
|
+
}
|