@devaloop/devalang 0.0.1-alpha.12 → 0.0.1-alpha.14
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 +8 -9
- package/Cargo.toml +8 -3
- package/README.md +36 -34
- package/docs/CHANGELOG.md +65 -1
- package/docs/CONTRIBUTING.md +1 -0
- package/docs/ROADMAP.md +2 -2
- package/docs/TODO.md +6 -5
- package/examples/bank.deva +2 -4
- package/examples/function.deva +15 -0
- package/examples/index.deva +25 -14
- package/out-tsc/bin/devalang.exe +0 -0
- package/package.json +6 -6
- package/project-version.json +3 -3
- package/rust/cli/bank.rs +2 -1
- package/rust/cli/build.rs +76 -14
- package/rust/cli/check.rs +71 -8
- 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 +45 -20
- package/rust/common/api.rs +8 -0
- package/rust/common/cdn.rs +2 -5
- package/rust/common/mod.rs +3 -1
- package/rust/common/sso.rs +8 -0
- package/rust/config/driver.rs +19 -1
- package/rust/config/loader.rs +56 -10
- package/rust/core/audio/engine.rs +254 -91
- package/rust/core/audio/interpreter/arrow_call.rs +34 -15
- package/rust/core/audio/interpreter/call.rs +72 -47
- package/rust/core/audio/interpreter/condition.rs +14 -12
- package/rust/core/audio/interpreter/driver.rs +90 -128
- package/rust/core/audio/interpreter/function.rs +21 -0
- package/rust/core/audio/interpreter/load.rs +1 -1
- package/rust/core/audio/interpreter/loop_.rs +24 -18
- package/rust/core/audio/interpreter/mod.rs +2 -1
- package/rust/core/audio/interpreter/sleep.rs +0 -6
- package/rust/core/audio/interpreter/spawn.rs +78 -60
- package/rust/core/audio/interpreter/trigger.rs +157 -70
- package/rust/core/audio/loader/trigger.rs +37 -4
- package/rust/core/audio/player.rs +20 -10
- package/rust/core/audio/renderer.rs +24 -25
- package/rust/core/builder/mod.rs +11 -6
- package/rust/core/debugger/mod.rs +2 -0
- package/rust/core/debugger/module.rs +47 -0
- package/rust/core/debugger/store.rs +25 -11
- package/rust/core/error/mod.rs +6 -0
- package/rust/core/lexer/handler/driver.rs +23 -1
- package/rust/core/lexer/handler/identifier.rs +1 -0
- package/rust/core/lexer/handler/indent.rs +16 -2
- package/rust/core/lexer/handler/mod.rs +1 -0
- package/rust/core/lexer/handler/parenthesis.rs +41 -0
- package/rust/core/lexer/token.rs +4 -0
- package/rust/core/mod.rs +2 -1
- package/rust/core/parser/driver.rs +47 -4
- package/rust/core/parser/handler/arrow_call.rs +78 -18
- package/rust/core/parser/handler/bank.rs +35 -7
- package/rust/core/parser/handler/dot.rs +81 -123
- package/rust/core/parser/handler/identifier/call.rs +69 -22
- package/rust/core/parser/handler/identifier/function.rs +92 -0
- package/rust/core/parser/handler/identifier/let_.rs +13 -19
- package/rust/core/parser/handler/identifier/mod.rs +1 -0
- package/rust/core/parser/handler/identifier/spawn.rs +74 -27
- package/rust/core/parser/statement.rs +16 -4
- package/rust/core/plugin/loader.rs +48 -0
- package/rust/core/plugin/mod.rs +1 -0
- package/rust/core/preprocessor/loader.rs +50 -32
- package/rust/core/preprocessor/module.rs +3 -1
- package/rust/core/preprocessor/processor.rs +26 -1
- package/rust/core/preprocessor/resolver/call.rs +61 -84
- package/rust/core/preprocessor/resolver/condition.rs +11 -6
- package/rust/core/preprocessor/resolver/driver.rs +52 -6
- package/rust/core/preprocessor/resolver/function.rs +78 -0
- package/rust/core/preprocessor/resolver/group.rs +43 -13
- package/rust/core/preprocessor/resolver/let_.rs +7 -10
- package/rust/core/preprocessor/resolver/mod.rs +2 -1
- package/rust/core/preprocessor/resolver/spawn.rs +64 -30
- package/rust/core/preprocessor/resolver/trigger.rs +7 -3
- package/rust/core/preprocessor/resolver/value.rs +10 -1
- package/rust/core/shared/value.rs +4 -1
- package/rust/core/store/function.rs +34 -0
- package/rust/core/store/global.rs +9 -10
- package/rust/core/store/mod.rs +2 -1
- package/rust/core/store/variable.rs +6 -0
- package/rust/installer/addon.rs +80 -0
- package/rust/installer/bank.rs +24 -14
- package/rust/installer/mod.rs +4 -1
- package/rust/installer/plugin.rs +55 -0
- package/rust/lib.rs +10 -7
- package/rust/main.rs +32 -9
- package/rust/utils/logger.rs +16 -0
- package/rust/utils/mod.rs +45 -1
- package/rust/utils/spinner.rs +2 -4
package/rust/cli/check.rs
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
use crate::{
|
|
2
2
|
config::driver::Config,
|
|
3
3
|
core::{
|
|
4
|
+
debugger::{
|
|
5
|
+
lexer::write_lexer_log_file,
|
|
6
|
+
module::{ write_module_function_log_file, write_module_variable_log_file },
|
|
7
|
+
preprocessor::write_preprocessor_log_file,
|
|
8
|
+
store::{ write_function_log_file, write_variables_log_file },
|
|
9
|
+
},
|
|
4
10
|
preprocessor::loader::ModuleLoader,
|
|
5
11
|
store::global::GlobalStore,
|
|
6
12
|
utils::path::{ find_entry_file, normalize_path },
|
|
7
13
|
},
|
|
8
|
-
utils::{
|
|
14
|
+
utils::{
|
|
15
|
+
collect_errors_recursively,
|
|
16
|
+
logger::{ LogLevel, Logger },
|
|
17
|
+
spinner::with_spinner,
|
|
18
|
+
watcher::watch_directory,
|
|
19
|
+
},
|
|
9
20
|
};
|
|
10
21
|
use std::{ thread, time::Duration };
|
|
11
22
|
|
|
@@ -14,7 +25,8 @@ pub fn handle_check_command(
|
|
|
14
25
|
config: Option<Config>,
|
|
15
26
|
entry: Option<String>,
|
|
16
27
|
output: Option<String>,
|
|
17
|
-
watch: bool
|
|
28
|
+
watch: bool,
|
|
29
|
+
debug: bool
|
|
18
30
|
) {
|
|
19
31
|
let fetched_entry = if entry.is_none() {
|
|
20
32
|
config
|
|
@@ -70,7 +82,7 @@ pub fn handle_check_command(
|
|
|
70
82
|
|
|
71
83
|
// SECTION Begin check
|
|
72
84
|
if fetched_watch {
|
|
73
|
-
begin_check(entry_file.clone(), fetched_output.clone());
|
|
85
|
+
begin_check(entry_file.clone(), fetched_output.clone(), debug);
|
|
74
86
|
|
|
75
87
|
logger.log_message(
|
|
76
88
|
LogLevel::Watcher,
|
|
@@ -80,14 +92,14 @@ pub fn handle_check_command(
|
|
|
80
92
|
watch_directory(entry_file.clone(), move || {
|
|
81
93
|
logger.log_message(LogLevel::Watcher, "Detected changes, re-checking...");
|
|
82
94
|
|
|
83
|
-
begin_check(entry_file.clone(), fetched_output.clone());
|
|
95
|
+
begin_check(entry_file.clone(), fetched_output.clone(), debug);
|
|
84
96
|
}).unwrap();
|
|
85
97
|
} else {
|
|
86
|
-
begin_check(entry_file.clone(), fetched_output.clone());
|
|
98
|
+
begin_check(entry_file.clone(), fetched_output.clone(), debug);
|
|
87
99
|
}
|
|
88
100
|
}
|
|
89
101
|
|
|
90
|
-
fn begin_check(entry: String, output: String) {
|
|
102
|
+
fn begin_check(entry: String, output: String, debug: bool) {
|
|
91
103
|
let spinner = with_spinner("Checking...", || {
|
|
92
104
|
thread::sleep(Duration::from_millis(800));
|
|
93
105
|
});
|
|
@@ -104,7 +116,58 @@ fn begin_check(entry: String, output: String) {
|
|
|
104
116
|
// NOTE: We don't use modules in the check command, but we still need to load them
|
|
105
117
|
let modules = module_loader.load_all_modules(&mut global_store);
|
|
106
118
|
|
|
107
|
-
//
|
|
119
|
+
// Debugging: Log loaded modules and errors
|
|
120
|
+
let logger = Logger::new();
|
|
121
|
+
logger.log_message(LogLevel::Info, "Loaded modules:");
|
|
122
|
+
for (module_name, _) in &modules.0 {
|
|
123
|
+
logger.log_message(LogLevel::Info, &format!("- {}", module_name));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if debug {
|
|
127
|
+
for (module_path, module) in global_store.modules.clone() {
|
|
128
|
+
write_module_variable_log_file(
|
|
129
|
+
&normalized_output_dir,
|
|
130
|
+
&module_path,
|
|
131
|
+
&module.variable_table
|
|
132
|
+
);
|
|
133
|
+
write_module_function_log_file(
|
|
134
|
+
&normalized_output_dir,
|
|
135
|
+
&module_path,
|
|
136
|
+
&module.function_table
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
write_lexer_log_file(&normalized_output_dir, "lexer_tokens.log", modules.0.clone());
|
|
141
|
+
write_preprocessor_log_file(
|
|
142
|
+
&normalized_output_dir,
|
|
143
|
+
"resolved_statements.log",
|
|
144
|
+
modules.1.clone()
|
|
145
|
+
);
|
|
146
|
+
write_variables_log_file(
|
|
147
|
+
&normalized_output_dir,
|
|
148
|
+
"global_variables.log",
|
|
149
|
+
global_store.variables.clone()
|
|
150
|
+
);
|
|
151
|
+
write_function_log_file(
|
|
152
|
+
&normalized_output_dir,
|
|
153
|
+
"global_functions.log",
|
|
154
|
+
global_store.functions.clone()
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
let mut all_errors = Vec::new();
|
|
159
|
+
for (_, statements) in &modules.1 {
|
|
160
|
+
all_errors.extend(collect_errors_recursively(statements));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if !all_errors.is_empty() {
|
|
164
|
+
logger.log_message(LogLevel::Error, "Errors detected during check:");
|
|
165
|
+
for error in all_errors {
|
|
166
|
+
logger.log_message(LogLevel::Error, &format!("- {}", error.message));
|
|
167
|
+
}
|
|
168
|
+
} else {
|
|
169
|
+
logger.log_message(LogLevel::Success, "No errors detected.");
|
|
170
|
+
}
|
|
108
171
|
|
|
109
172
|
let success_message = format!(
|
|
110
173
|
"Check completed successfully in {:.2?}. Output files written to: '{}'",
|
|
@@ -112,6 +175,6 @@ fn begin_check(entry: String, output: String) {
|
|
|
112
175
|
normalized_output_dir
|
|
113
176
|
);
|
|
114
177
|
|
|
115
|
-
|
|
178
|
+
spinner.finish_and_clear();
|
|
116
179
|
logger.log_message(LogLevel::Success, &success_message);
|
|
117
180
|
}
|
package/rust/cli/driver.rs
CHANGED
|
@@ -21,6 +21,14 @@ pub enum InstallCommand {
|
|
|
21
21
|
Bank {
|
|
22
22
|
name: String,
|
|
23
23
|
},
|
|
24
|
+
/// Installs a plugin.
|
|
25
|
+
Plugin {
|
|
26
|
+
name: String,
|
|
27
|
+
},
|
|
28
|
+
/// Installs a preset.
|
|
29
|
+
Preset {
|
|
30
|
+
name: String,
|
|
31
|
+
},
|
|
24
32
|
}
|
|
25
33
|
|
|
26
34
|
#[derive(Subcommand)]
|
|
@@ -103,10 +111,12 @@ pub enum Commands {
|
|
|
103
111
|
/// - `entry` - The entry point of the program to build. Defaults to "./src".
|
|
104
112
|
/// - `output` - The directory where the output files will be generated. Defaults to "./output".
|
|
105
113
|
/// - `watch` - Whether to watch for changes and rebuild. Defaults to "true".
|
|
114
|
+
/// - `debug` - Whether to print debug information. Defaults to "false".
|
|
115
|
+
/// - `compress` - Whether to compress the output files. Defaults to "false".
|
|
106
116
|
///
|
|
107
117
|
/// ### Example
|
|
108
118
|
/// ```bash
|
|
109
|
-
/// devalang build --entry ./src --output ./output --watch true
|
|
119
|
+
/// devalang build --entry ./src --output ./output --watch true --debug false --compress false
|
|
110
120
|
/// ```
|
|
111
121
|
///
|
|
112
122
|
Build {
|
|
@@ -128,19 +138,6 @@ pub enum Commands {
|
|
|
128
138
|
///
|
|
129
139
|
watch: bool,
|
|
130
140
|
|
|
131
|
-
#[arg(long, default_value = "real-time")]
|
|
132
|
-
/// The mode of compilation.
|
|
133
|
-
///
|
|
134
|
-
/// ### Default value
|
|
135
|
-
/// - `real-time`
|
|
136
|
-
///
|
|
137
|
-
/// ### Possible values
|
|
138
|
-
/// - `real-time` - Compiles files as soon as possible.
|
|
139
|
-
/// - `batch` - Compiles files one by one.
|
|
140
|
-
/// - `check` - Analyzes the code without compiling it.
|
|
141
|
-
///
|
|
142
|
-
compilation_mode: String,
|
|
143
|
-
|
|
144
141
|
#[arg(short, long, default_value_t = false)]
|
|
145
142
|
/// Whether to print debug information.
|
|
146
143
|
///
|
|
@@ -164,9 +161,13 @@ pub enum Commands {
|
|
|
164
161
|
/// - `entry` - The entry point of the program to analyze. Defaults to "./src".
|
|
165
162
|
/// - `output` - The directory where the output files will be generated. Defaults to "./output".
|
|
166
163
|
/// - `watch` - Whether to watch for changes and re-analyze. Defaults to "true".
|
|
167
|
-
/// - `compilation_mode` - The mode of compilation. Defaults to "real-time".
|
|
168
164
|
/// - `debug` - Whether to print debug information. Defaults to "false".
|
|
169
165
|
///
|
|
166
|
+
/// ### Example
|
|
167
|
+
/// ```bash
|
|
168
|
+
/// devalang check --entry ./src --output ./output --watch true --debug false
|
|
169
|
+
/// ```
|
|
170
|
+
///
|
|
170
171
|
Check {
|
|
171
172
|
#[arg(short, long)]
|
|
172
173
|
/// The entry point of the program to analyze.
|
|
@@ -184,19 +185,6 @@ pub enum Commands {
|
|
|
184
185
|
///
|
|
185
186
|
watch: bool,
|
|
186
187
|
|
|
187
|
-
#[arg(short, long, default_value = "real-time")]
|
|
188
|
-
/// The mode of compilation.
|
|
189
|
-
///
|
|
190
|
-
/// ### Default value
|
|
191
|
-
/// - `real-time`
|
|
192
|
-
///
|
|
193
|
-
/// ### Possible values
|
|
194
|
-
/// - `real-time` - Analyzes files as soon as possible.
|
|
195
|
-
/// - `batch` - Analyzes files one by one.
|
|
196
|
-
/// - `check` - Analyzes the code without compiling it.
|
|
197
|
-
///
|
|
198
|
-
compilation_mode: String,
|
|
199
|
-
|
|
200
188
|
#[arg(short, long, default_value_t = false)]
|
|
201
189
|
/// Whether to print debug information.
|
|
202
190
|
///
|
|
@@ -213,6 +201,14 @@ pub enum Commands {
|
|
|
213
201
|
/// - `output` - The directory where the output files will be generated. Defaults to "./output".
|
|
214
202
|
/// - `watch` - Whether to watch for changes and re-play. Defaults to "false".
|
|
215
203
|
/// - `repeat` - Whether to replay the program after it finishes. Defaults to "false".
|
|
204
|
+
/// - `debug` - Whether to print debug information. Defaults to "false".
|
|
205
|
+
///
|
|
206
|
+
/// Note: `--repeat` and `--watch` cannot be used together. Instead use `repeat` to watch for changes and replay the program.
|
|
207
|
+
///
|
|
208
|
+
/// ### Example
|
|
209
|
+
/// ```bash
|
|
210
|
+
/// devalang play --entry ./src --output ./output --repeat true --debug false
|
|
211
|
+
/// ```
|
|
216
212
|
///
|
|
217
213
|
Play {
|
|
218
214
|
#[arg(short, long)]
|
|
@@ -238,6 +234,14 @@ pub enum Commands {
|
|
|
238
234
|
/// - `false`
|
|
239
235
|
///
|
|
240
236
|
repeat: bool,
|
|
237
|
+
|
|
238
|
+
#[arg(short, long, default_value_t = false)]
|
|
239
|
+
/// Whether to print debug information.
|
|
240
|
+
///
|
|
241
|
+
/// ### Default value
|
|
242
|
+
/// - `false`
|
|
243
|
+
///
|
|
244
|
+
debug: bool,
|
|
241
245
|
},
|
|
242
246
|
|
|
243
247
|
/// Update the Devalang CLI to the latest version.
|
|
@@ -277,4 +281,12 @@ pub enum Commands {
|
|
|
277
281
|
#[command(subcommand)]
|
|
278
282
|
command: BankCommand,
|
|
279
283
|
},
|
|
284
|
+
|
|
285
|
+
/// Log in to your Devaloop account.
|
|
286
|
+
///
|
|
287
|
+
Login {},
|
|
288
|
+
|
|
289
|
+
/// Log out of your Devaloop account.
|
|
290
|
+
///
|
|
291
|
+
Logout {},
|
|
280
292
|
}
|
package/rust/cli/install.rs
CHANGED
|
@@ -1,16 +1,31 @@
|
|
|
1
|
-
use crate::installer::
|
|
1
|
+
use crate::installer::addon::{ install_addon, AddonType };
|
|
2
2
|
|
|
3
|
+
/// Handles the installation command for a given addon type and name.
|
|
3
4
|
#[cfg(feature = "cli")]
|
|
4
|
-
pub async fn
|
|
5
|
+
pub async fn handle_install_command(name: String, addon_type: AddonType) -> Result<(), String> {
|
|
6
|
+
use crate::utils::{ logger::{ LogLevel, Logger }, spinner::with_spinner };
|
|
7
|
+
use std::{ thread, time::Duration };
|
|
8
|
+
|
|
9
|
+
let logger = Logger::new();
|
|
5
10
|
let deva_dir = std::path::Path::new("./.deva/");
|
|
6
11
|
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
let spinner = with_spinner("Installing...", || {
|
|
13
|
+
thread::sleep(Duration::from_millis(800));
|
|
14
|
+
});
|
|
9
15
|
|
|
10
|
-
if let Err(e) =
|
|
11
|
-
|
|
16
|
+
if let Err(e) = install_addon(addon_type.clone(), name.as_str(), deva_dir).await {
|
|
17
|
+
spinner.finish_and_clear();
|
|
18
|
+
logger.log_message_with_trace(
|
|
19
|
+
LogLevel::Error,
|
|
20
|
+
&format!("Error installing {:?} '{}'", addon_type, name),
|
|
21
|
+
vec![&e]
|
|
22
|
+
);
|
|
12
23
|
} else {
|
|
13
|
-
|
|
24
|
+
spinner.finish_and_clear();
|
|
25
|
+
logger.log_message(
|
|
26
|
+
LogLevel::Success,
|
|
27
|
+
&format!("{:?} '{}' installed successfully!", addon_type, name)
|
|
28
|
+
);
|
|
14
29
|
}
|
|
15
30
|
|
|
16
31
|
Ok(())
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
use std::fs;
|
|
2
|
+
use tiny_http::{ Server, Response };
|
|
3
|
+
use webbrowser;
|
|
4
|
+
use serde::{ Serialize, Deserialize };
|
|
5
|
+
use dirs::home_dir;
|
|
6
|
+
use crate::common::sso::get_sso_url;
|
|
7
|
+
use std::{ thread, time::Duration };
|
|
8
|
+
use tiny_http::Header;
|
|
9
|
+
use std::str::FromStr;
|
|
10
|
+
|
|
11
|
+
#[derive(Serialize, Deserialize)]
|
|
12
|
+
struct UserConfig {
|
|
13
|
+
token: String,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/// Handle the login command
|
|
17
|
+
/// This function initiates the login process by opening the browser and waiting for the callback.
|
|
18
|
+
#[cfg(feature = "cli")]
|
|
19
|
+
pub async fn handle_login_command() -> Result<(), String> {
|
|
20
|
+
use crate::utils::spinner::with_spinner;
|
|
21
|
+
use crate::utils::logger::Logger;
|
|
22
|
+
use crate::utils::logger::LogLevel;
|
|
23
|
+
|
|
24
|
+
let logger = Logger::new();
|
|
25
|
+
|
|
26
|
+
let mut listener_port = 7878;
|
|
27
|
+
|
|
28
|
+
let test_port_already_in_use = format!("127.0.0.1:{}", listener_port);
|
|
29
|
+
while std::net::TcpListener::bind(&test_port_already_in_use).is_err() {
|
|
30
|
+
listener_port += 1;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let redirect_uri = format!("http://127.0.0.1:{}/callback", listener_port);
|
|
34
|
+
let login_url = format!(
|
|
35
|
+
"{}/?response_type=code&referer=cli&redirect_uri={}",
|
|
36
|
+
get_sso_url(),
|
|
37
|
+
redirect_uri
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
if webbrowser::open(&login_url).is_ok() {
|
|
41
|
+
logger.log_message(LogLevel::Info, "Opening browser for login...");
|
|
42
|
+
logger.log_message(
|
|
43
|
+
LogLevel::Info,
|
|
44
|
+
&format!("If the browser does not open, please visit the following URL: {}", login_url)
|
|
45
|
+
);
|
|
46
|
+
} else {
|
|
47
|
+
logger.log_message(
|
|
48
|
+
LogLevel::Info,
|
|
49
|
+
"Please open the following URL in your browser to login:"
|
|
50
|
+
);
|
|
51
|
+
logger.log_message(LogLevel::Info, &login_url);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let server = Server::http(format!("127.0.0.1:{}", listener_port)).unwrap();
|
|
55
|
+
|
|
56
|
+
let spinner = with_spinner("Waiting for authentication...", || {
|
|
57
|
+
thread::sleep(Duration::from_millis(800));
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
for request in server.incoming_requests() {
|
|
61
|
+
let query = request.url().to_string();
|
|
62
|
+
if request.url().starts_with("/callback") {
|
|
63
|
+
if query.contains("session=") || query.contains("error=") {
|
|
64
|
+
let token = query.split("session=").nth(1).unwrap_or("").to_string();
|
|
65
|
+
|
|
66
|
+
if token.len() > 0 {
|
|
67
|
+
let response_html =
|
|
68
|
+
r#"
|
|
69
|
+
<html>
|
|
70
|
+
<body>
|
|
71
|
+
<h1>Authentication Successful</h1>
|
|
72
|
+
<h2>You can now close this window.</h2>
|
|
73
|
+
</body>
|
|
74
|
+
</html>
|
|
75
|
+
"#;
|
|
76
|
+
|
|
77
|
+
let response = Response::from_string(response_html)
|
|
78
|
+
.with_status_code(200)
|
|
79
|
+
.with_header(Header::from_str("Content-Type: text/html").unwrap());
|
|
80
|
+
|
|
81
|
+
request.respond(response).unwrap();
|
|
82
|
+
|
|
83
|
+
save_token(&token);
|
|
84
|
+
|
|
85
|
+
spinner.finish_and_clear();
|
|
86
|
+
|
|
87
|
+
logger.log_message(
|
|
88
|
+
LogLevel::Success,
|
|
89
|
+
"Authentication successful. Token saved to ~/.devalang/session_token.json"
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
break;
|
|
93
|
+
} else {
|
|
94
|
+
spinner.finish_and_clear();
|
|
95
|
+
logger.log_message(LogLevel::Error, "Invalid session token.");
|
|
96
|
+
request.respond(Response::from_string("Invalid session token.")).unwrap();
|
|
97
|
+
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
println!("Invalid callback: {}", request.url());
|
|
102
|
+
|
|
103
|
+
spinner.finish_and_clear();
|
|
104
|
+
logger.log_message(LogLevel::Error, "Invalid callback.");
|
|
105
|
+
request.respond(Response::from_string("Invalid callback.")).unwrap();
|
|
106
|
+
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
} else if request.url().starts_with("/favicon.ico") {
|
|
110
|
+
// Ignore favicon requests
|
|
111
|
+
} else {
|
|
112
|
+
spinner.finish_and_clear();
|
|
113
|
+
logger.log_message(LogLevel::Error, "Invalid request.");
|
|
114
|
+
request.respond(Response::from_string("Invalid request.")).unwrap();
|
|
115
|
+
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
Ok(())
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/// Save the session token to a file in the user's home directory
|
|
124
|
+
fn save_token(token: &str) {
|
|
125
|
+
let config = UserConfig { token: token.to_string() };
|
|
126
|
+
let json = serde_json::to_string(&config).unwrap();
|
|
127
|
+
|
|
128
|
+
let mut path = home_dir().unwrap();
|
|
129
|
+
path.push(".devalang");
|
|
130
|
+
fs::create_dir_all(&path).unwrap();
|
|
131
|
+
|
|
132
|
+
path.push("session_token.json");
|
|
133
|
+
fs::write(path, json).unwrap();
|
|
134
|
+
}
|
package/rust/cli/mod.rs
CHANGED
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,8 +125,8 @@ pub fn handle_play_command(
|
|
|
126
125
|
}
|
|
127
126
|
} else {
|
|
128
127
|
// Single execution
|
|
129
|
-
begin_play(&config, &entry_file, &output_path);
|
|
130
|
-
|
|
128
|
+
begin_play(&config, &entry_file, &output_path, debug);
|
|
129
|
+
|
|
131
130
|
logger.log_message(LogLevel::Info, "🎵 Playback started (once mode)...");
|
|
132
131
|
|
|
133
132
|
audio_player.play_file_once(&audio_file);
|
|
@@ -135,7 +134,7 @@ pub fn handle_play_command(
|
|
|
135
134
|
}
|
|
136
135
|
}
|
|
137
136
|
|
|
138
|
-
fn begin_play(config: &Option<Config>, entry_file: &str, output: &str) {
|
|
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/common/cdn.rs
CHANGED
|
@@ -2,10 +2,7 @@ pub fn get_cdn_url() -> String {
|
|
|
2
2
|
let cdn_url = std::env
|
|
3
3
|
::var("CDN_URL")
|
|
4
4
|
.unwrap_or_else(|_| "https://cdn.devalang.com".to_string());
|
|
5
|
+
// .unwrap_or_else(|_| "http://127.0.0.1:8888".to_string());
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
format!("{}/", cdn_url)
|
|
8
|
-
} else {
|
|
9
|
-
cdn_url
|
|
10
|
-
}
|
|
7
|
+
cdn_url
|
|
11
8
|
}
|
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
|
|