@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
|
@@ -1,176 +1,112 @@
|
|
|
1
1
|
use std::collections::HashMap;
|
|
2
2
|
|
|
3
|
-
use crate::
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
module::Module,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
variable::VariableValue,
|
|
3
|
+
use crate::{
|
|
4
|
+
core::{
|
|
5
|
+
parser::statement::{ Statement, StatementKind },
|
|
6
|
+
preprocessor::module::Module,
|
|
7
|
+
shared::{ duration::Duration, value::Value },
|
|
8
|
+
store::global::GlobalStore,
|
|
10
9
|
},
|
|
10
|
+
utils::logger::Logger,
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
pub fn
|
|
13
|
+
pub fn resolve_trigger(
|
|
14
14
|
stmt: &Statement,
|
|
15
|
-
entity:
|
|
16
|
-
duration:
|
|
17
|
-
module: &Module
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
let
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
_ => "unknown",
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
let duration_variable_value = module.variable_table.variables.get(duration_raw_value);
|
|
36
|
-
let mut parsed_duration_value = TokenDuration::Unknown;
|
|
37
|
-
|
|
38
|
-
if duration_variable_value.is_some() {
|
|
39
|
-
parsed_duration_value = duration_variable_value
|
|
40
|
-
.as_ref()
|
|
41
|
-
.map_or(TokenDuration::Unknown, |value| {
|
|
42
|
-
match value {
|
|
43
|
-
VariableValue::Text(text) => TokenDuration::Identifier(text.clone()),
|
|
44
|
-
VariableValue::Number(num) => TokenDuration::Number(*num),
|
|
45
|
-
VariableValue::Boolean(_) => TokenDuration::Unknown,
|
|
46
|
-
_ => {
|
|
47
|
-
eprintln!("⚠️ Invalid duration type for Trigger: {:?}", value);
|
|
48
|
-
TokenDuration::Unknown
|
|
49
|
-
}
|
|
15
|
+
entity: &str,
|
|
16
|
+
duration: &mut Duration,
|
|
17
|
+
module: &Module,
|
|
18
|
+
path: &str,
|
|
19
|
+
global_store: &GlobalStore
|
|
20
|
+
) -> Statement {
|
|
21
|
+
let logger = Logger::new();
|
|
22
|
+
|
|
23
|
+
let mut final_duration = duration.clone();
|
|
24
|
+
let mut final_value = stmt.value.clone();
|
|
25
|
+
|
|
26
|
+
// Duration resolution
|
|
27
|
+
if let Duration::Identifier(ident) = duration {
|
|
28
|
+
if let Some(val) = resolve_identifier(ident, module, global_store) {
|
|
29
|
+
match val {
|
|
30
|
+
Value::Number(n) => {
|
|
31
|
+
final_duration = Duration::Number(n);
|
|
50
32
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
parsed_duration_value = TokenDuration::Number(num);
|
|
54
|
-
} else if duration_raw_value == "auto" {
|
|
55
|
-
parsed_duration_value = TokenDuration::Auto;
|
|
56
|
-
} else if duration_raw_value == "infinite" {
|
|
57
|
-
parsed_duration_value = TokenDuration::Infinite;
|
|
58
|
-
} else {
|
|
59
|
-
eprintln!("⚠️ Invalid duration format: {}", duration_raw_value);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
match &stmt.value {
|
|
63
|
-
VariableValue::Text(text) => {
|
|
64
|
-
if let Some(value) = module.variable_table.variables.get(text) {
|
|
65
|
-
let parsed_entity_value: StatementResolvedValue = match value {
|
|
66
|
-
VariableValue::Array(arr) => {
|
|
67
|
-
StatementResolvedValue::Array(
|
|
68
|
-
parse_with_resolving_with_module(arr.clone(), module)
|
|
69
|
-
)
|
|
70
|
-
}
|
|
71
|
-
VariableValue::Map(map) => {
|
|
72
|
-
let mut resolved_map = HashMap::new();
|
|
73
|
-
|
|
74
|
-
for (key, value) in map {
|
|
75
|
-
let resolved_value = match value {
|
|
76
|
-
TokenParamValue::String(text) =>
|
|
77
|
-
StatementResolvedValue::String(text.clone()),
|
|
78
|
-
TokenParamValue::Number(num) =>
|
|
79
|
-
StatementResolvedValue::Number(*num),
|
|
80
|
-
TokenParamValue::Boolean(b) => StatementResolvedValue::Boolean(*b),
|
|
81
|
-
_ => {
|
|
82
|
-
eprintln!(
|
|
83
|
-
"⚠️ Unsupported variable type for Trigger map: {:?}",
|
|
84
|
-
value
|
|
85
|
-
);
|
|
86
|
-
StatementResolvedValue::Unknown
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
resolved_map.insert(key.clone(), resolved_value);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
StatementResolvedValue::Map(resolved_map)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
| VariableValue::Text(_)
|
|
96
|
-
| VariableValue::Number(_)
|
|
97
|
-
| VariableValue::Boolean(_) => {
|
|
98
|
-
StatementResolvedValue::String(text.clone())
|
|
99
|
-
}
|
|
100
|
-
_ => {
|
|
101
|
-
eprintln!("⚠️ Unsupported variable type for Trigger entity: {:?}", value);
|
|
102
|
-
StatementResolvedValue::Unknown
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
StatementResolved {
|
|
107
|
-
kind: StatementKind::Trigger {
|
|
108
|
-
entity: entity.clone(),
|
|
109
|
-
duration: parsed_duration_value,
|
|
110
|
-
},
|
|
111
|
-
value: parsed_entity_value,
|
|
112
|
-
indent: stmt.indent,
|
|
113
|
-
line: stmt.line,
|
|
114
|
-
column: stmt.column,
|
|
33
|
+
Value::String(s) => {
|
|
34
|
+
final_duration = Duration::Identifier(s);
|
|
115
35
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
StatementResolved {
|
|
119
|
-
kind: StatementKind::Trigger {
|
|
120
|
-
entity: entity.clone(),
|
|
121
|
-
duration: parsed_duration_value,
|
|
122
|
-
},
|
|
123
|
-
value: StatementResolvedValue::Unknown,
|
|
124
|
-
indent: stmt.indent,
|
|
125
|
-
line: stmt.line,
|
|
126
|
-
column: stmt.column,
|
|
36
|
+
Value::Identifier(s) if s == "auto" => {
|
|
37
|
+
final_duration = Duration::Auto;
|
|
127
38
|
}
|
|
39
|
+
_ => {}
|
|
128
40
|
}
|
|
129
41
|
}
|
|
130
|
-
|
|
131
|
-
let mut resolved_map = HashMap::new();
|
|
132
|
-
|
|
133
|
-
// TODO Handle nested maps and arrays
|
|
42
|
+
}
|
|
134
43
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}
|
|
44
|
+
// Params value resolution
|
|
45
|
+
final_value = match &stmt.value {
|
|
46
|
+
Value::Identifier(ident) => {
|
|
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
|
+
})
|
|
145
54
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
55
|
+
Value::Map(map) => {
|
|
56
|
+
let mut resolved_map = HashMap::new();
|
|
57
|
+
for (k, v) in map {
|
|
58
|
+
let resolved = match v {
|
|
59
|
+
Value::Identifier(id) => {
|
|
60
|
+
resolve_identifier(id, module, global_store).unwrap_or(Value::Null)
|
|
61
|
+
}
|
|
62
|
+
other => other.clone(),
|
|
63
|
+
};
|
|
64
|
+
resolved_map.insert(k.clone(), resolved);
|
|
156
65
|
}
|
|
66
|
+
Value::Map(resolved_map)
|
|
157
67
|
}
|
|
68
|
+
other => other.clone(),
|
|
69
|
+
};
|
|
158
70
|
|
|
159
|
-
|
|
71
|
+
Statement {
|
|
72
|
+
kind: StatementKind::Trigger {
|
|
73
|
+
entity: entity.to_string(),
|
|
74
|
+
duration: final_duration,
|
|
75
|
+
},
|
|
76
|
+
value: final_value,
|
|
77
|
+
line: stmt.line,
|
|
78
|
+
column: stmt.column,
|
|
79
|
+
indent: stmt.indent,
|
|
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
|
+
}
|
|
160
87
|
|
|
161
|
-
|
|
162
|
-
|
|
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
|
+
}
|
|
163
96
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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));
|
|
173
107
|
}
|
|
108
|
+
Value::Map(resolved)
|
|
174
109
|
}
|
|
110
|
+
other => other.clone(),
|
|
175
111
|
}
|
|
176
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
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
use serde::{ Deserialize, Serialize };
|
|
2
|
+
|
|
3
|
+
#[derive(Debug, Deserialize)]
|
|
4
|
+
pub struct BankInfo {
|
|
5
|
+
pub name: String,
|
|
6
|
+
pub version: String,
|
|
7
|
+
pub description: String,
|
|
8
|
+
pub author: String,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
#[derive(Debug, Deserialize)]
|
|
12
|
+
pub struct BankFile {
|
|
13
|
+
pub bank: BankInfo,
|
|
14
|
+
pub triggers: Option<Vec<BankTrigger>>,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
#[derive(Debug, Deserialize)]
|
|
18
|
+
pub struct BankTrigger {
|
|
19
|
+
pub name: String,
|
|
20
|
+
pub path: String,
|
|
21
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
use serde::{ Deserialize, Serialize };
|
|
3
|
+
|
|
4
|
+
use crate::core::parser::statement::Statement;
|
|
5
|
+
|
|
6
|
+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
7
|
+
pub enum Value {
|
|
8
|
+
Boolean(bool),
|
|
9
|
+
Number(f32),
|
|
10
|
+
Identifier(String),
|
|
11
|
+
String(String),
|
|
12
|
+
Array(Vec<Value>),
|
|
13
|
+
Map(HashMap<String, Value>),
|
|
14
|
+
Block(Vec<Statement>),
|
|
15
|
+
Sample(String),
|
|
16
|
+
Beat(String),
|
|
17
|
+
Unknown,
|
|
18
|
+
Null,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
impl Value {
|
|
22
|
+
pub fn get(&self, key: &str) -> Option<&Value> {
|
|
23
|
+
if let Value::Map(map) = self {
|
|
24
|
+
map.get(key)
|
|
25
|
+
} else {
|
|
26
|
+
None
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
use crate::core::shared::value::Value;
|
|
4
|
+
|
|
5
|
+
#[derive(Debug, Default, Clone, PartialEq)]
|
|
6
|
+
pub struct ExportTable {
|
|
7
|
+
pub exports: HashMap<String, Value>,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
impl ExportTable {
|
|
11
|
+
pub fn new() -> Self {
|
|
12
|
+
ExportTable {
|
|
13
|
+
exports: HashMap::new(),
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
pub fn add_export(&mut self, name: String, value: Value) {
|
|
18
|
+
self.exports.insert(name, value);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
pub fn get_export(&self, name: &str) -> Option<&Value> {
|
|
22
|
+
self.exports.get(name)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
pub fn remove_export(&mut self, name: &str) -> Option<Value> {
|
|
26
|
+
self.exports.remove(name)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
use crate::core::preprocessor::module::Module;
|
|
3
|
+
|
|
4
|
+
#[derive(Debug, Default, Clone)]
|
|
5
|
+
pub struct GlobalStore {
|
|
6
|
+
pub modules: HashMap<String, Module>,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
impl GlobalStore {
|
|
10
|
+
pub fn new() -> Self {
|
|
11
|
+
GlobalStore {
|
|
12
|
+
modules: HashMap::new(),
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
pub fn resolve_all_imports(&mut self) {
|
|
17
|
+
for module in self.modules.values_mut() {
|
|
18
|
+
for (name, source_path) in &module.import_table.imports {
|
|
19
|
+
println!("Resolving import: {} from {:?}", name, source_path);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
pub fn insert_module(&mut self, path: String, module: Module) {
|
|
25
|
+
self.modules.insert(path, module);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
pub fn modules_mut(&mut self) -> &mut HashMap<String, Module> {
|
|
29
|
+
&mut self.modules
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
pub fn get_module(&self, path: &str) -> Option<&Module> {
|
|
33
|
+
self.modules.get(path)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
pub fn remove_module(&mut self, path: &str) -> Option<Module> {
|
|
37
|
+
self.modules.remove(path)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
use crate::core::shared::value::Value;
|
|
4
|
+
|
|
5
|
+
#[derive(Debug, Default, Clone, PartialEq)]
|
|
6
|
+
pub struct ImportTable {
|
|
7
|
+
pub imports: HashMap<String, Value>,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
impl ImportTable {
|
|
11
|
+
pub fn new() -> Self {
|
|
12
|
+
ImportTable {
|
|
13
|
+
imports: HashMap::new(),
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
pub fn add_import(&mut self, name: String, value: Value) {
|
|
18
|
+
self.imports.insert(name, value);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
pub fn get_import(&self, name: &str) -> Option<&Value> {
|
|
22
|
+
self.imports.get(name)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
pub fn remove_import(&mut self, name: &str) -> Option<Value> {
|
|
26
|
+
self.imports.remove(name)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
use crate::core::shared::value::Value;
|
|
4
|
+
|
|
5
|
+
#[derive(Debug, Default, Clone, PartialEq)]
|
|
6
|
+
pub struct VariableTable {
|
|
7
|
+
pub variables: HashMap<String, Value>,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
impl VariableTable {
|
|
11
|
+
pub fn new() -> Self {
|
|
12
|
+
VariableTable {
|
|
13
|
+
variables: HashMap::new(),
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
pub fn set(&mut self, name: String, value: Value) {
|
|
18
|
+
self.variables.insert(name, value);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
pub fn get(&self, name: &str) -> Option<&Value> {
|
|
22
|
+
self.variables.get(name)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
pub fn remove(&mut self, name: &str) -> Option<Value> {
|
|
26
|
+
self.variables.remove(name)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
use std::path::{ Component, Path, PathBuf };
|
|
2
|
+
|
|
3
|
+
pub fn find_entry_file(entry: &str) -> Option<String> {
|
|
4
|
+
let path = Path::new(entry);
|
|
5
|
+
|
|
6
|
+
if path.is_file() {
|
|
7
|
+
return Some(normalize_path(entry));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if path.is_dir() {
|
|
11
|
+
let candidate = path.join("index.deva");
|
|
12
|
+
if candidate.exists() {
|
|
13
|
+
return Some(normalize_path(&candidate));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
None
|
|
18
|
+
}
|
|
19
|
+
|
|
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
|
+
}
|
|
24
|
+
|
|
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("\\", "/")
|
|
31
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
use crate::core::{ preprocessor::module::Module, shared::value::Value, store::global::GlobalStore };
|
|
2
|
+
|
|
3
|
+
// NOTE: Deprecated functions, kept for reference
|
|
4
|
+
|
|
5
|
+
// pub fn is_valid_entity(entity: &str, module: &Module, global_store: &GlobalStore) -> bool {
|
|
6
|
+
// let built_ins = ["kick", "snare", "hat", "clap"];
|
|
7
|
+
|
|
8
|
+
// if built_ins.contains(&entity) {
|
|
9
|
+
// return true;
|
|
10
|
+
// }
|
|
11
|
+
|
|
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
|
+
// }
|
|
21
|
+
|
|
22
|
+
// pub fn is_valid_identifier(ident: &str, module: &Module) -> bool {
|
|
23
|
+
// let built_ins = ["auto"];
|
|
24
|
+
|
|
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
|
+
// }
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
use std::path::{ Path, PathBuf };
|
|
2
|
+
use crate::{
|
|
3
|
+
common::cdn::get_cdn_url,
|
|
4
|
+
config::loader::{ add_bank_to_config, load_config },
|
|
5
|
+
utils::installer::{ download_file, extract_archive },
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
pub async fn install_bank(name: &str, target_dir: &Path) -> Result<(), String> {
|
|
9
|
+
let cdn_url = get_cdn_url();
|
|
10
|
+
let url = format!("{}/bank/{}", cdn_url, name);
|
|
11
|
+
|
|
12
|
+
let bank_dir = target_dir.join("bank");
|
|
13
|
+
let archive_path = PathBuf::from(format!("./.deva/tmp/{}.devabank", name));
|
|
14
|
+
let extract_path = bank_dir.join(name);
|
|
15
|
+
|
|
16
|
+
if extract_path.exists() {
|
|
17
|
+
println!(
|
|
18
|
+
"Bank '{}' already exists at '{}'. Skipping install.",
|
|
19
|
+
name,
|
|
20
|
+
extract_path.display()
|
|
21
|
+
);
|
|
22
|
+
return Ok(());
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
download_file(&url, &archive_path).await.map_err(|e| format!("Failed to download: {}", e))?;
|
|
26
|
+
|
|
27
|
+
extract_archive(&archive_path, &extract_path).await.map_err(|e|
|
|
28
|
+
format!("Failed to extract: {}", e)
|
|
29
|
+
)?;
|
|
30
|
+
|
|
31
|
+
// Add the bank to the config
|
|
32
|
+
let root_dir = target_dir
|
|
33
|
+
.parent()
|
|
34
|
+
.ok_or_else(|| "Failed to determine root directory".to_string())?;
|
|
35
|
+
|
|
36
|
+
let config_path = root_dir.join(".devalang");
|
|
37
|
+
if !config_path.exists() {
|
|
38
|
+
return Err(
|
|
39
|
+
format!(
|
|
40
|
+
"Config file not found at '{}'. Please run 'devalang init' before adding an addon",
|
|
41
|
+
config_path.display()
|
|
42
|
+
)
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let mut config = load_config(Some(&config_path)).ok_or_else(||
|
|
47
|
+
format!("Failed to load config from '{}'", config_path.display())
|
|
48
|
+
)?;
|
|
49
|
+
|
|
50
|
+
let dependency_path = &format!("devalang://bank/{}", name);
|
|
51
|
+
|
|
52
|
+
add_bank_to_config(&mut config, &extract_path, &dependency_path);
|
|
53
|
+
|
|
54
|
+
Ok(())
|
|
55
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pub mod bank;
|