@devaloop/devalang 0.0.1-alpha.1 → 0.0.1-alpha.3
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 +4 -0
- package/Cargo.toml +46 -45
- package/README.md +35 -10
- package/docs/CHANGELOG.md +58 -0
- package/docs/COMMANDS.md +29 -6
- package/docs/CONFIG.md +28 -0
- package/docs/ROADMAP.md +6 -2
- package/docs/TODO.md +21 -18
- package/examples/exported.deva +1 -1
- package/examples/index.deva +2 -1
- package/out-tsc/bin/devalang.exe +0 -0
- package/package.json +2 -3
- package/project-version.json +4 -4
- package/rust/cli/build.rs +99 -29
- package/rust/cli/check.rs +95 -103
- package/rust/cli/init.rs +77 -0
- package/rust/cli/mod.rs +174 -1
- package/rust/cli/template.rs +56 -0
- package/rust/config/loader.rs +14 -0
- package/rust/config/mod.rs +15 -0
- package/rust/core/builder/mod.rs +21 -27
- package/rust/core/debugger/lexer.rs +12 -0
- package/rust/core/debugger/mod.rs +12 -49
- package/rust/core/debugger/preprocessor.rs +23 -0
- package/rust/core/error/mod.rs +60 -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/equal.rs +32 -0
- package/rust/core/lexer/handler/identifier.rs +38 -0
- package/rust/core/lexer/handler/indent.rs +52 -0
- package/rust/core/lexer/handler/mod.rs +238 -0
- package/rust/core/lexer/handler/newline.rs +19 -0
- package/rust/core/lexer/handler/number.rs +31 -0
- package/rust/core/lexer/handler/string.rs +66 -0
- package/rust/core/lexer/mod.rs +16 -324
- package/rust/core/lexer/token.rs +55 -0
- package/rust/core/mod.rs +5 -2
- package/rust/core/parser/handler/at.rs +166 -0
- package/rust/core/parser/handler/bank.rs +38 -0
- package/rust/core/parser/handler/dot.rs +112 -0
- package/rust/core/parser/handler/identifier.rs +134 -0
- package/rust/core/parser/handler/loop_.rs +55 -0
- package/rust/core/parser/handler/mod.rs +6 -0
- package/rust/core/parser/handler/tempo.rs +47 -0
- package/rust/core/parser/mod.rs +204 -166
- package/rust/core/parser/statement.rs +91 -0
- package/rust/core/preprocessor/loader.rs +105 -0
- package/rust/core/preprocessor/mod.rs +2 -24
- package/rust/core/preprocessor/module.rs +37 -56
- package/rust/core/preprocessor/processor.rs +41 -0
- package/rust/core/preprocessor/resolver.rs +372 -0
- package/rust/core/shared/duration.rs +8 -0
- package/rust/core/shared/mod.rs +2 -0
- package/rust/core/shared/value.rs +18 -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/validation.rs +35 -0
- package/rust/lib.rs +0 -1
- package/rust/main.rs +39 -30
- package/rust/utils/file.rs +35 -0
- package/rust/utils/logger.rs +69 -34
- package/rust/utils/mod.rs +3 -2
- package/rust/utils/watcher.rs +25 -0
- package/templates/minimal/.devalang +4 -0
- package/templates/minimal/src/index.deva +2 -0
- package/templates/welcome/.devalang +4 -0
- package/templates/welcome/README.md +185 -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/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/preprocessor/resolver/bank.rs +0 -59
- package/rust/core/preprocessor/resolver/loop_.rs +0 -82
- package/rust/core/preprocessor/resolver/mod.rs +0 -113
- package/rust/core/preprocessor/resolver/tempo.rs +0 -70
- package/rust/core/preprocessor/resolver/trigger.rs +0 -176
- 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 → core/utils}/path.rs +0 -0
- /package/rust/utils/{loader.rs → spinner.rs} +0 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
use crate::core::{ preprocessor::module::Module, shared::value::Value, store::global::GlobalStore };
|
|
2
|
+
|
|
3
|
+
pub fn is_valid_entity(entity: &str, module: &Module, global_store: &GlobalStore) -> bool {
|
|
4
|
+
let built_ins = ["kick", "snare", "hat", "clap"];
|
|
5
|
+
|
|
6
|
+
if built_ins.contains(&entity) {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if let Some(val) = module.variable_table.get(entity) {
|
|
11
|
+
match val {
|
|
12
|
+
Value::Sample(_) => true,
|
|
13
|
+
_ => false,
|
|
14
|
+
}
|
|
15
|
+
} else {
|
|
16
|
+
false
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
pub fn is_valid_identifier(ident: &str, module: &Module) -> bool {
|
|
21
|
+
let built_ins = ["auto"];
|
|
22
|
+
|
|
23
|
+
if built_ins.contains(&ident) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if let Some(val) = module.variable_table.get(ident) {
|
|
28
|
+
match val {
|
|
29
|
+
Value::Identifier(_) => true,
|
|
30
|
+
_ => false,
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
false
|
|
34
|
+
}
|
|
35
|
+
}
|
package/rust/lib.rs
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
// TODO WebAssembly support
|
package/rust/main.rs
CHANGED
|
@@ -1,48 +1,57 @@
|
|
|
1
1
|
pub mod core;
|
|
2
2
|
pub mod cli;
|
|
3
|
-
pub mod runner;
|
|
4
|
-
pub mod audio;
|
|
5
3
|
pub mod utils;
|
|
4
|
+
pub mod config;
|
|
6
5
|
|
|
7
|
-
use std::
|
|
6
|
+
use std::io;
|
|
7
|
+
use cli::{ Cli };
|
|
8
8
|
use clap::Parser;
|
|
9
9
|
use crate::{
|
|
10
|
-
cli::{
|
|
11
|
-
|
|
10
|
+
cli::{
|
|
11
|
+
build::handle_build_command,
|
|
12
|
+
check::handle_check_command,
|
|
13
|
+
init::handle_init_command,
|
|
14
|
+
template::{ handle_template_info_command, handle_template_list_command },
|
|
15
|
+
Commands,
|
|
16
|
+
TemplateCommand,
|
|
17
|
+
},
|
|
18
|
+
config::{ loader::load_config, Config },
|
|
12
19
|
};
|
|
13
20
|
|
|
14
21
|
fn main() -> io::Result<()> {
|
|
15
|
-
let cli = Cli::parse();
|
|
22
|
+
let cli: Cli = Cli::parse();
|
|
23
|
+
let mut config: Option<Config> = None;
|
|
24
|
+
|
|
25
|
+
if !cli.no_config {
|
|
26
|
+
config = load_config(None);
|
|
27
|
+
} else {
|
|
28
|
+
println!("No configuration file loaded. Running with arguments only.");
|
|
29
|
+
}
|
|
16
30
|
|
|
17
31
|
match cli.command {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
CliCommands::Build { entry, output, watch, compilation_mode, debug, compress } => {
|
|
35
|
-
handle_build_command(entry, output);
|
|
32
|
+
Commands::Init { name, template } => {
|
|
33
|
+
handle_init_command(name, template);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
Commands::Template { command } =>
|
|
37
|
+
match command {
|
|
38
|
+
TemplateCommand::List => {
|
|
39
|
+
handle_template_list_command();
|
|
40
|
+
}
|
|
41
|
+
TemplateCommand::Info { name } => {
|
|
42
|
+
handle_template_info_command(name);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
Commands::Check { entry, output, watch, compilation_mode, debug } => {
|
|
47
|
+
handle_check_command(config, entry, output, watch);
|
|
36
48
|
}
|
|
37
49
|
|
|
38
|
-
|
|
39
|
-
|
|
50
|
+
Commands::Build { entry, output, watch, compilation_mode, debug, compress } => {
|
|
51
|
+
handle_build_command(config, entry, output, watch);
|
|
40
52
|
}
|
|
41
53
|
|
|
42
|
-
|
|
43
|
-
// CliCommands::Play {} => {
|
|
44
|
-
// log_message("Command 'play' is not implemented yet.", "WARNING");
|
|
45
|
-
// }
|
|
54
|
+
_ => {}
|
|
46
55
|
}
|
|
47
56
|
|
|
48
57
|
Ok(())
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
use std::{ fs::{ self }, path::Path };
|
|
2
|
+
use include_dir::{ Dir, DirEntry };
|
|
3
|
+
|
|
4
|
+
pub fn copy_dir_recursive(dir: &Dir, target_root: &Path, base_path: &Path) {
|
|
5
|
+
for entry in dir.entries() {
|
|
6
|
+
match entry {
|
|
7
|
+
DirEntry::Dir(subdir) => {
|
|
8
|
+
copy_dir_recursive(subdir, target_root, base_path);
|
|
9
|
+
}
|
|
10
|
+
DirEntry::File(file) => {
|
|
11
|
+
let rel_path = file.path().strip_prefix(base_path).unwrap();
|
|
12
|
+
let dest_path = target_root.join(rel_path);
|
|
13
|
+
|
|
14
|
+
if let Some(parent) = dest_path.parent() {
|
|
15
|
+
fs::create_dir_all(parent).unwrap();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
fs::write(&dest_path, file.contents()).expect("Error writing file");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
pub fn format_file_size(bytes: u64) -> String {
|
|
25
|
+
const KB: u64 = 1024;
|
|
26
|
+
const MB: u64 = 1024 * 1024;
|
|
27
|
+
|
|
28
|
+
if bytes >= MB {
|
|
29
|
+
format!("{:.2} Mb", (bytes as f64) / (MB as f64))
|
|
30
|
+
} else if bytes >= KB {
|
|
31
|
+
format!("{:.2} Kb", (bytes as f64) / (KB as f64))
|
|
32
|
+
} else {
|
|
33
|
+
format!("{} bytes", bytes)
|
|
34
|
+
}
|
|
35
|
+
}
|
package/rust/utils/logger.rs
CHANGED
|
@@ -1,49 +1,84 @@
|
|
|
1
|
-
use crossterm::style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor};
|
|
1
|
+
use crossterm::style::{ Attribute, Color, ResetColor, SetAttribute, SetForegroundColor };
|
|
2
2
|
use std::{ fmt::Write };
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
5
|
+
pub enum LogLevel {
|
|
6
|
+
Success,
|
|
7
|
+
Error,
|
|
8
|
+
Info,
|
|
9
|
+
Warning,
|
|
10
|
+
Watcher,
|
|
11
|
+
Debug,
|
|
7
12
|
}
|
|
8
13
|
|
|
9
|
-
|
|
10
|
-
|
|
14
|
+
#[derive(Debug, Clone)]
|
|
15
|
+
pub struct Logger {}
|
|
11
16
|
|
|
12
|
-
|
|
13
|
-
|
|
17
|
+
impl Logger {
|
|
18
|
+
pub fn new() -> Self {
|
|
19
|
+
Logger {}
|
|
20
|
+
}
|
|
14
21
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
pub fn log_message(&self, level: LogLevel, message: &str) {
|
|
23
|
+
let formatted_status = self.format_status(level);
|
|
24
|
+
println!("🦊 {} {} {}", self.language_signature(), formatted_status, message);
|
|
25
|
+
}
|
|
19
26
|
|
|
20
|
-
|
|
21
|
-
|
|
27
|
+
pub fn log_error_with_stacktrace(&self, message: &str, stacktrace: &str) {
|
|
28
|
+
let formatted_status = self.format_status(LogLevel::Error);
|
|
29
|
+
println!("🦊 {} {} {}", self.language_signature(), formatted_status, message);
|
|
30
|
+
println!(" ↳ {}", stacktrace);
|
|
31
|
+
}
|
|
22
32
|
|
|
23
|
-
|
|
33
|
+
fn language_signature(&self) -> String {
|
|
34
|
+
let mut s = String::new();
|
|
24
35
|
|
|
25
|
-
|
|
26
|
-
|
|
36
|
+
write!(&mut s, "{}", SetForegroundColor(Color::Grey)).unwrap();
|
|
37
|
+
s.push('[');
|
|
38
|
+
|
|
39
|
+
write!(&mut s, "{}", SetForegroundColor(Color::Rgb { r: 29, g: 211, b: 176 })).unwrap();
|
|
40
|
+
write!(&mut s, "{}", SetAttribute(Attribute::Bold)).unwrap();
|
|
41
|
+
s.push_str("Devalang");
|
|
42
|
+
write!(&mut s, "{}", SetAttribute(Attribute::Reset)).unwrap();
|
|
43
|
+
|
|
44
|
+
write!(&mut s, "{}", SetForegroundColor(Color::Grey)).unwrap();
|
|
45
|
+
s.push(']');
|
|
46
|
+
|
|
47
|
+
write!(&mut s, "{}", ResetColor).unwrap();
|
|
48
|
+
|
|
49
|
+
s
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fn format_status(&self, level: LogLevel) -> String {
|
|
53
|
+
let mut s = String::new();
|
|
27
54
|
|
|
28
|
-
|
|
29
|
-
|
|
55
|
+
let color = match level {
|
|
56
|
+
LogLevel::Success => Color::Rgb { r: 76, g: 175, b: 80 },
|
|
57
|
+
LogLevel::Error => Color::Rgb { r: 244, g: 67, b: 54 },
|
|
58
|
+
LogLevel::Info => Color::Rgb { r: 33, g: 150, b: 243 },
|
|
59
|
+
LogLevel::Warning => Color::Rgb { r: 255, g: 152, b: 0 },
|
|
60
|
+
LogLevel::Watcher => Color::Rgb { r: 156, g: 39, b: 176 },
|
|
61
|
+
LogLevel::Debug => Color::Rgb { r: 103, g: 58, b: 183 },
|
|
62
|
+
};
|
|
30
63
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
64
|
+
let status = match level {
|
|
65
|
+
LogLevel::Success => "SUCCESS",
|
|
66
|
+
LogLevel::Error => "ERROR",
|
|
67
|
+
LogLevel::Info => "INFO",
|
|
68
|
+
LogLevel::Warning => "WARNING",
|
|
69
|
+
LogLevel::Watcher => "WATCHER",
|
|
70
|
+
LogLevel::Debug => "DEBUG",
|
|
71
|
+
};
|
|
38
72
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
73
|
+
s.push('[');
|
|
74
|
+
write!(&mut s, "{}", SetForegroundColor(color)).unwrap();
|
|
75
|
+
write!(&mut s, "{}", SetAttribute(Attribute::Bold)).unwrap();
|
|
76
|
+
s.push_str(status);
|
|
77
|
+
write!(&mut s, "{}", SetAttribute(Attribute::Reset)).unwrap();
|
|
78
|
+
s.push(']');
|
|
45
79
|
|
|
46
|
-
|
|
80
|
+
write!(&mut s, "{}", ResetColor).unwrap();
|
|
47
81
|
|
|
48
|
-
|
|
82
|
+
s
|
|
83
|
+
}
|
|
49
84
|
}
|
package/rust/utils/mod.rs
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
use notify::{ Watcher, RecursiveMode, Config, RecommendedWatcher };
|
|
2
|
+
use std::sync::mpsc::channel;
|
|
3
|
+
|
|
4
|
+
pub fn watch_directory<F>(entry: String, callback: F) -> notify::Result<()>
|
|
5
|
+
where F: Fn() + Send + 'static
|
|
6
|
+
{
|
|
7
|
+
let (tx, rx) = channel();
|
|
8
|
+
|
|
9
|
+
let mut watcher: RecommendedWatcher = Watcher::new(tx, Config::default())?;
|
|
10
|
+
watcher.watch(&entry.as_ref(), RecursiveMode::Recursive)?;
|
|
11
|
+
|
|
12
|
+
loop {
|
|
13
|
+
match rx.recv() {
|
|
14
|
+
Ok(_) => {
|
|
15
|
+
callback();
|
|
16
|
+
}
|
|
17
|
+
Err(e) => {
|
|
18
|
+
eprintln!("Channel error : {:?}", e);
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
Ok(())
|
|
25
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="https://firebasestorage.googleapis.com/v0/b/devaloop-labs.firebasestorage.app/o/devalang-teal-logo.svg?alt=media&token=d2a5705a-1eba-4b49-88e6-895a761fb7f7" alt="Devalang Logo">
|
|
3
|
+
</div>
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
12
|
+

|
|
13
|
+
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
## 🎼 Devalang, by **Devaloop Labs**
|
|
17
|
+
|
|
18
|
+
🎶 Compose music with code — simple, structured, sonic.
|
|
19
|
+
|
|
20
|
+
Devalang is a tiny domain-specific language (DSL) for music makers, sound designers, and audio hackers.
|
|
21
|
+
Compose loops, control samples, and automate parameters — all in clean, readable text.
|
|
22
|
+
|
|
23
|
+
🦊 Whether you're building a track, shaping textures, or performing live, Devalang helps you think in rhythms. It’s designed to be simple, expressive, and fast — because your ideas shouldn’t wait.
|
|
24
|
+
|
|
25
|
+
From studio sketches to live sets, Devalang gives you rhythmic control — with the elegance of code.
|
|
26
|
+
|
|
27
|
+
> 🚧 **v0.0.1-alpha.1 Notice** 🚧
|
|
28
|
+
>
|
|
29
|
+
> Devalang is still in early development. This version does not yet include **sound rendering**.
|
|
30
|
+
>
|
|
31
|
+
> You can parse code, generate the AST, and validate syntax — all essential building blocks for the upcoming audio engine.
|
|
32
|
+
>
|
|
33
|
+
> Currently, only `.kick` is included as a built-in trigger.
|
|
34
|
+
> Custom instruments can be defined with `@load`, allowing any sound sample to be triggered with the same syntax.
|
|
35
|
+
>
|
|
36
|
+
> Currently, Devalang CLI is only available for **Windows**.
|
|
37
|
+
> Linux and macOS binaries will be added in future releases via cross-platform builds.
|
|
38
|
+
|
|
39
|
+
## 🚀 Features
|
|
40
|
+
|
|
41
|
+
- 🧩 Module system for importing and exporting variables between files (`@import`, `@export`)
|
|
42
|
+
- 📜 Structured AST generation for debugging and future compilation
|
|
43
|
+
- 🔢 Basic data types: strings, numbers, booleans, maps, arrays
|
|
44
|
+
- 👁️ Watch mode for `build` and `check` commands
|
|
45
|
+
- ⏱️ `bpm` assignment for setting tempo
|
|
46
|
+
- 🧱 `bank` declaration to define the instrument set
|
|
47
|
+
- 🔁 Looping system with fixed repetitions (`loop 4:`)
|
|
48
|
+
- 🧪 Instruction calls with parameters (e.g. `.kick auto {reverb:10, decay:20}`) for testing pattern syntax
|
|
49
|
+
- 📄 `let` assignments for storing reusable values
|
|
50
|
+
- 🔄 `@load` assignment to load a sample (.mp3, .wav) to use it as a value
|
|
51
|
+
- 🛠️ CLI tools for syntax checking (`check`), AST output (`build`)
|
|
52
|
+
|
|
53
|
+
## 📆 Installation
|
|
54
|
+
|
|
55
|
+
### For users
|
|
56
|
+
|
|
57
|
+
> - ⚠️ Requires [Node.js 18+](https://nodejs.org/en/download)
|
|
58
|
+
|
|
59
|
+
Install the package globally (NPM)
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install -g @devaloop/devalang
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Usage without install (NPX)
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npx @devaloop/devalang <command>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### For contributors
|
|
72
|
+
|
|
73
|
+
> - ⚠️ Requires [Node.js 18+](https://nodejs.org/en/download)
|
|
74
|
+
> - ⚠️ Requires [Rust 1.70+](https://www.rust-lang.org/learn/get-started#installing-rust)
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
> git clone https://github.com/devaloop-labs/devalang.git
|
|
78
|
+
> cd devalang
|
|
79
|
+
> npm install
|
|
80
|
+
> cargo install --path .
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Usage for development (feel free to change arguments in package.json)
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# For syntax checking test
|
|
87
|
+
npm run rust:dev <command>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## ❔ Usage
|
|
91
|
+
|
|
92
|
+
For more examples, see [docs/COMMANDS.md](./docs/COMMANDS.md)
|
|
93
|
+
|
|
94
|
+
### Initialize a new project
|
|
95
|
+
|
|
96
|
+
In the current directory
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
devalang init
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Or use optional arguments to specify a directory name and a template
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
devalang init --name <project-name> --template <template-name>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Checking syntax only and output debug files
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
devalang check --entry <entry-directory> --output <output-directory> --watch
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Building output file(s) (AST generation for the moment)
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
devalang build --entry <entry-directory> --output <output-directory> --watch
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## ⚙️ Configuration
|
|
121
|
+
|
|
122
|
+
You can use a configuration file to set default values for various settings, making it easier to manage your Devalang project.
|
|
123
|
+
|
|
124
|
+
To do this, create a `.devalang` file in the root of your project directory.
|
|
125
|
+
|
|
126
|
+
See [docs/CONFIG.md](./docs/CONFIG.md) for more information.
|
|
127
|
+
|
|
128
|
+
## 📄 Syntax example
|
|
129
|
+
|
|
130
|
+
For more examples, see [docs/SYNTAX.md](./docs/SYNTAX.md)
|
|
131
|
+
|
|
132
|
+
```deva
|
|
133
|
+
# index.deva
|
|
134
|
+
|
|
135
|
+
@import { globalBpm, globalBank, kickDuration } from "global.deva"
|
|
136
|
+
|
|
137
|
+
bpm globalBpm
|
|
138
|
+
# Will declare the tempo at the globalBpm variable beats per minute
|
|
139
|
+
|
|
140
|
+
bank globalBank
|
|
141
|
+
# Will declare a custom instrument bank using the globalBank variable
|
|
142
|
+
|
|
143
|
+
loop 5:
|
|
144
|
+
.kick kickDuration {reverb=50, drive=25}
|
|
145
|
+
# Will play 5 times a kick for the duration of the kickDuration variable with reverb and drive effects
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```deva
|
|
149
|
+
# global.deva
|
|
150
|
+
|
|
151
|
+
let globalBpm = 120
|
|
152
|
+
let globalBank = 808
|
|
153
|
+
let kickDuration = 500
|
|
154
|
+
|
|
155
|
+
@export { globalBpm, globalBank, kickDuration }
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## 🧯 Known issues
|
|
159
|
+
|
|
160
|
+
- No support yet for Audio Engine
|
|
161
|
+
- No support yet for `if`, `else`, `else if` statements
|
|
162
|
+
- No support yet for `@group`, `@pattern`, `@function` statements
|
|
163
|
+
- Nested loops and conditions may not be fully tested
|
|
164
|
+
|
|
165
|
+
## 🧪 Roadmap Highlights
|
|
166
|
+
|
|
167
|
+
For more info, see [docs/ROADMAP.md](./docs/ROADMAP.md)
|
|
168
|
+
|
|
169
|
+
- ⏳ Audio engine integration
|
|
170
|
+
- ⏳ Other statements (e.g `if`, `@group`, ...)
|
|
171
|
+
- ⏳ Cross-platform support (Linux, macOS)
|
|
172
|
+
- ⏳ More built-in instruments (e.g. snare, hi-hat, etc.)
|
|
173
|
+
|
|
174
|
+
## 🛡️ License
|
|
175
|
+
|
|
176
|
+
MIT — see [LICENSE](./LICENSE)
|
|
177
|
+
|
|
178
|
+
## 🤝 Contributing
|
|
179
|
+
|
|
180
|
+
Contributions, bug reports and suggestions are welcome !
|
|
181
|
+
Feel free to open an issue or submit a pull request.
|
|
182
|
+
|
|
183
|
+
## 📢 Contact
|
|
184
|
+
|
|
185
|
+
📧 [contact@devaloop.com](mailto:contact@devaloop.com)
|
|
Binary file
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# 🦊 Welcome to Devalang !
|
|
2
|
+
# This is your first Devalang program ?
|
|
3
|
+
# Let's start with a simple example that plays a sample in a loop.
|
|
4
|
+
|
|
5
|
+
@import { bpmVar, bankVar, loopVar } from './variables.deva'
|
|
6
|
+
@load "../samples/kick-808.wav" as sample
|
|
7
|
+
|
|
8
|
+
bpm bpmVar
|
|
9
|
+
|
|
10
|
+
bank bankVar
|
|
11
|
+
|
|
12
|
+
loop loopVar:
|
|
13
|
+
.sample auto
|
package/rust/audio/mod.rs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
// TODO Audio engine
|
package/rust/cli/new.rs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
// TODO Implement the new command to create a new project with a template
|