@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.
Files changed (49) hide show
  1. package/.devalang +4 -0
  2. package/Cargo.toml +3 -2
  3. package/README.md +30 -6
  4. package/docs/CHANGELOG.md +53 -0
  5. package/docs/COMMANDS.md +29 -6
  6. package/docs/CONFIG.md +28 -0
  7. package/docs/ROADMAP.md +1 -1
  8. package/docs/TODO.md +43 -15
  9. package/examples/index.deva +1 -1
  10. package/out-tsc/bin/devalang.exe +0 -0
  11. package/package.json +2 -2
  12. package/project-version.json +3 -3
  13. package/rust/cli/build.rs +58 -5
  14. package/rust/cli/check.rs +73 -17
  15. package/rust/cli/init.rs +77 -0
  16. package/rust/cli/mod.rs +2 -1
  17. package/rust/cli/template.rs +56 -0
  18. package/rust/core/lexer/at.rs +21 -0
  19. package/rust/core/lexer/brace.rs +41 -0
  20. package/rust/core/lexer/bracket.rs +41 -0
  21. package/rust/core/lexer/colon.rs +21 -0
  22. package/rust/core/lexer/comment.rs +30 -0
  23. package/rust/core/lexer/dot.rs +21 -0
  24. package/rust/core/lexer/driver.rs +286 -0
  25. package/rust/core/lexer/equal.rs +32 -0
  26. package/rust/core/lexer/identifier.rs +38 -0
  27. package/rust/core/lexer/indent.rs +47 -0
  28. package/rust/core/lexer/mod.rs +14 -333
  29. package/rust/core/lexer/newline.rs +23 -0
  30. package/rust/core/lexer/number.rs +31 -0
  31. package/rust/core/lexer/quote.rs +61 -0
  32. package/rust/core/parser/dot.rs +48 -18
  33. package/rust/core/preprocessor/module.rs +1 -1
  34. package/rust/core/types/cli.rs +53 -31
  35. package/rust/core/types/config.rs +15 -0
  36. package/rust/core/types/mod.rs +2 -1
  37. package/rust/main.rs +30 -19
  38. package/rust/utils/config.rs +13 -0
  39. package/rust/utils/file.rs +35 -0
  40. package/rust/utils/mod.rs +4 -1
  41. package/rust/utils/watcher.rs +25 -0
  42. package/templates/minimal/.devalang +4 -0
  43. package/templates/minimal/src/index.deva +2 -0
  44. package/templates/welcome/.devalang +4 -0
  45. package/templates/welcome/README.md +185 -0
  46. package/templates/welcome/samples/kick-808.wav +0 -0
  47. package/templates/welcome/src/index.deva +13 -0
  48. package/templates/welcome/src/variables.deva +5 -0
  49. package/rust/cli/new.rs +0 -1
