@devaloop/devalang 0.0.1-alpha.1 → 0.0.1-alpha.10
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 +49 -45
- package/README.md +127 -46
- package/docs/CHANGELOG.md +172 -0
- package/docs/COMMANDS.md +60 -6
- package/docs/CONFIG.md +30 -0
- package/docs/ROADMAP.md +10 -7
- package/docs/SYNTAX.md +100 -18
- package/docs/TODO.md +31 -28
- package/examples/condition.deva +20 -0
- package/examples/group.deva +12 -0
- package/examples/index.deva +13 -4
- 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/build.rs +114 -28
- package/rust/cli/check.rs +96 -103
- package/rust/cli/init.rs +79 -0
- package/rust/cli/mod.rs +203 -1
- package/rust/cli/play.rs +193 -0
- package/rust/cli/template.rs +57 -0
- package/rust/config/loader.rs +13 -0
- package/rust/config/mod.rs +16 -0
- package/rust/core/audio/engine.rs +214 -0
- package/rust/core/audio/evaluator.rs +31 -0
- package/rust/core/audio/interpreter/arrow_call.rs +129 -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 +69 -0
- package/rust/core/audio/loader/mod.rs +1 -0
- package/rust/core/audio/loader/trigger.rs +52 -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 +230 -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 +14 -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/string.rs +63 -0
- package/rust/core/lexer/mod.rs +37 -319
- package/rust/core/lexer/token.rs +86 -0
- package/rust/core/mod.rs +6 -2
- package/rust/core/parser/driver.rs +331 -0
- package/rust/core/parser/handler/arrow_call.rs +126 -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 +112 -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 +229 -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 +227 -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/duration.rs +8 -0
- package/rust/core/shared/mod.rs +2 -0
- package/rust/core/shared/value.rs +28 -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/lib.rs +161 -1
- package/rust/main.rs +46 -30
- package/rust/utils/file.rs +35 -0
- package/rust/utils/logger.rs +108 -34
- package/rust/utils/mod.rs +3 -2
- 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/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
|
@@ -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
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
12
|
+

|
|
13
|
+
|
|
14
|
+

|
|
15
|
+

|
|
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)
|
|
@@ -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
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
12
|
+

|
|
13
|
+
|
|
14
|
+

|
|
15
|
+

