@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.
Files changed (168) hide show
  1. package/.devalang +9 -0
  2. package/Cargo.toml +15 -6
  3. package/README.md +79 -81
  4. package/docs/CHANGELOG.md +213 -0
  5. package/docs/ROADMAP.md +11 -8
  6. package/docs/TODO.md +32 -29
  7. package/examples/bank.deva +9 -0
  8. package/examples/condition.deva +20 -0
  9. package/examples/duration.deva +9 -0
  10. package/examples/group.deva +12 -0
  11. package/examples/index.deva +12 -5
  12. package/examples/loop.deva +16 -0
  13. package/examples/samples/hat-808.wav +0 -0
  14. package/examples/synth.deva +14 -0
  15. package/examples/variables.deva +9 -0
  16. package/out-tsc/bin/devalang.exe +0 -0
  17. package/out-tsc/scripts/version/fetch.js +1 -5
  18. package/package.json +5 -4
  19. package/project-version.json +3 -3
  20. package/rust/cli/bank.rs +455 -0
  21. package/rust/cli/build.rs +114 -28
  22. package/rust/cli/check.rs +96 -103
  23. package/rust/cli/driver.rs +280 -0
  24. package/rust/cli/init.rs +79 -0
  25. package/rust/cli/install.rs +17 -0
  26. package/rust/cli/mod.rs +8 -1
  27. package/rust/cli/play.rs +193 -0
  28. package/rust/cli/template.rs +57 -0
  29. package/rust/cli/update.rs +4 -0
  30. package/rust/common/cdn.rs +11 -0
  31. package/rust/common/mod.rs +1 -0
  32. package/rust/config/driver.rs +76 -0
  33. package/rust/config/loader.rs +110 -0
  34. package/rust/config/mod.rs +2 -0
  35. package/rust/core/audio/engine.rs +242 -0
  36. package/rust/core/audio/evaluator.rs +31 -0
  37. package/rust/core/audio/interpreter/arrow_call.rs +142 -0
  38. package/rust/core/audio/interpreter/call.rs +70 -0
  39. package/rust/core/audio/interpreter/condition.rs +69 -0
  40. package/rust/core/audio/interpreter/driver.rs +236 -0
  41. package/rust/core/audio/interpreter/let_.rs +19 -0
  42. package/rust/core/audio/interpreter/load.rs +18 -0
  43. package/rust/core/audio/interpreter/loop_.rs +67 -0
  44. package/rust/core/audio/interpreter/mod.rs +12 -0
  45. package/rust/core/audio/interpreter/sleep.rs +36 -0
  46. package/rust/core/audio/interpreter/spawn.rs +84 -0
  47. package/rust/core/audio/interpreter/tempo.rs +16 -0
  48. package/rust/core/audio/interpreter/trigger.rs +102 -0
  49. package/rust/core/audio/loader/mod.rs +1 -0
  50. package/rust/core/audio/loader/trigger.rs +64 -0
  51. package/rust/core/audio/mod.rs +6 -0
  52. package/rust/core/audio/player.rs +54 -0
  53. package/rust/core/audio/renderer.rs +54 -0
  54. package/rust/core/builder/mod.rs +70 -27
  55. package/rust/core/debugger/lexer.rs +27 -0
  56. package/rust/core/debugger/mod.rs +13 -49
  57. package/rust/core/debugger/preprocessor.rs +27 -0
  58. package/rust/core/debugger/store.rs +25 -0
  59. package/rust/core/error/mod.rs +60 -0
  60. package/rust/core/lexer/handler/arrow.rs +31 -0
  61. package/rust/core/lexer/handler/at.rs +21 -0
  62. package/rust/core/lexer/handler/brace.rs +41 -0
  63. package/rust/core/lexer/handler/colon.rs +21 -0
  64. package/rust/core/lexer/handler/comment.rs +30 -0
  65. package/rust/core/lexer/handler/dot.rs +21 -0
  66. package/rust/core/lexer/handler/driver.rs +241 -0
  67. package/rust/core/lexer/handler/identifier.rs +41 -0
  68. package/rust/core/lexer/handler/indent.rs +52 -0
  69. package/rust/core/lexer/handler/mod.rs +15 -0
  70. package/rust/core/lexer/handler/newline.rs +23 -0
  71. package/rust/core/lexer/handler/number.rs +31 -0
  72. package/rust/core/lexer/handler/operator.rs +44 -0
  73. package/rust/core/lexer/handler/slash.rs +21 -0
  74. package/rust/core/lexer/handler/string.rs +63 -0
  75. package/rust/core/lexer/mod.rs +37 -319
  76. package/rust/core/lexer/token.rs +87 -0
  77. package/rust/core/mod.rs +6 -2
  78. package/rust/core/parser/driver.rs +339 -0
  79. package/rust/core/parser/handler/arrow_call.rs +151 -0
  80. package/rust/core/parser/handler/at.rs +162 -0
  81. package/rust/core/parser/handler/bank.rs +41 -0
  82. package/rust/core/parser/handler/condition.rs +74 -0
  83. package/rust/core/parser/handler/dot.rs +178 -0
  84. package/rust/core/parser/handler/identifier/call.rs +41 -0
  85. package/rust/core/parser/handler/identifier/group.rs +75 -0
  86. package/rust/core/parser/handler/identifier/let_.rs +133 -0
  87. package/rust/core/parser/handler/identifier/mod.rs +51 -0
  88. package/rust/core/parser/handler/identifier/sleep.rs +33 -0
  89. package/rust/core/parser/handler/identifier/spawn.rs +41 -0
  90. package/rust/core/parser/handler/identifier/synth.rs +65 -0
  91. package/rust/core/parser/handler/loop_.rs +72 -0
  92. package/rust/core/parser/handler/mod.rs +8 -0
  93. package/rust/core/parser/handler/tempo.rs +47 -0
  94. package/rust/core/parser/mod.rs +3 -200
  95. package/rust/core/parser/statement.rs +96 -0
  96. package/rust/core/preprocessor/loader.rs +308 -0
  97. package/rust/core/preprocessor/mod.rs +2 -24
  98. package/rust/core/preprocessor/module.rs +42 -56
  99. package/rust/core/preprocessor/processor.rs +76 -0
  100. package/rust/core/preprocessor/resolver/bank.rs +41 -51
  101. package/rust/core/preprocessor/resolver/call.rs +123 -0
  102. package/rust/core/preprocessor/resolver/condition.rs +92 -0
  103. package/rust/core/preprocessor/resolver/driver.rs +232 -0
  104. package/rust/core/preprocessor/resolver/group.rs +61 -0
  105. package/rust/core/preprocessor/resolver/let_.rs +31 -0
  106. package/rust/core/preprocessor/resolver/loop_.rs +76 -67
  107. package/rust/core/preprocessor/resolver/mod.rs +12 -111
  108. package/rust/core/preprocessor/resolver/spawn.rs +58 -0
  109. package/rust/core/preprocessor/resolver/synth.rs +50 -0
  110. package/rust/core/preprocessor/resolver/tempo.rs +40 -61
  111. package/rust/core/preprocessor/resolver/trigger.rs +90 -154
  112. package/rust/core/preprocessor/resolver/value.rs +78 -0
  113. package/rust/core/shared/bank.rs +21 -0
  114. package/rust/core/shared/duration.rs +9 -0
  115. package/rust/core/shared/mod.rs +3 -0
  116. package/rust/core/shared/value.rs +29 -0
  117. package/rust/core/store/export.rs +28 -0
  118. package/rust/core/store/global.rs +39 -0
  119. package/rust/core/store/import.rs +28 -0
  120. package/rust/core/store/mod.rs +4 -0
  121. package/rust/core/store/variable.rs +28 -0
  122. package/rust/core/utils/mod.rs +2 -0
  123. package/rust/core/utils/path.rs +31 -0
  124. package/rust/core/utils/validation.rs +37 -0
  125. package/rust/installer/bank.rs +55 -0
  126. package/rust/installer/mod.rs +1 -0
  127. package/rust/lib.rs +162 -1
  128. package/rust/main.rs +104 -31
  129. package/rust/utils/file.rs +35 -0
  130. package/rust/utils/installer.rs +56 -0
  131. package/rust/utils/logger.rs +108 -34
  132. package/rust/utils/mod.rs +5 -3
  133. package/rust/utils/{loader.rs → spinner.rs} +2 -0
  134. package/rust/utils/watcher.rs +33 -0
  135. package/templates/minimal/.devalang +5 -0
  136. package/templates/minimal/README.md +202 -0
  137. package/templates/minimal/src/index.deva +2 -0
  138. package/templates/welcome/.devalang +5 -0
  139. package/templates/welcome/README.md +202 -0
  140. package/templates/welcome/samples/kick-808.wav +0 -0
  141. package/templates/welcome/src/index.deva +13 -0
  142. package/templates/welcome/src/variables.deva +5 -0
  143. package/typescript/scripts/version/fetch.ts +1 -6
  144. package/docs/COMMANDS.md +0 -31
  145. package/docs/SYNTAX.md +0 -148
  146. package/examples/exported.deva +0 -7
  147. package/rust/audio/mod.rs +0 -1
  148. package/rust/cli/new.rs +0 -1
  149. package/rust/core/parser/at.rs +0 -142
  150. package/rust/core/parser/bank.rs +0 -42
  151. package/rust/core/parser/dot.rs +0 -107
  152. package/rust/core/parser/identifer.rs +0 -91
  153. package/rust/core/parser/loop_.rs +0 -62
  154. package/rust/core/parser/tempo.rs +0 -42
  155. package/rust/core/parser/variable.rs +0 -129
  156. package/rust/core/preprocessor/dependencies.rs +0 -54
  157. package/rust/core/preprocessor/resolver/at.rs +0 -24
  158. package/rust/core/types/cli.rs +0 -160
  159. package/rust/core/types/mod.rs +0 -7
  160. package/rust/core/types/module.rs +0 -41
  161. package/rust/core/types/parser.rs +0 -73
  162. package/rust/core/types/statement.rs +0 -105
  163. package/rust/core/types/store.rs +0 -116
  164. package/rust/core/types/token.rs +0 -83
  165. package/rust/core/types/variable.rs +0 -32
  166. package/rust/runner/executer.rs +0 -44
  167. package/rust/runner/mod.rs +0 -1
  168. package/rust/utils/path.rs +0 -46
