@devaloop/devalang 0.0.1-alpha.1 → 0.0.1-alpha.11
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/.devalang +9 -0
- package/Cargo.toml +15 -6
- package/README.md +79 -81
- package/docs/CHANGELOG.md +213 -0
- package/docs/ROADMAP.md +11 -8
- package/docs/TODO.md +32 -29
- package/examples/bank.deva +9 -0
- package/examples/condition.deva +20 -0
- package/examples/duration.deva +9 -0
- package/examples/group.deva +12 -0
- package/examples/index.deva +12 -5
- package/examples/loop.deva +16 -0
- package/examples/samples/hat-808.wav +0 -0
- package/examples/synth.deva +14 -0
- package/examples/variables.deva +9 -0
- package/out-tsc/bin/devalang.exe +0 -0
- package/out-tsc/scripts/version/fetch.js +1 -5
- package/package.json +5 -4
- package/project-version.json +3 -3
- package/rust/cli/bank.rs +455 -0
- package/rust/cli/build.rs +114 -28
- package/rust/cli/check.rs +96 -103
- package/rust/cli/driver.rs +280 -0
- package/rust/cli/init.rs +79 -0
- package/rust/cli/install.rs +17 -0
- package/rust/cli/mod.rs +8 -1
- package/rust/cli/play.rs +193 -0
- package/rust/cli/template.rs +57 -0
- package/rust/cli/update.rs +4 -0
- package/rust/common/cdn.rs +11 -0
- package/rust/common/mod.rs +1 -0
- package/rust/config/driver.rs +76 -0
- package/rust/config/loader.rs +110 -0
- package/rust/config/mod.rs +2 -0
- package/rust/core/audio/engine.rs +242 -0
- package/rust/core/audio/evaluator.rs +31 -0
- package/rust/core/audio/interpreter/arrow_call.rs +142 -0
- package/rust/core/audio/interpreter/call.rs +70 -0
- package/rust/core/audio/interpreter/condition.rs +69 -0
- package/rust/core/audio/interpreter/driver.rs +236 -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 +84 -0
- package/rust/core/audio/interpreter/tempo.rs +16 -0
- package/rust/core/audio/interpreter/trigger.rs +102 -0
- package/rust/core/audio/loader/mod.rs +1 -0
- package/rust/core/audio/loader/trigger.rs +64 -0
- package/rust/core/audio/mod.rs +6 -0
- package/rust/core/audio/player.rs +54 -0
- package/rust/core/audio/renderer.rs +54 -0
- package/rust/core/builder/mod.rs +70 -27
- package/rust/core/debugger/lexer.rs +27 -0
- package/rust/core/debugger/mod.rs +13 -49
- package/rust/core/debugger/preprocessor.rs +27 -0
- package/rust/core/debugger/store.rs +25 -0
- package/rust/core/error/mod.rs +60 -0
- package/rust/core/lexer/handler/arrow.rs +31 -0
- package/rust/core/lexer/handler/at.rs +21 -0
- package/rust/core/lexer/handler/brace.rs +41 -0
- package/rust/core/lexer/handler/colon.rs +21 -0
- package/rust/core/lexer/handler/comment.rs +30 -0
- package/rust/core/lexer/handler/dot.rs +21 -0
- package/rust/core/lexer/handler/driver.rs +241 -0
- package/rust/core/lexer/handler/identifier.rs +41 -0
- package/rust/core/lexer/handler/indent.rs +52 -0
- package/rust/core/lexer/handler/mod.rs +15 -0
- package/rust/core/lexer/handler/newline.rs +23 -0
- package/rust/core/lexer/handler/number.rs +31 -0
- package/rust/core/lexer/handler/operator.rs +44 -0
- package/rust/core/lexer/handler/slash.rs +21 -0
- package/rust/core/lexer/handler/string.rs +63 -0
- package/rust/core/lexer/mod.rs +37 -319
- package/rust/core/lexer/token.rs +87 -0
- package/rust/core/mod.rs +6 -2
- package/rust/core/parser/driver.rs +339 -0
- package/rust/core/parser/handler/arrow_call.rs +151 -0
- package/rust/core/parser/handler/at.rs +162 -0
- package/rust/core/parser/handler/bank.rs +41 -0
- package/rust/core/parser/handler/condition.rs +74 -0
- package/rust/core/parser/handler/dot.rs +178 -0
- 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 +72 -0
- package/rust/core/parser/handler/mod.rs +8 -0
- package/rust/core/parser/handler/tempo.rs +47 -0
- package/rust/core/parser/mod.rs +3 -200
- package/rust/core/parser/statement.rs +96 -0
- package/rust/core/preprocessor/loader.rs +308 -0
- package/rust/core/preprocessor/mod.rs +2 -24
- package/rust/core/preprocessor/module.rs +42 -56
- package/rust/core/preprocessor/processor.rs +76 -0
- package/rust/core/preprocessor/resolver/bank.rs +41 -51
- 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 +232 -0
- package/rust/core/preprocessor/resolver/group.rs +61 -0
- package/rust/core/preprocessor/resolver/let_.rs +31 -0
- package/rust/core/preprocessor/resolver/loop_.rs +76 -67
- package/rust/core/preprocessor/resolver/mod.rs +12 -111
- package/rust/core/preprocessor/resolver/spawn.rs +58 -0
- package/rust/core/preprocessor/resolver/synth.rs +50 -0
- package/rust/core/preprocessor/resolver/tempo.rs +40 -61
- package/rust/core/preprocessor/resolver/trigger.rs +90 -154
- package/rust/core/preprocessor/resolver/value.rs +78 -0
- package/rust/core/shared/bank.rs +21 -0
- package/rust/core/shared/duration.rs +9 -0
- package/rust/core/shared/mod.rs +3 -0
- package/rust/core/shared/value.rs +29 -0
- package/rust/core/store/export.rs +28 -0
- package/rust/core/store/global.rs +39 -0
- package/rust/core/store/import.rs +28 -0
- package/rust/core/store/mod.rs +4 -0
- package/rust/core/store/variable.rs +28 -0
- package/rust/core/utils/mod.rs +2 -0
- package/rust/core/utils/path.rs +31 -0
- package/rust/core/utils/validation.rs +37 -0
- package/rust/installer/bank.rs +55 -0
- package/rust/installer/mod.rs +1 -0
- package/rust/lib.rs +162 -1
- package/rust/main.rs +104 -31
- package/rust/utils/file.rs +35 -0
- package/rust/utils/installer.rs +56 -0
- package/rust/utils/logger.rs +108 -34
- package/rust/utils/mod.rs +5 -3
- package/rust/utils/{loader.rs → spinner.rs} +2 -0
- package/rust/utils/watcher.rs +33 -0
- package/templates/minimal/.devalang +5 -0
- package/templates/minimal/README.md +202 -0
- package/templates/minimal/src/index.deva +2 -0
- package/templates/welcome/.devalang +5 -0
- package/templates/welcome/README.md +202 -0
- package/templates/welcome/samples/kick-808.wav +0 -0
- package/templates/welcome/src/index.deva +13 -0
- package/templates/welcome/src/variables.deva +5 -0
- package/typescript/scripts/version/fetch.ts +1 -6
- package/docs/COMMANDS.md +0 -31
- package/docs/SYNTAX.md +0 -148
- package/examples/exported.deva +0 -7
- package/rust/audio/mod.rs +0 -1
- package/rust/cli/new.rs +0 -1
- package/rust/core/parser/at.rs +0 -142
- package/rust/core/parser/bank.rs +0 -42
- package/rust/core/parser/dot.rs +0 -107
- package/rust/core/parser/identifer.rs +0 -91
- package/rust/core/parser/loop_.rs +0 -62
- package/rust/core/parser/tempo.rs +0 -42
- package/rust/core/parser/variable.rs +0 -129
- package/rust/core/preprocessor/dependencies.rs +0 -54
- package/rust/core/preprocessor/resolver/at.rs +0 -24
- package/rust/core/types/cli.rs +0 -160
- package/rust/core/types/mod.rs +0 -7
- package/rust/core/types/module.rs +0 -41
- package/rust/core/types/parser.rs +0 -73
- package/rust/core/types/statement.rs +0 -105
- package/rust/core/types/store.rs +0 -116
- package/rust/core/types/token.rs +0 -83
- package/rust/core/types/variable.rs +0 -32
- package/rust/runner/executer.rs +0 -44
- package/rust/runner/mod.rs +0 -1
- package/rust/utils/path.rs +0 -46
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
use std::{ collections::{ HashMap, HashSet }, path::Path };
|
|
2
|
+
use crate::{
|
|
3
|
+
core::{
|
|
4
|
+
error::ErrorHandler,
|
|
5
|
+
lexer::{ token::Token, Lexer },
|
|
6
|
+
parser::{ driver::Parser, statement::{ Statement, StatementKind } },
|
|
7
|
+
preprocessor::{ module::Module, processor::process_modules },
|
|
8
|
+
shared::{ bank::BankFile, value::Value },
|
|
9
|
+
store::global::GlobalStore,
|
|
10
|
+
utils::path::normalize_path,
|
|
11
|
+
},
|
|
12
|
+
utils::logger::Logger,
|
|
13
|
+
};
|
|
14
|
+
use crate::core::preprocessor::resolver::driver::{
|
|
15
|
+
resolve_all_modules,
|
|
16
|
+
resolve_and_flatten_all_modules,
|
|
17
|
+
};
|
|
18
|
+
use crate::core::utils::path::resolve_relative_path;
|
|
19
|
+
|
|
20
|
+
pub struct ModuleLoader {
|
|
21
|
+
pub entry: String,
|
|
22
|
+
pub output: String,
|
|
23
|
+
pub base_dir: String,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
impl ModuleLoader {
|
|
27
|
+
pub fn new(entry: &str, output: &str) -> Self {
|
|
28
|
+
let base_dir = Path::new(entry)
|
|
29
|
+
.parent()
|
|
30
|
+
.unwrap_or(Path::new(""))
|
|
31
|
+
.to_string_lossy()
|
|
32
|
+
.replace('\\', "/");
|
|
33
|
+
|
|
34
|
+
Self {
|
|
35
|
+
entry: entry.to_string(),
|
|
36
|
+
output: output.to_string(),
|
|
37
|
+
base_dir: base_dir,
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
pub fn from_raw_source(
|
|
42
|
+
entry_path: &str,
|
|
43
|
+
output_path: &str,
|
|
44
|
+
content: &str,
|
|
45
|
+
global_store: &mut GlobalStore
|
|
46
|
+
) -> Self {
|
|
47
|
+
let normalized_entry_path = normalize_path(entry_path);
|
|
48
|
+
|
|
49
|
+
let mut module = Module::new(&entry_path);
|
|
50
|
+
module.content = content.to_string();
|
|
51
|
+
|
|
52
|
+
global_store.insert_module(normalized_entry_path.to_string(), module);
|
|
53
|
+
|
|
54
|
+
Self {
|
|
55
|
+
entry: normalized_entry_path.to_string(),
|
|
56
|
+
output: output_path.to_string(),
|
|
57
|
+
base_dir: "".to_string(),
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
pub fn extract_statements_map(
|
|
62
|
+
&self,
|
|
63
|
+
global_store: &GlobalStore
|
|
64
|
+
) -> HashMap<String, Vec<Statement>> {
|
|
65
|
+
global_store.modules
|
|
66
|
+
.iter()
|
|
67
|
+
.map(|(path, module)| (path.clone(), module.statements.clone()))
|
|
68
|
+
.collect()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
pub fn load_single_module(&self, global_store: &mut GlobalStore) -> Result<Module, String> {
|
|
72
|
+
let mut module = global_store.modules
|
|
73
|
+
.remove(&self.entry)
|
|
74
|
+
.ok_or_else(|| format!("Module not found in store for path: {}", self.entry))?;
|
|
75
|
+
|
|
76
|
+
// SECTION Lexing the module content
|
|
77
|
+
let lexer = Lexer::new();
|
|
78
|
+
let tokens = lexer
|
|
79
|
+
.lex_from_source(&module.content)
|
|
80
|
+
.map_err(|e| format!("Lexer failed: {}", e))?;
|
|
81
|
+
|
|
82
|
+
module.tokens = tokens.clone();
|
|
83
|
+
|
|
84
|
+
// SECTION Parsing tokens into statements
|
|
85
|
+
let mut parser = Parser::new();
|
|
86
|
+
parser.set_current_module(self.entry.clone());
|
|
87
|
+
let statements = parser.parse_tokens(tokens, global_store);
|
|
88
|
+
module.statements = statements;
|
|
89
|
+
|
|
90
|
+
// SECTION Injecting bank triggers if any
|
|
91
|
+
if let Err(e) = self.inject_bank_triggers(&mut module, "808") {
|
|
92
|
+
return Err(format!("Failed to inject bank triggers: {}", e));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
global_store.modules.insert(self.entry.clone(), module.clone());
|
|
96
|
+
|
|
97
|
+
// SECTION Error handling
|
|
98
|
+
let mut error_handler = ErrorHandler::new();
|
|
99
|
+
error_handler.detect_from_statements(&mut parser, &module.statements);
|
|
100
|
+
|
|
101
|
+
Ok(module)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
pub fn load_wasm_module(&self, global_store: &mut GlobalStore) -> Result<(), String> {
|
|
105
|
+
// Step one : Load the module from the global store
|
|
106
|
+
let module = {
|
|
107
|
+
let module_ref = global_store.modules
|
|
108
|
+
.get(&self.entry)
|
|
109
|
+
.ok_or_else(|| format!("❌ Module not found for path: {}", self.entry))?;
|
|
110
|
+
|
|
111
|
+
Module::from_existing(&self.entry, module_ref.content.clone())
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// Step two : lexing
|
|
115
|
+
let lexer = Lexer::new();
|
|
116
|
+
let tokens = lexer
|
|
117
|
+
.lex_from_source(&module.content)
|
|
118
|
+
.map_err(|e| format!("Lexer failed: {}", e))?;
|
|
119
|
+
|
|
120
|
+
// Step three : parsing
|
|
121
|
+
let mut parser = Parser::new();
|
|
122
|
+
parser.set_current_module(self.entry.clone());
|
|
123
|
+
|
|
124
|
+
let statements = parser.parse_tokens(tokens.clone(), global_store);
|
|
125
|
+
|
|
126
|
+
let mut updated_module = module;
|
|
127
|
+
updated_module.tokens = tokens;
|
|
128
|
+
updated_module.statements = statements;
|
|
129
|
+
|
|
130
|
+
// Step four : error handling
|
|
131
|
+
let mut error_handler = ErrorHandler::new();
|
|
132
|
+
error_handler.detect_from_statements(&mut parser, &updated_module.statements);
|
|
133
|
+
|
|
134
|
+
// Final step : insert the updated module back into the global store
|
|
135
|
+
global_store.modules.insert(self.entry.clone(), updated_module);
|
|
136
|
+
|
|
137
|
+
Ok(())
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
#[cfg(feature = "cli")]
|
|
141
|
+
pub fn load_all_modules(
|
|
142
|
+
&self,
|
|
143
|
+
global_store: &mut GlobalStore
|
|
144
|
+
) -> (HashMap<String, Vec<Token>>, HashMap<String, Vec<Statement>>) {
|
|
145
|
+
// SECTION Load the entry module and its dependencies
|
|
146
|
+
|
|
147
|
+
let tokens_by_module = self.load_module_recursively(&self.entry, global_store);
|
|
148
|
+
|
|
149
|
+
// SECTION Process and resolve modules
|
|
150
|
+
process_modules(self, global_store);
|
|
151
|
+
resolve_all_modules(self, global_store);
|
|
152
|
+
|
|
153
|
+
let statemnts_by_module = resolve_and_flatten_all_modules(global_store);
|
|
154
|
+
|
|
155
|
+
(tokens_by_module, statemnts_by_module)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
#[cfg(feature = "cli")]
|
|
159
|
+
fn load_module_recursively(
|
|
160
|
+
&self,
|
|
161
|
+
raw_path: &str,
|
|
162
|
+
global_store: &mut GlobalStore
|
|
163
|
+
) -> HashMap<String, Vec<Token>> {
|
|
164
|
+
let path = normalize_path(raw_path);
|
|
165
|
+
|
|
166
|
+
// Check if already loaded
|
|
167
|
+
if global_store.modules.contains_key(&path) {
|
|
168
|
+
return HashMap::new();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
let lexer = Lexer::new();
|
|
172
|
+
let tokens = lexer.lex_tokens(&path);
|
|
173
|
+
|
|
174
|
+
let mut parser = Parser::new();
|
|
175
|
+
parser.set_current_module(path.clone());
|
|
176
|
+
|
|
177
|
+
let statements = parser.parse_tokens(tokens.clone(), global_store);
|
|
178
|
+
|
|
179
|
+
// Insert module into store
|
|
180
|
+
let mut module = Module::new(&path);
|
|
181
|
+
module.tokens = tokens.clone();
|
|
182
|
+
module.statements = statements.clone();
|
|
183
|
+
|
|
184
|
+
// Inject triggers for each bank used in module
|
|
185
|
+
for bank_name in ModuleLoader::extract_bank_names(&statements) {
|
|
186
|
+
if let Err(e) = self.inject_bank_triggers(&mut module, &bank_name) {
|
|
187
|
+
return HashMap::new(); // Return empty map on error
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
global_store.insert_module(path.clone(), module);
|
|
192
|
+
|
|
193
|
+
// Load dependencies
|
|
194
|
+
self.load_module_imports(&path, global_store);
|
|
195
|
+
|
|
196
|
+
// Error handling
|
|
197
|
+
let mut error_handler = ErrorHandler::new();
|
|
198
|
+
error_handler.detect_from_statements(&mut parser, &statements);
|
|
199
|
+
|
|
200
|
+
if error_handler.has_errors() {
|
|
201
|
+
let logger = Logger::new();
|
|
202
|
+
for error in error_handler.get_errors() {
|
|
203
|
+
let trace = format!("{}:{}:{}", path, error.line, error.column);
|
|
204
|
+
logger.log_error_with_stacktrace(&error.message, &trace);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Return tokens per module
|
|
209
|
+
global_store.modules
|
|
210
|
+
.iter()
|
|
211
|
+
.map(|(p, m)| (p.clone(), m.tokens.clone()))
|
|
212
|
+
.collect()
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
#[cfg(feature = "cli")]
|
|
216
|
+
fn load_module_imports(&self, path: &String, global_store: &mut GlobalStore) {
|
|
217
|
+
let import_paths: Vec<String> = {
|
|
218
|
+
let current_module = match global_store.modules.get(path) {
|
|
219
|
+
Some(module) => module,
|
|
220
|
+
None => {
|
|
221
|
+
eprintln!("[warn] Cannot resolve imports: module '{}' not found in store", path);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
current_module.statements
|
|
227
|
+
.iter()
|
|
228
|
+
.filter_map(|stmt| {
|
|
229
|
+
if let StatementKind::Import { source, .. } = &stmt.kind {
|
|
230
|
+
Some(source.clone())
|
|
231
|
+
} else {
|
|
232
|
+
None
|
|
233
|
+
}
|
|
234
|
+
})
|
|
235
|
+
.collect()
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
for import_path in import_paths {
|
|
239
|
+
let resolved = resolve_relative_path(path, &import_path);
|
|
240
|
+
self.load_module_recursively(&resolved, global_store);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
pub fn inject_bank_triggers(&self, module: &mut Module, bank_name: &str) -> Result<(), String> {
|
|
245
|
+
let bank_path = Path::new("./.deva/bank").join(bank_name);
|
|
246
|
+
let bank_file_path = bank_path.join("bank.toml");
|
|
247
|
+
|
|
248
|
+
if !bank_file_path.exists() {
|
|
249
|
+
return Ok(()); // Pas d'erreur si la banque n'existe pas encore
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
let content = std::fs
|
|
253
|
+
::read_to_string(&bank_file_path)
|
|
254
|
+
.map_err(|e| format!("Failed to read '{}': {}", bank_file_path.display(), e))?;
|
|
255
|
+
|
|
256
|
+
let parsed: BankFile = toml
|
|
257
|
+
::from_str(&content)
|
|
258
|
+
.map_err(|e| format!("Failed to parse '{}': {}", bank_file_path.display(), e))?;
|
|
259
|
+
|
|
260
|
+
let mut bank_map = HashMap::new();
|
|
261
|
+
|
|
262
|
+
for bank_trigger in parsed.triggers.unwrap_or_default() {
|
|
263
|
+
let trigger_name = bank_trigger.name.clone().replace("./", "");
|
|
264
|
+
let bank_trigger_path = format!("devalang://bank/{}/{}", bank_name, trigger_name);
|
|
265
|
+
|
|
266
|
+
bank_map.insert(bank_trigger.name.clone(), Value::String(bank_trigger_path.clone()));
|
|
267
|
+
|
|
268
|
+
if module.variable_table.variables.contains_key(bank_name) {
|
|
269
|
+
eprintln!(
|
|
270
|
+
"⚠️ Trigger '{}' already defined in module '{}', skipping injection.",
|
|
271
|
+
bank_name, module.path
|
|
272
|
+
);
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
module.variable_table.set(
|
|
277
|
+
format!("{}.{}", bank_name, bank_trigger.name),
|
|
278
|
+
Value::String(bank_trigger_path.clone())
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Inject the map under the bank name
|
|
283
|
+
module.variable_table.set(bank_name.to_string(), Value::Map(bank_map));
|
|
284
|
+
|
|
285
|
+
Ok(())
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
fn extract_bank_names(statements: &[Statement]) -> HashSet<String> {
|
|
289
|
+
let mut banks = HashSet::new();
|
|
290
|
+
|
|
291
|
+
for stmt in statements {
|
|
292
|
+
if let StatementKind::Trigger { entity, .. } = &stmt.kind {
|
|
293
|
+
let parts: Vec<&str> = entity.split('.').collect();
|
|
294
|
+
if parts.len() >= 2 {
|
|
295
|
+
banks.insert(parts[0].to_string()); // "808.kick" → "808"
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if let StatementKind::Bank = &stmt.kind {
|
|
300
|
+
if let Value::String(name) = &stmt.value {
|
|
301
|
+
banks.insert(name.clone());
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
banks
|
|
307
|
+
}
|
|
308
|
+
}
|
|
@@ -1,26 +1,4 @@
|
|
|
1
1
|
pub mod module;
|
|
2
|
-
pub mod
|
|
2
|
+
pub mod loader;
|
|
3
3
|
pub mod resolver;
|
|
4
|
-
|
|
5
|
-
use crate::core::{
|
|
6
|
-
preprocessor::{
|
|
7
|
-
dependencies::collect_dependencies_recursively,
|
|
8
|
-
module::load_module_into_global_store,
|
|
9
|
-
},
|
|
10
|
-
types::{ store::GlobalStore },
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
pub fn preprocess(entry_file: &str) -> GlobalStore {
|
|
14
|
-
println!("📦 Collecting dependencies for: {}", entry_file);
|
|
15
|
-
|
|
16
|
-
let files = collect_dependencies_recursively(entry_file);
|
|
17
|
-
let mut store = GlobalStore::default();
|
|
18
|
-
|
|
19
|
-
for file in &files {
|
|
20
|
-
if let Err(e) = load_module_into_global_store(file, &mut store) {
|
|
21
|
-
eprintln!("❌ Error while loading {}: {}", file, e);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
store
|
|
26
|
-
}
|
|
4
|
+
pub mod processor;
|
|
@@ -1,70 +1,56 @@
|
|
|
1
1
|
use crate::core::{
|
|
2
|
-
lexer::
|
|
3
|
-
parser::
|
|
4
|
-
|
|
5
|
-
collect_dependencies_recursively,
|
|
6
|
-
resolver::{ resolve_exports, resolve_imports },
|
|
7
|
-
},
|
|
8
|
-
types::{ module::Module, parser::Parser, store::{ ExportTable, GlobalStore, ImportTable } },
|
|
2
|
+
lexer::token::Token,
|
|
3
|
+
parser::statement::Statement,
|
|
4
|
+
store::{ export::ExportTable, import::ImportTable, variable::VariableTable },
|
|
9
5
|
};
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
#[derive(Debug, Clone)]
|
|
8
|
+
pub struct Module {
|
|
9
|
+
pub path: String,
|
|
10
|
+
pub resolved: bool,
|
|
11
|
+
pub tokens: Vec<Token>,
|
|
12
|
+
pub statements: Vec<Statement>,
|
|
13
|
+
pub variable_table: VariableTable,
|
|
14
|
+
pub export_table: ExportTable,
|
|
15
|
+
pub import_table: ImportTable,
|
|
16
|
+
pub content: String,
|
|
17
|
+
pub current_dir: String,
|
|
18
|
+
}
|
|
14
19
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
impl Module {
|
|
21
|
+
pub fn new(path: &str) -> Self {
|
|
22
|
+
Module {
|
|
23
|
+
path: path.to_string(),
|
|
24
|
+
tokens: Vec::new(),
|
|
25
|
+
statements: Vec::new(),
|
|
26
|
+
variable_table: VariableTable::new(),
|
|
27
|
+
export_table: ExportTable::new(),
|
|
28
|
+
import_table: ImportTable::new(),
|
|
29
|
+
resolved: false,
|
|
30
|
+
content: String::new(),
|
|
31
|
+
current_dir: String::new(),
|
|
18
32
|
}
|
|
19
33
|
}
|
|
20
34
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
let imports = resolve_imports(module, &mut global_store);
|
|
24
|
-
module.import_table = imports.clone();
|
|
25
|
-
|
|
26
|
-
let global_store_module = global_store.modules.get(&file.clone().to_string());
|
|
27
|
-
if let Some(global_store_module_found) = global_store_module {
|
|
28
|
-
global_store.insert_module(file.to_string(), module.clone());
|
|
29
|
-
} else {
|
|
30
|
-
eprintln!("❌ Module {} not found in global store after import resolution", file);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
35
|
+
pub fn is_resolved(&self) -> bool {
|
|
36
|
+
self.resolved
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
pub fn load_module_into_global_store(
|
|
39
|
-
path: &str,
|
|
40
|
-
global_store: &mut GlobalStore
|
|
41
|
-
) -> Result<(), String> {
|
|
42
|
-
if global_store.modules.contains_key(path) {
|
|
43
|
-
return Ok(());
|
|
39
|
+
pub fn set_resolved(&mut self, resolved: bool) {
|
|
40
|
+
self.resolved = resolved;
|
|
44
41
|
}
|
|
45
42
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
let mut parser = Parser::new(tokens.clone());
|
|
51
|
-
|
|
52
|
-
parser.current_module = path.to_string();
|
|
53
|
-
|
|
54
|
-
let raw_statements = parse_without_resolving(tokens.clone(), &mut parser, global_store);
|
|
55
|
-
|
|
56
|
-
let export_table = resolve_exports(&raw_statements, &mut parser);
|
|
57
|
-
|
|
58
|
-
let mut module = Module {
|
|
59
|
-
path: path.to_string(),
|
|
60
|
-
tokens: tokens.clone(),
|
|
61
|
-
statements: raw_statements,
|
|
62
|
-
variable_table: parser.variable_table.clone(),
|
|
63
|
-
export_table: export_table.clone(),
|
|
64
|
-
import_table: parser.import_table.clone(),
|
|
65
|
-
};
|
|
43
|
+
pub fn add_token(&mut self, token: Token) {
|
|
44
|
+
self.tokens.push(token);
|
|
45
|
+
}
|
|
66
46
|
|
|
67
|
-
|
|
47
|
+
pub fn add_statement(&mut self, statement: Statement) {
|
|
48
|
+
self.statements.push(statement);
|
|
49
|
+
}
|
|
68
50
|
|
|
69
|
-
|
|
51
|
+
pub fn from_existing(path: &str, content: String) -> Self {
|
|
52
|
+
let mut module = Module::new(path);
|
|
53
|
+
module.content = content;
|
|
54
|
+
module
|
|
55
|
+
}
|
|
70
56
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
use std::{ collections::HashMap, path::Path };
|
|
2
|
+
|
|
3
|
+
use crate::core::{
|
|
4
|
+
parser::{ driver::Parser, statement::StatementKind },
|
|
5
|
+
preprocessor::{ loader::ModuleLoader, resolver::group },
|
|
6
|
+
shared::value::Value,
|
|
7
|
+
store::global::GlobalStore,
|
|
8
|
+
utils::path::{normalize_path, resolve_relative_path},
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
pub fn process_modules(module_loader: &ModuleLoader, global_store: &mut GlobalStore) {
|
|
12
|
+
for module in global_store.modules.values_mut() {
|
|
13
|
+
for stmt in &module.statements {
|
|
14
|
+
match &stmt.kind {
|
|
15
|
+
StatementKind::Let { name } => {
|
|
16
|
+
module.variable_table.variables.insert(name.clone(), stmt.value.clone());
|
|
17
|
+
}
|
|
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
|
+
|
|
24
|
+
module.variable_table.variables.insert(
|
|
25
|
+
alias.clone(),
|
|
26
|
+
Value::Sample(resolved_path)
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
StatementKind::Export { names, source } => {
|
|
31
|
+
for name in names {
|
|
32
|
+
if let Some(val) = module.variable_table.get(name) {
|
|
33
|
+
module.export_table.add_export(name.clone(), val.clone());
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
StatementKind::Import { names, source } => {
|
|
39
|
+
let resolved = resolve_relative_path(&module.path, source);
|
|
40
|
+
for name in names {
|
|
41
|
+
module.import_table.add_import(
|
|
42
|
+
name.clone(),
|
|
43
|
+
Value::String(resolved.clone())
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
StatementKind::Group => {
|
|
49
|
+
if let Value::Map(map) = &stmt.value {
|
|
50
|
+
if
|
|
51
|
+
let (Some(Value::String(name)), Some(Value::Block(body))) = (
|
|
52
|
+
map.get("identifier"),
|
|
53
|
+
map.get("body"),
|
|
54
|
+
)
|
|
55
|
+
{
|
|
56
|
+
let mut stored_map = HashMap::new();
|
|
57
|
+
|
|
58
|
+
stored_map.insert(
|
|
59
|
+
"identifier".to_string(),
|
|
60
|
+
Value::String(name.clone())
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
stored_map.insert("body".to_string(), Value::Block(body.clone()));
|
|
64
|
+
|
|
65
|
+
module.variable_table.set(name.to_string(), Value::Map(stored_map));
|
|
66
|
+
} else {
|
|
67
|
+
eprintln!("❌ Invalid group definition: {:?}", stmt.value);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
_ => {}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -1,59 +1,49 @@
|
|
|
1
|
-
use crate::
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
use crate::{
|
|
2
|
+
core::{
|
|
3
|
+
parser::statement::{ Statement, StatementKind },
|
|
4
|
+
preprocessor::module::Module,
|
|
5
|
+
shared::value::Value,
|
|
6
|
+
store::global::GlobalStore,
|
|
7
|
+
},
|
|
8
|
+
utils::logger::Logger,
|
|
9
|
+
};
|
|
6
10
|
|
|
7
|
-
pub fn
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
let statement_value: StatementResolvedValue = match value {
|
|
16
|
-
VariableValue::Array(arr) => {
|
|
17
|
-
StatementResolvedValue::Array(
|
|
18
|
-
parse_with_resolving_with_module(arr.clone(), module)
|
|
19
|
-
)
|
|
20
|
-
}
|
|
21
|
-
VariableValue::Text(text) => StatementResolvedValue::String(text.clone()),
|
|
22
|
-
VariableValue::Number(num) => StatementResolvedValue::Number(*num),
|
|
23
|
-
VariableValue::Boolean(b) => StatementResolvedValue::Boolean(*b),
|
|
24
|
-
_ => {
|
|
25
|
-
eprintln!("⚠️ Unsupported variable type for Bank: {:?}", value);
|
|
26
|
-
StatementResolvedValue::Unknown
|
|
27
|
-
}
|
|
28
|
-
};
|
|
11
|
+
pub fn resolve_bank(
|
|
12
|
+
stmt: &Statement,
|
|
13
|
+
module: &Module,
|
|
14
|
+
path: &str,
|
|
15
|
+
_global_store: &GlobalStore
|
|
16
|
+
) -> Statement {
|
|
17
|
+
let mut new_stmt = stmt.clone();
|
|
18
|
+
let logger = Logger::new();
|
|
29
19
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
line: stmt.line,
|
|
35
|
-
column: stmt.column,
|
|
36
|
-
}
|
|
20
|
+
match &stmt.value {
|
|
21
|
+
Value::Identifier(ident) => {
|
|
22
|
+
if let Some(val) = module.variable_table.get(ident) {
|
|
23
|
+
new_stmt.value = val.clone();
|
|
37
24
|
} else {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
column: stmt.column,
|
|
45
|
-
}
|
|
25
|
+
let message = format!("Bank identifier '{ident}' not found in variable table");
|
|
26
|
+
logger.log_error_with_stacktrace(&message, &module.path);
|
|
27
|
+
new_stmt.kind = StatementKind::Error {
|
|
28
|
+
message: message.clone(),
|
|
29
|
+
};
|
|
30
|
+
new_stmt.value = Value::Null;
|
|
46
31
|
}
|
|
47
32
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
33
|
+
|
|
34
|
+
Value::String(_) => {}
|
|
35
|
+
|
|
36
|
+
Value::Number(_) => {}
|
|
37
|
+
|
|
38
|
+
other => {
|
|
39
|
+
let message = format!("Expected a string or identifier for bank, found {:?}", other);
|
|
40
|
+
logger.log_error_with_stacktrace(&message, &module.path);
|
|
41
|
+
new_stmt.kind = StatementKind::Error {
|
|
42
|
+
message: "Expected a string or identifier for bank".to_string(),
|
|
43
|
+
};
|
|
44
|
+
new_stmt.value = Value::Null;
|
|
57
45
|
}
|
|
58
46
|
}
|
|
47
|
+
|
|
48
|
+
new_stmt
|
|
59
49
|
}
|