@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
package/rust/cli/build.rs
CHANGED
|
@@ -1,51 +1,137 @@
|
|
|
1
|
-
use std::{ thread, time::Duration };
|
|
2
|
-
|
|
3
1
|
use crate::{
|
|
2
|
+
config::driver::Config,
|
|
4
3
|
core::{
|
|
5
|
-
builder::
|
|
6
|
-
debugger::
|
|
7
|
-
|
|
4
|
+
builder::Builder,
|
|
5
|
+
debugger::{
|
|
6
|
+
lexer::write_lexer_log_file,
|
|
7
|
+
preprocessor::write_preprocessor_log_file,
|
|
8
|
+
store::write_store_log_file,
|
|
9
|
+
},
|
|
10
|
+
preprocessor::loader::ModuleLoader,
|
|
11
|
+
store::global::GlobalStore,
|
|
12
|
+
utils::path::{ find_entry_file, normalize_path },
|
|
8
13
|
},
|
|
9
|
-
|
|
10
|
-
utils::{ loader::with_spinner, logger::log_message, path::{ find_entry_file, normalize_path } },
|
|
14
|
+
utils::{ logger::{ LogLevel, Logger }, spinner::with_spinner, watcher::watch_directory },
|
|
11
15
|
};
|
|
16
|
+
use std::{ thread, time::Duration };
|
|
17
|
+
|
|
18
|
+
#[cfg(feature = "cli")]
|
|
19
|
+
pub fn handle_build_command(
|
|
20
|
+
config: Option<Config>,
|
|
21
|
+
entry: Option<String>,
|
|
22
|
+
output: Option<String>,
|
|
23
|
+
watch: bool
|
|
24
|
+
) {
|
|
25
|
+
let fetched_entry = if entry.is_none() {
|
|
26
|
+
config
|
|
27
|
+
.as_ref()
|
|
28
|
+
.and_then(|c| c.defaults.entry.clone())
|
|
29
|
+
.unwrap_or_else(|| "".to_string())
|
|
30
|
+
} else {
|
|
31
|
+
entry.clone().unwrap_or_else(|| "".to_string())
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
let fetched_output = if output.is_none() {
|
|
35
|
+
config
|
|
36
|
+
.as_ref()
|
|
37
|
+
.and_then(|c| c.defaults.output.clone())
|
|
38
|
+
.unwrap_or_else(|| "".to_string())
|
|
39
|
+
} else {
|
|
40
|
+
output.clone().unwrap_or_else(|| "".to_string())
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
let fetched_watch = if watch {
|
|
44
|
+
watch
|
|
45
|
+
} else {
|
|
46
|
+
config
|
|
47
|
+
.as_ref()
|
|
48
|
+
.and_then(|c| c.defaults.watch)
|
|
49
|
+
.unwrap_or(false)
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
let logger = Logger::new();
|
|
53
|
+
|
|
54
|
+
if fetched_entry.is_empty() {
|
|
55
|
+
logger.log_message(
|
|
56
|
+
LogLevel::Error,
|
|
57
|
+
"Entry path is not specified. Please provide a valid entry path."
|
|
58
|
+
);
|
|
59
|
+
std::process::exit(1);
|
|
60
|
+
}
|
|
61
|
+
if fetched_output.is_empty() {
|
|
62
|
+
logger.log_message(
|
|
63
|
+
LogLevel::Error,
|
|
64
|
+
"Output directory is not specified. Please provide a valid output directory."
|
|
65
|
+
);
|
|
66
|
+
std::process::exit(1);
|
|
67
|
+
}
|
|
12
68
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
69
|
+
let entry_file = find_entry_file(&fetched_entry).unwrap_or_else(|| {
|
|
70
|
+
logger.log_message(
|
|
71
|
+
LogLevel::Error,
|
|
72
|
+
&format!("❌ index.deva not found in directory: {}", fetched_entry)
|
|
73
|
+
);
|
|
16
74
|
std::process::exit(1);
|
|
17
75
|
});
|
|
18
76
|
|
|
77
|
+
// SECTION Begin build
|
|
78
|
+
if fetched_watch {
|
|
79
|
+
begin_build(entry_file.clone(), fetched_output.clone());
|
|
80
|
+
|
|
81
|
+
logger.log_message(
|
|
82
|
+
LogLevel::Watcher,
|
|
83
|
+
&format!("Watching for changes in '{}'...", fetched_entry)
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
watch_directory(entry_file.clone(), move || {
|
|
87
|
+
logger.log_message(LogLevel::Watcher, "Detected changes, re-building...");
|
|
88
|
+
|
|
89
|
+
begin_build(entry_file.clone(), fetched_output.clone());
|
|
90
|
+
}).unwrap();
|
|
91
|
+
} else {
|
|
92
|
+
begin_build(entry_file.clone(), fetched_output.clone());
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
fn begin_build(entry: String, output: String) {
|
|
19
97
|
let spinner = with_spinner("Building...", || {
|
|
20
98
|
thread::sleep(Duration::from_millis(800));
|
|
21
99
|
});
|
|
22
100
|
|
|
23
101
|
let duration = std::time::Instant::now();
|
|
24
102
|
|
|
25
|
-
let normalized_entry_file = normalize_path(&
|
|
103
|
+
let normalized_entry_file = normalize_path(&entry);
|
|
26
104
|
let normalized_output_dir = normalize_path(&output);
|
|
27
105
|
|
|
28
|
-
let global_store =
|
|
106
|
+
let mut global_store = GlobalStore::new();
|
|
107
|
+
let module_loader = ModuleLoader::new(&normalized_entry_file, &normalized_output_dir);
|
|
29
108
|
|
|
30
|
-
|
|
31
|
-
|
|
109
|
+
// SECTION Load
|
|
110
|
+
// NOTE: We use modules in the build command, so we need to load them
|
|
111
|
+
let (modules_tokens, modules_statements) = module_loader.load_all_modules(&mut global_store);
|
|
32
112
|
|
|
33
|
-
|
|
113
|
+
// SECTION Write logs
|
|
114
|
+
write_lexer_log_file(&normalized_output_dir, "lexer_tokens.log", modules_tokens.clone());
|
|
115
|
+
write_preprocessor_log_file(
|
|
116
|
+
&normalized_output_dir,
|
|
117
|
+
"resolved_statements.log",
|
|
118
|
+
modules_statements.clone()
|
|
119
|
+
);
|
|
120
|
+
write_store_log_file(&normalized_output_dir, "global_store.log", global_store.modules.clone());
|
|
34
121
|
|
|
35
|
-
|
|
122
|
+
// SECTION Building AST and Audio
|
|
123
|
+
let builder = Builder::new();
|
|
124
|
+
builder.build_ast(&modules_statements, &normalized_output_dir);
|
|
125
|
+
builder.build_audio(&modules_statements, &normalized_output_dir, &mut global_store);
|
|
36
126
|
|
|
37
|
-
|
|
38
|
-
|
|
127
|
+
// SECTION Logging
|
|
128
|
+
let logger = Logger::new();
|
|
39
129
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
130
|
+
let success_message = format!(
|
|
131
|
+
"Build completed successfully in {:.2?}. Output files written to: '{}'",
|
|
132
|
+
duration.elapsed(),
|
|
133
|
+
normalized_output_dir
|
|
134
|
+
);
|
|
43
135
|
|
|
44
|
-
|
|
45
|
-
"Build completed successfully in {:.2?}. Output files written to: '{}'",
|
|
46
|
-
duration.elapsed(),
|
|
47
|
-
normalized_output_dir
|
|
48
|
-
);
|
|
49
|
-
log_message(&success_message, "SUCCESS");
|
|
50
|
-
}
|
|
136
|
+
logger.log_message(LogLevel::Success, &success_message);
|
|
51
137
|
}
|
package/rust/cli/check.rs
CHANGED
|
@@ -1,124 +1,117 @@
|
|
|
1
|
-
use std::{ thread, time::Duration };
|
|
2
|
-
|
|
3
1
|
use crate::{
|
|
2
|
+
config::driver::Config,
|
|
4
3
|
core::{
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
statement::{
|
|
9
|
-
Statement,
|
|
10
|
-
StatementIterator,
|
|
11
|
-
StatementKind,
|
|
12
|
-
StatementResolved,
|
|
13
|
-
StatementResolvedValue,
|
|
14
|
-
},
|
|
15
|
-
variable::VariableValue,
|
|
16
|
-
},
|
|
4
|
+
preprocessor::loader::ModuleLoader,
|
|
5
|
+
store::global::GlobalStore,
|
|
6
|
+
utils::path::{ find_entry_file, normalize_path },
|
|
17
7
|
},
|
|
18
|
-
|
|
19
|
-
utils::{ loader::with_spinner, logger::log_message, path::{ find_entry_file, normalize_path } },
|
|
8
|
+
utils::{ logger::{ LogLevel, Logger }, spinner::with_spinner, watcher::watch_directory },
|
|
20
9
|
};
|
|
10
|
+
use std::{ thread, time::Duration };
|
|
21
11
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
12
|
+
#[cfg(feature = "cli")]
|
|
13
|
+
pub fn handle_check_command(
|
|
14
|
+
config: Option<Config>,
|
|
15
|
+
entry: Option<String>,
|
|
16
|
+
output: Option<String>,
|
|
17
|
+
watch: bool
|
|
18
|
+
) {
|
|
19
|
+
let fetched_entry = if entry.is_none() {
|
|
20
|
+
config
|
|
21
|
+
.as_ref()
|
|
22
|
+
.and_then(|c| c.defaults.entry.clone())
|
|
23
|
+
.unwrap_or_else(|| "".to_string())
|
|
24
|
+
} else {
|
|
25
|
+
entry.clone().unwrap_or_else(|| "".to_string())
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
let fetched_output = if output.is_none() {
|
|
29
|
+
config
|
|
30
|
+
.as_ref()
|
|
31
|
+
.and_then(|c| c.defaults.output.clone())
|
|
32
|
+
.unwrap_or_else(|| "".to_string())
|
|
33
|
+
} else {
|
|
34
|
+
output.clone().unwrap_or_else(|| "".to_string())
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
let fetched_watch = if watch {
|
|
38
|
+
watch
|
|
39
|
+
} else {
|
|
40
|
+
config
|
|
41
|
+
.as_ref()
|
|
42
|
+
.and_then(|c| c.defaults.watch)
|
|
43
|
+
.unwrap_or(false)
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
let logger = Logger::new();
|
|
47
|
+
|
|
48
|
+
if fetched_entry.is_empty() {
|
|
49
|
+
logger.log_message(
|
|
50
|
+
LogLevel::Error,
|
|
51
|
+
"Entry path is not specified. Please provide a valid entry path."
|
|
52
|
+
);
|
|
25
53
|
std::process::exit(1);
|
|
26
|
-
}
|
|
54
|
+
}
|
|
55
|
+
if fetched_output.is_empty() {
|
|
56
|
+
logger.log_message(
|
|
57
|
+
LogLevel::Error,
|
|
58
|
+
"Output directory is not specified. Please provide a valid output directory."
|
|
59
|
+
);
|
|
60
|
+
std::process::exit(1);
|
|
61
|
+
}
|
|
27
62
|
|
|
28
|
-
let
|
|
29
|
-
|
|
63
|
+
let entry_file = find_entry_file(&fetched_entry).unwrap_or_else(|| {
|
|
64
|
+
logger.log_message(
|
|
65
|
+
LogLevel::Error,
|
|
66
|
+
&format!("❌ index.deva not found in directory: {}", fetched_entry)
|
|
67
|
+
);
|
|
68
|
+
std::process::exit(1);
|
|
30
69
|
});
|
|
31
70
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
let normalized_output_dir = normalize_path(&output);
|
|
36
|
-
|
|
37
|
-
let global_store = load_all_modules(&normalized_entry_file);
|
|
71
|
+
// SECTION Begin check
|
|
72
|
+
if fetched_watch {
|
|
73
|
+
begin_check(entry_file.clone(), fetched_output.clone());
|
|
38
74
|
|
|
39
|
-
|
|
40
|
-
|
|
75
|
+
logger.log_message(
|
|
76
|
+
LogLevel::Watcher,
|
|
77
|
+
&format!("Watching for changes in '{}'...", fetched_entry)
|
|
78
|
+
);
|
|
41
79
|
|
|
42
|
-
|
|
80
|
+
watch_directory(entry_file.clone(), move || {
|
|
81
|
+
logger.log_message(LogLevel::Watcher, "Detected changes, re-checking...");
|
|
43
82
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
83
|
+
begin_check(entry_file.clone(), fetched_output.clone());
|
|
84
|
+
}).unwrap();
|
|
85
|
+
} else {
|
|
86
|
+
begin_check(entry_file.clone(), fetched_output.clone());
|
|
87
|
+
}
|
|
88
|
+
}
|
|
47
89
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
90
|
+
fn begin_check(entry: String, output: String) {
|
|
91
|
+
let spinner = with_spinner("Checking...", || {
|
|
92
|
+
thread::sleep(Duration::from_millis(800));
|
|
93
|
+
});
|
|
51
94
|
|
|
52
|
-
|
|
53
|
-
let warning_message = format!(
|
|
54
|
-
"Check completed with errors in {:.2?}. Output files written to: '{}'",
|
|
55
|
-
duration.elapsed(),
|
|
56
|
-
normalized_output_dir
|
|
57
|
-
);
|
|
95
|
+
let duration = std::time::Instant::now();
|
|
58
96
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
let success_message = format!(
|
|
62
|
-
"Check completed successfully in {:.2?}. Output files written to: '{}'",
|
|
63
|
-
duration.elapsed(),
|
|
64
|
-
normalized_output_dir
|
|
65
|
-
);
|
|
97
|
+
let normalized_entry_file = normalize_path(&entry);
|
|
98
|
+
let normalized_output_dir = normalize_path(&output);
|
|
66
99
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
}
|
|
100
|
+
let mut global_store = GlobalStore::new();
|
|
101
|
+
let module_loader = ModuleLoader::new(&normalized_entry_file, &normalized_output_dir);
|
|
71
102
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
StatementResolvedValue::Map(map) => {
|
|
77
|
-
for (key, value) in map {
|
|
78
|
-
if match_error_recursively_resolved_value(&value) {
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
StatementResolvedValue::Array(array) => {
|
|
85
|
-
for item in array {
|
|
86
|
-
if match_error_recursively_resolved(&item) {
|
|
87
|
-
return true;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
_ => {
|
|
93
|
-
if let StatementKind::Error = stmt.kind {
|
|
94
|
-
eprintln!("❌ Error found in statement: {:?}", stmt);
|
|
95
|
-
return true;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
103
|
+
// SECTION Load
|
|
104
|
+
// NOTE: We don't use modules in the check command, but we still need to load them
|
|
105
|
+
let modules = module_loader.load_all_modules(&mut global_store);
|
|
99
106
|
|
|
100
|
-
|
|
101
|
-
}
|
|
107
|
+
// TODO: Implement debugging
|
|
102
108
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
return true;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
StatementResolvedValue::Array(array) => {
|
|
114
|
-
for item in array {
|
|
115
|
-
if match_error_recursively_resolved(item) {
|
|
116
|
-
return true;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
_ => {}
|
|
121
|
-
}
|
|
109
|
+
let success_message = format!(
|
|
110
|
+
"Check completed successfully in {:.2?}. Output files written to: '{}'",
|
|
111
|
+
duration.elapsed(),
|
|
112
|
+
normalized_output_dir
|
|
113
|
+
);
|
|
122
114
|
|
|
123
|
-
|
|
115
|
+
let logger = Logger::new();
|
|
116
|
+
logger.log_message(LogLevel::Success, &success_message);
|
|
124
117
|
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
use clap::{ Parser, Subcommand };
|
|
2
|
+
use crate::utils::version::get_version;
|
|
3
|
+
|
|
4
|
+
#[derive(Parser)]
|
|
5
|
+
#[command(name = "devalang")]
|
|
6
|
+
#[command(author = "Devaloop")]
|
|
7
|
+
#[command(version = get_version())]
|
|
8
|
+
#[command(about = "🦊 Devalang – A programming language for music and sound.")]
|
|
9
|
+
pub struct Cli {
|
|
10
|
+
#[arg(long, global = true)]
|
|
11
|
+
/// Skips loading the configuration file.
|
|
12
|
+
pub no_config: bool,
|
|
13
|
+
|
|
14
|
+
#[command(subcommand)]
|
|
15
|
+
pub command: Commands,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
#[derive(Subcommand)]
|
|
19
|
+
pub enum InstallCommand {
|
|
20
|
+
/// Installs a bank.
|
|
21
|
+
Bank {
|
|
22
|
+
name: String,
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#[derive(Subcommand)]
|
|
27
|
+
pub enum TemplateCommand {
|
|
28
|
+
/// Lists all available templates for Devalang projects.
|
|
29
|
+
List,
|
|
30
|
+
/// Displays information about a specific template.
|
|
31
|
+
Info {
|
|
32
|
+
name: String,
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#[derive(Subcommand)]
|
|
37
|
+
pub enum BankCommand {
|
|
38
|
+
/// Lists installed banks.
|
|
39
|
+
List,
|
|
40
|
+
/// Lists all available banks.
|
|
41
|
+
Available,
|
|
42
|
+
/// Displays information about a specific bank.
|
|
43
|
+
Info {
|
|
44
|
+
name: String,
|
|
45
|
+
},
|
|
46
|
+
/// Removes a bank.
|
|
47
|
+
Remove {
|
|
48
|
+
name: String,
|
|
49
|
+
},
|
|
50
|
+
/// Updates a specific or all banks.
|
|
51
|
+
Update {
|
|
52
|
+
name: Option<String>,
|
|
53
|
+
},
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
#[derive(Subcommand)]
|
|
57
|
+
pub enum Commands {
|
|
58
|
+
/// Create a new Devalang project.
|
|
59
|
+
///
|
|
60
|
+
/// ### Arguments
|
|
61
|
+
/// - `name` - The name of the project to create.
|
|
62
|
+
/// - `template` - The template to use for the project. Defaults to "default".
|
|
63
|
+
///
|
|
64
|
+
/// ### Example
|
|
65
|
+
/// ```bash
|
|
66
|
+
/// devalang init --name my_project --template default
|
|
67
|
+
///
|
|
68
|
+
Init {
|
|
69
|
+
#[arg(short, long)]
|
|
70
|
+
/// The optional name (directory) of the project to create.
|
|
71
|
+
name: Option<String>,
|
|
72
|
+
|
|
73
|
+
#[arg(short, long)]
|
|
74
|
+
/// The template to use for the project.
|
|
75
|
+
///
|
|
76
|
+
/// ### Default value
|
|
77
|
+
/// - `default`
|
|
78
|
+
///
|
|
79
|
+
template: Option<String>,
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
/// Manage templates for Devalang projects.
|
|
83
|
+
///
|
|
84
|
+
/// ### Subcommands
|
|
85
|
+
/// - `list` - Lists all available templates.
|
|
86
|
+
/// - `info <name>` - Displays information about a specific template.
|
|
87
|
+
///
|
|
88
|
+
/// ### Example
|
|
89
|
+
/// ```bash
|
|
90
|
+
/// devalang template list
|
|
91
|
+
/// devalang template info my_template
|
|
92
|
+
/// ```bash
|
|
93
|
+
///
|
|
94
|
+
Template {
|
|
95
|
+
#[command(subcommand)]
|
|
96
|
+
/// The template command to execute.
|
|
97
|
+
command: TemplateCommand,
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
/// Build the program and generate output files.
|
|
101
|
+
///
|
|
102
|
+
/// ### Arguments
|
|
103
|
+
/// - `entry` - The entry point of the program to build. Defaults to "./src".
|
|
104
|
+
/// - `output` - The directory where the output files will be generated. Defaults to "./output".
|
|
105
|
+
/// - `watch` - Whether to watch for changes and rebuild. Defaults to "true".
|
|
106
|
+
///
|
|
107
|
+
/// ### Example
|
|
108
|
+
/// ```bash
|
|
109
|
+
/// devalang build --entry ./src --output ./output --watch true
|
|
110
|
+
/// ```
|
|
111
|
+
///
|
|
112
|
+
Build {
|
|
113
|
+
#[arg(short, long)]
|
|
114
|
+
/// The entry point of the program to build.
|
|
115
|
+
///
|
|
116
|
+
entry: Option<String>,
|
|
117
|
+
|
|
118
|
+
#[arg(short, long)]
|
|
119
|
+
/// The directory where the output files will be generated.
|
|
120
|
+
///
|
|
121
|
+
output: Option<String>,
|
|
122
|
+
|
|
123
|
+
#[arg(long, default_value_t = false)]
|
|
124
|
+
/// Whether to watch for changes and rebuild.
|
|
125
|
+
///
|
|
126
|
+
/// ### Default value
|
|
127
|
+
/// - `false`
|
|
128
|
+
///
|
|
129
|
+
watch: bool,
|
|
130
|
+
|
|
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
|
+
#[arg(short, long, default_value_t = false)]
|
|
145
|
+
/// Whether to print debug information.
|
|
146
|
+
///
|
|
147
|
+
/// ### Default value
|
|
148
|
+
/// - `false`
|
|
149
|
+
///
|
|
150
|
+
debug: bool,
|
|
151
|
+
|
|
152
|
+
#[arg(short, long, default_value_t = false)]
|
|
153
|
+
/// Whether to compress the output files.
|
|
154
|
+
///
|
|
155
|
+
/// ### Default value
|
|
156
|
+
/// - `false`
|
|
157
|
+
///
|
|
158
|
+
compress: bool,
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
/// Analyze the program for errors and warnings.
|
|
162
|
+
///
|
|
163
|
+
/// ### Arguments
|
|
164
|
+
/// - `entry` - The entry point of the program to analyze. Defaults to "./src".
|
|
165
|
+
/// - `output` - The directory where the output files will be generated. Defaults to "./output".
|
|
166
|
+
/// - `watch` - Whether to watch for changes and re-analyze. Defaults to "true".
|
|
167
|
+
/// - `compilation_mode` - The mode of compilation. Defaults to "real-time".
|
|
168
|
+
/// - `debug` - Whether to print debug information. Defaults to "false".
|
|
169
|
+
///
|
|
170
|
+
Check {
|
|
171
|
+
#[arg(short, long)]
|
|
172
|
+
/// The entry point of the program to analyze.
|
|
173
|
+
entry: Option<String>,
|
|
174
|
+
|
|
175
|
+
#[arg(short, long)]
|
|
176
|
+
/// The directory where the output files will be generated.
|
|
177
|
+
output: Option<String>,
|
|
178
|
+
|
|
179
|
+
#[arg(long, default_value_t = false)]
|
|
180
|
+
/// Whether to watch for changes and re-analyze.
|
|
181
|
+
///
|
|
182
|
+
/// ### Default value
|
|
183
|
+
/// - `false`
|
|
184
|
+
///
|
|
185
|
+
watch: bool,
|
|
186
|
+
|
|
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
|
+
#[arg(short, long, default_value_t = false)]
|
|
201
|
+
/// Whether to print debug information.
|
|
202
|
+
///
|
|
203
|
+
/// ### Default value
|
|
204
|
+
/// - `false`
|
|
205
|
+
///
|
|
206
|
+
debug: bool,
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
/// Play the program and generate output files.
|
|
210
|
+
///
|
|
211
|
+
/// ### Arguments
|
|
212
|
+
/// - `entry` - The entry point of the program to play. Defaults to "./src".
|
|
213
|
+
/// - `output` - The directory where the output files will be generated. Defaults to "./output".
|
|
214
|
+
/// - `watch` - Whether to watch for changes and re-play. Defaults to "false".
|
|
215
|
+
/// - `repeat` - Whether to replay the program after it finishes. Defaults to "false".
|
|
216
|
+
///
|
|
217
|
+
Play {
|
|
218
|
+
#[arg(short, long)]
|
|
219
|
+
/// The entry point of the program to play.
|
|
220
|
+
entry: Option<String>,
|
|
221
|
+
|
|
222
|
+
#[arg(short, long)]
|
|
223
|
+
/// The directory where the output files will be generated.
|
|
224
|
+
output: Option<String>,
|
|
225
|
+
|
|
226
|
+
#[arg(long, default_value_t = false)]
|
|
227
|
+
/// Whether to watch for changes and re-play.
|
|
228
|
+
///
|
|
229
|
+
/// ### Default value
|
|
230
|
+
/// - `false`
|
|
231
|
+
///
|
|
232
|
+
watch: bool,
|
|
233
|
+
|
|
234
|
+
#[arg(long, default_value_t = false)]
|
|
235
|
+
/// Whether to replay the program after it finishes.
|
|
236
|
+
///
|
|
237
|
+
/// ### Default value
|
|
238
|
+
/// - `false`
|
|
239
|
+
///
|
|
240
|
+
repeat: bool,
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
/// Update the Devalang CLI to the latest version.
|
|
244
|
+
///
|
|
245
|
+
/// ### Arguments
|
|
246
|
+
/// - `only` - Selects what to update (separated by commas). Defaults to updating all components.
|
|
247
|
+
///
|
|
248
|
+
Update {
|
|
249
|
+
// #[arg(long, default_value_t = false)]
|
|
250
|
+
/// Whether to allow updates when the working directory is dirty.
|
|
251
|
+
// allow_dirty: bool,
|
|
252
|
+
|
|
253
|
+
#[arg(long, default_value = "")]
|
|
254
|
+
/// Selects what to update (separated by commas).
|
|
255
|
+
only: Option<String>,
|
|
256
|
+
},
|
|
257
|
+
|
|
258
|
+
/// Install templates, banks, or plugins.
|
|
259
|
+
///
|
|
260
|
+
/// ### Subcommands
|
|
261
|
+
/// - `template` - Installs a template.
|
|
262
|
+
/// - `bank` - Installs a bank.
|
|
263
|
+
/// - `plugin` - Installs a plugin.
|
|
264
|
+
///
|
|
265
|
+
Install {
|
|
266
|
+
#[command(subcommand)]
|
|
267
|
+
command: InstallCommand,
|
|
268
|
+
},
|
|
269
|
+
|
|
270
|
+
/// Manage banks for Devalang projects.
|
|
271
|
+
///
|
|
272
|
+
/// ### Subcommands
|
|
273
|
+
/// - `list` - Lists all available banks.
|
|
274
|
+
/// - `info <name>` - Displays information about a specific bank.
|
|
275
|
+
///
|
|
276
|
+
Bank {
|
|
277
|
+
#[command(subcommand)]
|
|
278
|
+
command: BankCommand,
|
|
279
|
+
},
|
|
280
|
+
}
|