@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
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::{ build_ast, write_ast_to_file },
6
- debugger::Debugger,
7
- preprocessor::module::load_all_modules,
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
- runner::executer::execute_statements,
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
- pub fn handle_build_command(entry: String, output: String) {
14
- let entry_file = find_entry_file(&entry).unwrap_or_else(|| {
15
- eprintln!("❌ index.deva not found in directory: {}", entry);
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(&entry_file);
103
+ let normalized_entry_file = normalize_path(&entry);
26
104
  let normalized_output_dir = normalize_path(&output);
27
105
 
28
- let global_store = load_all_modules(&normalized_entry_file);
106
+ let mut global_store = GlobalStore::new();
107
+ let module_loader = ModuleLoader::new(&normalized_entry_file, &normalized_output_dir);
29
108
 
30
- if let Some(module) = global_store.modules.get(&normalized_entry_file) {
31
- let mut module_clone = module.clone();
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
- let resolved_statements = execute_statements(&mut module_clone);
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
- let ast = build_ast(&resolved_statements);
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
- let ast_dir = format!("{}/json", normalized_output_dir.clone());
38
- write_ast_to_file(&ast, &ast_dir);
127
+ // SECTION Logging
128
+ let logger = Logger::new();
39
129
 
40
- let debugger = Debugger::new(&module_clone);
41
- let debug_dir = format!("{}/debug/", normalized_output_dir.clone());
42
- debugger.write_files(debug_dir.as_str(), resolved_statements);
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
- let success_message = format!(
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
- debugger::Debugger,
6
- preprocessor::module::load_all_modules,
7
- types::{
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
- runner::executer::execute_statements,
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
- pub fn handle_check_command(entry: String, output: String) -> () {
23
- let entry_file = find_entry_file(&entry).unwrap_or_else(|| {
24
- eprintln!("❌ index.deva not found in directory: {}", entry);
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 spinner = with_spinner("Checking...", || {
29
- thread::sleep(Duration::from_millis(800));
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
- let duration = std::time::Instant::now();
33
-
34
- let normalized_entry_file = normalize_path(&entry_file);
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
- if let Some(module) = global_store.modules.get(&normalized_entry_file) {
40
- let mut module_clone = module.clone();
75
+ logger.log_message(
76
+ LogLevel::Watcher,
77
+ &format!("Watching for changes in '{}'...", fetched_entry)
78
+ );
41
79
 
42
- let resolved_statements = execute_statements(&mut module_clone);
80
+ watch_directory(entry_file.clone(), move || {
81
+ logger.log_message(LogLevel::Watcher, "Detected changes, re-checking...");
43
82
 
44
- let debugger = Debugger::new(&module_clone);
45
- let debug_dir = format!("{}/debug/", normalized_output_dir.clone());
46
- debugger.write_files(debug_dir.as_str(), resolved_statements.clone());
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
- let has_errors = resolved_statements.iter().any(|stmt| {
49
- match_error_recursively_resolved(&stmt.clone())
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
- if has_errors {
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
- log_message(&warning_message, "WARNING");
60
- } else {
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
- log_message(&success_message, "SUCCESS");
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
- fn match_error_recursively_resolved(stmt: &StatementResolved) -> bool {
73
- match stmt.value.clone() {
74
- // TODO Other statement value types here
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
- false
101
- }
107
+ // TODO: Implement debugging
102
108
 
103
- fn match_error_recursively_resolved_value(value: &StatementResolvedValue) -> bool {
104
- match value {
105
- StatementResolvedValue::Map(map) => {
106
- for (_, v) in map {
107
- if match_error_recursively_resolved_value(v) {
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
- false
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
+ }