@devaloop/devalang 0.0.1-alpha.17 → 0.0.1-alpha.18
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 +5 -1
- package/Cargo.toml +4 -4
- package/README.md +9 -6
- package/docs/CHANGELOG.md +46 -1
- package/docs/TODO.md +1 -1
- package/examples/index.deva +9 -6
- package/examples/pattern.deva +5 -5
- package/out-tsc/pkg/devalang_core.d.ts +1 -1
- package/out-tsc/pkg/devalang_core_bg.wasm.d.ts +7 -7
- package/package.json +1 -1
- package/project-version.json +3 -3
- package/rust/cli/build/commands.rs +10 -0
- package/rust/cli/install/addon.rs +84 -38
- package/rust/cli/telemetry/event_creator.rs +17 -17
- package/rust/core/audio/engine/helpers.rs +21 -9
- package/rust/core/audio/engine/sample.rs +68 -7
- package/rust/core/audio/engine/synth.rs +19 -4
- package/rust/core/audio/evaluator.rs +64 -26
- package/rust/core/audio/interpreter/arrow_call.rs +21 -16
- package/rust/core/audio/interpreter/call.rs +156 -1
- package/rust/core/audio/interpreter/spawn.rs +145 -1
- package/rust/core/audio/special/math.rs +22 -2
- package/rust/core/lexer/driver.rs +61 -0
- package/rust/core/lexer/handler/identifier.rs +3 -2
- package/rust/core/lexer/mod.rs +1 -62
- package/rust/core/lexer/token.rs +1 -0
- package/rust/core/parser/driver.rs +12 -9
- package/rust/core/parser/handler/dot.rs +3 -2
- package/rust/core/parser/handler/loop_.rs +2 -2
- package/rust/core/parser/handler/mod.rs +1 -0
- package/rust/core/parser/handler/pattern.rs +74 -0
- package/rust/core/preprocessor/loader.rs +87 -127
- package/rust/core/preprocessor/processor.rs +7 -7
- package/rust/core/preprocessor/resolver/call.rs +28 -0
- package/rust/core/preprocessor/resolver/driver.rs +15 -13
- package/rust/core/preprocessor/resolver/mod.rs +1 -0
- package/rust/core/preprocessor/resolver/pattern.rs +75 -0
- package/rust/core/preprocessor/resolver/spawn.rs +27 -0
- package/rust/core/store/variable.rs +15 -1
- package/rust/main.rs +4 -1
- package/rust/types/Cargo.toml +3 -0
- package/rust/types/src/ast.rs +4 -0
- package/rust/utils/Cargo.toml +4 -1
- package/rust/web/api.rs +2 -2
|
@@ -1,26 +1,23 @@
|
|
|
1
1
|
#[cfg(feature = "cli")]
|
|
2
2
|
use crate::core::preprocessor::resolver::driver::{
|
|
3
|
-
resolve_all_modules,
|
|
3
|
+
resolve_all_modules,
|
|
4
|
+
resolve_and_flatten_all_modules,
|
|
4
5
|
};
|
|
5
6
|
#[cfg(feature = "cli")]
|
|
6
7
|
use crate::core::utils::path::resolve_relative_path;
|
|
7
8
|
#[cfg_attr(not(feature = "cli"), allow(unused_imports))]
|
|
8
9
|
use crate::core::{
|
|
9
10
|
error::ErrorHandler,
|
|
10
|
-
lexer::{
|
|
11
|
-
parser::{
|
|
12
|
-
driver::Parser,
|
|
13
|
-
statement::{Statement, StatementKind},
|
|
14
|
-
},
|
|
11
|
+
lexer::{ token::Token, driver::Lexer },
|
|
12
|
+
parser::{ driver::Parser, statement::{ Statement, StatementKind } },
|
|
15
13
|
plugin::loader::load_plugin,
|
|
16
|
-
preprocessor::{module::Module, processor::process_modules},
|
|
14
|
+
preprocessor::{ module::Module, processor::process_modules },
|
|
17
15
|
store::global::GlobalStore,
|
|
18
16
|
utils::path::normalize_path,
|
|
19
17
|
};
|
|
20
|
-
use devalang_types::{BankFile, Value};
|
|
21
|
-
|
|
22
|
-
use
|
|
23
|
-
use std::{collections::HashMap, path::Path};
|
|
18
|
+
use devalang_types::{ BankFile, Value };
|
|
19
|
+
use devalang_utils::logger::{ LogLevel, Logger };
|
|
20
|
+
use std::{ collections::HashMap, path::Path };
|
|
24
21
|
|
|
25
22
|
pub struct ModuleLoader {
|
|
26
23
|
pub entry: String,
|
|
@@ -47,7 +44,7 @@ impl ModuleLoader {
|
|
|
47
44
|
entry_path: &str,
|
|
48
45
|
output_path: &str,
|
|
49
46
|
content: &str,
|
|
50
|
-
global_store: &mut GlobalStore
|
|
47
|
+
global_store: &mut GlobalStore
|
|
51
48
|
) -> Self {
|
|
52
49
|
let normalized_entry_path = normalize_path(entry_path);
|
|
53
50
|
|
|
@@ -68,18 +65,16 @@ impl ModuleLoader {
|
|
|
68
65
|
|
|
69
66
|
pub fn extract_statements_map(
|
|
70
67
|
&self,
|
|
71
|
-
global_store: &GlobalStore
|
|
68
|
+
global_store: &GlobalStore
|
|
72
69
|
) -> HashMap<String, Vec<Statement>> {
|
|
73
|
-
global_store
|
|
74
|
-
.modules
|
|
70
|
+
global_store.modules
|
|
75
71
|
.iter()
|
|
76
72
|
.map(|(path, module)| (path.clone(), module.statements.clone()))
|
|
77
73
|
.collect()
|
|
78
74
|
}
|
|
79
75
|
|
|
80
76
|
pub fn load_single_module(&self, global_store: &mut GlobalStore) -> Result<Module, String> {
|
|
81
|
-
let mut module = global_store
|
|
82
|
-
.modules
|
|
77
|
+
let mut module = global_store.modules
|
|
83
78
|
.remove(&self.entry)
|
|
84
79
|
.ok_or_else(|| format!("Module not found in store for path: {}", self.entry))?;
|
|
85
80
|
|
|
@@ -106,9 +101,7 @@ impl ModuleLoader {
|
|
|
106
101
|
self.load_plugin_and_register(&mut module, &plugin_name, &alias, global_store);
|
|
107
102
|
}
|
|
108
103
|
|
|
109
|
-
global_store
|
|
110
|
-
.modules
|
|
111
|
-
.insert(self.entry.clone(), module.clone());
|
|
104
|
+
global_store.modules.insert(self.entry.clone(), module.clone());
|
|
112
105
|
|
|
113
106
|
// SECTION Error handling
|
|
114
107
|
let mut error_handler = ErrorHandler::new();
|
|
@@ -120,8 +113,7 @@ impl ModuleLoader {
|
|
|
120
113
|
pub fn load_wasm_module(&self, global_store: &mut GlobalStore) -> Result<(), String> {
|
|
121
114
|
// Step one : Load the module from the global store
|
|
122
115
|
let module = {
|
|
123
|
-
let module_ref = global_store
|
|
124
|
-
.modules
|
|
116
|
+
let module_ref = global_store.modules
|
|
125
117
|
.get(&self.entry)
|
|
126
118
|
.ok_or_else(|| format!("❌ Module not found for path: {}", self.entry))?;
|
|
127
119
|
|
|
@@ -152,9 +144,7 @@ impl ModuleLoader {
|
|
|
152
144
|
// Insert the updated module into the global store before processing so
|
|
153
145
|
// process_modules can operate on it and populate variable_table, imports,
|
|
154
146
|
// and other derived structures.
|
|
155
|
-
global_store
|
|
156
|
-
.modules
|
|
157
|
-
.insert(self.entry.clone(), updated_module.clone());
|
|
147
|
+
global_store.modules.insert(self.entry.clone(), updated_module.clone());
|
|
158
148
|
|
|
159
149
|
// Process modules to populate module.variable_table, import/export tables,
|
|
160
150
|
// and other derived structures so runtime execution can resolve groups/synths.
|
|
@@ -174,25 +164,17 @@ impl ModuleLoader {
|
|
|
174
164
|
// (it lives in `global_store.modules`) because `updated_module` is a local
|
|
175
165
|
// clone and won't contain the mutations applied by `process_modules`.
|
|
176
166
|
if let Some(stored_module) = global_store.modules.get(&self.entry) {
|
|
177
|
-
global_store
|
|
178
|
-
|
|
179
|
-
.variables
|
|
180
|
-
.extend(stored_module.variable_table.variables.clone());
|
|
181
|
-
global_store
|
|
182
|
-
.functions
|
|
183
|
-
.functions
|
|
184
|
-
.extend(stored_module.function_table.functions.clone());
|
|
167
|
+
global_store.variables.variables.extend(stored_module.variable_table.variables.clone());
|
|
168
|
+
global_store.functions.functions.extend(stored_module.function_table.functions.clone());
|
|
185
169
|
} else {
|
|
186
170
|
// Fallback to the local updated_module if for any reason the module
|
|
187
171
|
// wasn't inserted into the store (defensive programming).
|
|
188
|
-
global_store
|
|
189
|
-
.variables
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
.functions
|
|
195
|
-
.extend(updated_module.function_table.functions.clone());
|
|
172
|
+
global_store.variables.variables.extend(
|
|
173
|
+
updated_module.variable_table.variables.clone()
|
|
174
|
+
);
|
|
175
|
+
global_store.functions.functions.extend(
|
|
176
|
+
updated_module.function_table.functions.clone()
|
|
177
|
+
);
|
|
196
178
|
}
|
|
197
179
|
|
|
198
180
|
Ok(())
|
|
@@ -201,7 +183,7 @@ impl ModuleLoader {
|
|
|
201
183
|
#[cfg(feature = "cli")]
|
|
202
184
|
pub fn load_all_modules(
|
|
203
185
|
&self,
|
|
204
|
-
global_store: &mut GlobalStore
|
|
186
|
+
global_store: &mut GlobalStore
|
|
205
187
|
) -> (HashMap<String, Vec<Token>>, HashMap<String, Vec<Statement>>) {
|
|
206
188
|
// SECTION Load the entry module and its dependencies
|
|
207
189
|
let tokens_by_module = self.load_module_recursively(&self.entry, global_store);
|
|
@@ -220,7 +202,7 @@ impl ModuleLoader {
|
|
|
220
202
|
fn load_module_recursively(
|
|
221
203
|
&self,
|
|
222
204
|
raw_path: &str,
|
|
223
|
-
global_store: &mut GlobalStore
|
|
205
|
+
global_store: &mut GlobalStore
|
|
224
206
|
) -> HashMap<String, Vec<Token>> {
|
|
225
207
|
let path = normalize_path(raw_path);
|
|
226
208
|
|
|
@@ -261,14 +243,8 @@ impl ModuleLoader {
|
|
|
261
243
|
}
|
|
262
244
|
|
|
263
245
|
// Inject module variables and functions into global store
|
|
264
|
-
global_store
|
|
265
|
-
|
|
266
|
-
.variables
|
|
267
|
-
.extend(module.variable_table.variables.clone());
|
|
268
|
-
global_store
|
|
269
|
-
.functions
|
|
270
|
-
.functions
|
|
271
|
-
.extend(module.function_table.functions.clone());
|
|
246
|
+
global_store.variables.variables.extend(module.variable_table.variables.clone());
|
|
247
|
+
global_store.functions.functions.extend(module.function_table.functions.clone());
|
|
272
248
|
|
|
273
249
|
// Inject the module into the global store
|
|
274
250
|
global_store.insert_module(path.clone(), module);
|
|
@@ -293,8 +269,7 @@ impl ModuleLoader {
|
|
|
293
269
|
}
|
|
294
270
|
|
|
295
271
|
// Return tokens per module
|
|
296
|
-
global_store
|
|
297
|
-
.modules
|
|
272
|
+
global_store.modules
|
|
298
273
|
.iter()
|
|
299
274
|
.map(|(p, m)| (p.clone(), m.tokens.clone()))
|
|
300
275
|
.collect()
|
|
@@ -306,16 +281,12 @@ impl ModuleLoader {
|
|
|
306
281
|
let current_module = match global_store.modules.get(path) {
|
|
307
282
|
Some(module) => module,
|
|
308
283
|
None => {
|
|
309
|
-
eprintln!(
|
|
310
|
-
"[warn] Cannot resolve imports: module '{}' not found in store",
|
|
311
|
-
path
|
|
312
|
-
);
|
|
284
|
+
eprintln!("[warn] Cannot resolve imports: module '{}' not found in store", path);
|
|
313
285
|
return;
|
|
314
286
|
}
|
|
315
287
|
};
|
|
316
288
|
|
|
317
|
-
current_module
|
|
318
|
-
.statements
|
|
289
|
+
current_module.statements
|
|
319
290
|
.iter()
|
|
320
291
|
.filter_map(|stmt| {
|
|
321
292
|
if let StatementKind::Import { source, .. } = &stmt.kind {
|
|
@@ -337,13 +308,9 @@ impl ModuleLoader {
|
|
|
337
308
|
&self,
|
|
338
309
|
module: &mut Module,
|
|
339
310
|
bank_name: &str,
|
|
340
|
-
alias_override: Option<String
|
|
311
|
+
alias_override: Option<String>
|
|
341
312
|
) -> Result<Module, String> {
|
|
342
|
-
let default_alias = bank_name
|
|
343
|
-
.split('.')
|
|
344
|
-
.next_back()
|
|
345
|
-
.unwrap_or(bank_name)
|
|
346
|
-
.to_string();
|
|
313
|
+
let default_alias = bank_name.split('.').next_back().unwrap_or(bank_name).to_string();
|
|
347
314
|
let alias_ref = alias_override.as_deref().unwrap_or(&default_alias);
|
|
348
315
|
|
|
349
316
|
let bank_path = match devalang_utils::path::get_deva_dir() {
|
|
@@ -356,10 +323,12 @@ impl ModuleLoader {
|
|
|
356
323
|
return Ok(module.clone());
|
|
357
324
|
}
|
|
358
325
|
|
|
359
|
-
let content = std::fs
|
|
326
|
+
let content = std::fs
|
|
327
|
+
::read_to_string(&bank_toml_path)
|
|
360
328
|
.map_err(|e| format!("Failed to read '{}': {}", bank_toml_path.display(), e))?;
|
|
361
329
|
|
|
362
|
-
let parsed_bankfile: BankFile = toml
|
|
330
|
+
let parsed_bankfile: BankFile = toml
|
|
331
|
+
::from_str(&content)
|
|
363
332
|
.map_err(|e| format!("Failed to parse '{}': {}", bank_toml_path.display(), e))?;
|
|
364
333
|
|
|
365
334
|
let mut bank_map = HashMap::new();
|
|
@@ -368,38 +337,30 @@ impl ModuleLoader {
|
|
|
368
337
|
// Use the configured path from the bank file as the entity reference so
|
|
369
338
|
// that bank entries can point to files or nested paths. Clean common
|
|
370
339
|
// local prefixes like "./" to keep the URI tidy.
|
|
371
|
-
let entity_ref = bank_trigger
|
|
372
|
-
.path
|
|
373
|
-
.clone()
|
|
374
|
-
.replace("\\", "/")
|
|
375
|
-
.replace("./", "");
|
|
340
|
+
let entity_ref = bank_trigger.path.clone().replace("\\", "/").replace("./", "");
|
|
376
341
|
let bank_trigger_path = format!("devalang://bank/{}/{}", bank_name, entity_ref);
|
|
377
342
|
|
|
378
343
|
// Keep the trigger key as declared (bank_trigger.name) but expose its
|
|
379
344
|
// value as a devalang://bank URI pointing to the configured path.
|
|
380
|
-
bank_map.insert(
|
|
381
|
-
bank_trigger.name.clone(),
|
|
382
|
-
Value::String(bank_trigger_path.clone()),
|
|
383
|
-
);
|
|
345
|
+
bank_map.insert(bank_trigger.name.clone(), Value::String(bank_trigger_path.clone()));
|
|
384
346
|
|
|
385
347
|
if module.variable_table.variables.contains_key(alias_ref) {
|
|
386
348
|
eprintln!(
|
|
387
349
|
"⚠️ Trigger '{}' already defined in module '{}', skipping injection.",
|
|
388
|
-
alias_ref,
|
|
350
|
+
alias_ref,
|
|
351
|
+
module.path
|
|
389
352
|
);
|
|
390
353
|
continue;
|
|
391
354
|
}
|
|
392
355
|
|
|
393
356
|
module.variable_table.set(
|
|
394
357
|
format!("{}.{}", alias_ref, bank_trigger.name),
|
|
395
|
-
Value::String(bank_trigger_path.clone())
|
|
358
|
+
Value::String(bank_trigger_path.clone())
|
|
396
359
|
);
|
|
397
360
|
}
|
|
398
361
|
|
|
399
362
|
// Inject the map under the bank name
|
|
400
|
-
module
|
|
401
|
-
.variable_table
|
|
402
|
-
.set(alias_ref.to_string(), Value::Map(bank_map));
|
|
363
|
+
module.variable_table.set(alias_ref.to_string(), Value::Map(bank_map));
|
|
403
364
|
|
|
404
365
|
Ok(module.clone())
|
|
405
366
|
}
|
|
@@ -445,7 +406,7 @@ impl ModuleLoader {
|
|
|
445
406
|
module: &mut Module,
|
|
446
407
|
plugin_name: &str,
|
|
447
408
|
alias: &str,
|
|
448
|
-
global_store: &mut GlobalStore
|
|
409
|
+
global_store: &mut GlobalStore
|
|
449
410
|
) {
|
|
450
411
|
// plugin_name expected format: "author.name"
|
|
451
412
|
let mut parts = plugin_name.split('.');
|
|
@@ -464,10 +425,7 @@ impl ModuleLoader {
|
|
|
464
425
|
}
|
|
465
426
|
};
|
|
466
427
|
if parts.next().is_some() {
|
|
467
|
-
eprintln!(
|
|
468
|
-
"Invalid plugin name '{}': expected <author>.<name>",
|
|
469
|
-
plugin_name
|
|
470
|
-
);
|
|
428
|
+
eprintln!("Invalid plugin name '{}': expected <author>.<name>", plugin_name);
|
|
471
429
|
return;
|
|
472
430
|
}
|
|
473
431
|
|
|
@@ -499,8 +457,7 @@ impl ModuleLoader {
|
|
|
499
457
|
// Inject a single, clear error into the module so it is reported once by the error handler
|
|
500
458
|
module.statements.push(Statement {
|
|
501
459
|
kind: StatementKind::Error {
|
|
502
|
-
message: "plugin present in local files but missing in .devalang config"
|
|
503
|
-
.to_string(),
|
|
460
|
+
message: "plugin present in local files but missing in .devalang config".to_string(),
|
|
504
461
|
},
|
|
505
462
|
value: Value::Null,
|
|
506
463
|
indent: 0,
|
|
@@ -514,20 +471,16 @@ impl ModuleLoader {
|
|
|
514
471
|
match load_plugin(author, name) {
|
|
515
472
|
Ok((info, wasm)) => {
|
|
516
473
|
let uri = format!("devalang://plugin/{}.{}", author, name);
|
|
517
|
-
global_store
|
|
518
|
-
.plugins
|
|
519
|
-
.insert(format!("{}:{}", author, name), (info, wasm));
|
|
474
|
+
global_store.plugins.insert(format!("{}:{}", author, name), (info, wasm));
|
|
520
475
|
// Set alias to URI, and inject exported variables
|
|
521
|
-
module
|
|
522
|
-
.variable_table
|
|
523
|
-
.set(alias.to_string(), Value::String(uri.clone()));
|
|
476
|
+
module.variable_table.set(alias.to_string(), Value::String(uri.clone()));
|
|
524
477
|
// Also expose alias at global level so runtime can resolve it
|
|
525
|
-
global_store
|
|
526
|
-
.variables
|
|
527
|
-
.set(alias.to_string(), Value::String(uri.clone()));
|
|
478
|
+
global_store.variables.set(alias.to_string(), Value::String(uri.clone()));
|
|
528
479
|
|
|
529
|
-
if
|
|
530
|
-
global_store.plugins.get(
|
|
480
|
+
if
|
|
481
|
+
let Some((plugin_info, _)) = global_store.plugins.get(
|
|
482
|
+
&format!("{}:{}", author, name)
|
|
483
|
+
)
|
|
531
484
|
{
|
|
532
485
|
for exp in &plugin_info.exports {
|
|
533
486
|
match exp.kind.as_str() {
|
|
@@ -536,18 +489,18 @@ impl ModuleLoader {
|
|
|
536
489
|
if let Ok(n) = s.parse::<f32>() {
|
|
537
490
|
module.variable_table.set(
|
|
538
491
|
format!("{}.{}", alias, exp.name),
|
|
539
|
-
Value::Number(n)
|
|
492
|
+
Value::Number(n)
|
|
540
493
|
);
|
|
541
494
|
}
|
|
542
495
|
} else if let Some(toml::Value::Integer(i)) = &exp.default {
|
|
543
496
|
module.variable_table.set(
|
|
544
497
|
format!("{}.{}", alias, exp.name),
|
|
545
|
-
Value::Number(*i as f32)
|
|
498
|
+
Value::Number(*i as f32)
|
|
546
499
|
);
|
|
547
500
|
} else if let Some(toml::Value::Float(f)) = &exp.default {
|
|
548
501
|
module.variable_table.set(
|
|
549
502
|
format!("{}.{}", alias, exp.name),
|
|
550
|
-
Value::Number(*f as f32)
|
|
503
|
+
Value::Number(*f as f32)
|
|
551
504
|
);
|
|
552
505
|
}
|
|
553
506
|
}
|
|
@@ -555,22 +508,23 @@ impl ModuleLoader {
|
|
|
555
508
|
if let Some(toml::Value::String(s)) = &exp.default {
|
|
556
509
|
module.variable_table.set(
|
|
557
510
|
format!("{}.{}", alias, exp.name),
|
|
558
|
-
Value::String(s.clone())
|
|
511
|
+
Value::String(s.clone())
|
|
559
512
|
);
|
|
560
513
|
}
|
|
561
514
|
}
|
|
562
515
|
"bool" => {
|
|
563
516
|
if let Some(toml::Value::Boolean(b)) = &exp.default {
|
|
564
|
-
module
|
|
565
|
-
.
|
|
566
|
-
|
|
517
|
+
module.variable_table.set(
|
|
518
|
+
format!("{}.{}", alias, exp.name),
|
|
519
|
+
Value::Boolean(*b)
|
|
520
|
+
);
|
|
567
521
|
}
|
|
568
522
|
}
|
|
569
523
|
"synth" => {
|
|
570
524
|
// Provide a discoverable marker: alias.<synthName> resolves to alias.synthName waveform string
|
|
571
525
|
module.variable_table.set(
|
|
572
526
|
format!("{}.{}", alias, exp.name),
|
|
573
|
-
Value::String(format!("{}.{}", alias, exp.name))
|
|
527
|
+
Value::String(format!("{}.{}", alias, exp.name))
|
|
574
528
|
);
|
|
575
529
|
}
|
|
576
530
|
_ => {
|
|
@@ -581,23 +535,28 @@ impl ModuleLoader {
|
|
|
581
535
|
toml::Value::Integer(i) => Value::Number(*i as f32),
|
|
582
536
|
toml::Value::Float(f) => Value::Number(*f as f32),
|
|
583
537
|
toml::Value::Boolean(b) => Value::Boolean(*b),
|
|
584
|
-
toml::Value::Array(arr) =>
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
538
|
+
toml::Value::Array(arr) =>
|
|
539
|
+
Value::Array(
|
|
540
|
+
arr
|
|
541
|
+
.iter()
|
|
542
|
+
.map(|v| {
|
|
543
|
+
match v {
|
|
544
|
+
toml::Value::String(s) => {
|
|
545
|
+
Value::String(s.clone())
|
|
546
|
+
}
|
|
547
|
+
toml::Value::Integer(i) => {
|
|
548
|
+
Value::Number(*i as f32)
|
|
549
|
+
}
|
|
550
|
+
toml::Value::Float(f) => {
|
|
551
|
+
Value::Number(*f as f32)
|
|
552
|
+
}
|
|
553
|
+
toml::Value::Boolean(b) =>
|
|
554
|
+
Value::Boolean(*b),
|
|
555
|
+
_ => Value::Null,
|
|
556
|
+
}
|
|
557
|
+
})
|
|
558
|
+
.collect()
|
|
559
|
+
),
|
|
601
560
|
toml::Value::Table(t) => {
|
|
602
561
|
let mut m = std::collections::HashMap::new();
|
|
603
562
|
for (k, v) in t.iter() {
|
|
@@ -621,9 +580,10 @@ impl ModuleLoader {
|
|
|
621
580
|
_ => Value::Null,
|
|
622
581
|
};
|
|
623
582
|
if val != Value::Null {
|
|
624
|
-
module
|
|
625
|
-
.
|
|
626
|
-
|
|
583
|
+
module.variable_table.set(
|
|
584
|
+
format!("{}.{}", alias, exp.name),
|
|
585
|
+
val
|
|
586
|
+
);
|
|
627
587
|
}
|
|
628
588
|
}
|
|
629
589
|
}
|
|
@@ -10,11 +10,14 @@ use devalang_types::Value;
|
|
|
10
10
|
|
|
11
11
|
pub fn process_modules(_module_loader: &ModuleLoader, global_store: &mut GlobalStore) {
|
|
12
12
|
for module in global_store.modules.values_mut() {
|
|
13
|
+
let logger = devalang_utils::logger::Logger::new();
|
|
14
|
+
use devalang_utils::logger::LogLevel;
|
|
15
|
+
|
|
13
16
|
for stmt in &module.statements {
|
|
14
17
|
match &stmt.kind {
|
|
15
18
|
StatementKind::Let { name } => {
|
|
16
19
|
if let Value::Null = stmt.value {
|
|
17
|
-
|
|
20
|
+
logger.log_message(LogLevel::Error, &format!("Variable '{}' is declared but not initialized.", name));
|
|
18
21
|
|
|
19
22
|
module.variable_table.variables.insert(
|
|
20
23
|
name.clone(),
|
|
@@ -25,15 +28,12 @@ pub fn process_modules(_module_loader: &ModuleLoader, global_store: &mut GlobalS
|
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
if module.variable_table.get(name).is_some() {
|
|
28
|
-
|
|
31
|
+
logger.log_message(LogLevel::Error, &format!("Variable '{}' is already defined in this scope.", name));
|
|
29
32
|
continue;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
if let Some(module_variable) = module.variable_table.variables.get(name) {
|
|
33
|
-
|
|
34
|
-
"❌ Variable '{}' is already defined globally with value: {:?}",
|
|
35
|
-
name, module_variable
|
|
36
|
-
);
|
|
36
|
+
logger.log_message(LogLevel::Error, &format!("Variable '{}' is already defined globally with value: {:?}", name, module_variable));
|
|
37
37
|
continue;
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -87,7 +87,7 @@ pub fn process_modules(_module_loader: &ModuleLoader, global_store: &mut GlobalS
|
|
|
87
87
|
.variable_table
|
|
88
88
|
.set(name.to_string(), Value::Map(stored_map));
|
|
89
89
|
} else {
|
|
90
|
-
|
|
90
|
+
logger.log_message(LogLevel::Error, &format!("Invalid group definition: {:?}", stmt.value));
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
}
|
|
@@ -60,6 +60,34 @@ pub fn resolve_call(
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
+
// Pattern case
|
|
64
|
+
if let StatementKind::Pattern { .. } = stmt_box.kind {
|
|
65
|
+
// pattern value may be a string or a map stored on the statement
|
|
66
|
+
let mut resolved_map = std::collections::HashMap::new();
|
|
67
|
+
resolved_map.insert("identifier".to_string(), Value::String(name.clone()));
|
|
68
|
+
// pattern value
|
|
69
|
+
match &stmt_box.value {
|
|
70
|
+
Value::String(s) => {
|
|
71
|
+
resolved_map.insert("pattern".to_string(), Value::String(s.clone()));
|
|
72
|
+
}
|
|
73
|
+
Value::Map(m) => {
|
|
74
|
+
if let Some(val) = m.get("pattern") {
|
|
75
|
+
resolved_map.insert("pattern".to_string(), val.clone());
|
|
76
|
+
}
|
|
77
|
+
if let Some(val) = m.get("target") {
|
|
78
|
+
resolved_map.insert("target".to_string(), val.clone());
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
_ => {}
|
|
82
|
+
}
|
|
83
|
+
resolved_map.insert("args".to_string(), Value::Array(args.clone()));
|
|
84
|
+
|
|
85
|
+
return Statement {
|
|
86
|
+
kind: StatementKind::Call { name, args },
|
|
87
|
+
value: Value::Map(resolved_map),
|
|
88
|
+
..stmt.clone()
|
|
89
|
+
};
|
|
90
|
+
}
|
|
63
91
|
}
|
|
64
92
|
|
|
65
93
|
// Otherwise, log an error
|
|
@@ -5,7 +5,7 @@ use crate::core::{
|
|
|
5
5
|
module::Module,
|
|
6
6
|
resolver::{
|
|
7
7
|
bank::resolve_bank, call::resolve_call, condition::resolve_condition,
|
|
8
|
-
|
|
8
|
+
function::resolve_function, group::resolve_group, pattern::resolve_pattern, let_::resolve_let,
|
|
9
9
|
loop_::resolve_loop, spawn::resolve_spawn, tempo::resolve_tempo,
|
|
10
10
|
trigger::resolve_trigger,
|
|
11
11
|
},
|
|
@@ -14,6 +14,7 @@ use crate::core::{
|
|
|
14
14
|
};
|
|
15
15
|
use devalang_types::Value;
|
|
16
16
|
use devalang_utils::logger::Logger;
|
|
17
|
+
use devalang_utils::logger::LogLevel;
|
|
17
18
|
use std::collections::HashMap;
|
|
18
19
|
|
|
19
20
|
pub fn resolve_all_modules(module_loader: &ModuleLoader, global_store: &mut GlobalStore) {
|
|
@@ -66,7 +67,8 @@ pub fn resolve_statement(
|
|
|
66
67
|
global_store,
|
|
67
68
|
),
|
|
68
69
|
StatementKind::If => resolve_condition(stmt, module, path, global_store),
|
|
69
|
-
|
|
70
|
+
StatementKind::Group => resolve_group(stmt, module, path, global_store),
|
|
71
|
+
StatementKind::Pattern { .. } => resolve_pattern(stmt, module, path, global_store),
|
|
70
72
|
StatementKind::Call { name, args } => {
|
|
71
73
|
resolve_call(stmt, name.clone(), args.clone(), module, path, global_store)
|
|
72
74
|
}
|
|
@@ -90,6 +92,7 @@ pub fn resolve_statement(
|
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
fn resolve_value(value: &Value, module: &Module, global_store: &mut GlobalStore) -> Value {
|
|
95
|
+
let logger = Logger::new();
|
|
93
96
|
match value {
|
|
94
97
|
Value::Identifier(name) => {
|
|
95
98
|
if let Some(original_val) = module.variable_table.get(name) {
|
|
@@ -107,7 +110,7 @@ fn resolve_value(value: &Value, module: &Module, global_store: &mut GlobalStore)
|
|
|
107
110
|
Value::String(s) => Value::String(s.clone()),
|
|
108
111
|
|
|
109
112
|
Value::Beat(beat_str) => {
|
|
110
|
-
|
|
113
|
+
logger.log_message(LogLevel::Warning, &format!("[warn] '{:?}': unresolved beat '{}'", module.path, beat_str));
|
|
111
114
|
Value::Beat(beat_str.clone())
|
|
112
115
|
}
|
|
113
116
|
|
|
@@ -141,6 +144,7 @@ fn find_export_value(name: &str, global_store: &GlobalStore) -> Option<Value> {
|
|
|
141
144
|
}
|
|
142
145
|
|
|
143
146
|
pub fn resolve_imports(_module_loader: &ModuleLoader, global_store: &mut GlobalStore) {
|
|
147
|
+
let logger = Logger::new();
|
|
144
148
|
for (module_path, module) in global_store.clone().modules.iter_mut() {
|
|
145
149
|
for (name, source_path) in &module.import_table.imports {
|
|
146
150
|
match source_path {
|
|
@@ -149,21 +153,14 @@ pub fn resolve_imports(_module_loader: &ModuleLoader, global_store: &mut GlobalS
|
|
|
149
153
|
if let Some(value) = source_module.export_table.get_export(name) {
|
|
150
154
|
module.variable_table.set(name.clone(), value.clone());
|
|
151
155
|
} else {
|
|
152
|
-
|
|
153
|
-
"[warn] '{module_path}': '{name}' not found in exports of '{source_path}'"
|
|
154
|
-
);
|
|
156
|
+
logger.log_message(LogLevel::Warning, &format!("[warn] '{module_path}': '{name}' not found in exports of '{source_path}'"));
|
|
155
157
|
}
|
|
156
158
|
} else {
|
|
157
|
-
|
|
158
|
-
"[warn] '{module_path}': cannot find source module '{source_path}'"
|
|
159
|
-
);
|
|
159
|
+
logger.log_message(LogLevel::Warning, &format!("[warn] '{module_path}': cannot find source module '{source_path}'"));
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
_ => {
|
|
163
|
-
|
|
164
|
-
"[warn] '{module_path}': expected string for import source, found {:?}",
|
|
165
|
-
source_path
|
|
166
|
-
);
|
|
163
|
+
logger.log_message(LogLevel::Warning, &format!("[warn] '{module_path}': expected string for import source, found {:?}", source_path));
|
|
167
164
|
}
|
|
168
165
|
}
|
|
169
166
|
}
|
|
@@ -286,6 +283,11 @@ pub fn resolve_and_flatten_all_modules(
|
|
|
286
283
|
resolved.push(resolved_stmt);
|
|
287
284
|
}
|
|
288
285
|
|
|
286
|
+
StatementKind::Pattern { .. } => {
|
|
287
|
+
let resolved_stmt = resolve_pattern(&stmt, &module, &path, global_store);
|
|
288
|
+
resolved.push(resolved_stmt);
|
|
289
|
+
}
|
|
290
|
+
|
|
289
291
|
StatementKind::Function {
|
|
290
292
|
name: _,
|
|
291
293
|
parameters: _,
|