@devaloop/devalang 0.0.1-alpha.4 → 0.0.1-alpha.7

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 (54) hide show
  1. package/Cargo.toml +7 -5
  2. package/README.md +26 -7
  3. package/docs/CHANGELOG.md +34 -2
  4. package/docs/ROADMAP.md +3 -3
  5. package/docs/SYNTAX.md +42 -14
  6. package/docs/TODO.md +9 -8
  7. package/examples/group.deva +12 -0
  8. package/examples/index.deva +10 -9
  9. package/examples/loop.deva +15 -0
  10. package/examples/variables.deva +9 -0
  11. package/out-tsc/bin/devalang.exe +0 -0
  12. package/package.json +43 -41
  13. package/project-version.json +5 -5
  14. package/rust/cli/build.rs +4 -4
  15. package/rust/cli/check.rs +2 -1
  16. package/rust/cli/init.rs +4 -2
  17. package/rust/cli/play.rs +5 -3
  18. package/rust/cli/template.rs +2 -1
  19. package/rust/config/loader.rs +0 -1
  20. package/rust/{audio → core/audio}/engine.rs +1 -5
  21. package/rust/core/audio/interpreter.rs +317 -0
  22. package/rust/{audio → core/audio}/loader.rs +4 -0
  23. package/rust/{audio → core/audio}/render.rs +1 -5
  24. package/rust/core/builder/mod.rs +9 -8
  25. package/rust/core/lexer/handler/indent.rs +1 -1
  26. package/rust/core/lexer/handler/mod.rs +3 -4
  27. package/rust/core/lexer/handler/newline.rs +5 -1
  28. package/rust/core/lexer/handler/string.rs +3 -6
  29. package/rust/core/lexer/mod.rs +10 -5
  30. package/rust/core/mod.rs +2 -1
  31. package/rust/core/parser/handler/identifier.rs +127 -1
  32. package/rust/core/parser/handler/loop_.rs +11 -0
  33. package/rust/core/parser/mod.rs +0 -1
  34. package/rust/core/parser/statement.rs +9 -5
  35. package/rust/core/preprocessor/loader.rs +65 -3
  36. package/rust/core/preprocessor/module.rs +2 -0
  37. package/rust/core/preprocessor/processor.rs +28 -2
  38. package/rust/core/preprocessor/resolver/bank.rs +10 -9
  39. package/rust/core/preprocessor/resolver/group.rs +113 -0
  40. package/rust/core/preprocessor/resolver/loop_.rs +15 -13
  41. package/rust/core/preprocessor/resolver/mod.rs +11 -5
  42. package/rust/core/preprocessor/resolver/trigger.rs +0 -3
  43. package/rust/lib.rs +117 -0
  44. package/rust/main.rs +2 -1
  45. package/rust/utils/logger.rs +45 -6
  46. package/rust/utils/spinner.rs +2 -0
  47. package/templates/minimal/.devalang +2 -1
  48. package/templates/minimal/README.md +202 -0
  49. package/templates/welcome/.devalang +2 -1
  50. package/templates/welcome/README.md +48 -31
  51. package/examples/exported.deva +0 -7
  52. package/rust/audio/interpreter.rs +0 -143
  53. /package/rust/{audio → core/audio}/mod.rs +0 -0
  54. /package/rust/{audio → core/audio}/player.rs +0 -0
@@ -1,6 +1,8 @@
1
+ #[cfg(feature = "cli")]
1
2
  use indicatif::{ ProgressBar, ProgressStyle };
2
3
  use std::{ time::Duration };
3
4
 