@@ -0,0 +1,56 @@
1
+ use include_dir::{ include_dir, Dir, DirEntry };
2
+
3
+ use crate::utils::file::format_file_size;
4
+
5
+ static TEMPLATES_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/templates");
6
+
7
+ pub fn handle_template_list_command() {
8
+ let available_templates = get_available_templates();
9
+
10
+ println!("📦 Available templates ({}) :\n", available_templates.len());
11
+
12
+ for dir in available_templates {
13
+ println!("• {}", dir);
14
+ }
15
+
16
+ println!("\nUsage : devalang init --name <project-name> --template <template-name>");
17
+ }
18
+
19
+ pub fn handle_template_info_command(name: String) {
20
+ let template_dir = TEMPLATES_DIR.get_dir(name.clone()).unwrap_or_else(|| {
21
+ println!("❌ The template '{}' is not found.", name);
22
+
23
+ std::process::exit(1);
24
+ });
25
+
26
+ let mut file_count = 0;
27
+ let mut dir_count = 0;
28
+ let mut total_size: u64 = 0;
29
+
30
+ fn walk(dir: &Dir, file_count: &mut u32, dir_count: &mut u32, total_size: &mut u64) {
31
+ for entry in dir.entries() {
32
+ match entry {
33
+ DirEntry::File(file) => {
34
+ *file_count += 1;
35
+ *total_size += file.contents().len() as u64;
36
+ }
37
+ DirEntry::Dir(subdir) => {
38
+ *dir_count += 1;
39
+ walk(subdir, file_count, dir_count, total_size);
40
+ }
41
+ }
42
+ }
43
+ }
44
+
45
+ walk(template_dir, &mut file_count, &mut dir_count, &mut total_size);
46
+
47
+ println!("📦 Template : {}", name);
48
+ println!("📂 Content : {file_count} file(s), {dir_count} folder(s)");
49
+ println!("💾 Size : {}", format_file_size(total_size));
50
+ }
51
+
52
+ pub fn get_available_templates() -> Vec<String> {
53
+ TEMPLATES_DIR.dirs()
54
+ .map(|dir| dir.path().file_name().unwrap().to_string_lossy().to_string())
55
+ .collect()
56
+ }
@@ -0,0 +1,21 @@
1
+ use crate::core::types::token::{ Token, TokenKind };
2
+
3
+ pub fn handle_at_lexer(
4
+ char: char,
5
+ chars: &mut std::iter::Peekable<std::str::Chars>,
6
+ current_indent: &mut usize,
7
+ indent_stack: &mut Vec<usize>,
8
+ tokens: &mut Vec<Token>,
9
+ line: &mut usize,
10
+ column: &mut usize
11
+ ) {
12
+ tokens.push(Token {
13
+ kind: TokenKind::At,
14
+ lexeme: char.to_string(),
15
+ line: *line,
16
+ column: *column,
17
+ indent: *current_indent,
18
+ });
19
+
20
+ *column += 1;
21
+ }
@@ -0,0 +1,41 @@
1
+ use crate::core::types::token::{ Token, TokenKind };
2
+
3
+ pub fn handle_rbrace_lexer(
4
+ char: char,
5
+ chars: &mut std::iter::Peekable<std::str::Chars>,
6
+ current_indent: &mut usize,
7
+ indent_stack: &mut Vec<usize>,
8
+ tokens: &mut Vec<Token>,
9
+ line: &mut usize,
10
+ column: &mut usize
11
+ ) {
12
+ tokens.push(Token {
13
+ kind: TokenKind::RBrace,
14
+ lexeme: char.to_string(),
15
+ line: *line,
16
+ column: *column,
17
+ indent: *current_indent,
18
+ });
19
+
20
+ *column += 1;
21
+ }
22
+
23
+ pub fn handle_lbrace_lexer(
24
+ char: char,
25
+ chars: &mut std::iter::Peekable<std::str::Chars>,
26
+ current_indent: &mut usize,
27
+ indent_stack: &mut Vec<usize>,
28
+ tokens: &mut Vec<Token>,
29
+ line: &mut usize,
30
+ column: &mut usize
31
+ ) {
32
+ tokens.push(Token {
33
+ kind: TokenKind::LBrace,
34
+ lexeme: char.to_string(),
35
+ line: *line,
36
+ column: *column,
37
+ indent: *current_indent,
38
+ });
39
+
40
+ *column += 1;
41
+ }
@@ -0,0 +1,41 @@
1
+ use crate::core::types::token::{ Token, TokenKind };
2
+
3
+ pub fn handle_rbracket_lexer(
4
+ char: char,
5
+ chars: &mut std::iter::Peekable<std::str::Chars>,
6
+ current_indent: &mut usize,
7
+ indent_stack: &mut Vec<usize>,
8
+ tokens: &mut Vec<Token>,
9
+ line: &mut usize,
10
+ column: &mut usize
11
+ ) {
12
+ tokens.push(Token {
13
+ kind: TokenKind::RBracket,
14
+ lexeme: char.to_string(),
15
+ line: *line,
16
+ column: *column,
17
+ indent: *current_indent,
18
+ });
19
+
20
+ *column += 1;
21
+ }
22
+
23
+ pub fn handle_lbracket_lexer(
24
+ char: char,
25
+ chars: &mut std::iter::Peekable<std::str::Chars>,
26
+ current_indent: &mut usize,
27
+ indent_stack: &mut Vec<usize>,
28
+ tokens: &mut Vec<Token>,
29
+ line: &mut usize,
30
+ column: &mut usize
31
+ ) {
32
+ tokens.push(Token {
33
+ kind: TokenKind::LBracket,
34
+ lexeme: char.to_string(),
35
+ line: *line,
36
+ column: *column,
37
+ indent: *current_indent,
38
+ });
39
+
40
+ *column += 1;
41
+ }
@@ -0,0 +1,21 @@
1
+ use crate::core::types::token::{Token, TokenKind};
2
+
3
+ pub fn handle_colon_lexer(
4
+ char: char,
5
+ chars: &mut std::iter::Peekable<std::str::Chars>,
6
+ current_indent: &mut usize,
7
+ indent_stack: &mut Vec<usize>,
8
+ tokens: &mut Vec<Token>,
9
+ line: &mut usize,
10
+ column: &mut usize
11
+ ) {
12
+ tokens.push(Token {
13
+ kind: TokenKind::Colon,
14
+ lexeme: char.to_string(),
15
+ line: *line,
16
+ column: *column,
17
+ indent: *current_indent,
18
+ });
19
+
20
+ *column += 1;
21
+ }
@@ -0,0 +1,30 @@
1
+ use crate::core::types::token::{ Token, TokenKind };
2
+
3
+ pub fn handle_comment_lexer(
4
+ char: char,
5
+ chars: &mut std::iter::Peekable<std::str::Chars>,
6
+ current_indent: &mut usize,
7
+ indent_stack: &mut Vec<usize>,
8
+ tokens: &mut Vec<Token>,
9
+ line: &mut usize,
10
+ column: &mut usize
11
+ ) {
12
+ let mut comment = String::new();
13
+
14
+ while let Some(&c) = chars.peek() {
15
+ if c == '\n' {
16
+ break;
17
+ }
18
+ comment.push(c);
19
+ chars.next();
20
+ *column += 1;
21
+ }
22
+
23
+ tokens.push(Token {
24
+ kind: TokenKind::Comment(comment.trim().to_string()),
25
+ lexeme: char.to_string(),
26
+ line: *line,
27
+ column: *column,
28
+ indent: *current_indent,
29
+ });
30
+ }
@@ -0,0 +1,21 @@
1
+ use crate::core::types::token::{Token, TokenKind};
2
+
3
+ pub fn handle_dot_lexer(
4
+ char: char,
5
+ chars: &mut std::iter::Peekable<std::str::Chars>,
6
+ current_indent: &mut usize,
7
+ indent_stack: &mut Vec<usize>,
8
+ tokens: &mut Vec<Token>,
9
+ line: &mut usize,
10
+ column: &mut usize
11
+ ) {
12
+ tokens.push(Token {
13
+ kind: TokenKind::Dot,
14
+ lexeme: char.to_string(),
15
+ line: *line,
16
+ column: *column,
17
+ indent: *current_indent,
18
+ });
19
+
20
+ *column += 1;
21
+ }
@@ -0,0 +1,286 @@
1
+
2
+
3
+ use crate::core::{
4
+ lexer::{
5
+ at::handle_at_lexer,
6
+ brace::{ handle_lbrace_lexer, handle_rbrace_lexer },
7
+ colon::handle_colon_lexer,
8
+ comment::handle_comment_lexer,
9
+ equal::handle_equal_lexer,
10
+ newline::handle_newline_lexer,
11
+ bracket::{ handle_lbracket_lexer, handle_rbracket_lexer },
12
+ dot::handle_dot_lexer,
13
+ identifier::handle_identifier_lexer,
14
+ indent::handle_indent_lexer,
15
+ number::handle_number_lexer,
16
+ quote::{ handle_double_quote_lexer, handle_single_quote_lexer },
17
+ },
18
+ types::token::{ Token, TokenKind },
19
+ };
20
+
21
+ pub fn lex(input: String) -> Vec<Token> {
22
+ let mut tokens = Vec::new();
23
+
24
+ let mut line = 1;
25
+ let mut column = 1;
26
+
27
+ let mut indent_stack: Vec<usize> = vec![0];
28
+ let mut current_indent = 0;
29
+ let mut at_line_start = true;
30
+
31
+ let mut chars = input.chars().peekable();
32
+
33
+ while let Some(_) = chars.peek() {
34
+ if at_line_start {
35
+ let (new_tokens, new_indent_stack, new_line, new_column) = handle_indent_lexer(
36
+ &mut chars,
37
+ &mut current_indent,
38
+ &mut indent_stack,
39
+ &mut tokens,
40
+ &mut line,
41
+ &mut column
42
+ );
43
+
44
+ // Update the main tokens vector and indent stack
45
+ tokens = new_tokens;
46
+ indent_stack = new_indent_stack;
47
+ line = new_line;
48
+ column = new_column;
49
+
50
+ // Reset at_line_start flag
51
+ at_line_start = false;
52
+ }
53
+
54
+ // Read the next character
55
+ let Some(ch) = chars.next() else {
56
+ break;
57
+ };
58
+
59
+ // Newline handling
60
+ if ch == '\n' {
61
+ handle_newline_lexer(
62
+ ch,
63
+ &mut chars,
64
+ &mut tokens,
65
+ &mut line,
66
+ &mut column,
67
+ &mut at_line_start,
68
+ &mut current_indent
69
+ );
70
+
71
+ continue;
72
+ }
73
+
74
+ if ch == ' ' || ch == '\t' {
75
+ column += if ch == '\t' { 4 } else { 1 };
76
+ continue;
77
+ }
78
+
79
+ if ch == '#' {
80
+ handle_comment_lexer(
81
+ ch,
82
+ &mut chars,
83
+ &mut current_indent,
84
+ &mut indent_stack,
85
+ &mut tokens,
86
+ &mut line,
87
+ &mut column
88
+ );
89
+
90
+ continue;
91
+ }
92
+
93
+ if ch == ':' {
94
+ handle_colon_lexer(
95
+ ch,
96
+ &mut chars,
97
+ &mut current_indent,
98
+ &mut indent_stack,
99
+ &mut tokens,
100
+ &mut line,
101
+ &mut column
102
+ );
103
+
104
+ continue;
105
+ }
106
+
107
+ if ch == '=' {
108
+ handle_equal_lexer(
109
+ ch,
110
+ &mut chars,
111
+ &mut current_indent,
112
+ &mut indent_stack,
113
+ &mut tokens,
114
+ &mut line,
115
+ &mut column
116
+ );
117
+
118
+ continue;
119
+ }
120
+
121
+ if ch == '[' {
122
+ handle_lbracket_lexer(
123
+ ch,
124
+ &mut chars,
125
+ &mut current_indent,
126
+ &mut indent_stack,
127
+ &mut tokens,
128
+ &mut line,
129
+ &mut column
130
+ );
131
+
132
+ continue;
133
+ }
134
+
135
+ if ch == ']' {
136
+ handle_rbracket_lexer(
137
+ ch,
138
+ &mut chars,
139
+ &mut current_indent,
140
+ &mut indent_stack,
141
+ &mut tokens,
142
+ &mut line,
143
+ &mut column
144
+ );
145
+
146
+ continue;
147
+ }
148
+
149
+ if ch == '{' {
150
+ handle_lbrace_lexer(
151
+ ch,
152
+ &mut chars,
153
+ &mut current_indent,
154
+ &mut indent_stack,
155
+ &mut tokens,
156
+ &mut line,
157
+ &mut column
158
+ );
159
+
160
+ continue;
161
+ }
162
+
163
+ if ch == '}' {
164
+ handle_rbrace_lexer(
165
+ ch,
166
+ &mut chars,
167
+ &mut current_indent,
168
+ &mut indent_stack,
169
+ &mut tokens,
170
+ &mut line,
171
+ &mut column
172
+ );
173
+
174
+ continue;
175
+ }
176
+
177
+ if ch == '"' {
178
+ handle_double_quote_lexer(
179
+ ch,
180
+ &mut chars,
181
+ &mut current_indent,
182
+ &mut indent_stack,
183
+ &mut tokens,
184
+ &mut line,
185
+ &mut column
186
+ );
187
+
188
+ continue;
189
+ }
190
+
191
+ if ch == '\'' {
192
+ handle_single_quote_lexer(
193
+ ch,
194
+ &mut chars,
195
+ &mut current_indent,
196
+ &mut indent_stack,
197
+ &mut tokens,
198
+ &mut line,
199
+ &mut column
200
+ );
201
+
202
+ continue;
203
+ }
204
+
205
+ if ch == '.' {
206
+ handle_dot_lexer(
207
+ ch,
208
+ &mut chars,
209
+ &mut current_indent,
210
+ &mut indent_stack,
211
+ &mut tokens,
212
+ &mut line,
213
+ &mut column
214
+ );
215
+
216
+ continue;
217
+ }
218
+
219
+ if ch == '@' {
220
+ handle_at_lexer(
221
+ ch,
222
+ &mut chars,
223
+ &mut current_indent,
224
+ &mut indent_stack,
225
+ &mut tokens,
226
+ &mut line,
227
+ &mut column
228
+ );
229
+
230
+ continue;
231
+ }
232
+
233
+ if ch.is_ascii_digit() {
234
+ handle_number_lexer(
235
+ ch,
236
+ &mut chars,
237
+ &mut current_indent,
238
+ &mut indent_stack,
239
+ &mut tokens,
240
+ &mut line,
241
+ &mut column
242
+ );
243
+
244
+ continue;
245
+ }
246
+
247
+ if ch.is_ascii_alphabetic() {
248
+ handle_identifier_lexer(
249
+ ch,
250
+ &mut chars,
251
+ &mut current_indent,
252
+ &mut indent_stack,
253
+ &mut tokens,
254
+ &mut line,
255
+ &mut column
256
+ );
257
+
258
+ continue;
259
+ }
260
+
261
+ // Skip unknown char
262
+ column += 1;
263
+ }
264
+
265
+ while indent_stack.len() > 1 {
266
+ indent_stack.pop();
267
+ current_indent = *indent_stack.last().unwrap();
268
+ tokens.push(Token {
269
+ kind: TokenKind::Dedent,
270
+ lexeme: String::new(),
271
+ line,
272
+ column,
273
+ indent: current_indent,
274
+ });
275
+ }
276
+
277
+ tokens.push(Token {
278
+ kind: TokenKind::EOF,
279
+ lexeme: String::new(),
280
+ line: line + 1, // EOF is considered to be on the next line
281
+ column: 0, // EOF has no column
282
+ indent: 0, // EOF has no indent
283
+ });
284
+
285
+ tokens
286
+ }
@@ -0,0 +1,32 @@
1
+ use crate::core::types::token::{Token, TokenKind};
2
+
3
+ pub fn handle_equal_lexer(
4
+ char: char,
5
+ chars: &mut std::iter::Peekable<std::str::Chars>,
6
+ current_indent: &mut usize,
7
+ indent_stack: &mut Vec<usize>,
8
+ tokens: &mut Vec<Token>,
9
+ line: &mut usize,
10
+ column: &mut usize
11
+ ) {
12
+ if let Some('=') = chars.peek() {
13
+ chars.next();
14
+ tokens.push(Token {
15
+ kind: TokenKind::DoubleEquals,
16
+ lexeme: char.to_string(),
17
+ line: *line,
18
+ column: *column,
19
+ indent: *current_indent,
20
+ });
21
+ *column += 2;
22
+ } else {
23
+ tokens.push(Token {
24
+ kind: TokenKind::Equals,
25
+ lexeme: char.to_string(),
26
+ line: *line,
27
+ column: *column,
28
+ indent: *current_indent,
29
+ });
30
+ *column += 1;
31
+ }
32
+ }
@@ -0,0 +1,38 @@
1
+ use crate::core::types::token::{ Token, TokenKind };
2
+
3
+ pub fn handle_identifier_lexer(
4
+ char: char,
5
+ chars: &mut std::iter::Peekable<std::str::Chars>,
6
+ current_indent: &mut usize,
7
+ indent_stack: &mut Vec<usize>,
8
+ tokens: &mut Vec<Token>,
9
+ line: &mut usize,
10
+ column: &mut usize
11
+ ) {
12
+ let mut ident = char.to_string();
13
+
14
+ while let Some(&c) = chars.peek() {
15
+ if c.is_ascii_alphanumeric() || c == '_' {
16
+ ident.push(c);
17
+ chars.next();
18
+ *column += 1;
19
+ } else {
20
+ break;
21
+ }
22
+ }
23
+
24
+ let kind = match ident.as_str() {
25
+ "bank" => TokenKind::Bank,
26
+ "bpm" => TokenKind::Tempo,
27
+ "loop" => TokenKind::Loop,
28
+ _ => TokenKind::Identifier,
29
+ };
30
+
31
+ tokens.push(Token {
32
+ kind: kind.clone(),
33
+ lexeme: ident,
34
+ line: *line,
35
+ column: *column,
36
+ indent: *current_indent,
37
+ });
38
+ }
@@ -0,0 +1,47 @@
1
+ use crate::core::types::token::{ Token, TokenKind };
2
+
3
+ pub fn handle_indent_lexer(
4
+ chars: &mut std::iter::Peekable<std::str::Chars>,
5
+ current_indent: &mut usize,
6
+ indent_stack: &mut Vec<usize>,
7
+ tokens: &mut Vec<Token>,
8
+ line: &mut usize,
9
+ column: &mut usize
10
+ ) -> (Vec<Token>, Vec<usize>, usize, usize) {
11
+ *current_indent = 0;
12
+
13
+ while let Some(&c) = chars.peek() {
14
+ if c == ' ' {
15
+ *current_indent += 1;
16
+ chars.next();
17
+ *column += 1;
18
+ } else {
19
+ break;
20
+ }
21
+ }
22
+
23
+ let last_indent = *indent_stack.last().unwrap();
24
+ if *current_indent > last_indent {
25
+ indent_stack.push(*current_indent);
26
+ tokens.push(Token {
27
+ kind: TokenKind::Indent,
28
+ lexeme: String::new(),
29
+ line: *line,
30
+ column: *column,
31
+ indent: *current_indent,
32
+ });
33
+ } else {
34
+ while *current_indent < *indent_stack.last().unwrap() {
35
+ indent_stack.pop();
36
+ tokens.push(Token {
37
+ kind: TokenKind::Dedent,
38
+ lexeme: String::new(),
39
+ line: *line,
40
+ column: *column,
41
+ indent: *current_indent,
42
+ });
43
+ }
44
+ }
45
+
46
+ (tokens.clone(), indent_stack.clone(), *line, *column)
47
+ }