@devaloop/devalang 0.0.1-alpha.2 → 0.0.1-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/Cargo.toml +46 -46
  2. package/README.md +7 -6
  3. package/docs/CHANGELOG.md +11 -6
  4. package/docs/ROADMAP.md +5 -1
  5. package/docs/TODO.md +6 -31
  6. package/examples/exported.deva +1 -1
  7. package/examples/index.deva +1 -0
  8. package/out-tsc/bin/devalang.exe +0 -0
  9. package/package.json +1 -2
  10. package/project-version.json +3 -3
  11. package/rust/cli/build.rs +57 -40
  12. package/rust/cli/check.rs +47 -111
  13. package/rust/cli/init.rs +1 -1
  14. package/rust/cli/mod.rs +174 -2
  15. package/rust/{utils/config.rs → config/loader.rs} +3 -2
  16. package/rust/{core/types/config.rs → config/mod.rs} +5 -5
  17. package/rust/core/builder/mod.rs +21 -27
  18. package/rust/core/debugger/lexer.rs +12 -0
  19. package/rust/core/debugger/mod.rs +12 -49
  20. package/rust/core/debugger/preprocessor.rs +23 -0
  21. package/rust/core/error/mod.rs +60 -0
  22. package/rust/core/lexer/{at.rs → handler/at.rs} +1 -1
  23. package/rust/core/lexer/{brace.rs → handler/brace.rs} +1 -1
  24. package/rust/core/lexer/{colon.rs → handler/colon.rs} +1 -1
  25. package/rust/core/lexer/{comment.rs → handler/comment.rs} +3 -3
  26. package/rust/core/lexer/{dot.rs → handler/dot.rs} +1 -1
  27. package/rust/core/lexer/{equal.rs → handler/equal.rs} +1 -1
  28. package/rust/core/lexer/{identifier.rs → handler/identifier.rs} +1 -1
  29. package/rust/core/lexer/{indent.rs → handler/indent.rs} +10 -5
  30. package/rust/core/lexer/handler/mod.rs +238 -0
  31. package/rust/core/lexer/{newline.rs → handler/newline.rs} +6 -10
  32. package/rust/core/lexer/{number.rs → handler/number.rs} +1 -1
  33. package/rust/core/lexer/handler/string.rs +66 -0
  34. package/rust/core/lexer/mod.rs +25 -14
  35. package/rust/core/lexer/token.rs +55 -0
  36. package/rust/core/mod.rs +5 -2
  37. package/rust/core/parser/handler/at.rs +166 -0
  38. package/rust/core/parser/handler/bank.rs +38 -0
  39. package/rust/core/parser/handler/dot.rs +112 -0
  40. package/rust/core/parser/handler/identifier.rs +134 -0
  41. package/rust/core/parser/handler/loop_.rs +55 -0
  42. package/rust/core/parser/handler/mod.rs +6 -0
  43. package/rust/core/parser/handler/tempo.rs +47 -0
  44. package/rust/core/parser/mod.rs +204 -166
  45. package/rust/core/parser/statement.rs +91 -0
  46. package/rust/core/preprocessor/loader.rs +105 -0
  47. package/rust/core/preprocessor/mod.rs +2 -24
  48. package/rust/core/preprocessor/module.rs +37 -56
  49. package/rust/core/preprocessor/processor.rs +41 -0
  50. package/rust/core/preprocessor/resolver.rs +372 -0
  51. package/rust/core/shared/duration.rs +8 -0
  52. package/rust/core/shared/mod.rs +2 -0
  53. package/rust/core/shared/value.rs +18 -0
  54. package/rust/core/store/export.rs +28 -0
  55. package/rust/core/store/global.rs +39 -0
  56. package/rust/core/store/import.rs +28 -0
  57. package/rust/core/store/mod.rs +4 -0
  58. package/rust/core/store/variable.rs +28 -0
  59. package/rust/core/utils/mod.rs +2 -0
  60. package/rust/core/utils/validation.rs +35 -0
  61. package/rust/lib.rs +0 -1
  62. package/rust/main.rs +17 -19
  63. package/rust/utils/logger.rs +69 -34
  64. package/rust/utils/mod.rs +3 -5
  65. package/templates/minimal/.devalang +1 -1
  66. package/templates/welcome/.devalang +1 -1
  67. package/rust/audio/mod.rs +0 -1
  68. package/rust/core/lexer/bracket.rs +0 -41
  69. package/rust/core/lexer/driver.rs +0 -286
  70. package/rust/core/lexer/quote.rs +0 -61
  71. package/rust/core/parser/at.rs +0 -142
  72. package/rust/core/parser/bank.rs +0 -42
  73. package/rust/core/parser/dot.rs +0 -137
  74. package/rust/core/parser/identifer.rs +0 -91
  75. package/rust/core/parser/loop_.rs +0 -62
  76. package/rust/core/parser/tempo.rs +0 -42
  77. package/rust/core/parser/variable.rs +0 -129
  78. package/rust/core/preprocessor/dependencies.rs +0 -54
  79. package/rust/core/preprocessor/resolver/at.rs +0 -24
  80. package/rust/core/preprocessor/resolver/bank.rs +0 -59
  81. package/rust/core/preprocessor/resolver/loop_.rs +0 -82
  82. package/rust/core/preprocessor/resolver/mod.rs +0 -113
  83. package/rust/core/preprocessor/resolver/tempo.rs +0 -70
  84. package/rust/core/preprocessor/resolver/trigger.rs +0 -176
  85. package/rust/core/types/cli.rs +0 -182
  86. package/rust/core/types/mod.rs +0 -8
  87. package/rust/core/types/module.rs +0 -41
  88. package/rust/core/types/parser.rs +0 -73
  89. package/rust/core/types/statement.rs +0 -105
  90. package/rust/core/types/store.rs +0 -116
  91. package/rust/core/types/token.rs +0 -83
  92. package/rust/core/types/variable.rs +0 -32
  93. package/rust/runner/executer.rs +0 -44
  94. package/rust/runner/mod.rs +0 -1
  95. /package/rust/{utils → core/utils}/path.rs +0 -0
  96. /package/rust/utils/{loader.rs → spinner.rs} +0 -0
