@devaloop/devalang 0.0.1-alpha.13 → 0.0.1-alpha.15
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 +2 -3
- package/Cargo.toml +58 -54
- package/README.md +59 -27
- package/docs/CHANGELOG.md +99 -2
- package/docs/CONTRIBUTING.md +1 -0
- package/docs/ROADMAP.md +3 -3
- package/docs/TODO.md +5 -4
- package/examples/automation.deva +44 -0
- package/examples/bank.deva +2 -4
- package/examples/function.deva +15 -0
- package/examples/index.deva +41 -11
- package/examples/plugin.deva +15 -0
- package/out-tsc/bin/devalang.exe +0 -0
- package/package.json +6 -6
- package/project-version.json +3 -3
- package/rust/cli/bank.rs +16 -16
- package/rust/cli/build.rs +69 -30
- package/rust/cli/check.rs +46 -6
- package/rust/cli/driver.rs +40 -28
- package/rust/cli/install.rs +22 -7
- package/rust/cli/login.rs +134 -0
- package/rust/cli/mod.rs +2 -1
- package/rust/cli/play.rs +44 -19
- package/rust/cli/update.rs +1 -1
- package/rust/common/api.rs +5 -0
- package/rust/common/cdn.rs +3 -9
- package/rust/common/mod.rs +3 -1
- package/rust/common/sso.rs +5 -0
- package/rust/config/driver.rs +19 -1
- package/rust/config/loader.rs +56 -10
- package/rust/core/audio/engine.rs +314 -63
- package/rust/core/audio/evaluator.rs +101 -0
- package/rust/core/audio/interpreter/arrow_call.rs +60 -15
- package/rust/core/audio/interpreter/automate.rs +18 -0
- package/rust/core/audio/interpreter/call.rs +4 -4
- package/rust/core/audio/interpreter/condition.rs +3 -3
- package/rust/core/audio/interpreter/driver.rs +68 -30
- package/rust/core/audio/interpreter/let_.rs +14 -7
- package/rust/core/audio/interpreter/loop_.rs +39 -6
- package/rust/core/audio/interpreter/mod.rs +2 -1
- package/rust/core/audio/interpreter/sleep.rs +2 -4
- package/rust/core/audio/interpreter/spawn.rs +4 -4
- package/rust/core/audio/loader/trigger.rs +2 -5
- package/rust/core/audio/mod.rs +2 -1
- package/rust/core/audio/renderer.rs +1 -1
- package/rust/core/audio/special/easing.rs +120 -0
- package/rust/core/audio/special/env.rs +41 -0
- package/rust/core/audio/special/math.rs +92 -0
- package/rust/core/audio/special/mod.rs +9 -0
- package/rust/core/audio/special/modulator.rs +120 -0
- package/rust/core/builder/mod.rs +11 -6
- package/rust/core/debugger/store.rs +1 -1
- package/rust/core/error/mod.rs +4 -1
- package/rust/core/lexer/handler/arrow.rs +60 -9
- package/rust/core/lexer/handler/at.rs +4 -4
- package/rust/core/lexer/handler/brace.rs +8 -8
- package/rust/core/lexer/handler/colon.rs +4 -4
- package/rust/core/lexer/handler/comment.rs +2 -2
- package/rust/core/lexer/handler/dot.rs +4 -4
- package/rust/core/lexer/handler/driver.rs +42 -13
- package/rust/core/lexer/handler/identifier.rs +5 -4
- package/rust/core/lexer/handler/indent.rs +16 -2
- package/rust/core/lexer/handler/newline.rs +1 -1
- package/rust/core/lexer/handler/number.rs +3 -3
- package/rust/core/lexer/handler/operator.rs +3 -1
- package/rust/core/lexer/handler/parenthesis.rs +8 -8
- package/rust/core/lexer/handler/slash.rs +5 -5
- package/rust/core/lexer/handler/string.rs +1 -1
- package/rust/core/lexer/mod.rs +1 -1
- package/rust/core/lexer/token.rs +4 -0
- package/rust/core/mod.rs +2 -1
- package/rust/core/parser/driver.rs +134 -11
- package/rust/core/parser/handler/arrow_call.rs +141 -65
- package/rust/core/parser/handler/at.rs +1 -1
- package/rust/core/parser/handler/bank.rs +35 -7
- package/rust/core/parser/handler/dot.rs +43 -22
- package/rust/core/parser/handler/identifier/automate.rs +194 -0
- package/rust/core/parser/handler/identifier/function.rs +2 -3
- package/rust/core/parser/handler/identifier/let_.rs +16 -0
- package/rust/core/parser/handler/identifier/mod.rs +14 -10
- package/rust/core/parser/handler/identifier/print.rs +29 -0
- package/rust/core/parser/handler/identifier/sleep.rs +1 -1
- package/rust/core/parser/handler/identifier/synth.rs +7 -9
- package/rust/core/parser/handler/loop_.rs +60 -43
- package/rust/core/parser/statement.rs +5 -0
- package/rust/core/plugin/loader.rs +48 -0
- package/rust/core/plugin/mod.rs +1 -0
- package/rust/core/preprocessor/loader.rs +7 -5
- package/rust/core/preprocessor/processor.rs +4 -4
- package/rust/core/preprocessor/resolver/bank.rs +1 -2
- package/rust/core/preprocessor/resolver/call.rs +19 -18
- package/rust/core/preprocessor/resolver/driver.rs +7 -5
- package/rust/core/preprocessor/resolver/function.rs +3 -13
- package/rust/core/preprocessor/resolver/loop_.rs +31 -1
- package/rust/core/preprocessor/resolver/spawn.rs +3 -22
- package/rust/core/preprocessor/resolver/tempo.rs +1 -1
- package/rust/core/preprocessor/resolver/trigger.rs +2 -3
- package/rust/core/preprocessor/resolver/value.rs +6 -12
- package/rust/core/shared/bank.rs +1 -1
- package/rust/core/utils/path.rs +1 -1
- package/rust/core/utils/validation.rs +0 -1
- package/rust/installer/addon.rs +80 -0
- package/rust/installer/bank.rs +25 -15
- package/rust/installer/mod.rs +4 -1
- package/rust/installer/plugin.rs +55 -0
- package/rust/main.rs +32 -10
- package/rust/utils/error.rs +51 -0
- package/rust/utils/logger.rs +20 -0
- package/rust/utils/mod.rs +1 -44
- package/rust/utils/spinner.rs +3 -5
package/rust/cli/play.rs
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
use crate::{
|
|
2
|
-
core::{
|
|
2
|
+
config::driver::Config, core::{
|
|
3
3
|
builder::Builder,
|
|
4
|
-
debugger::{ lexer::write_lexer_log_file, preprocessor::write_preprocessor_log_file },
|
|
4
|
+
debugger::{ lexer::write_lexer_log_file, module::{write_module_function_log_file, write_module_variable_log_file}, preprocessor::write_preprocessor_log_file, store::{write_function_log_file, write_variables_log_file} },
|
|
5
5
|
preprocessor::loader::ModuleLoader,
|
|
6
6
|
store::global::GlobalStore,
|
|
7
7
|
utils::path::{ find_entry_file, normalize_path },
|
|
8
|
-
},
|
|
9
|
-
config::driver::Config,
|
|
10
|
-
utils::{ logger::{ LogLevel, Logger }, spinner::with_spinner, watcher::watch_directory },
|
|
8
|
+
}, utils::{ logger::{ LogLevel, Logger }, spinner::with_spinner, watcher::watch_directory }
|
|
11
9
|
};
|
|
12
10
|
|
|
13
11
|
use std::{ path::Path, sync::mpsc::channel, thread, time::Duration };
|
|
@@ -20,7 +18,8 @@ pub fn handle_play_command(
|
|
|
20
18
|
entry: Option<String>,
|
|
21
19
|
output: Option<String>,
|
|
22
20
|
watch: bool,
|
|
23
|
-
repeat: bool
|
|
21
|
+
repeat: bool,
|
|
22
|
+
debug: bool
|
|
24
23
|
) {
|
|
25
24
|
use crate::core::audio::player::AudioPlayer;
|
|
26
25
|
|
|
@@ -76,7 +75,7 @@ pub fn handle_play_command(
|
|
|
76
75
|
});
|
|
77
76
|
|
|
78
77
|
// Main thread: build + play in a loop
|
|
79
|
-
begin_play(&config, &entry_file, &output_path);
|
|
78
|
+
begin_play(&config, &entry_file, &output_path, debug);
|
|
80
79
|
audio_player.play_file_once(&audio_file);
|
|
81
80
|
|
|
82
81
|
logger.log_message(LogLevel::Watcher, "Watching for changes... Press Ctrl+C to exit.");
|
|
@@ -84,7 +83,7 @@ pub fn handle_play_command(
|
|
|
84
83
|
while let Ok(_) = rx.recv() {
|
|
85
84
|
logger.log_message(LogLevel::Watcher, "Change detected, rebuilding...");
|
|
86
85
|
|
|
87
|
-
begin_play(&config, &entry_file, &output_path);
|
|
86
|
+
begin_play(&config, &entry_file, &output_path, debug);
|
|
88
87
|
|
|
89
88
|
logger.log_message(LogLevel::Info, "🎵 Playback started (once mode)...");
|
|
90
89
|
|
|
@@ -92,7 +91,7 @@ pub fn handle_play_command(
|
|
|
92
91
|
}
|
|
93
92
|
} else if fetched_repeat {
|
|
94
93
|
// Initial build to start from a clean slate
|
|
95
|
-
begin_play(&config, &entry_file, &output_path);
|
|
94
|
+
begin_play(&config, &entry_file, &output_path, debug);
|
|
96
95
|
|
|
97
96
|
logger.log_message(LogLevel::Info, "🎵 Playback started (repeat mode)...");
|
|
98
97
|
|
|
@@ -112,7 +111,7 @@ pub fn handle_play_command(
|
|
|
112
111
|
|
|
113
112
|
// Rebuild in a separate thread
|
|
114
113
|
std::thread::spawn(move || {
|
|
115
|
-
begin_play(&config_clone, &entry_file, &output_path);
|
|
114
|
+
begin_play(&config_clone, &entry_file, &output_path, debug);
|
|
116
115
|
});
|
|
117
116
|
|
|
118
117
|
last_snapshot = current_snapshot;
|
|
@@ -126,7 +125,7 @@ pub fn handle_play_command(
|
|
|
126
125
|
}
|
|
127
126
|
} else {
|
|
128
127
|
// Single execution
|
|
129
|
-
begin_play(&config, &entry_file, &output_path);
|
|
128
|
+
begin_play(&config, &entry_file, &output_path, debug);
|
|
130
129
|
|
|
131
130
|
logger.log_message(LogLevel::Info, "🎵 Playback started (once mode)...");
|
|
132
131
|
|
|
@@ -135,7 +134,7 @@ pub fn handle_play_command(
|
|
|
135
134
|
}
|
|
136
135
|
}
|
|
137
136
|
|
|
138
|
-
fn begin_play(
|
|
137
|
+
fn begin_play(_config: &Option<Config>, entry_file: &str, output: &str, debug: bool) {
|
|
139
138
|
let spinner = with_spinner("Building...", || {
|
|
140
139
|
thread::sleep(Duration::from_millis(800));
|
|
141
140
|
});
|
|
@@ -149,16 +148,41 @@ fn begin_play(config: &Option<Config>, entry_file: &str, output: &str) {
|
|
|
149
148
|
let (modules_tokens, modules_statements) = loader.load_all_modules(&mut global_store);
|
|
150
149
|
|
|
151
150
|
// SECTION Write logs
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
151
|
+
if debug {
|
|
152
|
+
for (module_path, module) in global_store.modules.clone() {
|
|
153
|
+
write_module_variable_log_file(
|
|
154
|
+
&normalized_output_dir,
|
|
155
|
+
&module_path,
|
|
156
|
+
&module.variable_table
|
|
157
|
+
);
|
|
158
|
+
write_module_function_log_file(
|
|
159
|
+
&normalized_output_dir,
|
|
160
|
+
&module_path,
|
|
161
|
+
&module.function_table
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
write_lexer_log_file(&normalized_output_dir, "lexer_tokens.log", modules_tokens.clone());
|
|
166
|
+
write_preprocessor_log_file(
|
|
167
|
+
&normalized_output_dir,
|
|
168
|
+
"resolved_statements.log",
|
|
169
|
+
modules_statements.clone()
|
|
170
|
+
);
|
|
171
|
+
write_variables_log_file(
|
|
172
|
+
&normalized_output_dir,
|
|
173
|
+
"global_variables.log",
|
|
174
|
+
global_store.variables.clone()
|
|
175
|
+
);
|
|
176
|
+
write_function_log_file(
|
|
177
|
+
&normalized_output_dir,
|
|
178
|
+
"global_functions.log",
|
|
179
|
+
global_store.functions.clone()
|
|
180
|
+
);
|
|
181
|
+
}
|
|
158
182
|
|
|
159
183
|
// SECTION Building AST and Audio
|
|
160
184
|
let builder = Builder::new();
|
|
161
|
-
builder.build_ast(&modules_statements, &output);
|
|
185
|
+
builder.build_ast(&modules_statements, &output, false);
|
|
162
186
|
builder.build_audio(&modules_statements, &output, &mut global_store);
|
|
163
187
|
|
|
164
188
|
// SECTION Logging
|
|
@@ -169,6 +193,7 @@ fn begin_play(config: &Option<Config>, entry_file: &str, output: &str) {
|
|
|
169
193
|
normalized_output_dir
|
|
170
194
|
);
|
|
171
195
|
|
|
196
|
+
spinner.finish_and_clear();
|
|
172
197
|
logger.log_message(LogLevel::Success, &success_message);
|
|
173
198
|
}
|
|
174
199
|
|
package/rust/cli/update.rs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
pub async fn handle_update_command(
|
|
1
|
+
pub async fn handle_update_command(_only: Option<String>) -> Result<(), Box<dyn std::error::Error>> {
|
|
2
2
|
println!("Updates are not yet implemented. This is a placeholder function.");
|
|
3
3
|
Ok(())
|
|
4
4
|
}
|
package/rust/common/cdn.rs
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
pub fn get_cdn_url() -> String {
|
|
2
|
-
let cdn_url =
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
if !cdn_url.ends_with('/') {
|
|
7
|
-
format!("{}/", cdn_url)
|
|
8
|
-
} else {
|
|
9
|
-
cdn_url
|
|
10
|
-
}
|
|
2
|
+
let cdn_url = "https://cdn.devalang.com";
|
|
3
|
+
// let cdn_url = "http://127.0.0.1:8888";
|
|
4
|
+
cdn_url.to_string()
|
|
11
5
|
}
|
package/rust/common/mod.rs
CHANGED
package/rust/config/driver.rs
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
1
3
|
use serde::{ Deserialize, Serialize };
|
|
2
4
|
|
|
3
5
|
#[derive(Debug, Deserialize, Clone, Serialize)]
|
|
4
6
|
pub struct Config {
|
|
5
7
|
pub defaults: ConfigDefaults,
|
|
6
8
|
pub banks: Option<Vec<BankEntry>>,
|
|
9
|
+
pub plugins: Option<Vec<PluginEntry>>,
|
|
7
10
|
}
|
|
8
11
|
|
|
9
12
|
#[derive(Debug, Deserialize, Clone, Serialize)]
|
|
@@ -14,11 +17,24 @@ pub struct ConfigDefaults {
|
|
|
14
17
|
pub repeat: Option<bool>,
|
|
15
18
|
}
|
|
16
19
|
|
|
20
|
+
#[derive(Debug, Deserialize, Clone, Serialize)]
|
|
21
|
+
pub struct BankMetadata {
|
|
22
|
+
pub bank: HashMap<String, String>,
|
|
23
|
+
pub triggers: Option<Vec<HashMap<String, String>>>,
|
|
24
|
+
}
|
|
25
|
+
|
|
17
26
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
|
18
27
|
pub struct BankEntry {
|
|
19
28
|
pub path: String,
|
|
20
29
|
pub version: Option<String>,
|
|
21
|
-
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
|
33
|
+
pub struct PluginEntry {
|
|
34
|
+
pub path: String,
|
|
35
|
+
pub version: String,
|
|
36
|
+
pub author: String,
|
|
37
|
+
pub access: String,
|
|
22
38
|
}
|
|
23
39
|
|
|
24
40
|
impl Config {
|
|
@@ -31,6 +47,7 @@ impl Config {
|
|
|
31
47
|
repeat: None,
|
|
32
48
|
},
|
|
33
49
|
banks: Some(Vec::new()),
|
|
50
|
+
plugins: Some(Vec::new()),
|
|
34
51
|
}
|
|
35
52
|
}
|
|
36
53
|
|
|
@@ -48,6 +65,7 @@ impl Config {
|
|
|
48
65
|
repeat,
|
|
49
66
|
},
|
|
50
67
|
banks: Some(Vec::new()),
|
|
68
|
+
plugins: Some(Vec::new()),
|
|
51
69
|
}
|
|
52
70
|
}
|
|
53
71
|
|
package/rust/config/loader.rs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
use std::{ fs, path::Path };
|
|
2
|
-
use
|
|
3
|
-
use crate::config::driver::{ BankEntry, Config };
|
|
2
|
+
use crate::config::driver::{ BankEntry, BankMetadata, Config };
|
|
4
3
|
|
|
5
4
|
pub fn load_config(path: Option<&Path>) -> Option<Config> {
|
|
6
5
|
let config_path = path.unwrap_or_else(|| Path::new(".devalang"));
|
|
@@ -56,6 +55,59 @@ pub fn remove_bank_from_config(config: &mut Config, dependency: &str) {
|
|
|
56
55
|
}
|
|
57
56
|
}
|
|
58
57
|
|
|
58
|
+
pub fn add_plugin_to_config(config: &mut Config, real_path: &Path, dependency: &str) {
|
|
59
|
+
if config.plugins.is_none() {
|
|
60
|
+
config.plugins = Some(Vec::new());
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let plugins = config.plugins.as_mut().unwrap();
|
|
64
|
+
|
|
65
|
+
let exists = plugins.iter().any(|p| p.path == dependency);
|
|
66
|
+
if exists {
|
|
67
|
+
println!("Plugin '{}' already in config", dependency);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let metadata_path = Path::new(real_path).join("plugin.toml");
|
|
72
|
+
|
|
73
|
+
if !metadata_path.exists() {
|
|
74
|
+
eprintln!("❌ Plugin metadata file '{}' does not exist", metadata_path.display());
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let metadata_content = std::fs
|
|
79
|
+
::read_to_string(&metadata_path)
|
|
80
|
+
.expect("Failed to read plugin metadata file");
|
|
81
|
+
|
|
82
|
+
let metadata: std::collections::HashMap<String, String> = toml
|
|
83
|
+
::from_str(&metadata_content)
|
|
84
|
+
.expect("Failed to parse plugin metadata file");
|
|
85
|
+
|
|
86
|
+
let plugin_entry = crate::config::driver::PluginEntry {
|
|
87
|
+
path: dependency.to_string(),
|
|
88
|
+
version: metadata
|
|
89
|
+
.get("version")
|
|
90
|
+
.cloned()
|
|
91
|
+
.unwrap_or_else(|| "0.0.1".to_string()),
|
|
92
|
+
author: metadata
|
|
93
|
+
.get("author")
|
|
94
|
+
.cloned()
|
|
95
|
+
.unwrap_or_else(|| "unknown".to_string()),
|
|
96
|
+
access: metadata
|
|
97
|
+
.get("access")
|
|
98
|
+
.cloned()
|
|
99
|
+
.unwrap_or_else(|| "public".to_string()),
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
plugins.push(plugin_entry);
|
|
103
|
+
|
|
104
|
+
if let Err(e) = config.write(config) {
|
|
105
|
+
eprintln!("❌ Failed to write config: {}", e);
|
|
106
|
+
} else {
|
|
107
|
+
println!("✅ Plugin '{}' added to config", dependency);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
59
111
|
pub fn add_bank_to_config(config: &mut Config, real_path: &Path, dependency: &str) {
|
|
60
112
|
if config.banks.is_none() {
|
|
61
113
|
config.banks = Some(Vec::new());
|
|
@@ -80,24 +132,18 @@ pub fn add_bank_to_config(config: &mut Config, real_path: &Path, dependency: &st
|
|
|
80
132
|
::read_to_string(&metadata_path)
|
|
81
133
|
.expect("Failed to read bank metadata file");
|
|
82
134
|
|
|
83
|
-
let metadata:
|
|
135
|
+
let metadata: BankMetadata = toml
|
|
84
136
|
::from_str(&metadata_content)
|
|
85
137
|
.expect("Failed to parse bank metadata file");
|
|
86
138
|
|
|
87
139
|
let bank_to_insert = BankEntry {
|
|
88
140
|
path: dependency.to_string(),
|
|
89
141
|
version: Some(
|
|
90
|
-
metadata
|
|
142
|
+
metadata.bank
|
|
91
143
|
.get("version")
|
|
92
144
|
.cloned()
|
|
93
145
|
.unwrap_or_else(|| "0.0.1".to_string())
|
|
94
146
|
),
|
|
95
|
-
author: Some(
|
|
96
|
-
metadata
|
|
97
|
-
.get("author")
|
|
98
|
-
.cloned()
|
|
99
|
-
.unwrap_or_else(|| "unknown".to_string())
|
|
100
|
-
),
|
|
101
147
|
};
|
|
102
148
|
|
|
103
149
|
banks.push(bank_to_insert);
|