@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
package/docs/ROADMAP.md
CHANGED
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
Devalang is a work in progress. Here’s what we’re planning next:
|
|
8
8
|
|
|
9
|
+
## Completed
|
|
10
|
+
|
|
11
|
+
- ✅ **Audio engine**: Integrate the audio engine for sound playback.
|
|
9
12
|
- ✅ **Basic syntax**: Implement the core syntax for Devalang, including data types and basic statements.
|
|
13
|
+
- ✅ **Watch mode**: Add a watch mode to automatically rebuild on file changes.
|
|
10
14
|
- ✅ **Module system**: Add support for importing and exporting variables between files using `@import` and `@export`.
|
|
11
15
|
- ✅ **AST generation**: Implement the Abstract Syntax Tree (AST) generation for debugging and future compilation.
|
|
12
16
|
- ✅ **Basic data types**: Support strings, numbers, booleans, maps, and arrays.
|
|
@@ -16,12 +20,11 @@ Devalang is a work in progress. Here’s what we’re planning next:
|
|
|
16
20
|
- ✅ **Instruction calls**: Add support for instruction calls with parameters (e.g. `.kick auto {reverb:10, decay:20}`).
|
|
17
21
|
- ✅ **Let assignments**: Implement `let` assignments for storing reusable values.
|
|
18
22
|
- ✅ **Sample loading**: Add `@load` assignment to load samples (.mp3, .wav) for use as values.
|
|
23
|
+
- ✅ **WASM support**: Compile Devalang to WebAssembly for use in web applications and other environments.
|
|
24
|
+
- ✅ **VSCode extension**: Create a VSCode extension for syntax highlighting and code completion.
|
|
25
|
+
|
|
26
|
+
## Upcoming
|
|
19
27
|
|
|
20
|
-
- ⏳ **
|
|
21
|
-
- ⏳ **
|
|
22
|
-
- ⏳ **Other statements**: Implement `if`, `else`, and other control structures.
|
|
23
|
-
- ⏳ **Pattern and group statements**: Add support for `@pattern` and `@group` to organize code.
|
|
24
|
-
- ⏳ **Watch mode**: Add a watch mode to automatically rebuild on file changes.
|
|
25
|
-
- ⏳ **Functions**: Add support for defining and calling functions.
|
|
26
|
-
- ⏳ **Audio engine**: Integrate the audio engine for sound playback.
|
|
28
|
+
- ⏳ **Smart modules**: Let Devalang detect and use groups, samples, and variables without needing to import them manually.
|
|
29
|
+
- ⏳ **Other statements**: Implement `pattern`, `function`, and other control structures.
|
|
27
30
|
- ⏳ **Testing**: Expand test coverage for all features.
|
package/docs/SYNTAX.md
CHANGED
|
@@ -17,6 +17,18 @@ The engine uses indentation to define blocks, similar to Python. Each block must
|
|
|
17
17
|
<details>
|
|
18
18
|
<summary>Show available types</summary>
|
|
19
19
|
|
|
20
|
+
### Duration
|
|
21
|
+
|
|
22
|
+
Duration is defined using a number. It represents the length of a sound in milliseconds.
|
|
23
|
+
|
|
24
|
+
```deva
|
|
25
|
+
let duration = 1000
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Will play a sound for 1000 milliseconds (1 second).
|
|
29
|
+
|
|
30
|
+
NOTE: Other time units like seconds or beats are not supported yet, but will be in the future.
|
|
31
|
+
|
|
20
32
|
### String
|
|
21
33
|
|
|
22
34
|
Strings are defined using double quotes.
|
|
@@ -46,7 +58,7 @@ let boolean = false
|
|
|
46
58
|
Maps are key-value pairs defined using curly braces. Keys are strings, and values can be of any type (string, number, boolean, map, or array).
|
|
47
59
|
|
|
48
60
|
```deva
|
|
49
|
-
let map = {myKey: 99}
|
|
61
|
+
let map = { myKey: 99 }
|
|
50
62
|
```
|
|
51
63
|
|
|
52
64
|
### Array
|
|
@@ -81,13 +93,17 @@ bank 808
|
|
|
81
93
|
|
|
82
94
|
Modules can be imported and exported to share variables between different files.
|
|
83
95
|
|
|
96
|
+
> ⚠️ The import/export system is still experimental and may change in the future.
|
|
97
|
+
>
|
|
98
|
+
> You must explicitly declare imports and exports in each file — Devalang does not automatically detect or resolve them.
|
|
99
|
+
|
|
84
100
|
Exporting variables from a module :
|
|
85
101
|
|
|
86
102
|
```deva
|
|
87
103
|
# exported.deva
|
|
88
104
|
|
|
89
105
|
let exportedIterator = 10
|
|
90
|
-
let exportedParams = {drive: 50, decay: 30}
|
|
106
|
+
let exportedParams = { drive: 50, decay: 30 }
|
|
91
107
|
|
|
92
108
|
@export { exportedIterator, exportedParams }
|
|
93
109
|
```
|
|
@@ -103,22 +119,13 @@ loop exportedIterator:
|
|
|
103
119
|
.kick auto exportedParams
|
|
104
120
|
```
|
|
105
121
|
|
|
106
|
-
###
|
|
107
|
-
|
|
108
|
-
Usage : `.<trigger-name> <duration> <effects-map>`
|
|
122
|
+
### Loading Samples
|
|
109
123
|
|
|
110
|
-
|
|
111
|
-
You can also create custom triggers using the `@load` directive.
|
|
124
|
+
You can load your own samples and use them in your music.
|
|
112
125
|
|
|
113
|
-
|
|
114
|
-
.kick
|
|
115
|
-
.kick 1/4
|
|
116
|
-
.kick auto {reverb: 50, decay: 30}
|
|
117
|
-
```
|
|
126
|
+
Load usage : `@load <path> as <name>`
|
|
118
127
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
Same usage as built-in triggers, but with custom audio files or effects.
|
|
128
|
+
Trigger usage : `.<name> <duration> <params>`
|
|
122
129
|
|
|
123
130
|
```deva
|
|
124
131
|
@load "./path/to/instrument.mp3" as mySample
|
|
@@ -126,7 +133,7 @@ Same usage as built-in triggers, but with custom audio files or effects.
|
|
|
126
133
|
.mySample auto {reverb: 50, drive: 25}
|
|
127
134
|
```
|
|
128
135
|
|
|
129
|
-
###
|
|
136
|
+
### Variables
|
|
130
137
|
|
|
131
138
|
Variables are defined using the `let` keyword, followed by the variable name and its value. The value can be of any type (string, number, boolean, map, or array).
|
|
132
139
|
|
|
@@ -134,11 +141,11 @@ Variables are defined using the `let` keyword, followed by the variable name and
|
|
|
134
141
|
let number = 0
|
|
135
142
|
let boolean = true
|
|
136
143
|
let string = "string"
|
|
137
|
-
let map = {myKey: 200}
|
|
144
|
+
let map = { myKey: 200 }
|
|
138
145
|
let array = [0, 1, 2]
|
|
139
146
|
```
|
|
140
147
|
|
|
141
|
-
###
|
|
148
|
+
### Loops
|
|
142
149
|
|
|
143
150
|
Loops are defined using the `loop` keyword, followed by the number of iterations. The body of the loop is indented.
|
|
144
151
|
|
|
@@ -146,3 +153,78 @@ Loops are defined using the `loop` keyword, followed by the number of iterations
|
|
|
146
153
|
loop 10:
|
|
147
154
|
# ...
|
|
148
155
|
```
|
|
156
|
+
|
|
157
|
+
### Groups
|
|
158
|
+
|
|
159
|
+
Groups are defined using the `group` keyword, followed by the group name. The body of the group is indented.
|
|
160
|
+
|
|
161
|
+
Groups allow you to organize your code into reusable blocks. They can be called or spawned later in the code.
|
|
162
|
+
|
|
163
|
+
```deva
|
|
164
|
+
group myGroup:
|
|
165
|
+
# ...
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Conditions
|
|
169
|
+
|
|
170
|
+
Conditions are defined using the `if` keyword, followed by a condition. The body of the condition is indented.
|
|
171
|
+
|
|
172
|
+
```deva
|
|
173
|
+
if myCondition:
|
|
174
|
+
# ...
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
You can also use `else` and `else if` for alternative branches:
|
|
178
|
+
|
|
179
|
+
```deva
|
|
180
|
+
if myCondition:
|
|
181
|
+
# ...
|
|
182
|
+
else if anotherCondition:
|
|
183
|
+
# ...
|
|
184
|
+
else:
|
|
185
|
+
# ...
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Calling Groups (Sequential Execution)
|
|
189
|
+
|
|
190
|
+
Groups can be called using the `call` keyword, which executes only the group in sequence.
|
|
191
|
+
|
|
192
|
+
> ⚠️ `call` only works on `group` declarations. It does not apply to other statements.
|
|
193
|
+
|
|
194
|
+
This executes the entire group in the current execution thread, following a sequential order.
|
|
195
|
+
|
|
196
|
+
```deva
|
|
197
|
+
call myGroup
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Spawning Groups (Parallel Execution)
|
|
201
|
+
|
|
202
|
+
Groups can be spawned using the `spawn` keyword, which executes only the group in parallel.
|
|
203
|
+
|
|
204
|
+
> ⚠️ spawn also only works on group declarations. It does not make the group’s content parallel unless it explicitly uses spawn inside.
|
|
205
|
+
|
|
206
|
+
This runs the entire group in a separate execution thread, allowing it to play alongside other actions.
|
|
207
|
+
|
|
208
|
+
```deva
|
|
209
|
+
spawn myGroup
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Synthesizers
|
|
213
|
+
|
|
214
|
+
Synthesizers are defined using the `synth` keyword, followed by the synthesizer type. You can create a synthesizer instance and use it to play notes.
|
|
215
|
+
|
|
216
|
+
```deva
|
|
217
|
+
let mySynth = synth sine
|
|
218
|
+
|
|
219
|
+
mySynth -> note(C4, { duration: 400 })
|
|
220
|
+
mySynth -> note(G4, { duration: 400 })
|
|
221
|
+
mySynth -> note(E4, { duration: 600 })
|
|
222
|
+
mySynth -> note(A4, { duration: 400 })
|
|
223
|
+
mySynth -> note(F4, { duration: 800 })
|
|
224
|
+
mySynth -> note(D4, { duration: 400 })
|
|
225
|
+
mySynth -> note(B3, { duration: 600 })
|
|
226
|
+
|
|
227
|
+
# You can use call or spawn to execute the synthesizer actions in sequence or parallel.
|
|
228
|
+
|
|
229
|
+
call mySynth
|
|
230
|
+
```
|
package/docs/TODO.md
CHANGED
|
@@ -8,26 +8,29 @@ This is a list of tasks and features to be implemented in Devalang. Note that th
|
|
|
8
8
|
|
|
9
9
|
## Commands
|
|
10
10
|
|
|
11
|
-
- [
|
|
12
|
-
- [
|
|
13
|
-
- [
|
|
14
|
-
- [ ] Implement
|
|
11
|
+
- [x] Init project
|
|
12
|
+
- [x] Implement init command
|
|
13
|
+
- [x] Implement template selector
|
|
14
|
+
- [ ] Implement project name validation
|
|
15
|
+
- [x] Template
|
|
16
|
+
- [x] Implement template list
|
|
17
|
+
- [x] Implement template info
|
|
15
18
|
- [x] Checking
|
|
16
|
-
- [
|
|
19
|
+
- [x] Implement watch mode
|
|
17
20
|
- [ ] Implement debug mode
|
|
18
21
|
- [ ] Implement compilation mode
|
|
19
22
|
- [x] Building
|
|
20
|
-
- [
|
|
23
|
+
- [x] Implement watch mode
|
|
21
24
|
- [ ] Implement debug mode
|
|
22
25
|
- [ ] Implement compilation mode
|
|
23
26
|
- [ ] Implement compression mode
|
|
24
|
-
- [
|
|
25
|
-
- [
|
|
26
|
-
- [
|
|
27
|
+
- [x] Play
|
|
28
|
+
- [x] Implement Audio Engine
|
|
29
|
+
- [x] Implement loop mode
|
|
27
30
|
|
|
28
31
|
## Core components
|
|
29
32
|
|
|
30
|
-
- [
|
|
33
|
+
- [x] Audio Engine
|
|
31
34
|
- [x] Lexer
|
|
32
35
|
- [x] Parser
|
|
33
36
|
- [x] Preprocessor
|
|
@@ -36,31 +39,31 @@ This is a list of tasks and features to be implemented in Devalang. Note that th
|
|
|
36
39
|
|
|
37
40
|
## Syntax elements
|
|
38
41
|
|
|
39
|
-
- [
|
|
42
|
+
- [x] #
|
|
40
43
|
- [x] @import
|
|
41
44
|
- [x] @export
|
|
42
|
-
- [ ] @group
|
|
43
|
-
- [ ] @pattern
|
|
44
|
-
- [ ] @function
|
|
45
45
|
- [x] @load
|
|
46
46
|
- [ ] @include
|
|
47
|
+
- [ ] function
|
|
48
|
+
- [ ] pattern
|
|
49
|
+
- [x] group
|
|
50
|
+
- [x] call
|
|
51
|
+
- [x] spawn
|
|
52
|
+
- [x] sleep
|
|
47
53
|
- [x] bpm
|
|
48
54
|
- [x] bank
|
|
49
55
|
- [x] loop
|
|
50
56
|
- [x] let
|
|
51
|
-
- [
|
|
52
|
-
- [
|
|
53
|
-
- [
|
|
57
|
+
- [x] if
|
|
58
|
+
- [x] else
|
|
59
|
+
- [x] else if
|
|
54
60
|
|
|
55
|
-
##
|
|
61
|
+
## Triggers
|
|
56
62
|
|
|
57
|
-
- [x]
|
|
58
|
-
- [
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
- [ ]
|
|
63
|
-
- [ ]
|
|
64
|
-
- [ ] .synth
|
|
65
|
-
- [ ] .bass
|
|
66
|
-
- [ ] .pad
|
|
63
|
+
- [x] Built-in triggers
|
|
64
|
+
- [x] Custom triggers
|
|
65
|
+
|
|
66
|
+
## Other TODOs
|
|
67
|
+
|
|
68
|
+
- [ ] Comment all core components
|
|
69
|
+
- [ ] Add unit tests for all core components
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# This file demonstrates the use of conditional blocks in Devalang.
|
|
2
|
+
|
|
3
|
+
@import { duration, default_bank, params, loopCount, tempo } from "./variables.deva"
|
|
4
|
+
@import { myGroup } from "./group.deva"
|
|
5
|
+
|
|
6
|
+
@load "./samples/kick-808.wav" as kickCustom
|
|
7
|
+
@load "./samples/hat-808.wav" as hatCustom
|
|
8
|
+
|
|
9
|
+
group conditionBlock:
|
|
10
|
+
if tempo > 120:
|
|
11
|
+
# Will be executed if the condition is true
|
|
12
|
+
.kickCustom auto
|
|
13
|
+
else if tempo > 155:
|
|
14
|
+
# Will be executed if the condition is false
|
|
15
|
+
.hatCustom auto
|
|
16
|
+
else:
|
|
17
|
+
.kickCustom auto
|
|
18
|
+
.hatCustom auto
|
|
19
|
+
|
|
20
|
+
@export { conditionBlock }
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# This file demonstrates the use of grouping in Devalang.
|
|
2
|
+
|
|
3
|
+
@import { duration, default_bank, params, loopCount, tempo } from "./variables.deva"
|
|
4
|
+
|
|
5
|
+
@load "./samples/kick-808.wav" as kickCustom
|
|
6
|
+
@load "./samples/hat-808.wav" as hatCustom
|
|
7
|
+
|
|
8
|
+
group myGroup:
|
|
9
|
+
.kickCustom duration params
|
|
10
|
+
.hatCustom duration params
|
|
11
|
+
|
|
12
|
+
@export { myGroup }
|
package/examples/index.deva
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# This file demonstrates the use of main features in Devalang.
|
|
2
|
+
|
|
3
|
+
@import { duration, default_bank, params, loopCount, tempo } from "./variables.deva"
|
|
4
|
+
@import { myLead } from "./synth.deva"
|
|
5
|
+
@import { myLoop } from "./loop.deva"
|
|
6
|
+
|
|
7
|
+
@load "./samples/kick-808.wav" as kickCustom
|
|
8
|
+
@load "./samples/hat-808.wav" as hatCustom
|
|
3
9
|
|
|
4
10
|
bpm tempo
|
|
5
11
|
|
|
6
12
|
bank default_bank
|
|
7
13
|
|
|
8
|
-
|
|
9
|
-
|
|
14
|
+
group myTrack:
|
|
15
|
+
spawn myLoop
|
|
16
|
+
spawn myLead
|
|
17
|
+
|
|
18
|
+
call myTrack
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# This file demonstrates the use of a loop in Devalang.
|
|
2
|
+
|
|
3
|
+
@import { duration, default_bank, params, loopCount, tempo } from "./variables.deva"
|
|
4
|
+
|
|
5
|
+
@load "./samples/kick-808.wav" as kickCustom
|
|
6
|
+
@load "./samples/hat-808.wav" as hatCustom
|
|
7
|
+
|
|
8
|
+
group myLoop:
|
|
9
|
+
loop loopCount:
|
|
10
|
+
.kickCustom duration params
|
|
11
|
+
|
|
12
|
+
# Uncomment the next line (.hatCustom) while executing "play" command
|
|
13
|
+
# with `--repeat` option to see magic happen !
|
|
14
|
+
# .hatCustom duration params
|
|
15
|
+
|
|
16
|
+
@export { myLoop }
|
|
Binary file
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# This file defines a simple synth lead using Devalang's syntax.
|
|
2
|
+
|
|
3
|
+
group myLead:
|
|
4
|
+
let mySynth = synth sine
|
|
5
|
+
|
|
6
|
+
mySynth -> note(C4, { duration: 400 })
|
|
7
|
+
mySynth -> note(G4, { duration: 400 })
|
|
8
|
+
mySynth -> note(E4, { duration: 600 })
|
|
9
|
+
mySynth -> note(A4, { duration: 400 })
|
|
10
|
+
mySynth -> note(F4, { duration: 800 })
|
|
11
|
+
mySynth -> note(D4, { duration: 400 })
|
|
12
|
+
mySynth -> note(B3, { duration: 600 })
|
|
13
|
+
|
|
14
|
+
@export { myLead }
|
package/out-tsc/bin/devalang.exe
CHANGED
|
Binary file
|
|
@@ -16,19 +16,15 @@ exports.fetchVersion = void 0;
|
|
|
16
16
|
const fs_1 = __importDefault(require("fs"));
|
|
17
17
|
const child_process_1 = require("child_process");
|
|
18
18
|
const fetchVersion = (projectVersionPath) => __awaiter(void 0, void 0, void 0, function* () {
|
|
19
|
-
// Lire le fichier
|
|
20
19
|
const data = JSON.parse(fs_1.default.readFileSync(projectVersionPath, "utf-8"));
|
|
21
|
-
// Incrémenter le numéro de build
|
|
22
20
|
data.build = (data.build || 0) + 1;
|
|
23
|
-
// Récupérer le dernier hash git
|
|
24
21
|
try {
|
|
25
22
|
const commit = (0, child_process_1.execSync)("git rev-parse HEAD").toString().trim();
|
|
26
23
|
data.lastCommit = commit;
|
|
27
24
|
}
|
|
28
25
|
catch (err) {
|
|
29
|
-
console.warn("⚠️
|
|
26
|
+
console.warn("⚠️ Unable to fetch git commit hash. Ensure you are in a git repository.");
|
|
30
27
|
}
|
|
31
|
-
// Écrire la mise à jour
|
|
32
28
|
fs_1.default.writeFileSync(projectVersionPath, JSON.stringify(data, null, 2));
|
|
33
29
|
});
|
|
34
30
|
exports.fetchVersion = fetchVersion;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devaloop/devalang",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.0.1-alpha.
|
|
4
|
+
"version": "0.0.1-alpha.10",
|
|
5
5
|
"description": "Write music like code. Devalang is a domain-specific language (DSL) for sound designers and music hackers. Compose, automate, and control sound — in plain text.",
|
|
6
6
|
"main": "out-tsc/index.js",
|
|
7
7
|
"bin": {
|
|
@@ -9,13 +9,14 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"prepublish": "cargo build --release && npm run script:postbuild",
|
|
12
|
-
"rust:dev": "cargo run",
|
|
13
12
|
"rust:dev:build": "cargo run build --entry examples --output output",
|
|
14
13
|
"rust:dev:check": "cargo run check --entry examples --output output",
|
|
14
|
+
"rust:wasm:web": "wasm-pack build --target=web --no-default-features",
|
|
15
|
+
"rust:wasm:node": "wasm-pack build --target=nodejs --no-default-features",
|
|
15
16
|
"script:postbuild": "tsc && node out-tsc/scripts/postbuild.js",
|
|
16
17
|
"script:version:bump": "tsc && node out-tsc/scripts/version/index.js"
|
|
17
18
|
},
|
|
18
|
-
"homepage": "https://
|
|
19
|
+
"homepage": "https://devalang.com",
|
|
19
20
|
"keywords": [
|
|
20
21
|
"devalang",
|
|
21
22
|
"music",
|
|
@@ -40,4 +41,4 @@
|
|
|
40
41
|
"dependencies": {
|
|
41
42
|
"@types/node": "^24.0.3"
|
|
42
43
|
}
|
|
43
|
-
}
|
|
44
|
+
}
|
package/project-version.json
CHANGED
package/rust/cli/build.rs
CHANGED
|
@@ -1,51 +1,137 @@
|
|
|
1
|
-
use std::{ thread, time::Duration };
|
|
2
|
-
|
|
3
1
|
use crate::{
|
|
2
|
+
config::Config,
|
|
4
3
|
core::{
|
|
5
|
-
builder::
|
|
6
|
-
debugger::
|
|
7
|
-
|
|
4
|
+
builder::Builder,
|
|
5
|
+
debugger::{
|
|
6
|
+
lexer::write_lexer_log_file,
|
|
7
|
+
preprocessor::write_preprocessor_log_file,
|
|
8
|
+
store::write_store_log_file,
|
|
9
|
+
},
|
|
10
|
+
preprocessor::loader::ModuleLoader,
|
|
11
|
+
store::global::GlobalStore,
|
|
12
|
+
utils::path::{ find_entry_file, normalize_path },
|
|
8
13
|
},
|
|
9
|
-
|
|
10
|
-
utils::{ loader::with_spinner, logger::log_message, path::{ find_entry_file, normalize_path } },
|
|
14
|
+
utils::{ logger::{ LogLevel, Logger }, spinner::with_spinner, watcher::watch_directory },
|
|
11
15
|
};
|
|
16
|
+
use std::{ thread, time::Duration };
|
|
17
|
+
|
|
18
|
+
#[cfg(feature = "cli")]
|
|
19
|
+
pub fn handle_build_command(
|
|
20
|
+
config: Option<Config>,
|
|
21
|
+
entry: Option<String>,
|
|
22
|
+
output: Option<String>,
|
|
23
|
+
watch: bool
|
|
24
|
+
) {
|
|
25
|
+
let fetched_entry = if entry.is_none() {
|
|
26
|
+
config
|
|
27
|
+
.as_ref()
|
|
28
|
+
.and_then(|c| c.defaults.entry.clone())
|
|
29
|
+
.unwrap_or_else(|| "".to_string())
|
|
30
|
+
} else {
|
|
31
|
+
entry.clone().unwrap_or_else(|| "".to_string())
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
let fetched_output = if output.is_none() {
|
|
35
|
+
config
|
|
36
|
+
.as_ref()
|
|
37
|
+
.and_then(|c| c.defaults.output.clone())
|
|
38
|
+
.unwrap_or_else(|| "".to_string())
|
|
39
|
+
} else {
|
|
40
|
+
output.clone().unwrap_or_else(|| "".to_string())
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
let fetched_watch = if watch {
|
|
44
|
+
watch
|
|
45
|
+
} else {
|
|
46
|
+
config
|
|
47
|
+
.as_ref()
|
|
48
|
+
.and_then(|c| c.defaults.watch)
|
|
49
|
+
.unwrap_or(false)
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
let logger = Logger::new();
|
|
53
|
+
|
|
54
|
+
if fetched_entry.is_empty() {
|
|
55
|
+
logger.log_message(
|
|
56
|
+
LogLevel::Error,
|
|
57
|
+
"Entry path is not specified. Please provide a valid entry path."
|
|
58
|
+
);
|
|
59
|
+
std::process::exit(1);
|
|
60
|
+
}
|
|
61
|
+
if fetched_output.is_empty() {
|
|
62
|
+
logger.log_message(
|
|
63
|
+
LogLevel::Error,
|
|
64
|
+
"Output directory is not specified. Please provide a valid output directory."
|
|
65
|
+
);
|
|
66
|
+
std::process::exit(1);
|
|
67
|
+
}
|
|
12
68
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
69
|
+
let entry_file = find_entry_file(&fetched_entry).unwrap_or_else(|| {
|
|
70
|
+
logger.log_message(
|
|
71
|
+
LogLevel::Error,
|
|
72
|
+
&format!("❌ index.deva not found in directory: {}", fetched_entry)
|
|
73
|
+
);
|
|
16
74
|
std::process::exit(1);
|
|
17
75
|
});
|
|
18
76
|
|
|
77
|
+
// SECTION Begin build
|
|
78
|
+
if fetched_watch {
|
|
79
|
+
begin_build(entry_file.clone(), fetched_output.clone());
|
|
80
|
+
|
|
81
|
+
logger.log_message(
|
|
82
|
+
LogLevel::Watcher,
|
|
83
|
+
&format!("Watching for changes in '{}'...", fetched_entry)
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
watch_directory(entry_file.clone(), move || {
|
|
87
|
+
logger.log_message(LogLevel::Watcher, "Detected changes, re-building...");
|
|
88
|
+
|
|
89
|
+
begin_build(entry_file.clone(), fetched_output.clone());
|
|
90
|
+
}).unwrap();
|
|
91
|
+
} else {
|
|
92
|
+
begin_build(entry_file.clone(), fetched_output.clone());
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
fn begin_build(entry: String, output: String) {
|
|
19
97
|
let spinner = with_spinner("Building...", || {
|
|
20
98
|
thread::sleep(Duration::from_millis(800));
|
|
21
99
|
});
|
|
22
100
|
|
|
23
101
|
let duration = std::time::Instant::now();
|
|
24
102
|
|
|
25
|
-
let normalized_entry_file = normalize_path(&
|
|
103
|
+
let normalized_entry_file = normalize_path(&entry);
|
|
26
104
|
let normalized_output_dir = normalize_path(&output);
|
|
27
105
|
|
|
28
|
-
let global_store =
|
|
106
|
+
let mut global_store = GlobalStore::new();
|
|
107
|
+
let module_loader = ModuleLoader::new(&normalized_entry_file, &normalized_output_dir);
|
|
29
108
|
|
|
30
|
-
|
|
31
|
-
|
|
109
|
+
// SECTION Load
|
|
110
|
+
// NOTE: We use modules in the build command, so we need to load them
|
|
111
|
+
let (modules_tokens, modules_statements) = module_loader.load_all_modules(&mut global_store);
|
|
32
112
|
|
|
33
|
-
|
|
113
|
+
// SECTION Write logs
|
|
114
|
+
write_lexer_log_file(&normalized_output_dir, "lexer_tokens.log", modules_tokens.clone());
|
|
115
|
+
write_preprocessor_log_file(
|
|
116
|
+
&normalized_output_dir,
|
|
117
|
+
"resolved_statements.log",
|
|
118
|
+
modules_statements.clone()
|
|
119
|
+
);
|
|
120
|
+
write_store_log_file(&normalized_output_dir, "global_store.log", global_store.modules.clone());
|
|
34
121
|
|
|
35
|
-
|
|
122
|
+
// SECTION Building AST and Audio
|
|
123
|
+
let builder = Builder::new();
|
|
124
|
+
builder.build_ast(&modules_statements, &normalized_output_dir);
|
|
125
|
+
builder.build_audio(&modules_statements, &normalized_output_dir, &mut global_store);
|
|
36
126
|
|
|
37
|
-
|
|
38
|
-
|
|
127
|
+
// SECTION Logging
|
|
128
|
+
let logger = Logger::new();
|
|
39
129
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
130
|
+
let success_message = format!(
|
|
131
|
+
"Build completed successfully in {:.2?}. Output files written to: '{}'",
|
|
132
|
+
duration.elapsed(),
|
|
133
|
+
normalized_output_dir
|
|
134
|
+
);
|
|
43
135
|
|
|
44
|
-
|
|
45
|
-
"Build completed successfully in {:.2?}. Output files written to: '{}'",
|
|
46
|
-
duration.elapsed(),
|
|
47
|
-
normalized_output_dir
|
|
48
|
-
);
|
|
49
|
-
log_message(&success_message, "SUCCESS");
|
|
50
|
-
}
|
|
136
|
+
logger.log_message(LogLevel::Success, &success_message);
|
|
51
137
|
}
|