package/Cargo.toml CHANGED
@@ -1,46 +1,46 @@
1
- [package]
2
- name = "devalang"
3
- version = "0.0.1-alpha.2"
4
- authors = ["Devaloop <contact@devaloop.com>"]
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
- license = "MIT"
7
- repository = "https://github.com/devaloop-labs/devalang"
8
- keywords = ["music", "dsl", "audio", "cli"]
9
- categories = ["command-line-utilities", "audio", "development-tools"]
10
- readme = "README.md"
11
- homepage = "https://devaloop.com"
12
- documentation = "https://docs.rs/devalang"
13
- edition = "2024"
14
-
15
- [[bin]]
16
- name = "devalang"
17
- path = "rust/main.rs"
18
-
19
- [lib]
20
- path = "rust/lib.rs"
21
- crate-type = ["cdylib"]
22
-
23
- [profile.release]
24
- opt-level = "s"
25
-
26
- [features]
27
- default = ["cli"]
28
- cli = ["crossterm"]
29
-
30
- [dependencies]
31
- clap = { version = "4.5", features = ["derive"] }
32
- serde = { version = "1.0", features = ["derive"] }
33
- serde_json = "1.0"
34
- rodio = "0.17"
35
- hound = "3.4.0"
36
- toml = "0.8"
37
- notify = "6.1"
38
- fs_extra = "1.3"
39
- include_dir = "0.7"
40
- wasm-bindgen = "0.2"
41
- serde-wasm-bindgen = "0.4"
42
- nom_locate = "4.0.0"
43
- chrono = "0.4"
44
- crossterm = { version = "0.27", optional = true }
45
- indicatif = "0.17"
46
- inquire = "0.7.5"
1
+ [package]
2
+ name = "devalang"
3
+ version = "0.0.1-alpha.3"
4
+ authors = ["Devaloop <contact@devaloop.com>"]
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
+ license = "MIT"
7
+ repository = "https://github.com/devaloop-labs/devalang"
8
+ keywords = ["music", "dsl", "audio", "cli"]
9
+ categories = ["command-line-utilities", "audio", "development-tools"]
10
+ readme = "README.md"
11
+ homepage = "https://devaloop.com"
12
+ documentation = "https://docs.rs/devalang"
13
+ edition = "2024"
14
+
15
+ [[bin]]
16
+ name = "devalang"
17
+ path = "rust/main.rs"
18
+
19
+ [lib]
20
+ path = "rust/lib.rs"
21
+ crate-type = ["cdylib"]
22
+
23
+ [profile.release]
24
+ opt-level = "s"
25
+
26
+ [features]
27
+ default = ["cli"]
28
+ cli = ["crossterm"]
29
+
30
+ [dependencies]
31
+ clap = { version = "4.5", features = ["derive"] }
32
+ serde = { version = "1.0", features = ["derive"] }
33
+ serde_json = "1.0"
34
+ rodio = "0.17"
35
+ hound = "3.4.0"
36
+ toml = "0.8"
37
+ notify = "6.1"
38
+ fs_extra = "1.3"
39
+ include_dir = "0.7"
40
+ wasm-bindgen = "0.2"
41
+ serde-wasm-bindgen = "0.4"
42
+ nom_locate = "4.0.0"
43
+ chrono = "0.4"
44
+ crossterm = { version = "0.27", optional = true }
45
+ indicatif = "0.17"
46
+ inquire = "0.7.5"
package/README.md CHANGED
@@ -30,7 +30,6 @@ From studio sketches to live sets, Devalang gives you rhythmic control — with
30
30
  >
