@devaloop/devalang 0.0.1-alpha.1 → 0.0.1-alpha.2
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 +3 -2
- package/README.md +30 -6
- package/docs/CHANGELOG.md +53 -0
- package/docs/COMMANDS.md +29 -6
- package/docs/CONFIG.md +28 -0
- package/docs/ROADMAP.md +1 -1
- package/docs/TODO.md +43 -15
- package/examples/index.deva +1 -1
- package/out-tsc/bin/devalang.exe +0 -0
- package/package.json +2 -2
- package/project-version.json +3 -3
- package/rust/cli/build.rs +58 -5
- package/rust/cli/check.rs +73 -17
- package/rust/cli/init.rs +77 -0
- package/rust/cli/mod.rs +2 -1
- package/rust/cli/template.rs +56 -0
- package/rust/core/lexer/at.rs +21 -0
- package/rust/core/lexer/brace.rs +41 -0
- package/rust/core/lexer/bracket.rs +41 -0
- package/rust/core/lexer/colon.rs +21 -0
- package/rust/core/lexer/comment.rs +30 -0
- package/rust/core/lexer/dot.rs +21 -0
- package/rust/core/lexer/driver.rs +286 -0
- package/rust/core/lexer/equal.rs +32 -0
- package/rust/core/lexer/identifier.rs +38 -0
- package/rust/core/lexer/indent.rs +47 -0
- package/rust/core/lexer/mod.rs +14 -333
- package/rust/core/lexer/newline.rs +23 -0
- package/rust/core/lexer/number.rs +31 -0
- package/rust/core/lexer/quote.rs +61 -0
- package/rust/core/parser/dot.rs +48 -18
- package/rust/core/preprocessor/module.rs +1 -1
- package/rust/core/types/cli.rs +53 -31
- package/rust/core/types/config.rs +15 -0
- package/rust/core/types/mod.rs +2 -1
- package/rust/main.rs +30 -19
- package/rust/utils/config.rs +13 -0
- package/rust/utils/file.rs +35 -0
- package/rust/utils/mod.rs +4 -1
- 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/cli/new.rs +0 -1
package/.devalang
ADDED
package/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "devalang"
|
|
3
|
-
version = "0.0.1-alpha.
|
|
3
|
+
version = "0.0.1-alpha.2"
|
|
4
4
|
authors = ["Devaloop <contact@devaloop.com>"]
|
|
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
|
license = "MIT"
|
|
@@ -42,4 +42,5 @@ serde-wasm-bindgen = "0.4"
|
|
|
42
42
|
nom_locate = "4.0.0"
|
|
43
43
|
chrono = "0.4"
|
|
44
44
|
crossterm = { version = "0.27", optional = true }
|
|
45
|
-
indicatif = "0.17"
|
|
45
|
+
indicatif = "0.17"
|
|
46
|
+
inquire = "0.7.5"
|
package/README.md
CHANGED
|
@@ -41,6 +41,7 @@ From studio sketches to live sets, Devalang gives you rhythmic control — with
|
|
|
41
41
|
- 🧩 Module system for importing and exporting variables between files (`@import`, `@export`)
|
|
42
42
|
- 📜 Structured AST generation for debugging and future compilation
|
|
43
43
|
- 🔢 Basic data types: strings, numbers, booleans, maps, arrays
|
|
44
|
+
- 👁️ Watch mode for `build` and `check` commands
|
|
44
45
|
- ⏱️ `bpm` assignment for setting tempo
|
|
45
46
|
- 🧱 `bank` declaration to define the instrument set
|
|
46
47
|
- 🔁 Looping system with fixed repetitions (`loop 4:`)
|
|
@@ -90,18 +91,40 @@ npm run rust:dev <command>
|
|
|
90
91
|
|
|
91
92
|
For more examples, see [docs/COMMANDS.md](./docs/COMMANDS.md)
|
|
92
93
|
|
|
93
|
-
|
|
94
|
+
### Initialize a new project
|
|
95
|
+
|
|
96
|
+
In the current directory
|
|
94
97
|
|
|
95
98
|
```bash
|
|
96
|
-
devalang
|
|
99
|
+
devalang init
|
|
97
100
|
```
|
|
98
101
|
|
|
99
|
-
|
|
102
|
+
Or use optional arguments to specify a directory name and a template
|
|
100
103
|
|
|
101
104
|
```bash
|
|
102
|
-
devalang
|
|
105
|
+
devalang init --name <project-name> --template <template-name>
|
|
103
106
|
```
|
|
104
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
|
+
|
|
105
128
|
## 📄 Syntax example
|
|
106
129
|
|
|
107
130
|
For more examples, see [docs/SYNTAX.md](./docs/SYNTAX.md)
|
|
@@ -127,7 +150,7 @@ loop 5:
|
|
|
127
150
|
|
|
128
151
|
let globalBpm = 120
|
|
129
152
|
let globalBank = 808
|
|
130
|
-
let kickDuration = 500
|
|
153
|
+
let kickDuration = 500
|
|
131
154
|
|
|
132
155
|
@export { globalBpm, globalBank, kickDuration }
|
|
133
156
|
```
|
|
@@ -145,7 +168,8 @@ For more info, see [docs/ROADMAP.md](./docs/ROADMAP.md)
|
|
|
145
168
|
|
|
146
169
|
- ⏳ Audio engine integration
|
|
147
170
|
- ⏳ Other statements (e.g `if`, `@group`, ...)
|
|
148
|
-
- ⏳
|
|
171
|
+
- ⏳ Cross-platform support (Linux, macOS)
|
|
172
|
+
- ⏳ More built-in instruments (e.g. snare, hi-hat, etc.)
|
|
149
173
|
|
|
150
174
|
## 🛡️ License
|
|
151
175
|
|
|
@@ -0,0 +1,53 @@
|
|
|
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
|
+
# Changelog
|
|
6
|
+
|
|
7
|
+
## Version 0.0.1-alpha.2 (2024-06-26)
|
|
8
|
+
|
|
9
|
+
### Commands
|
|
10
|
+
|
|
11
|
+
- Implemented `init` command to initialize a new Devalang project.
|
|
12
|
+
- Implemented `template` command to manage templates.
|
|
13
|
+
- Added `list` subcommand to list available templates.
|
|
14
|
+
- Added `info` subcommand to show information about a specific template.
|
|
15
|
+
- Implemented `watch` subcommand for the `build` and `check` command to watch for changes in files and automatically rebuild or check them.
|
|
16
|
+
|
|
17
|
+
### Core Components
|
|
18
|
+
|
|
19
|
+
- Implemented Config manager to handle configuration files.
|
|
20
|
+
- Added support for `.devalang` configuration file as a TOML file.
|
|
21
|
+
- Added support for `--no-config` flag to disable configuration file usage.
|
|
22
|
+
- Implemented File System watcher to monitor file changes.
|
|
23
|
+
- Implemented Template manager to handle templates and their metadata.
|
|
24
|
+
- Refactored Lexer to support new syntax elements and directives.
|
|
25
|
+
|
|
26
|
+
### Syntax
|
|
27
|
+
|
|
28
|
+
- Added support for built-in triggers for `.snare`, `.hihat`, `.clap`, `.tom`, `.crash`, `.ride`.
|
|
29
|
+
- Added support for custom triggers with `@load` using the syntax `.trigger-name`.
|
|
30
|
+
|
|
31
|
+
## Version 0.0.1-alpha.1 (2024-06-25)
|
|
32
|
+
|
|
33
|
+
### Syntax
|
|
34
|
+
|
|
35
|
+
- Added support for `@import` directive to import other Devalang files.
|
|
36
|
+
- Added support for `@export` directive to export variables and functions.
|
|
37
|
+
- Added support for `@load` directive to load external resources.
|
|
38
|
+
- Added support for `bpm` directive to set the beats per minute.
|
|
39
|
+
- Added support for `bank` directive to define a bank of sounds.
|
|
40
|
+
- Added support for `loop` directive to define loops in the code.
|
|
41
|
+
|
|
42
|
+
### Commands
|
|
43
|
+
|
|
44
|
+
- Implemented `check` command to check the syntax of Devalang files.
|
|
45
|
+
- Implemented `build` command to build the Abstract Syntax Tree (AST) of Devalang files.
|
|
46
|
+
|
|
47
|
+
### Core Components
|
|
48
|
+
|
|
49
|
+
- Implemented Lexer to tokenize Devalang source code.
|
|
50
|
+
- Implemented Parser to parse the tokens and build the AST.
|
|
51
|
+
- Implemented Preprocessor to handle directives and preprocess the source code.
|
|
52
|
+
- Implemented Debugger to debug Devalang code.
|
|
53
|
+
- Implemented Builder to build the final output from the AST.
|
package/docs/COMMANDS.md
CHANGED
|
@@ -4,28 +4,51 @@
|
|
|
4
4
|
|
|
5
5
|
# Devalang Commands Guide
|
|
6
6
|
|
|
7
|
+
## Initialization
|
|
8
|
+
|
|
9
|
+
Initialize a new Devalang project (current folder)
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
devalang init
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Initialize a new Devalang project (new folder)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
devalang init --name <project-name> --template <template-name>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Available arguments:
|
|
22
|
+
|
|
23
|
+
- `--name`: The name of the project (cannot be empty)
|
|
24
|
+
- `--template`: The template to use for the project (default to `welcome`)
|
|
25
|
+
|
|
7
26
|
## Checking
|
|
8
27
|
|
|
9
28
|
Checking syntax of .deva file(s)
|
|
10
29
|
|
|
11
30
|
```bash
|
|
12
|
-
devalang check --entry ./examples --output ./output
|
|
31
|
+
devalang check --entry ./examples --output ./output --watch
|
|
13
32
|
```
|
|
14
33
|
|
|
15
34
|
Available arguments :
|
|
16
35
|
|
|
17
|
-
-
|
|
18
|
-
-
|
|
36
|
+
- `--no-config`: Whether to ignore the configuration file (default to `false`)
|
|
37
|
+
- `--entry`: The input folder (default to `./src`)
|
|
38
|
+
- `--output`: The output folder (default to `./output`)
|
|
39
|
+
- `--watch`: Whether to watch for changes and re-analyze (default to `false`)
|
|
19
40
|
|
|
20
41
|
## Building
|
|
21
42
|
|
|
22
43
|
Building AST of .deva file(s)
|
|
23
44
|
|
|
24
45
|
```bash
|
|
25
|
-
devalang build --entry ./examples --output ./output
|
|
46
|
+
devalang build --entry ./examples --output ./output --watch
|
|
26
47
|
```
|
|
27
48
|
|
|
28
49
|
Available arguments :
|
|
29
50
|
|
|
30
|
-
-
|
|
31
|
-
-
|
|
51
|
+
- `--no-config`: Whether to ignore the configuration file (default to `false`)
|
|
52
|
+
- `--entry`: The input folder (default to `./src`)
|
|
53
|
+
- `--output`: The output folder (default to `./output`)
|
|
54
|
+
- `--watch`: Whether to watch for changes and rebuild (default to `false`)
|
package/docs/CONFIG.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
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
|
+
# Devalang Configuration File
|
|
6
|
+
|
|
7
|
+
Use a configuration file if you don't want to pass command-line arguments every time you run a command. The configuration file allows you to set default values for various settings, making it easier to manage your Devalang project.
|
|
8
|
+
|
|
9
|
+
## Ignoring the Configuration File
|
|
10
|
+
|
|
11
|
+
If you prefer not to use a configuration file, you can ignore it by passing the `--no-config` flag when running Devalang commands. This will bypass any settings defined in the configuration file and use only the command-line arguments you provide.
|
|
12
|
+
|
|
13
|
+
## Structure of the Configuration File
|
|
14
|
+
|
|
15
|
+
The configuration file is a TOML (Tom's Obvious, Minimal Language) file that contains key-value pairs to define various settings for your Devalang project. Below is a sample configuration file:
|
|
16
|
+
|
|
17
|
+
```toml
|
|
18
|
+
[defaults]
|
|
19
|
+
entry = "./src"
|
|
20
|
+
output = "./output"
|
|
21
|
+
watch = true
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Available Settings
|
|
25
|
+
|
|
26
|
+
- `entry`: (String) The entry point for your Devalang project
|
|
27
|
+
- `output`: (String) The output directory for generated files
|
|
28
|
+
- `watch`: (Boolean) Whether to watch for changes in files and automatically rebuild or check them
|
package/docs/ROADMAP.md
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
Devalang is a work in progress. Here’s what we’re planning next:
|
|
8
8
|
|
|
9
9
|
- ✅ **Basic syntax**: Implement the core syntax for Devalang, including data types and basic statements.
|
|
10
|
+
- ✅ **Watch mode**: Add a watch mode to automatically rebuild on file changes.
|
|
10
11
|
- ✅ **Module system**: Add support for importing and exporting variables between files using `@import` and `@export`.
|
|
11
12
|
- ✅ **AST generation**: Implement the Abstract Syntax Tree (AST) generation for debugging and future compilation.
|
|
12
13
|
- ✅ **Basic data types**: Support strings, numbers, booleans, maps, and arrays.
|
|
@@ -21,7 +22,6 @@ Devalang is a work in progress. Here’s what we’re planning next:
|
|
|
21
22
|
- ⏳ **WASM support**: Compile Devalang to WebAssembly for use in web applications.
|
|
22
23
|
- ⏳ **Other statements**: Implement `if`, `else`, and other control structures.
|
|
23
24
|
- ⏳ **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
25
|
- ⏳ **Functions**: Add support for defining and calling functions.
|
|
26
26
|
- ⏳ **Audio engine**: Integrate the audio engine for sound playback.
|
|
27
27
|
- ⏳ **Testing**: Expand test coverage for all features.
|
package/docs/TODO.md
CHANGED
|
@@ -8,16 +8,19 @@ 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
|
|
@@ -28,6 +31,7 @@ This is a list of tasks and features to be implemented in Devalang. Note that th
|
|
|
28
31
|
## Core components
|
|
29
32
|
|
|
30
33
|
- [ ] Audio Engine
|
|
34
|
+
- [x] Configuration
|
|
31
35
|
- [x] Lexer
|
|
32
36
|
- [x] Parser
|
|
33
37
|
- [x] Preprocessor
|
|
@@ -36,7 +40,7 @@ This is a list of tasks and features to be implemented in Devalang. Note that th
|
|
|
36
40
|
|
|
37
41
|
## Syntax elements
|
|
38
42
|
|
|
39
|
-
- [
|
|
43
|
+
- [x] #
|
|
40
44
|
- [x] @import
|
|
41
45
|
- [x] @export
|
|
42
46
|
- [ ] @group
|
|
@@ -52,15 +56,39 @@ This is a list of tasks and features to be implemented in Devalang. Note that th
|
|
|
52
56
|
- [ ] else
|
|
53
57
|
- [ ] else if
|
|
54
58
|
|
|
55
|
-
##
|
|
59
|
+
## Triggers
|
|
60
|
+
|
|
61
|
+
### One-shot triggers
|
|
56
62
|
|
|
57
63
|
- [x] .kick
|
|
58
|
-
- [
|
|
59
|
-
- [
|
|
60
|
-
- [
|
|
61
|
-
- [
|
|
62
|
-
- [
|
|
63
|
-
- [
|
|
64
|
-
|
|
64
|
+
- [x] .snare
|
|
65
|
+
- [x] .hihat
|
|
66
|
+
- [x] .tom
|
|
67
|
+
- [x] .clap
|
|
68
|
+
- [x] .crash
|
|
69
|
+
- [x] .ride
|
|
70
|
+
|
|
71
|
+
### Instrument triggers
|
|
72
|
+
|
|
73
|
+
- [ ] .guitar
|
|
74
|
+
- [ ] .piano
|
|
75
|
+
- [ ] .flute
|
|
76
|
+
- [ ] .violin
|
|
77
|
+
|
|
78
|
+
### Synth & effects triggers
|
|
79
|
+
|
|
80
|
+
- [ ] .lead
|
|
65
81
|
- [ ] .bass
|
|
66
82
|
- [ ] .pad
|
|
83
|
+
- [ ] .arp
|
|
84
|
+
- [ ] .fx
|
|
85
|
+
- [ ] .vocal
|
|
86
|
+
|
|
87
|
+
## Other TODOs
|
|
88
|
+
|
|
89
|
+
- [ ] Possibility to overload built-in triggers
|
|
90
|
+
- [ ] Implement a more robust error handling system
|
|
91
|
+
- [ ] Replace eprintln & println with `log_message` function
|
|
92
|
+
- [ ] Implement a more comprehensive logging system
|
|
93
|
+
- [ ] Add unit tests for all core components
|
|
94
|
+
- [ ] Comment all core components
|
package/examples/index.deva
CHANGED
package/out-tsc/bin/devalang.exe
CHANGED
|
Binary file
|
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.2",
|
|
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": {
|
|
@@ -40,4 +40,4 @@
|
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@types/node": "^24.0.3"
|
|
42
42
|
}
|
|
43
|
-
}
|
|
43
|
+
}
|
package/project-version.json
CHANGED
package/rust/cli/build.rs
CHANGED
|
@@ -5,24 +5,77 @@ use crate::{
|
|
|
5
5
|
builder::{ build_ast, write_ast_to_file },
|
|
6
6
|
debugger::Debugger,
|
|
7
7
|
preprocessor::module::load_all_modules,
|
|
8
|
+
types::config::DevalangConfig,
|
|
8
9
|
},
|
|
9
10
|
runner::executer::execute_statements,
|
|
10
|
-
utils::{
|
|
11
|
+
utils::{
|
|
12
|
+
loader::with_spinner,
|
|
13
|
+
logger::log_message,
|
|
14
|
+
path::{ find_entry_file, normalize_path },
|
|
15
|
+
watcher::watch_directory,
|
|
16
|
+
},
|
|
11
17
|
};
|
|
12
18
|
|
|
13
|
-
pub fn handle_build_command(
|
|
14
|
-
|
|
15
|
-
|
|
19
|
+
pub fn handle_build_command(
|
|
20
|
+
config: Option<DevalangConfig>,
|
|
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 entry_file = find_entry_file(&fetched_entry).unwrap_or_else(|| {
|
|
53
|
+
eprintln!("❌ index.deva not found in directory: {}", fetched_entry);
|
|
16
54
|
std::process::exit(1);
|
|
17
55
|
});
|
|
18
56
|
|
|
57
|
+
if watch == true {
|
|
58
|
+
log_message("Watch mode enabled, waiting for file changes...", "INFO");
|
|
59
|
+
|
|
60
|
+
begin_build(entry_file.clone(), fetched_output.clone(), watch);
|
|
61
|
+
|
|
62
|
+
watch_directory(entry_file.clone(), move || {
|
|
63
|
+
log_message("File change detected, rebuilding...", "INFO");
|
|
64
|
+
begin_build(entry_file.clone(), fetched_output.clone(), watch);
|
|
65
|
+
}).unwrap();
|
|
66
|
+
} else {
|
|
67
|
+
begin_build(entry_file.clone(), fetched_output.clone(), watch);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
fn begin_build(entry: String, output: String, watch: bool) {
|
|
19
72
|
let spinner = with_spinner("Building...", || {
|
|
20
73
|
thread::sleep(Duration::from_millis(800));
|
|
21
74
|
});
|
|
22
75
|
|
|
23
76
|
let duration = std::time::Instant::now();
|
|
24
77
|
|
|
25
|
-
let normalized_entry_file = normalize_path(&
|
|
78
|
+
let normalized_entry_file = normalize_path(&entry);
|
|
26
79
|
let normalized_output_dir = normalize_path(&output);
|
|
27
80
|
|
|
28
81
|
let global_store = load_all_modules(&normalized_entry_file);
|
package/rust/cli/check.rs
CHANGED
|
@@ -5,33 +5,89 @@ use crate::{
|
|
|
5
5
|
debugger::Debugger,
|
|
6
6
|
preprocessor::module::load_all_modules,
|
|
7
7
|
types::{
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
StatementIterator,
|
|
11
|
-
StatementKind,
|
|
12
|
-
StatementResolved,
|
|
13
|
-
StatementResolvedValue,
|
|
14
|
-
},
|
|
15
|
-
variable::VariableValue,
|
|
8
|
+
config::{ DevalangConfig },
|
|
9
|
+
statement::{ StatementKind, StatementResolved, StatementResolvedValue },
|
|
16
10
|
},
|
|
17
11
|
},
|
|
18
12
|
runner::executer::execute_statements,
|
|
19
|
-
utils::{
|
|
13
|
+
utils::{
|
|
14
|
+
loader::with_spinner,
|
|
15
|
+
logger::log_message,
|
|
16
|
+
path::{ find_entry_file, normalize_path },
|
|
17
|
+
watcher::watch_directory,
|
|
18
|
+
},
|
|
20
19
|
};
|
|
21
20
|
|
|
22
|
-
pub fn handle_check_command(
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
pub fn handle_check_command(
|
|
22
|
+
config: Option<DevalangConfig>,
|
|
23
|
+
entry: Option<String>,
|
|
24
|
+
output: Option<String>,
|
|
25
|
+
watch: bool
|
|
26
|
+
) -> () {
|
|
27
|
+
let fetched_entry = if entry.is_none() {
|
|
28
|
+
config
|
|
29
|
+
.as_ref()
|
|
30
|
+
.and_then(|c| c.defaults.entry.clone())
|
|
31
|
+
.unwrap_or_else(|| "".to_string())
|
|
32
|
+
} else {
|
|
33
|
+
entry.clone().unwrap_or_else(|| "".to_string())
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
let fetched_output = if output.is_none() {
|
|
37
|
+
config
|
|
38
|
+
.as_ref()
|
|
39
|
+
.and_then(|c| c.defaults.output.clone())
|
|
40
|
+
.unwrap_or_else(|| "".to_string())
|
|
41
|
+
} else {
|
|
42
|
+
output.clone().unwrap_or_else(|| "".to_string())
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
let fetched_watch = if watch {
|
|
46
|
+
watch
|
|
47
|
+
} else {
|
|
48
|
+
config
|
|
49
|
+
.as_ref()
|
|
50
|
+
.and_then(|c| c.defaults.watch)
|
|
51
|
+
.unwrap_or(false)
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
if fetched_entry.is_empty() {
|
|
55
|
+
eprintln!("❌ Entry path is not specified. Please provide a valid entry path.");
|
|
56
|
+
std::process::exit(1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if fetched_output.is_empty() {
|
|
60
|
+
eprintln!("❌ Output directory is not specified. Please provide a valid output directory.");
|
|
61
|
+
std::process::exit(1);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let entry_file = find_entry_file(&fetched_entry).unwrap_or_else(|| {
|
|
65
|
+
eprintln!("❌ index.deva not found in directory: {}", fetched_entry);
|
|
25
66
|
std::process::exit(1);
|
|
26
67
|
});
|
|
27
68
|
|
|
69
|
+
if fetched_watch.clone() == true {
|
|
70
|
+
log_message("Watch mode enabled, waiting for file changes...", "INFO");
|
|
71
|
+
|
|
72
|
+
begin_check(entry_file.clone(), fetched_output.clone(), fetched_watch.clone());
|
|
73
|
+
|
|
74
|
+
watch_directory(entry_file.clone(), move || {
|
|
75
|
+
log_message("File change detected, rebuilding...", "INFO");
|
|
76
|
+
begin_check(entry_file.clone(), fetched_output.clone(), fetched_watch.clone());
|
|
77
|
+
}).unwrap();
|
|
78
|
+
} else {
|
|
79
|
+
begin_check(entry_file.clone(), fetched_output.clone(), fetched_watch.clone());
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
fn begin_check(entry: String, output: String, watch: bool) {
|
|
28
84
|
let spinner = with_spinner("Checking...", || {
|
|
29
85
|
thread::sleep(Duration::from_millis(800));
|
|
30
86
|
});
|
|
31
87
|
|
|
32
88
|
let duration = std::time::Instant::now();
|
|
33
89
|
|
|
34
|
-
let normalized_entry_file = normalize_path(&
|
|
90
|
+
let normalized_entry_file = normalize_path(&entry);
|
|
35
91
|
let normalized_output_dir = normalize_path(&output);
|
|
36
92
|
|
|
37
93
|
let global_store = load_all_modules(&normalized_entry_file);
|
|
@@ -45,9 +101,9 @@ pub fn handle_check_command(entry: String, output: String) -> () {
|
|
|
45
101
|
let debug_dir = format!("{}/debug/", normalized_output_dir.clone());
|
|
46
102
|
debugger.write_files(debug_dir.as_str(), resolved_statements.clone());
|
|
47
103
|
|
|
48
|
-
let has_errors = resolved_statements
|
|
49
|
-
|
|
50
|
-
|
|
104
|
+
let has_errors = resolved_statements
|
|
105
|
+
.iter()
|
|
106
|
+
.any(|stmt| { match_error_recursively_resolved(&stmt.clone()) });
|
|
51
107
|
|
|
52
108
|
if has_errors {
|
|
53
109
|
let warning_message = format!(
|
|
@@ -109,7 +165,7 @@ fn match_error_recursively_resolved_value(value: &StatementResolvedValue) -> boo
|
|
|
109
165
|
}
|
|
110
166
|
}
|
|
111
167
|
}
|
|
112
|
-
|
|
168
|
+
|
|
113
169
|
StatementResolvedValue::Array(array) => {
|
|
114
170
|
for item in array {
|
|
115
171
|
if match_error_recursively_resolved(item) {
|
package/rust/cli/init.rs
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
use std::{ fs, path::Path };
|
|
2
|
+
use include_dir::{ include_dir, Dir };
|
|
3
|
+
use inquire::{ Select, Confirm };
|
|
4
|
+
|
|
5
|
+
use crate::{ cli::template::{ get_available_templates }, utils::file::copy_dir_recursive };
|
|
6
|
+
|
|
7
|
+
static TEMPLATES_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/templates");
|
|
8
|
+
|
|
9
|
+
pub fn handle_init_command(name: Option<String>, template: Option<String>) {
|
|
10
|
+
let current_dir = std::env::current_dir().unwrap();
|
|
11
|
+
let project_name = name
|
|
12
|
+
.clone()
|
|
13
|
+
.unwrap_or_else(|| {
|
|
14
|
+
current_dir.file_name().unwrap_or_default().to_string_lossy().to_string()
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// Select a template if not provided
|
|
18
|
+
let selected_template = template.unwrap_or_else(|| {
|
|
19
|
+
Select::new("Select a template for your project:", get_available_templates())
|
|
20
|
+
.prompt()
|
|
21
|
+
.unwrap_or_else(|_| {
|
|
22
|
+
eprintln!("No template selected. Exiting...");
|
|
23
|
+
std::process::exit(1);
|
|
24
|
+
})
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
if selected_template.is_empty() {
|
|
28
|
+
eprintln!("Template cannot be empty.");
|
|
29
|
+
std::process::exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if name.is_none() {
|
|
33
|
+
// Case of initialization in the current directory
|
|
34
|
+
if fs::read_dir(¤t_dir).unwrap().next().is_some() {
|
|
35
|
+
let confirm = Confirm::new(
|
|
36
|
+
"The current directory is not empty. Do you want to continue?"
|
|
37
|
+
)
|
|
38
|
+
.with_default(false)
|
|
39
|
+
.prompt()
|
|
40
|
+
.unwrap_or(false);
|
|
41
|
+
|
|
42
|
+
if !confirm {
|
|
43
|
+
eprintln!("Operation cancelled by the user.");
|
|
44
|
+
std::process::exit(0);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
scaffold_project_current_dir(current_dir.as_path(), selected_template);
|
|
49
|
+
println!(
|
|
50
|
+
"✅ Initialized '{}' project in current directory: {}",
|
|
51
|
+
project_name,
|
|
52
|
+
current_dir.display()
|
|
53
|
+
);
|
|
54
|
+
} else {
|
|
55
|
+
// Case of initialization in a new directory
|
|
56
|
+
let target_path = current_dir.join(&project_name);
|
|
57
|
+
|
|
58
|
+
if target_path.exists() {
|
|
59
|
+
eprintln!("❌ A folder named '{}' already exists.", project_name);
|
|
60
|
+
std::process::exit(1);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
fs::create_dir_all(&target_path).expect("Error creating project directory");
|
|
64
|
+
|
|
65
|
+
scaffold_project_current_dir(&target_path, selected_template);
|
|
66
|
+
println!("✅ Initialized '{}' project in: {}", project_name, target_path.display());
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fn scaffold_project_current_dir(path: &Path, template: String) {
|
|
71
|
+
let template_dir = TEMPLATES_DIR.get_dir(&template).unwrap_or_else(|| {
|
|
72
|
+
eprintln!("❌ The template '{}' doesn't exist.", template);
|
|
73
|
+
std::process::exit(1);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
copy_dir_recursive(template_dir, path, &template_dir.path());
|
|
77
|
+
}
|
package/rust/cli/mod.rs
CHANGED