@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,158 +1,14 @@
|
|
|
1
|
+
pub mod driver;
|
|
2
|
+
|
|
3
|
+
pub mod value;
|
|
4
|
+
|
|
1
5
|
pub mod trigger;
|
|
2
6
|
pub mod loop_;
|
|
3
7
|
pub mod bank;
|
|
4
8
|
pub mod tempo;
|
|
5
9
|
pub mod group;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
preprocessor::{
|
|
12
|
-
loader::ModuleLoader,
|
|
13
|
-
resolver::{
|
|
14
|
-
bank::resolve_bank,
|
|
15
|
-
group::resolve_group,
|
|
16
|
-
loop_::resolve_loop,
|
|
17
|
-
tempo::resolve_tempo,
|
|
18
|
-
trigger::resolve_trigger,
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
shared::{ duration::Duration, value::Value },
|
|
22
|
-
store::global::GlobalStore,
|
|
23
|
-
utils::validation::{ is_valid_entity, is_valid_identifier },
|
|
24
|
-
},
|
|
25
|
-
utils::logger::Logger,
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
pub fn resolve_all_modules(module_loader: &ModuleLoader, global_store: &mut GlobalStore) {
|
|
29
|
-
for module in global_store.clone().modules.values_mut() {
|
|
30
|
-
resolve_imports(module_loader, global_store);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
pub fn resolve_imports(module_loader: &ModuleLoader, global_store: &mut GlobalStore) {
|
|
35
|
-
for (module_path, module) in global_store.clone().modules.iter_mut() {
|
|
36
|
-
for (name, source_path) in &module.import_table.imports {
|
|
37
|
-
match source_path {
|
|
38
|
-
Value::String(source_path) => {
|
|
39
|
-
if let Some(source_module) = global_store.modules.get(source_path) {
|
|
40
|
-
if let Some(value) = source_module.export_table.get_export(name) {
|
|
41
|
-
module.variable_table.set(name.clone(), value.clone());
|
|
42
|
-
} else {
|
|
43
|
-
println!(
|
|
44
|
-
"[warn] '{module_path}': '{name}' not found in exports of '{source_path}'"
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
} else {
|
|
48
|
-
println!(
|
|
49
|
-
"[warn] '{module_path}': cannot find source module '{source_path}'"
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
_ => {
|
|
54
|
-
println!(
|
|
55
|
-
"[warn] '{module_path}': expected string for import source, found {:?}",
|
|
56
|
-
source_path
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
pub fn resolve_and_flatten_all_modules(
|
|
65
|
-
global_store: &mut GlobalStore
|
|
66
|
-
) -> HashMap<String, Vec<Statement>> {
|
|
67
|
-
let logger = Logger::new();
|
|
68
|
-
let snapshot = global_store.clone();
|
|
69
|
-
|
|
70
|
-
// 1. Imports resolution
|
|
71
|
-
for (module_path, module) in global_store.modules.iter_mut() {
|
|
72
|
-
for (name, source_path) in &module.import_table.imports {
|
|
73
|
-
if let Value::String(source_path_str) = source_path {
|
|
74
|
-
match snapshot.modules.get(source_path_str) {
|
|
75
|
-
Some(source_module) => {
|
|
76
|
-
if let Some(value) = source_module.export_table.get_export(name) {
|
|
77
|
-
module.variable_table.set(name.clone(), value.clone());
|
|
78
|
-
} else {
|
|
79
|
-
logger.log_error_with_stacktrace(
|
|
80
|
-
&format!("'{name}' not found in exports of '{source_path_str}'"),
|
|
81
|
-
module_path
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
None => {
|
|
86
|
-
logger.log_error_with_stacktrace(
|
|
87
|
-
&format!("Cannot find source module '{source_path_str}'"),
|
|
88
|
-
module_path
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
} else {
|
|
93
|
-
logger.log_error_with_stacktrace(
|
|
94
|
-
&format!("Expected string for import source, found {:?}", source_path),
|
|
95
|
-
module_path
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// 2. Statements resolution
|
|
102
|
-
let mut resolved_map: HashMap<String, Vec<Statement>> = HashMap::new();
|
|
103
|
-
let store_snapshot = global_store.clone();
|
|
104
|
-
|
|
105
|
-
for (path, module) in &store_snapshot.modules {
|
|
106
|
-
let mut resolved = Vec::new();
|
|
107
|
-
|
|
108
|
-
for stmt in &module.statements {
|
|
109
|
-
let mut stmt = stmt.clone();
|
|
110
|
-
|
|
111
|
-
match &stmt.kind {
|
|
112
|
-
StatementKind::Trigger { entity, duration } => {
|
|
113
|
-
let resolved_stmt = resolve_trigger(
|
|
114
|
-
&stmt,
|
|
115
|
-
entity.as_str(),
|
|
116
|
-
&mut duration.clone(),
|
|
117
|
-
&module,
|
|
118
|
-
&path,
|
|
119
|
-
&store_snapshot
|
|
120
|
-
);
|
|
121
|
-
resolved.push(resolved_stmt);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
StatementKind::Loop => {
|
|
125
|
-
let resolved_stmt = resolve_loop(&stmt, &module, &path, &store_snapshot);
|
|
126
|
-
resolved.push(resolved_stmt);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
StatementKind::Bank => {
|
|
130
|
-
let resolved_stmt = resolve_bank(&stmt, &module, &path, &store_snapshot);
|
|
131
|
-
resolved.push(resolved_stmt);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
StatementKind::Tempo => {
|
|
135
|
-
let resolved_stmt = resolve_tempo(&stmt, &module, &path, &store_snapshot);
|
|
136
|
-
resolved.push(resolved_stmt);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
StatementKind::Import { .. } | StatementKind::Export { .. } => {
|
|
140
|
-
resolved.push(stmt.clone());
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
StatementKind::Group => {
|
|
144
|
-
let resolved_stmt = resolve_group(&stmt, &module, &path, &store_snapshot);
|
|
145
|
-
resolved.push(resolved_stmt);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
_ => {
|
|
149
|
-
resolved.push(stmt);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
resolved_map.insert(path.clone(), resolved);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
resolved_map
|
|
158
|
-
}
|
|
10
|
+
pub mod condition;
|
|
11
|
+
pub mod spawn;
|
|
12
|
+
pub mod call;
|
|
13
|
+
pub mod synth;
|
|
14
|
+
pub mod let_;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
use crate::{
|
|
2
|
+
core::{
|
|
3
|
+
parser::statement::{ Statement, StatementKind },
|
|
4
|
+
preprocessor::{
|
|
5
|
+
module::Module,
|
|
6
|
+
resolver::driver::resolve_statement,
|
|
7
|
+
resolver::value::resolve_value,
|
|
8
|
+
},
|
|
9
|
+
shared::value::Value,
|
|
10
|
+
store::global::GlobalStore,
|
|
11
|
+
},
|
|
12
|
+
utils::logger::{ Logger, LogLevel },
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
pub fn resolve_spawn(
|
|
16
|
+
stmt: &Statement,
|
|
17
|
+
module: &Module,
|
|
18
|
+
path: &str,
|
|
19
|
+
global_store: &mut GlobalStore
|
|
20
|
+
) -> Statement {
|
|
21
|
+
let logger = Logger::new();
|
|
22
|
+
|
|
23
|
+
let resolved_value = resolve_value(&stmt.value, module, global_store);
|
|
24
|
+
|
|
25
|
+
match resolved_value {
|
|
26
|
+
Value::Map(mut map) => {
|
|
27
|
+
if let Some(Value::Block(stmts)) = map.get("body") {
|
|
28
|
+
let resolved_block = stmts
|
|
29
|
+
.iter()
|
|
30
|
+
.map(|s| resolve_statement(s, module, path, global_store))
|
|
31
|
+
.collect();
|
|
32
|
+
map.insert("body".to_string(), Value::Block(resolved_block));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
Statement {
|
|
36
|
+
kind: StatementKind::Spawn,
|
|
37
|
+
value: Value::Map(map),
|
|
38
|
+
..stmt.clone()
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
_ => {
|
|
43
|
+
let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
|
|
44
|
+
logger.log_message(
|
|
45
|
+
LogLevel::Error,
|
|
46
|
+
&format!("Expected a map in spawn statement\n → at {stacktrace}")
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
Statement {
|
|
50
|
+
kind: StatementKind::Error {
|
|
51
|
+
message: "Invalid spawn value".to_string(),
|
|
52
|
+
},
|
|
53
|
+
value: Value::Null,
|
|
54
|
+
..stmt.clone()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
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::{ LogLevel, Logger },
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
pub fn resolve_synth(
|
|
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(synth_map) = &stmt.value else {
|
|
20
|
+
return type_error(&logger, module, stmt, "Expected a map in synth statement".to_string());
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
let mut resolved_map = synth_map.clone();
|
|
24
|
+
|
|
25
|
+
if let Some(Value::Block(body)) = synth_map.get("body") {
|
|
26
|
+
let resolved_body = body.iter()
|
|
27
|
+
.map(|s| resolve_statement(s, module, path, global_store))
|
|
28
|
+
.collect::<Vec<_>>();
|
|
29
|
+
resolved_map.insert("body".to_string(), Value::Block(resolved_body));
|
|
30
|
+
} else {
|
|
31
|
+
logger.log_message(LogLevel::Warning, "synth without a body");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
Statement {
|
|
35
|
+
kind: StatementKind::Synth,
|
|
36
|
+
value: Value::Map(resolved_map),
|
|
37
|
+
..stmt.clone()
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
fn type_error(logger: &Logger, module: &Module, stmt: &Statement, message: String) -> Statement {
|
|
42
|
+
let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
|
|
43
|
+
logger.log_error_with_stacktrace(&message, &stacktrace);
|
|
44
|
+
|
|
45
|
+
Statement {
|
|
46
|
+
kind: StatementKind::Error { message },
|
|
47
|
+
value: Value::Null,
|
|
48
|
+
..stmt.clone()
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -6,7 +6,6 @@ use crate::{
|
|
|
6
6
|
preprocessor::module::Module,
|
|
7
7
|
shared::{ duration::Duration, value::Value },
|
|
8
8
|
store::global::GlobalStore,
|
|
9
|
-
utils::validation::is_valid_entity,
|
|
10
9
|
},
|
|
11
10
|
utils::logger::Logger,
|
|
12
11
|
};
|
|
@@ -24,30 +23,17 @@ pub fn resolve_trigger(
|
|
|
24
23
|
let mut final_duration = duration.clone();
|
|
25
24
|
let mut final_value = stmt.value.clone();
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
let message = format!("Invalid entity '{}', expected a valid identifier", entity);
|
|
29
|
-
let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
|
|
30
|
-
logger.log_error_with_stacktrace(&message, &stacktrace);
|
|
31
|
-
|
|
32
|
-
return Statement {
|
|
33
|
-
kind: stmt.kind.clone(),
|
|
34
|
-
value: Value::Null,
|
|
35
|
-
line: stmt.line,
|
|
36
|
-
column: stmt.column,
|
|
37
|
-
indent: stmt.indent,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
26
|
+
// Duration resolution
|
|
41
27
|
if let Duration::Identifier(ident) = duration {
|
|
42
|
-
if let Some(val) =
|
|
28
|
+
if let Some(val) = resolve_identifier(ident, module, global_store) {
|
|
43
29
|
match val {
|
|
44
|
-
Value::Number(
|
|
45
|
-
final_duration = Duration::Number(
|
|
30
|
+
Value::Number(n) => {
|
|
31
|
+
final_duration = Duration::Number(n);
|
|
46
32
|
}
|
|
47
33
|
Value::String(s) => {
|
|
48
|
-
final_duration = Duration::Identifier(s
|
|
34
|
+
final_duration = Duration::Identifier(s);
|
|
49
35
|
}
|
|
50
|
-
Value::Identifier(
|
|
36
|
+
Value::Identifier(s) if s == "auto" => {
|
|
51
37
|
final_duration = Duration::Auto;
|
|
52
38
|
}
|
|
53
39
|
_ => {}
|
|
@@ -55,50 +41,34 @@ pub fn resolve_trigger(
|
|
|
55
41
|
}
|
|
56
42
|
}
|
|
57
43
|
|
|
44
|
+
// Params value resolution
|
|
58
45
|
final_value = match &stmt.value {
|
|
59
46
|
Value::Identifier(ident) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
logger.log_error_with_stacktrace(&message, &stacktrace);
|
|
68
|
-
Value::Null
|
|
69
|
-
}
|
|
70
|
-
}
|
|
47
|
+
resolve_identifier(ident, module, global_store).unwrap_or_else(|| {
|
|
48
|
+
logger.log_error_with_stacktrace(
|
|
49
|
+
&format!("'{path}': value identifier '{ident}' not found"),
|
|
50
|
+
&format!("{}:{}:{}", module.path, stmt.line, stmt.column)
|
|
51
|
+
);
|
|
52
|
+
Value::Null
|
|
53
|
+
})
|
|
71
54
|
}
|
|
72
55
|
Value::Map(map) => {
|
|
73
56
|
let mut resolved_map = HashMap::new();
|
|
74
|
-
for (k, v) in map
|
|
75
|
-
let
|
|
57
|
+
for (k, v) in map {
|
|
58
|
+
let resolved = match v {
|
|
76
59
|
Value::Identifier(id) => {
|
|
77
|
-
|
|
60
|
+
resolve_identifier(id, module, global_store).unwrap_or(Value::Null)
|
|
78
61
|
}
|
|
79
62
|
other => other.clone(),
|
|
80
63
|
};
|
|
81
|
-
resolved_map.insert(k.clone(),
|
|
64
|
+
resolved_map.insert(k.clone(), resolved);
|
|
82
65
|
}
|
|
83
66
|
Value::Map(resolved_map)
|
|
84
67
|
}
|
|
85
68
|
other => other.clone(),
|
|
86
69
|
};
|
|
87
70
|
|
|
88
|
-
|
|
89
|
-
return Statement {
|
|
90
|
-
kind: StatementKind::Trigger {
|
|
91
|
-
entity: entity.to_string(),
|
|
92
|
-
duration: final_duration,
|
|
93
|
-
},
|
|
94
|
-
value: final_value,
|
|
95
|
-
line: stmt.line,
|
|
96
|
-
column: stmt.column,
|
|
97
|
-
indent: stmt.indent,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return Statement {
|
|
71
|
+
Statement {
|
|
102
72
|
kind: StatementKind::Trigger {
|
|
103
73
|
entity: entity.to_string(),
|
|
104
74
|
duration: final_duration,
|
|
@@ -107,5 +77,36 @@ pub fn resolve_trigger(
|
|
|
107
77
|
line: stmt.line,
|
|
108
78
|
column: stmt.column,
|
|
109
79
|
indent: stmt.indent,
|
|
110
|
-
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
fn resolve_identifier(ident: &str, module: &Module, global_store: &GlobalStore) -> Option<Value> {
|
|
84
|
+
if let Some(val) = module.variable_table.get(ident) {
|
|
85
|
+
return Some(resolve_value(val, module, global_store));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
for (_, other_mod) in &global_store.modules {
|
|
89
|
+
if let Some(val) = other_mod.export_table.get_export(ident) {
|
|
90
|
+
return Some(resolve_value(val, other_mod, global_store));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
None
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
fn resolve_value(val: &Value, module: &Module, global_store: &GlobalStore) -> Value {
|
|
98
|
+
match val {
|
|
99
|
+
Value::Identifier(inner) =>
|
|
100
|
+
resolve_identifier(inner, module, global_store).unwrap_or(
|
|
101
|
+
Value::Identifier(inner.clone())
|
|
102
|
+
),
|
|
103
|
+
Value::Map(map) => {
|
|
104
|
+
let mut resolved = HashMap::new();
|
|
105
|
+
for (k, v) in map {
|
|
106
|
+
resolved.insert(k.clone(), resolve_value(v, module, global_store));
|
|
107
|
+
}
|
|
108
|
+
Value::Map(resolved)
|
|
109
|
+
}
|
|
110
|
+
other => other.clone(),
|
|
111
|
+
}
|
|
111
112
|
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
use crate::{
|
|
4
|
+
core::{
|
|
5
|
+
parser::statement::{ Statement, StatementKind },
|
|
6
|
+
preprocessor::{ module::Module, resolver::driver::resolve_statement },
|
|
7
|
+
shared::value::Value,
|
|
8
|
+
store::{ global::GlobalStore, variable::VariableTable },
|
|
9
|
+
},
|
|
10
|
+
utils::logger::{ LogLevel, Logger },
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
fn find_export_value(name: &str, global_store: &GlobalStore) -> Option<Value> {
|
|
14
|
+
for (_path, module) in &global_store.modules {
|
|
15
|
+
if let Some(val) = module.export_table.get_export(name) {
|
|
16
|
+
return Some(val.clone());
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
None
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
pub fn resolve_value(value: &Value, module: &Module, global_store: &mut GlobalStore) -> Value {
|
|
23
|
+
match value {
|
|
24
|
+
Value::Identifier(name) => {
|
|
25
|
+
if let Some(original_val) = module.variable_table.get(name) {
|
|
26
|
+
return resolve_value(original_val, module, global_store);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if let Some(export_val) = find_export_value(name, global_store) {
|
|
30
|
+
return resolve_value(&export_val, module, global_store);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
eprintln!("⚠️ Unresolved identifier '{}'", name);
|
|
34
|
+
Value::Null
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
Value::Map(map) => {
|
|
38
|
+
if let Some(Value::Identifier(entity)) = map.get("entity") {
|
|
39
|
+
// SECTION Synth
|
|
40
|
+
if entity == "synth" {
|
|
41
|
+
if let Some(Value::Map(synth_data)) = map.get("value") {
|
|
42
|
+
let resolved_waveform = synth_data
|
|
43
|
+
.get("waveform")
|
|
44
|
+
.map(|wf| resolve_value(wf, module, global_store))
|
|
45
|
+
.unwrap_or(Value::Null);
|
|
46
|
+
|
|
47
|
+
let resolved_params = synth_data
|
|
48
|
+
.get("parameters")
|
|
49
|
+
.map(|p| resolve_value(p, module, global_store))
|
|
50
|
+
.unwrap_or(Value::Map(HashMap::new()));
|
|
51
|
+
|
|
52
|
+
let mut result = HashMap::new();
|
|
53
|
+
result.insert("waveform".to_string(), resolved_waveform);
|
|
54
|
+
result.insert("parameters".to_string(), resolved_params);
|
|
55
|
+
|
|
56
|
+
return Value::Map(result);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let mut resolved = HashMap::new();
|
|
62
|
+
for (k, v) in map {
|
|
63
|
+
resolved.insert(k.clone(), resolve_value(v, module, global_store));
|
|
64
|
+
}
|
|
65
|
+
Value::Map(resolved)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
Value::Block(stmts) => {
|
|
69
|
+
let resolved_stmts = stmts
|
|
70
|
+
.iter()
|
|
71
|
+
.map(|stmt| resolve_statement(stmt, module, &module.path, global_store))
|
|
72
|
+
.collect();
|
|
73
|
+
Value::Block(resolved_stmts)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
other => other.clone(),
|
|
77
|
+
}
|
|
78
|
+
}
|
package/rust/core/utils/path.rs
CHANGED
|
@@ -1,46 +1,31 @@
|
|
|
1
|
-
use std::path::{ Component, Path };
|
|
1
|
+
use std::path::{ Component, Path, PathBuf };
|
|
2
2
|
|
|
3
|
-
pub fn find_entry_file(
|
|
4
|
-
let path = Path::new(
|
|
3
|
+
pub fn find_entry_file(entry: &str) -> Option<String> {
|
|
4
|
+
let path = Path::new(entry);
|
|
5
5
|
|
|
6
|
-
// Check if the path is a file
|
|
7
6
|
if path.is_file() {
|
|
8
|
-
return Some(
|
|
7
|
+
return Some(normalize_path(entry));
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
// Check if the path is a directory
|
|
12
10
|
if path.is_dir() {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return Some(index_path.to_string_lossy().to_string());
|
|
11
|
+
let candidate = path.join("index.deva");
|
|
12
|
+
if candidate.exists() {
|
|
13
|
+
return Some(normalize_path(&candidate));
|
|
17
14
|
}
|
|
18
15
|
}
|
|
19
16
|
|
|
20
17
|
None
|
|
21
18
|
}
|
|
22
19
|
|
|
23
|
-
pub fn normalize_path(path:
|
|
24
|
-
let
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
for comp in Path::new(path).components() {
|
|
28
|
-
match comp {
|
|
29
|
-
Component::CurDir => {
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
Component::Normal(c) => components.push(c),
|
|
33
|
-
Component::RootDir => components.clear(),
|
|
34
|
-
_ => {}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Join the components into a normalized path
|
|
39
|
-
let normalized = components
|
|
40
|
-
.iter()
|
|
41
|
-
.map(|c| c.to_string_lossy())
|
|
42
|
-
.collect::<Vec<_>>()
|
|
43
|
-
.join("/");
|
|
20
|
+
pub fn normalize_path<P: AsRef<Path>>(path: P) -> String {
|
|
21
|
+
let path_buf = PathBuf::from(path.as_ref());
|
|
22
|
+
path_buf.components().collect::<PathBuf>().to_string_lossy().replace('\\', "/")
|
|
23
|
+
}
|
|
44
24
|
|
|
45
|
-
|
|
25
|
+
pub fn resolve_relative_path(base: &str, import: &str) -> String {
|
|
26
|
+
let base_path = Path::new(base)
|
|
27
|
+
.parent()
|
|
28
|
+
.unwrap_or_else(|| Path::new(""));
|
|
29
|
+
let full_path = base_path.join(import);
|
|
30
|
+
full_path.components().collect::<PathBuf>().to_string_lossy().replace("\\", "/")
|
|
46
31
|
}
|
|
@@ -1,35 +1,37 @@
|
|
|
1
1
|
use crate::core::{ preprocessor::module::Module, shared::value::Value, store::global::GlobalStore };
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
let built_ins = ["kick", "snare", "hat", "clap"];
|
|
3
|
+
// NOTE: Deprecated functions, kept for reference
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
5
|
+
// pub fn is_valid_entity(entity: &str, module: &Module, global_store: &GlobalStore) -> bool {
|
|
6
|
+
// let built_ins = ["kick", "snare", "hat", "clap"];
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
_ => false,
|
|
14
|
-
}
|
|
15
|
-
} else {
|
|
16
|
-
false
|
|
17
|
-
}
|
|
18
|
-
}
|
|
8
|
+
// if built_ins.contains(&entity) {
|
|
9
|
+
// return true;
|
|
10
|
+
// }
|
|
19
11
|
|
|
20
|
-
|
|
21
|
-
|
|
12
|
+
// if let Some(val) = module.variable_table.get(entity) {
|
|
13
|
+
// match val {
|
|
14
|
+
// Value::Sample(_) => true,
|
|
15
|
+
// _ => false,
|
|
16
|
+
// }
|
|
17
|
+
// } else {
|
|
18
|
+
// false
|
|
19
|
+
// }
|
|
20
|
+
// }
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
22
|
+
// pub fn is_valid_identifier(ident: &str, module: &Module) -> bool {
|
|
23
|
+
// let built_ins = ["auto"];
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
25
|
+
// if built_ins.contains(&ident) {
|
|
26
|
+
// return true;
|
|
27
|
+
// }
|
|
28
|
+
|
|
29
|
+
// if let Some(val) = module.variable_table.get(ident) {
|
|
30
|
+
// match val {
|
|
31
|
+
// Value::Identifier(_) => true,
|
|
32
|
+
// _ => false,
|
|
33
|
+
// }
|
|
34
|
+
// } else {
|
|
35
|
+
// false
|
|
36
|
+
// }
|
|
37
|
+
// }
|
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
2
|
import { execSync } from "child_process";
|
|
4
3
|
|
|
5
4
|
export const fetchVersion = async (projectVersionPath: string) => {
|
|
6
|
-
// Lire le fichier
|
|
7
5
|
const data = JSON.parse(fs.readFileSync(projectVersionPath, "utf-8"));
|
|
8
6
|
|
|
9
|
-
// Incrémenter le numéro de build
|
|
10
7
|
data.build = (data.build || 0) + 1;
|
|
11
8
|
|
|
12
|
-
// Récupérer le dernier hash git
|
|
13
9
|
try {
|
|
14
10
|
const commit = execSync("git rev-parse HEAD").toString().trim();
|
|
15
11
|
data.lastCommit = commit;
|
|
16
12
|
} catch (err) {
|
|
17
|
-
console.warn("⚠️
|
|
13
|
+
console.warn("⚠️ Unable to fetch git commit hash. Ensure you are in a git repository.");
|
|
18
14
|
}
|
|
19
15
|
|
|
20
|
-
// Écrire la mise à jour
|
|
21
16
|
fs.writeFileSync(projectVersionPath, JSON.stringify(data, null, 2));
|
|
22
17
|
}
|
|
23
18
|
|