31
31
  > You can parse code, generate the AST, and validate syntax — all essential building blocks for the upcoming audio engine.
32
32
  >
33
- > Currently, only `.kick` is included as a built-in trigger.
34
33
  > Custom instruments can be defined with `@load`, allowing any sound sample to be triggered with the same syntax.
35
34
  >
36
35
  > Currently, Devalang CLI is only available for **Windows**.
@@ -84,7 +83,9 @@ Usage for development (feel free to change arguments in package.json)
84
83
 
85
84
  ```bash
86
85
  # For syntax checking test
87
- npm run rust:dev <command>
86
+ npm run rust:dev:check
87
+ # For building test
88
+ npm run rust:dev:build
88
89
  ```
89
90
 
90
91
  ## ❔ Usage
@@ -105,13 +106,13 @@ Or use optional arguments to specify a directory name and a template
105
106
  devalang init --name <project-name> --template <template-name>
106
107
  ```
107
108
 
108
- ### Checking syntax only and output debug files
109
+ ### Checking syntax only
109
110
 
110
111
  ```bash
111
112
  devalang check --entry <entry-directory> --output <output-directory> --watch
112
113
  ```
113
114
 
114
- ### Building output file(s) (AST generation for the moment)
115
+ ### Building output files
115
116
 
116
117
  ```bash
117
118
  devalang build --entry <entry-directory> --output <output-directory> --watch
@@ -160,13 +161,13 @@ let kickDuration = 500
160
161
  - No support yet for Audio Engine
161
162
  - No support yet for `if`, `else`, `else if` statements
162
163
  - No support yet for `@group`, `@pattern`, `@function` statements
163
- - Nested loops and conditions may not be fully tested
164
+ - No support yet for cross-platform builds (Linux, macOS)
164
165
 
165
166
  ## 🧪 Roadmap Highlights
166
167
 
167
168
  For more info, see [docs/ROADMAP.md](./docs/ROADMAP.md)
168
169
 
169
- - ⏳ Audio engine integration
170
+ - ⏳ Audio engine integration (priority for alpha.4)
170
171
  - ⏳ Other statements (e.g `if`, `@group`, ...)