5
+ #[cfg(feature = "cli")]
4
6
  pub fn with_spinner<T, F>(start_msg: &str, f: F) -> T where F: FnOnce() -> T {
5
7
  let spinner = ProgressBar::new_spinner();
6
8
  spinner.set_style(
@@ -1,4 +1,5 @@
1
1
  [defaults]
2
2
  entry = "./src"
3
3
  output = "./output"
4
- watch = false
4
+ watch = false
5
+ repeat = false
@@ -0,0 +1,202 @@
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
+ ![Rust](https://img.shields.io/badge/Made%20with-Rust-orange?logo=rust)
6
+ ![TypeScript](https://img.shields.io/badge/Built%20with-TypeScript-blue?logo=typescript)
7
+ ![Node.js](https://img.shields.io/badge/Node.js-18%2B-brightgreen?logo=node.js)
8
+
9
+ ![Project Status](https://img.shields.io/badge/status-alpha-red)
10
+ ![Version](https://img.shields.io/badge/version-0.0.1-blue)
11
+ ![License: MIT](https://img.shields.io/badge/license-MIT-green)
12
+ ![Platform](https://img.shields.io/badge/platform-Windows-blue)
13
+
14
+ ![npm](https://img.shields.io/npm/dt/@devaloop/devalang)
15
+ ![crates](https://img.shields.io/crates/d/devalang)
16
+
17
+ ## 🎼 Devalang, by **Devaloop Labs**
18
+
19
+ 🎶 Compose music with code — simple, structured, sonic.
20
+
21
+ Devalang is a tiny domain-specific language (DSL) for music makers, sound designers, and audio hackers.
22
+ Compose loops, control samples, render and play audio — all in clean, readable text.
23
+
24
+ 🦊 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.
25
+
26
+ From studio sketches to live sets, Devalang gives you rhythmic control — with the elegance of code.
27
+
28
+ > 🚧 **v0.0.1-alpha.5 Notice** 🚧
29
+ >
30
+ > Currently, Devalang CLI is only available for **Windows**.
31
+ > Linux and macOS binaries will be added in future releases via cross-platform builds.
32
+
33
+ ---
34
+
35
+ ## 📚 Quick Access
36
+
37
+ - [📖 Documentation](./docs/)
38
+ - [💡 Examples](./examples/)
39
+ - [🌐 Project Website](https://devalang.com)
40
+
41
+ ## 🚀 Features
42
+
43
+ - 🎵 **Audio Engine**: Integrated audio playback and rendering
44
+ - 🧩 **Module system** for importing and exporting variables between files
45
+ - 📜 **Structured AST** generation for debugging and future compilation
46
+ - 🔢 **Basic data types**: strings, numbers, booleans, maps, arrays
47
+ - 👁️ **Watch mode** for `build`, `check` and `play` commands
48
+ - 📂 **Project templates** for quick setup
49
+
50
+ ## 📆 Installation
51
+
52
+ ### For users
53
+
54
+ > - ⚠️ Requires [Node.js 18+](https://nodejs.org/en/download)
55
+
56
+ Install the package globally (NPM)
57
+
58
+ ```bash
59
+ npm install -g @devaloop/devalang
60
+ ```
61
+
62
+ Usage without install (NPX)
63
+
64
+ ```bash
65
+ npx @devaloop/devalang <command>
66
+ ```
67
+
68
+ ### For contributors
69
+
70
+ > - ⚠️ Requires [Node.js 18+](https://nodejs.org/en/download)
71
+ > - ⚠️ Requires [Rust 1.70+](https://www.rust-lang.org/learn/get-started#installing-rust)
72
+
73
+ ```bash
74
+ > git clone https://github.com/devaloop-labs/devalang.git
75
+ > cd devalang
76
+ > npm install
77
+ > cargo install --path .
78
+ ```
79
+
80
+ Development usage (you can customize arguments in package.json)
81
+
82
+ ```bash
83
+ # For syntax checking test
84
+ npm run rust:dev:check
85
+ # For building test
86
+ npm run rust:dev:build
87
+ ```
88
+
89
+ ## ❔ Usage
90
+
91
+ NOTE: Commands are available via `devalang` or `npx @devaloop/devalang`.
92
+
93
+ NOTE: Arguments can be passed to commands using `--<argument>` syntax. You can also use a configuration file to set default values for various settings, making it easier to manage your Devalang project.
94
+
95
+ NOTE: Some commands require a mandatory `--entry` argument to specify the input folder, and a `--output` argument to specify the output folder. If not specified, they default to `./src` and `./output` respectively.
96
+
97
+ For more examples, see [docs/COMMANDS.md](./docs/COMMANDS.md)
98
+
99
+ ### Initialize a new project
100
+
101
+ In the current directory
102
+
103
+ ```bash
104
+ devalang init
105
+ ```
106
+
107
+ Or use optional arguments to specify a directory name and a template
108
+
109
+ ```bash
110
+ devalang init --name <project-name> --template <template-name>
111
+ ```
112
+
113
+ ### Checking syntax only
114
+
115
+ ```bash
116
+ devalang check --watch
117
+ ```
118
+
119
+ ### Building output files
120
+
121
+ ```bash
122
+ devalang build --watch
123
+ ```
124
+
125
+ ### Playing audio files (once by file change)
126
+
127
+ ```bash
128
+ devalang play --watch
129
+ ```
130
+
131
+ ### Playing audio files (continuous playback, even without file changes)
132
+
133
+ ```bash
134
+ devalang play --repeat
135
+ ```
136
+
137
+ ## ⚙️ Configuration
138
+
139
+ You can use a configuration file to set default values for various settings, making it easier to manage your Devalang project.
140
+
141
+ To do this, create a `.devalang` file in the root of your project directory.
142
+
143
+ See [docs/CONFIG.md](./docs/CONFIG.md) for more information.
144
+
145
+ ## 📄 Syntax example
146
+
147
+ For more examples, see [docs/SYNTAX.md](./docs/SYNTAX.md)
148
+
149
+ ```deva
150
+ # index.deva
151
+
152
+ @import { globalBpm, globalBank, kickDuration } from "global.deva"
153
+
154
+ @load "./examples/samples/kick-808.wav" as customKick
155
+
156
+ bpm globalBpm
157
+ # Will declare the tempo at the globalBpm variable beats per minute
158
+
159
+ bank globalBank
160
+ # Will declare a custom instrument bank using the globalBank variable
161
+
162
+ loop 5:
163
+ .customKick kickDuration {reverb=50, drive=25}
164
+ # Will play 5 times a kick for the duration of the kickDuration variable with reverb and drive effects
165
+ ```
166
+
167
+ ```deva
168
+ # global.deva
169
+
170
+ let globalBpm = 120
171
+ let globalBank = 808
172
+ let kickDuration = 500
173
+
174
+ @export { globalBpm, globalBank, kickDuration }
175
+ ```
176
+
177
+ ## 🧯 Known issues
178
+
179
+ - No support yet for `if`, `else`, `else if` statements
180
+ - No support yet for `@group`, `@pattern`, `@function` statements
181
+ - No support yet for cross-platform builds (Linux, macOS)
182
+
183
+ ## 🧪 Roadmap Highlights
184
+
185
+ For more info, see [docs/ROADMAP.md](./docs/ROADMAP.md)
186
+
187
+ - ⏳ Other statements (e.g `if`, `@group`, ...)
188
+ - ⏳ Cross-platform support (Linux, macOS)
189
+ - ⏳ More built-in instruments (e.g. snare, hi-hat, etc.)
190
+
191
+ ## 🛡️ License
192
+
193
+ MIT — see [LICENSE](./LICENSE)
194
+
195
+ ## 🤝 Contributing
196
+
197
+ Contributions, bug reports and suggestions are welcome !
198
+ Feel free to open an issue or submit a pull request.
199
+
200
+ ## 📢 Contact
201
+
202
+ 📧 [contact@devaloop.com](mailto:contact@devaloop.com)
@@ -1,4 +1,5 @@
1
1
  [defaults]
2
2
  entry = "./src"
3
3
  output = "./output"
4
- watch = false
4
+ watch = false
5
+ repeat = false
@@ -11,44 +11,41 @@
11
11
  ![License: MIT](https://img.shields.io/badge/license-MIT-green)
12
12
  ![Platform](https://img.shields.io/badge/platform-Windows-blue)
13
13
 
14
- ![npm](https://img.shields.io/npm/dm/@devaloop/devalang)
14
+ ![npm](https://img.shields.io/npm/dt/@devaloop/devalang)
15
+ ![crates](https://img.shields.io/crates/d/devalang)
15
16
 
16
17
  ## 🎼 Devalang, by **Devaloop Labs**
17
18
 
18
19
  🎶 Compose music with code — simple, structured, sonic.
19
20
 
20
21
  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
+ Compose loops, control samples, render and play audio — all in clean, readable text.
22
23
 
23
24
  🦊 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
 
25
26
  From studio sketches to live sets, Devalang gives you rhythmic control — with the elegance of code.
26
27
 
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.
28
+ > 🚧 **v0.0.1-alpha.5 Notice** 🚧
35
29
  >
36
30
  > Currently, Devalang CLI is only available for **Windows**.
37
31
  > Linux and macOS binaries will be added in future releases via cross-platform builds.
38
32
 
33
+ ---
34
+
35
+ ## 📚 Quick Access
36
+
37
+ - [📖 Documentation](./docs/)
38
+ - [💡 Examples](./examples/)
39
+ - [🌐 Project Website](https://devalang.com)
40
+
39
41
  ## 🚀 Features
40
42
 
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`)
43
+ - 🎵 **Audio Engine**: Integrated audio playback and rendering
44
+ - 🧩 **Module system** for importing and exporting variables between files
45
+ - 📜 **Structured AST** generation for debugging and future compilation
46
+ - 🔢 **Basic data types**: strings, numbers, booleans, maps, arrays
47
+ - 👁️ **Watch mode** for `build`, `check` and `play` commands
48
+ - 📂 **Project templates** for quick setup
52
49
 
53
50
  ## 📆 Installation
54
51
 
@@ -80,15 +77,23 @@ npx @devaloop/devalang <command>
80
77
  > cargo install --path .
81
78
  ```
82
79
 
83
- Usage for development (feel free to change arguments in package.json)
80
+ Development usage (you can customize arguments in package.json)
84
81
 
85
82
  ```bash
86
83
  # For syntax checking test
87
- npm run rust:dev <command>
84
+ npm run rust:dev:check
85
+ # For building test
86
+ npm run rust:dev:build
88
87
  ```
89
88
 
90
89
  ## ❔ Usage
91
90
 
91
+ NOTE: Commands are available via `devalang` or `npx @devaloop/devalang`.
92
+
93
+ NOTE: Arguments can be passed to commands using `--<argument>` syntax. You can also use a configuration file to set default values for various settings, making it easier to manage your Devalang project.
94
+
95
+ NOTE: Some commands require a mandatory `--entry` argument to specify the input folder, and a `--output` argument to specify the output folder. If not specified, they default to `./src` and `./output` respectively.
96
+
92
97
  For more examples, see [docs/COMMANDS.md](./docs/COMMANDS.md)
93
98
 
94
99
  ### Initialize a new project
@@ -105,16 +110,28 @@ Or use optional arguments to specify a directory name and a template
105
110
  devalang init --name <project-name> --template <template-name>
106
111
  ```
107
112
 
108
- ### Checking syntax only and output debug files
113
+ ### Checking syntax only
109
114
 
110
115
  ```bash
111
- devalang check --entry <entry-directory> --output <output-directory> --watch
116
+ devalang check --watch
112
117
  ```
113
118
 
114
- ### Building output file(s) (AST generation for the moment)
119
+ ### Building output files
115
120
 
116
121
  ```bash
117
- devalang build --entry <entry-directory> --output <output-directory> --watch
122
+ devalang build --watch
123
+ ```
124
+
125
+ ### Playing audio files (once by file change)
126
+
127
+ ```bash
128
+ devalang play --watch
129
+ ```
130
+
131
+ ### Playing audio files (continuous playback, even without file changes)
132
+
133
+ ```bash
134
+ devalang play --repeat
118
135
  ```
119
136
 
120
137
  ## ⚙️ Configuration
@@ -134,6 +151,8 @@ For more examples, see [docs/SYNTAX.md](./docs/SYNTAX.md)
134
151
 
135
152
  @import { globalBpm, globalBank, kickDuration } from "global.deva"
136
153
 
154
+ @load "./examples/samples/kick-808.wav" as customKick
155
+
137
156
  bpm globalBpm
138
157
  # Will declare the tempo at the globalBpm variable beats per minute
139
158
 
@@ -141,7 +160,7 @@ bank globalBank
141
160
  # Will declare a custom instrument bank using the globalBank variable
142
161
 
143
162
  loop 5:
144
- .kick kickDuration {reverb=50, drive=25}
163
+ .customKick kickDuration {reverb=50, drive=25}
145
164
  # Will play 5 times a kick for the duration of the kickDuration variable with reverb and drive effects
146
165
  ```
147
166
 
@@ -157,16 +176,14 @@ let kickDuration = 500
157
176
 
158
177
  ## 🧯 Known issues
159
178
 
160
- - No support yet for Audio Engine
161
179
  - No support yet for `if`, `else`, `else if` statements
162
180
  - No support yet for `@group`, `@pattern`, `@function` statements
163
- - Nested loops and conditions may not be fully tested
181
+ - No support yet for cross-platform builds (Linux, macOS)
164
182
 
165
183
  ## 🧪 Roadmap Highlights
166
184
 
167
185
  For more info, see [docs/ROADMAP.md](./docs/ROADMAP.md)
168
186
 
169
- - ⏳ Audio engine integration
170
187
  - ⏳ Other statements (e.g `if`, `@group`, ...)
171
188
  - ⏳ Cross-platform support (Linux, macOS)
172
189
  - ⏳ More built-in instruments (e.g. snare, hi-hat, etc.)
@@ -1,7 +0,0 @@
1
- let duration = auto
2
- let default_bank = 808
3
- let params = {decay:10, delay:30}
4
- let loopCount = 5
5
- let tempo = 155
6
-
7
- @export { duration, default_bank, params, loopCount, tempo }
@@ -1,143 +0,0 @@
1
- use crate::{
2
- audio::{ engine::AudioEngine, loader::load_trigger },
3
- core::{
4
- parser::statement::{ Statement, StatementKind },
5
- shared::value::Value,
6
- store::variable::VariableTable,
7
- },
8
- };
9
-
10
- pub fn interprete_statements(
11
- statements: &Vec<Statement>,
12
- audio_engine: AudioEngine,
13
- entry: String,
14
- output: String
15
- ) -> (AudioEngine, f32, f32) {
16
- let mut base_bpm = 120.0;
17
- let mut base_duration = 60.0 / base_bpm;
18
-
19
- let variable_table = audio_engine.variables.clone();
20
-
21
- let (updated_audio_engine, base_bpm, max_end_time) = execute_audio_statements(
22
- audio_engine.clone(),
23
- variable_table.clone(),
24
- statements.clone(),
25
- base_bpm.clone(),
26
- base_duration.clone(),
27
- 0.0,
28
- 0.0
29
- );
30
-
31
- (updated_audio_engine, base_bpm, max_end_time)
32
- }
33
-
34
- pub fn execute_audio_statements(
35
- mut audio_engine: AudioEngine,
36
- mut variable_table: VariableTable,
37
- mut statements: Vec<Statement>,
38
- mut base_bpm: f32,
39
- mut base_duration: f32,
40
- mut max_end_time: f32,
41
- mut cursor_time: f32
42
- ) -> (AudioEngine, f32, f32) {
43
- for stmt in statements {
44
- match &stmt.kind {
45
- StatementKind::Load { source, alias } => {
46
- variable_table.set(alias.to_string(), Value::String(source.clone()));
47
- }
48
-
49
- StatementKind::Let { name } => {
50
- variable_table.set(name.to_string(), stmt.value.clone());
51
- }
52
-
53
- StatementKind::Tempo => {
54
- if let Value::Number(bpm_) = &stmt.value {
55
- base_bpm = *bpm_ as f32;
56
- base_duration = 60.0 / base_bpm;
57
- } else {
58
- eprintln!("❌ Invalid tempo value: {:?}", stmt.value);
59
- }
60
- }
61
-
62
- StatementKind::Trigger { entity, duration } => {
63
- if let Some(trigger_val) = variable_table.get(entity) {
64
- let (src, duration_secs) = load_trigger(
65
- trigger_val,
66
- duration,
67
- base_duration,
68
- variable_table.clone()
69
- );
70
-
71
- audio_engine.insert(&src, cursor_time, duration_secs, None);
72
-
73
- cursor_time += duration_secs;
74
-
75
- if cursor_time > max_end_time {
76
- max_end_time = cursor_time;
77
- }
78
- } else {
79
- eprintln!("❌ Unknown trigger entity: {}", entity);
80
- }
81
- }
82
-
83
- StatementKind::Loop => {
84
- if let Value::Map(loop_value) = &stmt.value {
85
- let iterator = loop_value.get("iterator");
86
- let body = loop_value.get("body");
87
-
88
- let loop_count = if let Some(Value::Number(n)) = iterator {
89
- *n as usize
90
- } else {
91
- eprintln!("❌ Loop iterator must be a number: {:?}", iterator);
92
- continue;
93
- };
94
-
95
- let loop_body = if let Some(Value::Block(body)) = body {
96
- body.clone()
97
- } else {
98
- eprintln!("❌ Loop body must be a block: {:?}", body);
99
- continue;
100
- };
101
-
102
- for _ in 0..loop_count {
103
- let (loop_engine, _, loop_end_time) = execute_audio_statements(
104
- audio_engine.clone(),
105
- variable_table.clone(),
106
- loop_body.clone(),
107
- base_bpm,
108
- base_duration,
109
- max_end_time,
110
- cursor_time
111
- );
112
-
113
- audio_engine = loop_engine;
114
-
115
- // Update time and max_end_time after each loop iteration
116
- cursor_time = loop_end_time;
117
- if loop_end_time > max_end_time {
118
- max_end_time = loop_end_time;
119
- }
120
- }
121
- }
122
- }
123
-
124
- StatementKind::Bank => {}
125
-
126
- StatementKind::Import { names, source } => {}
127
-
128
- StatementKind::Export { names, source } => {}
129
-
130
- StatementKind::Unknown => {
131
- // Ignore unknown statements
132
- }
133
-
134
- _ => {
135
- eprintln!("Unsupported statement kind: {:?}", stmt);
136
- }
137
- }
138
- }
139
-
140
- audio_engine.set_variables(variable_table);
141
-
142
- (audio_engine, base_bpm, max_end_time)
143
- }
File without changes
File without changes