|
|
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)
|
|
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
|
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
2
|
import { execSync } from "child_process";
|
|
4
3
|
|
|
5
4
|
export const fetchVersion = async (projectVersionPath: string) => {
|
|
6
|
-
// Lire le fichier
|
|
7
5
|
const data = JSON.parse(fs.readFileSync(projectVersionPath, "utf-8"));
|
|
8
6
|
|
|
9
|
-
// Incrémenter le numéro de build
|
|
10
7
|
data.build = (data.build || 0) + 1;
|
|
11
8
|
|
|
12
|
-
// Récupérer le dernier hash git
|
|
13
9
|
try {
|
|
14
10
|
const commit = execSync("git rev-parse HEAD").toString().trim();
|
|
15
11
|
data.lastCommit = commit;
|
|
16
12
|
} catch (err) {
|
|
17
|
-
console.warn("⚠️
|
|
13
|
+
console.warn("⚠️ Unable to fetch git commit hash. Ensure you are in a git repository.");
|
|
18
14
|
}
|
|
19
15
|
|
|
20
|
-
// Écrire la mise à jour
|
|
21
16
|
fs.writeFileSync(projectVersionPath, JSON.stringify(data, null, 2));
|
|
22
17
|
}
|
|
23
18
|
|
package/examples/exported.deva
DELETED
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
|
package/rust/core/parser/at.rs
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
use crate::core::types::{
|
|
2
|
-
parser::Parser,
|
|
3
|
-
statement::{ Statement, StatementKind },
|
|
4
|
-
token::TokenKind,
|
|
5
|
-
variable::VariableValue,
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
pub fn parse_at(parser: &mut Parser) -> Result<Statement, String> {
|
|
9
|
-
let token = parser.peek().ok_or("Unexpected EOF")?.clone();
|
|
10
|
-
|
|
11
|
-
if token.kind != TokenKind::At {
|
|
12
|
-
return Err(format!("Expected '@', found {:?}", token.kind));
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
parser.next();
|
|
16
|
-
|
|
17
|
-
let identifier_token = parser.peek().ok_or("Expected identifier after '@'")?.clone();
|
|
18
|
-
if identifier_token.kind != TokenKind::Identifier {
|
|
19
|
-
return Err(format!("Expected Identifier, found {:?}", identifier_token.kind));
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
match identifier_token.lexeme.as_str() {
|
|
23
|
-
"export" => {
|
|
24
|
-
parser.next();
|
|
25
|
-
|
|
26
|
-
if let Some(next_token) = parser.peek() {
|
|
27
|
-
if next_token.kind == TokenKind::LBrace {
|
|
28
|
-
parser.next(); // Consomme le LBrace
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
let exportable_tokens = parser.collect_until(|t| { t.kind == TokenKind::RBrace });
|
|
33
|
-
|
|
34
|
-
exportable_tokens.iter().for_each(|t| {
|
|
35
|
-
let variable_value = parser.variable_table
|
|
36
|
-
.get(&t.lexeme)
|
|
37
|
-
.cloned()
|
|
38
|
-
.unwrap_or_else(|| VariableValue::Text(t.lexeme.clone()));
|
|
39
|
-
|
|
40
|
-
parser.export_table.exports.insert(t.lexeme.clone(), variable_value);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
return Ok(Statement {
|
|
44
|
-
kind: StatementKind::Export,
|
|
45
|
-
value: VariableValue::Array(exportable_tokens),
|
|
46
|
-
indent: token.indent,
|
|
47
|
-
line: token.line,
|
|
48
|
-
column: token.column,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
"import" => {
|
|
52
|
-
parser.next();
|
|
53
|
-
|
|
54
|
-
if let Some(next_token) = parser.peek() {
|
|
55
|
-
if next_token.kind == TokenKind::LBrace {
|
|
56
|
-
parser.next();
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
let importable_tokens = parser.collect_until(|t| { t.kind == TokenKind::RBrace });
|
|
61
|
-
|
|
62
|
-
parser.next();
|
|
63
|
-
|
|
64
|
-
if let Some(from_token) = parser.peek() {
|
|
65
|
-
if from_token.kind == TokenKind::Identifier && from_token.lexeme == "from" {
|
|
66
|
-
parser.next();
|
|
67
|
-
} else {
|
|
68
|
-
return Err(format!("Expected 'from', found {:?}", from_token.kind));
|
|
69
|
-
}
|
|
70
|
-
} else {
|
|
71
|
-
return Err("Expected 'from' after import declaration".into());
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
let source_token = parser.peek().ok_or("Expected source after 'from'")?.clone();
|
|
75
|
-
if source_token.kind != TokenKind::String {
|
|
76
|
-
return Err(format!("Expected String, found {:?}", source_token.kind));
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
let statement = Statement {
|
|
80
|
-
kind: StatementKind::Import {
|
|
81
|
-
names: importable_tokens
|
|
82
|
-
.iter()
|
|
83
|
-
.map(|t| t.lexeme.clone())
|
|
84
|
-
.collect(),
|
|
85
|
-
source: source_token.lexeme.clone(),
|
|
86
|
-
},
|
|
87
|
-
value: VariableValue::Array(importable_tokens),
|
|
88
|
-
indent: token.indent,
|
|
89
|
-
line: token.line,
|
|
90
|
-
column: token.column,
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
return Ok(statement);
|
|
94
|
-
}
|
|
95
|
-
"load" => {
|
|
96
|
-
parser.next();
|
|
97
|
-
|
|
98
|
-
let source_token = parser.peek().ok_or("Expected source after load")?.clone();
|
|
99
|
-
if source_token.kind != TokenKind::String {
|
|
100
|
-
return Err(format!("Expected String, found {:?}", source_token.kind));
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
parser.next();
|
|
104
|
-
|
|
105
|
-
let as_token = parser.peek().ok_or("Expected 'as' after load")?.clone();
|
|
106
|
-
if as_token.kind != TokenKind::Identifier || as_token.lexeme != "as" {
|
|
107
|
-
return Err(format!("Expected 'as', found {:?}", as_token.kind));
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
parser.next();
|
|
111
|
-
|
|
112
|
-
let alias_token = parser.peek().ok_or("Expected alias after load")?.clone();
|
|
113
|
-
if alias_token.kind != TokenKind::Identifier {
|
|
114
|
-
return Err(format!("Expected Identifier, found {:?}", alias_token.kind));
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
parser.next();
|
|
118
|
-
|
|
119
|
-
let statement = Statement {
|
|
120
|
-
kind: StatementKind::Load {
|
|
121
|
-
source: source_token.lexeme.clone(),
|
|
122
|
-
alias: alias_token.lexeme.clone(),
|
|
123
|
-
},
|
|
124
|
-
value: VariableValue::Text(alias_token.lexeme.clone()),
|
|
125
|
-
indent: token.indent,
|
|
126
|
-
line: token.line,
|
|
127
|
-
column: token.column,
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
return Ok(statement);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
_ => {
|
|
134
|
-
return Err(
|
|
135
|
-
format!(
|
|
136
|
-
"Expected 'export', 'import' or 'load', found '{}'",
|
|
137
|
-
identifier_token.lexeme
|
|
138
|
-
)
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
package/rust/core/parser/bank.rs
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
use crate::core::types::{
|
|
2
|
-
parser::Parser,
|
|
3
|
-
statement::{ Statement, StatementKind },
|
|
4
|
-
store::GlobalStore,
|
|
5
|
-
token::TokenKind,
|
|
6
|
-
variable::VariableValue,
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
pub fn parse_bank(
|
|
10
|
-
parser: &mut Parser,
|
|
11
|
-
global_store: &mut GlobalStore
|
|
12
|
-
) -> Result<Statement, String> {
|
|
13
|
-
let token = parser.peek().ok_or("Unexpected EOF")?.clone();
|
|
14
|
-
|
|
15
|
-
let mut bank_name = String::new();
|
|
16
|
-
|
|
17
|
-
if parser.next().map(|t| t.kind.clone()) != Some(TokenKind::Bank) {
|
|
18
|
-
return Err("Expected 'bank' keyword".to_string());
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if let Some(token) = parser.next() {
|
|
22
|
-
if token.kind == TokenKind::Identifier {
|
|
23
|
-
bank_name = token.lexeme.clone();
|
|
24
|
-
} else if token.kind == TokenKind::String {
|
|
25
|
-
bank_name = token.lexeme.trim_matches('"').to_string();
|
|
26
|
-
} else if token.kind == TokenKind::Number {
|
|
27
|
-
bank_name = token.lexeme.clone();
|
|
28
|
-
} else {
|
|
29
|
-
return Err(format!("Expected bank name, found {:?}", token.kind));
|
|
30
|
-
}
|
|
31
|
-
} else {
|
|
32
|
-
return Err("Expected bank name after 'bank' keyword".to_string());
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
Ok(Statement {
|
|
36
|
-
kind: StatementKind::Bank,
|
|
37
|
-
value: VariableValue::Text(bank_name.clone()),
|
|
38
|
-
indent: token.indent,
|
|
39
|
-
line: token.line,
|
|
40
|
-
column: token.column,
|
|
41
|
-
})
|
|
42
|
-
}
|