171
172
  - ⏳ Cross-platform support (Linux, macOS)
172
173
  - ⏳ More built-in instruments (e.g. snare, hi-hat, etc.)
package/docs/CHANGELOG.md CHANGED
@@ -4,7 +4,15 @@
4
4
 
5
5
  # Changelog
6
6
 
7
- ## Version 0.0.1-alpha.2 (2024-06-26)
7
+ ## Version 0.0.1-alpha.3 (2025-07-01)
8
+
9
+ - /!\ Major refactor of the project structure and module system /!\
10
+ - Refactored module system to support multiple modules and submodules.
11
+ - Patched all directives to be compatible with the new project structure.
12
+ - Prepared for the upcoming audio engine integration and sound rendering capabilities.
13
+ - Updated documentation to reflect the new project structure and features.
14
+
15
+ ## Version 0.0.1-alpha.2 (2025-06-26)
8
16
 
9
17
  ### Commands
10
18
 
@@ -18,17 +26,14 @@
18
26
 
19
27
  - Implemented Config manager to handle configuration files.
20
28
  - Added support for `.devalang` configuration file as a TOML file.
21
- - Added support for `--no-config` flag to disable configuration file usage.
22
29
  - Implemented File System watcher to monitor file changes.
23
30
  - Implemented Template manager to handle templates and their metadata.
24
- - Refactored Lexer to support new syntax elements and directives.
25
31
 
26
32
  ### Syntax