@@ -1,176 +1,112 @@
1
1
  use std::collections::HashMap;
2
2
 
3
- use crate::core::{
4
- parser::parse_with_resolving_with_module,
5
- types::{
6
- module::Module,
7
- statement::{ Statement, StatementKind, StatementResolved, StatementResolvedValue },
8
- token::{ TokenDuration, TokenParamValue },
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 resolve_trigger_statement(
13
+ pub fn resolve_trigger(
14
14
  stmt: &Statement,
15
- entity: String,
16
- duration: TokenDuration,
17
- module: &Module
18
- ) -> StatementResolved {
19
- let mut entity_value = VariableValue::Unknown;
20
-
21
- if let Some(value) = module.variable_table.variables.get(&entity) {
22
- entity_value = value.clone();
23
- } else {
24
- entity_value = VariableValue::Text(entity.clone());
25
- }
26
-
27
- let duration_raw_value = match duration {
28
- TokenDuration::Auto => "auto",
29
- TokenDuration::Infinite => "infinite",
30
- TokenDuration::Number(n) => &n.to_string(),
31
- TokenDuration::Identifier(ref id) => id.as_str(),
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
- } else if let Ok(num) = duration_raw_value.parse::<f32>() {
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
- } else {
117
- eprintln!("⚠️ Trigger variable '{}' not found", text);
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
- VariableValue::Map(map) => {
131
- let mut resolved_map = HashMap::new();
132
-
133
- // TODO Handle nested maps and arrays
42
+ }
134
43
 
135
- StatementResolved {
136
- kind: StatementKind::Trigger {
137
- entity: entity.clone(),
138
- duration: parsed_duration_value,
139
- },
140
- value: StatementResolvedValue::Map(resolved_map),
141
- indent: stmt.indent,
142
- line: stmt.line,
143
- column: stmt.column,
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
- VariableValue::Null => {
147
- StatementResolved {
148
- kind: StatementKind::Trigger {
149
- entity: entity.clone(),
150
- duration: parsed_duration_value,
151
- },
152
- value: StatementResolvedValue::Map(HashMap::new()),
153
- indent: stmt.indent,
154
- line: stmt.line,
155
- column: stmt.column,
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
- // TODO Parse other parameters
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
- eprintln!("⚠️ Invalid value type for Trigger statement: {:?}", stmt.value);
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
- StatementResolved {
165
- kind: StatementKind::Trigger {
166
- entity: entity.clone(),
167
- duration: parsed_duration_value,
168
- },
169
- value: StatementResolvedValue::Unknown,
170
- indent: stmt.indent,
171
- line: stmt.line,
172
- column: stmt.column,
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,9 @@
1
+ use serde::{ Deserialize, Serialize };
2
+
3
+ #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
4
+ pub enum Duration {
5
+ Number(f32),
6
+ Identifier(String),
7
+ Beat(String),
8
+ Auto,
9
+ }
@@ -0,0 +1,3 @@
1
+ pub mod value;
2
+ pub mod duration;
3
+ pub mod bank;
@@ -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,4 @@
1
+ pub mod global;
2
+ pub mod export;
3
+ pub mod import;
4
+ pub mod variable;
@@ -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,2 @@
1
+ pub mod path;
2
+ pub mod validation;
@@ -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;