27
33
 
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`.
34
+ - Added support for built-in triggers for `.snare`, `.hihat`, `.clap`, `.tom`, `.crash`, `.ride`, `.synth`, `.bass`, and `.pad`.
30
35
 
31
- ## Version 0.0.1-alpha.1 (2024-06-25)
36
+ ## Version 0.0.1-alpha.1 (2025-06-25)
32
37
 
33
38
  ### Syntax
34
39
 
package/docs/ROADMAP.md CHANGED
@@ -6,6 +6,8 @@
6
6
 
7
7
  Devalang is a work in progress. Here’s what we’re planning next:
8
8
 
9
+ ### Stable
10
+
9
11
  - ✅ **Basic syntax**: Implement the core syntax for Devalang, including data types and basic statements.
10
12
  - ✅ **Watch mode**: Add a watch mode to automatically rebuild on file changes.
11
13
  - ✅ **Module system**: Add support for importing and exporting variables between files using `@import` and `@export`.
@@ -18,10 +20,12 @@ Devalang is a work in progress. Here’s what we’re planning next:
18
20
  - ✅ **Let assignments**: Implement `let` assignments for storing reusable values.
19
21
  - ✅ **Sample loading**: Add `@load` assignment to load samples (.mp3, .wav) for use as values.
20
22
 
23
+ ### Upcoming
24
+
25
+ - ⏳ **Audio engine**: Integrate the audio engine for sound playback.
21
26
  - ⏳ **VSCode extension**: Create a VSCode extension for syntax highlighting and code completion.
22
27
  - ⏳ **WASM support**: Compile Devalang to WebAssembly for use in web applications.
23
28
  - ⏳ **Other statements**: Implement `if`, `else`, and other control structures.
24
29
  - ⏳ **Pattern and group statements**: Add support for `@pattern` and `@group` to organize code.
25
30
  - ⏳ **Functions**: Add support for defining and calling functions.
26
- - ⏳ **Audio engine**: Integrate the audio engine for sound playback.
27
31
  - ⏳ **Testing**: Expand test coverage for all features.
package/docs/TODO.md CHANGED
@@ -31,7 +31,6 @@ This is a list of tasks and features to be implemented in Devalang. Note that th
31
31
  ## Core components
32
32
 
33
33
  - [ ] Audio Engine
34
- - [x] Configuration
35
34
  - [x] Lexer
36
35
  - [x] Parser
37
36
  - [x] Preprocessor
@@ -58,37 +57,13 @@ This is a list of tasks and features to be implemented in Devalang. Note that th
58
57
 
59
58
  ## Triggers
60
59
 
61
- ### One-shot triggers
62
-
63
- - [x] .kick
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
81
- - [ ] .bass
82
- - [ ] .pad
83
- - [ ] .arp
84
- - [ ] .fx
85
- - [ ] .vocal
60
+ - [x] Built-in triggers
61
+ - [x] Custom triggers
86
62
 
87
63
  ## Other TODOs
88
64
 
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
65
+ - [x] Implement a more robust error handling system
66
+ - [x] Replace eprintln & println with `log_message` function
67
+ - [x] Implement a more comprehensive logging system
93
68
  - [ ] Add unit tests for all core components
94
- - [ ] Comment all core components
69
+ - [ ] Comment all core components
@@ -1,7 +1,7 @@
1
1
  let duration = auto
2
2
  let default_bank = 808
3
3
  let params = {decay:10, delay:30}
4
- let loopCount = 15
4
+ let loopCount = 5
5
5
  let tempo = 155
6
6
 
7
7
  @export { duration, default_bank, params, loopCount, tempo }
@@ -1,4 +1,5 @@
1
1
  @import { duration, default_bank, params, loopCount, tempo } from "./examples/exported.deva"
2
+
2
3
  @load "./examples/samples/kick-808.wav" as sample
3
4
 
4
5
  bpm tempo
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.2",
4
+ "version": "0.0.1-alpha.3",
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,7 +9,6 @@
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",
15
14
  "script:postbuild": "tsc && node out-tsc/scripts/postbuild.js",
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "0.0.1-alpha.2",
2
+ "version": "0.0.1-alpha.3",
3
3
  "channel": "alpha",
4
- "lastCommit": "6f92a4421db96f45c6accd6607e09876c0735531",
4
+ "lastCommit": "850fd73787ae41844d6669017ee3d01699b2df3c",
5
5
  "build": 2
6
- }
6
+ }
package/rust/cli/build.rs CHANGED
@@ -1,23 +1,17 @@
1
- use std::{ thread, time::Duration };
2
-
3
1
  use crate::{
2
+ config::Config,
4
3
  core::{
5
- builder::{ build_ast, write_ast_to_file },
6
- debugger::Debugger,
7
- preprocessor::module::load_all_modules,
8
- types::config::DevalangConfig,
9
- },
10
- runner::executer::execute_statements,
11
- utils::{
12
- loader::with_spinner,
13
- logger::log_message,
14
- path::{ find_entry_file, normalize_path },
15
- watcher::watch_directory,
4
+ builder::Builder,
5
+ preprocessor::loader::ModuleLoader,
6
+ store::global::GlobalStore,
7
+ utils::path::{ find_entry_file, normalize_path },
16
8
  },
9
+ utils::{ logger::{ LogLevel, Logger }, spinner::with_spinner, watcher::watch_directory },
17
10
  };
11
+ use std::{ thread, time::Duration };
18
12
 
19
13
  pub fn handle_build_command(
20
- config: Option<DevalangConfig>,
14
+ config: Option<Config>,
21
15
  entry: Option<String>,
22
16
  output: Option<String>,
23
17
  watch: bool
@@ -49,26 +43,51 @@ pub fn handle_build_command(
49
43
  .unwrap_or(false)
50
44
  };
51
45
 
46
+ let logger = Logger::new();
47
+
48
+ if fetched_entry.is_empty() {
49
+ logger.log_message(
50
+ LogLevel::Error,
51
+ "Entry path is not specified. Please provide a valid entry path."
52
+ );
53
+ std::process::exit(1);
54
+ }
55
+ if fetched_output.is_empty() {
56
+ logger.log_message(
57
+ LogLevel::Error,
58
+ "Output directory is not specified. Please provide a valid output directory."
59
+ );
60
+ std::process::exit(1);
61
+ }
62
+
52
63
  let entry_file = find_entry_file(&fetched_entry).unwrap_or_else(|| {
53
- eprintln!("❌ index.deva not found in directory: {}", fetched_entry);
64
+ logger.log_message(
65
+ LogLevel::Error,
66
+ &format!("❌ index.deva not found in directory: {}", fetched_entry)
67
+ );
54
68
  std::process::exit(1);
55
69
  });
56
70
 
57
- if watch == true {
58
- log_message("Watch mode enabled, waiting for file changes...", "INFO");
71
+ // SECTION Begin build
72
+ if fetched_watch {
73
+ begin_build(entry_file.clone(), fetched_output.clone());
59
74
 
60
- begin_build(entry_file.clone(), fetched_output.clone(), watch);
75
+ logger.log_message(
76
+ LogLevel::Watcher,
77
+ &format!("Watching for changes in '{}'...", fetched_entry)
78
+ );
61
79
 
62
80
  watch_directory(entry_file.clone(), move || {
63
- log_message("File change detected, rebuilding...", "INFO");
64
- begin_build(entry_file.clone(), fetched_output.clone(), watch);
81
+ logger.log_message(LogLevel::Watcher, "Detected changes, re-building...");
82
+
83
+ begin_build(entry_file.clone(), fetched_output.clone());
65
84
  }).unwrap();
66
85
  } else {
67
- begin_build(entry_file.clone(), fetched_output.clone(), watch);
86
+ begin_build(entry_file.clone(), fetched_output.clone());
68
87
  }
69
88
  }
70
89
 
71
- fn begin_build(entry: String, output: String, watch: bool) {
90
+ fn begin_build(entry: String, output: String) {
72
91
  let spinner = with_spinner("Building...", || {
73
92
  thread::sleep(Duration::from_millis(800));
74
93
  });
@@ -78,27 +97,25 @@ fn begin_build(entry: String, output: String, watch: bool) {
78
97
  let normalized_entry_file = normalize_path(&entry);
79
98
  let normalized_output_dir = normalize_path(&output);
80
99
 
81
- let global_store = load_all_modules(&normalized_entry_file);
82
-
83
- if let Some(module) = global_store.modules.get(&normalized_entry_file) {
84
- let mut module_clone = module.clone();
100
+ let mut global_store = GlobalStore::new();
101
+ let module_loader = ModuleLoader::new(&normalized_entry_file, &normalized_output_dir);
85
102
 
86
- let resolved_statements = execute_statements(&mut module_clone);
103
+ // SECTION Load
104
+ // NOTE: We use modules in the build command, so we need to load them
105
+ let modules = module_loader.load_all(&mut global_store);
87
106
 
88
- let ast = build_ast(&resolved_statements);
107
+ // SECTION Build
108
+ let builder = Builder::new();
109
+ builder.build_ast(&modules);
89
110
 
90
- let ast_dir = format!("{}/json", normalized_output_dir.clone());
91
- write_ast_to_file(&ast, &ast_dir);
111
+ // TODO: Implement debugging
92
112
 
93
- let debugger = Debugger::new(&module_clone);
94
- let debug_dir = format!("{}/debug/", normalized_output_dir.clone());
95
- debugger.write_files(debug_dir.as_str(), resolved_statements);
113
+ let success_message = format!(
114
+ "Build completed successfully in {:.2?}. Output files written to: '{}'",
115
+ duration.elapsed(),
116
+ normalized_output_dir
117
+ );
96
118
 
97
- let success_message = format!(
98
- "Build completed successfully in {:.2?}. Output files written to: '{}'",
99
- duration.elapsed(),
100
- normalized_output_dir
101
- );
102
- log_message(&success_message, "SUCCESS");
103
- }
119
+ let logger = Logger::new();
120
+ logger.log_message(LogLevel::Success, &success_message);
104
121
  }
package/rust/cli/check.rs CHANGED
@@ -1,29 +1,20 @@
1
- use std::{ thread, time::Duration };
2
-
3
1
  use crate::{
2
+ config::Config,
4
3
  core::{
5
- debugger::Debugger,
6
- preprocessor::module::load_all_modules,
7
- types::{
8
- config::{ DevalangConfig },
9
- statement::{ StatementKind, StatementResolved, StatementResolvedValue },
10
- },
11
- },
12
- runner::executer::execute_statements,
13
- utils::{
14
- loader::with_spinner,
15
- logger::log_message,
16
- path::{ find_entry_file, normalize_path },
17
- watcher::watch_directory,
4
+ preprocessor::loader::ModuleLoader,
5
+ store::global::GlobalStore,
6
+ utils::path::{ find_entry_file, normalize_path },
18
7
  },
8
+ utils::{ logger::{ LogLevel, Logger }, spinner::with_spinner, watcher::watch_directory },
19
9
  };
10
+ use std::{ thread, time::Duration };
20
11
 
21
12
  pub fn handle_check_command(
22
- config: Option<DevalangConfig>,
13
+ config: Option<Config>,
23
14
  entry: Option<String>,
24
15
  output: Option<String>,
25
16
  watch: bool
26
- ) -> () {
17
+ ) {
27
18
  let fetched_entry = if entry.is_none() {
28
19
  config
29
20
  .as_ref()
@@ -51,36 +42,51 @@ pub fn handle_check_command(
51
42
  .unwrap_or(false)
52
43
  };
53
44
 
45
+ let logger = Logger::new();
46
+
54
47
  if fetched_entry.is_empty() {
55
- eprintln!("❌ Entry path is not specified. Please provide a valid entry path.");
48
+ logger.log_message(
49
+ LogLevel::Error,
50
+ "Entry path is not specified. Please provide a valid entry path."
51
+ );
56
52
  std::process::exit(1);
57
53
  }
58
-
59
54
  if fetched_output.is_empty() {
60
- eprintln!("❌ Output directory is not specified. Please provide a valid output directory.");
55
+ logger.log_message(
56
+ LogLevel::Error,
57
+ "Output directory is not specified. Please provide a valid output directory."
58
+ );
61
59
  std::process::exit(1);
62
60
  }
63
61
 
64
62
  let entry_file = find_entry_file(&fetched_entry).unwrap_or_else(|| {
65
- eprintln!("❌ index.deva not found in directory: {}", fetched_entry);
63
+ logger.log_message(
64
+ LogLevel::Error,
65
+ &format!("❌ index.deva not found in directory: {}", fetched_entry)
66
+ );
66
67
  std::process::exit(1);
67
68
  });
68
69
 
69
- if fetched_watch.clone() == true {
70
- log_message("Watch mode enabled, waiting for file changes...", "INFO");
70
+ // SECTION Begin check
71
+ if fetched_watch {
72
+ begin_check(entry_file.clone(), fetched_output.clone());
71
73
 
72
- begin_check(entry_file.clone(), fetched_output.clone(), fetched_watch.clone());
74
+ logger.log_message(
75
+ LogLevel::Watcher,
76
+ &format!("Watching for changes in '{}'...", fetched_entry)
77
+ );
73
78
 
74
79
  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());
80
+ logger.log_message(LogLevel::Watcher, "Detected changes, re-checking...");
81
+
82
+ begin_check(entry_file.clone(), fetched_output.clone());
77
83
  }).unwrap();
78
84
  } else {
79
- begin_check(entry_file.clone(), fetched_output.clone(), fetched_watch.clone());
85
+ begin_check(entry_file.clone(), fetched_output.clone());
80
86
  }
81
87
  }
82
88
 
83
- fn begin_check(entry: String, output: String, watch: bool) {
89
+ fn begin_check(entry: String, output: String) {
84
90
  let spinner = with_spinner("Checking...", || {
85
91
  thread::sleep(Duration::from_millis(800));
86
92
  });
@@ -90,91 +96,21 @@ fn begin_check(entry: String, output: String, watch: bool) {
90
96
  let normalized_entry_file = normalize_path(&entry);
91
97
  let normalized_output_dir = normalize_path(&output);
92
98
 
93
- let global_store = load_all_modules(&normalized_entry_file);
94
-
95
- if let Some(module) = global_store.modules.get(&normalized_entry_file) {
96
- let mut module_clone = module.clone();
97
-
98
- let resolved_statements = execute_statements(&mut module_clone);
99
-
100
- let debugger = Debugger::new(&module_clone);
101
- let debug_dir = format!("{}/debug/", normalized_output_dir.clone());
102
- debugger.write_files(debug_dir.as_str(), resolved_statements.clone());
99
+ let mut global_store = GlobalStore::new();
100
+ let module_loader = ModuleLoader::new(&normalized_entry_file, &normalized_output_dir);
103
101
 
104
- let has_errors = resolved_statements
105
- .iter()
106
- .any(|stmt| { match_error_recursively_resolved(&stmt.clone()) });
102
+ // SECTION Load
103
+ // NOTE: We don't use modules in the check command, but we still need to load them
104
+ let modules = module_loader.load_all(&mut global_store);
107
105
 
108
- if has_errors {
109
- let warning_message = format!(
110
- "Check completed with errors in {:.2?}. Output files written to: '{}'",
111
- duration.elapsed(),
112
- normalized_output_dir
113
- );
106
+ // TODO: Implement debugging
114
107
 
115
- log_message(&warning_message, "WARNING");
116
- } else {
117
- let success_message = format!(
118
- "Check completed successfully in {:.2?}. Output files written to: '{}'",
119
- duration.elapsed(),
120
- normalized_output_dir
121
- );
122
-
123
- log_message(&success_message, "SUCCESS");
124
- }
125
- }
126
- }
127
-
128
- fn match_error_recursively_resolved(stmt: &StatementResolved) -> bool {
129
- match stmt.value.clone() {
130
- // TODO Other statement value types here
131
-
132
- StatementResolvedValue::Map(map) => {
133
- for (key, value) in map {
134
- if match_error_recursively_resolved_value(&value) {
135
- return true;
136
- }
137
- }
138
- }
139
-
140
- StatementResolvedValue::Array(array) => {
141
- for item in array {
142
- if match_error_recursively_resolved(&item) {
143
- return true;
144
- }
145
- }
146
- }
147
-
148
- _ => {
149
- if let StatementKind::Error = stmt.kind {
150
- eprintln!("❌ Error found in statement: {:?}", stmt);
151
- return true;
152
- }
153
- }
154
- }
155
-
156
- false
157
- }
158
-
159
- fn match_error_recursively_resolved_value(value: &StatementResolvedValue) -> bool {
160
- match value {
161
- StatementResolvedValue::Map(map) => {
162
- for (_, v) in map {
163
- if match_error_recursively_resolved_value(v) {
164
- return true;
165
- }
166
- }
167
- }
168
-
169
- StatementResolvedValue::Array(array) => {
170
- for item in array {
171
- if match_error_recursively_resolved(item) {
172
- return true;
173
- }
174
- }
175
- }
176
- _ => {}
177
- }
108
+ let success_message = format!(
109
+ "Check completed successfully in {:.2?}. Output files written to: '{}'",
110
+ duration.elapsed(),
111
+ normalized_output_dir
112
+ );
178
113
 
179
- false
114
+ let logger = Logger::new();
115
+ logger.log_message(LogLevel::Success, &success_message);
180
116
  }
package/rust/cli/init.rs CHANGED
@@ -2,7 +2,7 @@ use std::{ fs, path::Path };
2
2
  use include_dir::{ include_dir, Dir };
3
3
  use inquire::{ Select, Confirm };
4
4
 
5
- use crate::{ cli::template::{ get_available_templates }, utils::file::copy_dir_recursive };
5
+ use crate::{ cli::template::get_available_templates, utils::file::copy_dir_recursive };
6
6
 
7
7
  static TEMPLATES_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/templates");
8
8