@devaloop/devalang 0.0.1-alpha.8 → 0.0.1-alpha.9

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 (59) hide show
  1. package/Cargo.toml +1 -1
  2. package/README.md +4 -8
  3. package/docs/CHANGELOG.md +27 -0
  4. package/examples/condition.deva +8 -12
  5. package/examples/group.deva +3 -3
  6. package/examples/index.deva +10 -8
  7. package/examples/loop.deva +10 -8
  8. package/examples/synth.deva +14 -0
  9. package/examples/variables.deva +1 -1
  10. package/out-tsc/bin/devalang.exe +0 -0
  11. package/out-tsc/scripts/version/fetch.js +1 -5
  12. package/package.json +1 -1
  13. package/project-version.json +3 -3
  14. package/rust/core/audio/engine.rs +89 -12
  15. package/rust/core/audio/interpreter/arrow_call.rs +129 -0
  16. package/rust/core/audio/interpreter/call.rs +29 -7
  17. package/rust/core/audio/interpreter/condition.rs +5 -1
  18. package/rust/core/audio/interpreter/driver.rs +41 -29
  19. package/rust/core/audio/interpreter/loop_.rs +11 -3
  20. package/rust/core/audio/interpreter/mod.rs +1 -0
  21. package/rust/core/audio/interpreter/spawn.rs +43 -42
  22. package/rust/core/audio/interpreter/trigger.rs +1 -1
  23. package/rust/core/audio/renderer.rs +15 -18
  24. package/rust/core/lexer/handler/arrow.rs +31 -0
  25. package/rust/core/lexer/handler/driver.rs +12 -1
  26. package/rust/core/lexer/handler/identifier.rs +1 -0
  27. package/rust/core/lexer/handler/mod.rs +1 -0
  28. package/rust/core/lexer/mod.rs +24 -3
  29. package/rust/core/lexer/token.rs +4 -0
  30. package/rust/core/parser/driver.rs +23 -4
  31. package/rust/core/parser/handler/arrow_call.rs +126 -0
  32. package/rust/core/parser/handler/identifier/call.rs +41 -0
  33. package/rust/core/parser/handler/identifier/group.rs +75 -0
  34. package/rust/core/parser/handler/identifier/let_.rs +133 -0
  35. package/rust/core/parser/handler/identifier/mod.rs +51 -0
  36. package/rust/core/parser/handler/identifier/sleep.rs +33 -0
  37. package/rust/core/parser/handler/identifier/spawn.rs +41 -0
  38. package/rust/core/parser/handler/identifier/synth.rs +65 -0
  39. package/rust/core/parser/handler/loop_.rs +24 -18
  40. package/rust/core/parser/handler/mod.rs +2 -1
  41. package/rust/core/parser/statement.rs +8 -0
  42. package/rust/core/preprocessor/loader.rs +57 -43
  43. package/rust/core/preprocessor/module.rs +3 -6
  44. package/rust/core/preprocessor/processor.rs +13 -4
  45. package/rust/core/preprocessor/resolver/call.rs +99 -29
  46. package/rust/core/preprocessor/resolver/condition.rs +38 -12
  47. package/rust/core/preprocessor/resolver/driver.rs +74 -29
  48. package/rust/core/preprocessor/resolver/group.rs +24 -81
  49. package/rust/core/preprocessor/resolver/let_.rs +31 -0
  50. package/rust/core/preprocessor/resolver/loop_.rs +62 -116
  51. package/rust/core/preprocessor/resolver/mod.rs +5 -1
  52. package/rust/core/preprocessor/resolver/spawn.rs +41 -36
  53. package/rust/core/preprocessor/resolver/synth.rs +50 -0
  54. package/rust/core/preprocessor/resolver/trigger.rs +51 -50
  55. package/rust/core/preprocessor/resolver/value.rs +78 -0
  56. package/rust/core/utils/path.rs +17 -32
  57. package/rust/core/utils/validation.rs +30 -28
  58. package/typescript/scripts/version/fetch.ts +1 -6
  59. package/rust/core/parser/handler/identifier.rs +0 -262
@@ -0,0 +1,78 @@
1
+ use std::collections::HashMap;
2
+
3
+ use crate::{
4
+ core::{
5
+ parser::statement::{ Statement, StatementKind },
6
+ preprocessor::{ module::Module, resolver::driver::resolve_statement },
7
+ shared::value::Value,
8
+ store::{ global::GlobalStore, variable::VariableTable },
9
+ },
10
+ utils::logger::{ LogLevel, Logger },
11
+ };
12
+
13
+ fn find_export_value(name: &str, global_store: &GlobalStore) -> Option<Value> {
14
+ for (_path, module) in &global_store.modules {
15
+ if let Some(val) = module.export_table.get_export(name) {
16
+ return Some(val.clone());
17
+ }
18
+ }
19
+ None
20
+ }
21
+
22
+ pub fn resolve_value(value: &Value, module: &Module, global_store: &mut GlobalStore) -> Value {
23
+ match value {
24
+ Value::Identifier(name) => {
25
+ if let Some(original_val) = module.variable_table.get(name) {
26
+ return resolve_value(original_val, module, global_store);
27
+ }
28
+
29
+ if let Some(export_val) = find_export_value(name, global_store) {
30
+ return resolve_value(&export_val, module, global_store);
31
+ }
32
+
33
+ eprintln!("⚠️ Unresolved identifier '{}'", name);
34
+ Value::Null
35
+ }
36
+
37
+ Value::Map(map) => {
38
+ if let Some(Value::Identifier(entity)) = map.get("entity") {
39
+ // SECTION Synth
40
+ if entity == "synth" {
41
+ if let Some(Value::Map(synth_data)) = map.get("value") {
42
+ let resolved_waveform = synth_data
43
+ .get("waveform")
44
+ .map(|wf| resolve_value(wf, module, global_store))
45
+ .unwrap_or(Value::Null);
46
+
47
+ let resolved_params = synth_data
48
+ .get("parameters")
49
+ .map(|p| resolve_value(p, module, global_store))
50
+ .unwrap_or(Value::Map(HashMap::new()));
51
+
52
+ let mut result = HashMap::new();
53
+ result.insert("waveform".to_string(), resolved_waveform);
54
+ result.insert("parameters".to_string(), resolved_params);
55
+
56
+ return Value::Map(result);
57
+ }
58
+ }
59
+ }
60
+
61
+ let mut resolved = HashMap::new();
62
+ for (k, v) in map {
63
+ resolved.insert(k.clone(), resolve_value(v, module, global_store));
64
+ }
65
+ Value::Map(resolved)
66
+ }
67
+
68
+ Value::Block(stmts) => {
69
+ let resolved_stmts = stmts
70
+ .iter()
71
+ .map(|stmt| resolve_statement(stmt, module, &module.path, global_store))
72
+ .collect();
73
+ Value::Block(resolved_stmts)
74
+ }
75
+
76
+ other => other.clone(),
77
+ }
78
+ }
@@ -1,46 +1,31 @@
1
- use std::path::{ Component, Path };
1
+ use std::path::{ Component, Path, PathBuf };
2
2
 
3
- pub fn find_entry_file(path: &str) -> Option<String> {
4
- let path = Path::new(path);
3
+ pub fn find_entry_file(entry: &str) -> Option<String> {
4
+ let path = Path::new(entry);
5
5
 
6
- // Check if the path is a file
7
6
  if path.is_file() {
8
- return Some(path.to_string_lossy().to_string());
7
+ return Some(normalize_path(entry));
9
8
  }
10
9
 
11
- // Check if the path is a directory
12
10
  if path.is_dir() {
13
- // Look for an index.deva file in the directory
14
- let index_path = path.join("index.deva");
15
- if index_path.is_file() {
16
- return Some(index_path.to_string_lossy().to_string());
11
+ let candidate = path.join("index.deva");
12
+ if candidate.exists() {
13
+ return Some(normalize_path(&candidate));
17
14
  }
18
15
  }
19
16
 
20
17
  None
21
18
  }
22
19
 
23
- pub fn normalize_path(path: &str) -> String {
24
- let mut components = Vec::new();
25
-
26
- // Iterate through the components of the path
27
- for comp in Path::new(path).components() {
28
- match comp {
29
- Component::CurDir => {
30
- continue;
31
- }
32
- Component::Normal(c) => components.push(c),
33
- Component::RootDir => components.clear(),
34
- _ => {}
35
- }
36
- }
37
-
38
- // Join the components into a normalized path
39
- let normalized = components
40
- .iter()
41
- .map(|c| c.to_string_lossy())
42
- .collect::<Vec<_>>()
43
- .join("/");
20
+ pub fn normalize_path<P: AsRef<Path>>(path: P) -> String {
21
+ let path_buf = PathBuf::from(path.as_ref());
22
+ path_buf.components().collect::<PathBuf>().to_string_lossy().replace('\\', "/")
23
+ }
44
24
 
45
- format!("./{}", normalized)
25
+ pub fn resolve_relative_path(base: &str, import: &str) -> String {
26
+ let base_path = Path::new(base)
27
+ .parent()
28
+ .unwrap_or_else(|| Path::new(""));
29
+ let full_path = base_path.join(import);
30
+ full_path.components().collect::<PathBuf>().to_string_lossy().replace("\\", "/")
46
31
  }
@@ -1,35 +1,37 @@
1
1
  use crate::core::{ preprocessor::module::Module, shared::value::Value, store::global::GlobalStore };
2
2
 
3
- pub fn is_valid_entity(entity: &str, module: &Module, global_store: &GlobalStore) -> bool {
4
- let built_ins = ["kick", "snare", "hat", "clap"];
3
+ // NOTE: Deprecated functions, kept for reference
5
4
 
6
- if built_ins.contains(&entity) {
7
- return true;
8
- }
5
+ // pub fn is_valid_entity(entity: &str, module: &Module, global_store: &GlobalStore) -> bool {
6
+ // let built_ins = ["kick", "snare", "hat", "clap"];
9
7
 
10
- if let Some(val) = module.variable_table.get(entity) {
11
- match val {
12
- Value::Sample(_) => true,
13
- _ => false,
14
- }
15
- } else {
16
- false
17
- }
18
- }
8
+ // if built_ins.contains(&entity) {
9
+ // return true;
10
+ // }
19
11
 
20
- pub fn is_valid_identifier(ident: &str, module: &Module) -> bool {
21
- let built_ins = ["auto"];
12
+ // if let Some(val) = module.variable_table.get(entity) {
13
+ // match val {
14
+ // Value::Sample(_) => true,
15
+ // _ => false,
16
+ // }
17
+ // } else {
18
+ // false
19
+ // }
20
+ // }
22
21
 
23
- if built_ins.contains(&ident) {
24
- return true;
25
- }
22
+ // pub fn is_valid_identifier(ident: &str, module: &Module) -> bool {
23
+ // let built_ins = ["auto"];
26
24
 
27
- if let Some(val) = module.variable_table.get(ident) {
28
- match val {
29
- Value::Identifier(_) => true,
30
- _ => false,
31
- }
32
- } else {
33
- false
34
- }
35
- }
25
+ // if built_ins.contains(&ident) {
26
+ // return true;
27
+ // }
28
+
29
+ // if let Some(val) = module.variable_table.get(ident) {
30
+ // match val {
31
+ // Value::Identifier(_) => true,
32
+ // _ => false,
33
+ // }
34
+ // } else {
35
+ // false
36
+ // }
37
+ // }
@@ -1,23 +1,18 @@
1
1
  import fs from "fs";
2
- import path from "path";
3
2
  import { execSync } from "child_process";
4
3
 
5
4
  export const fetchVersion = async (projectVersionPath: string) => {
6
- // Lire le fichier
7
5
  const data = JSON.parse(fs.readFileSync(projectVersionPath, "utf-8"));
8
6
 
9
- // Incrémenter le numéro de build
10
7
  data.build = (data.build || 0) + 1;
11
8
 
12
- // Récupérer le dernier hash git
13
9
  try {
14
10
  const commit = execSync("git rev-parse HEAD").toString().trim();
15
11
  data.lastCommit = commit;
16
12
  } catch (err) {
17
- console.warn("⚠️ Impossible de récupérer le hash git.");
13
+ console.warn("⚠️ Unable to fetch git commit hash. Ensure you are in a git repository.");
18
14
  }
19
15
 
20
- // Écrire la mise à jour
21
16
  fs.writeFileSync(projectVersionPath, JSON.stringify(data, null, 2));
22
17
  }
23
18
 
@@ -1,262 +0,0 @@
1
- use crate::core::{
2
- lexer::token::{ Token, TokenKind },
3
- parser::{ statement::{ Statement, StatementKind }, driver::Parser },
4
- shared::value::Value,
5
- store::global::GlobalStore,
6
- };
7
- use std::collections::HashMap;
8
-
9
- pub fn parse_identifier_token(parser: &mut Parser, global_store: &mut GlobalStore) -> Statement {
10
- let Some(current_token) = parser.peek_clone() else {
11
- return Statement::unknown();
12
- };
13
-
14
- if current_token.lexeme == "let" {
15
- parser.advance(); // consume "let"
16
-
17
- let identifier = if let Some(token) = parser.peek_clone() {
18
- if token.kind == TokenKind::Identifier {
19
- parser.advance();
20
- token.lexeme.clone()
21
- } else {
22
- return Statement::error(token, "Expected identifier after 'let'".to_string());
23
- }
24
- } else {
25
- return Statement::error(current_token, "Expected identifier after 'let'".to_string());
26
- };
27
-
28
- if !parser.match_token(TokenKind::Equals) {
29
- return Statement::error(current_token, "Expected '=' after identifier".to_string());
30
- }
31
-
32
- let value = match parser.peek_clone() {
33
- Some(token) if token.kind == TokenKind::Identifier => {
34
- parser.advance();
35
- Value::Identifier(token.lexeme.clone())
36
- }
37
- Some(token) if token.kind == TokenKind::String => {
38
- parser.advance();
39
- Value::String(token.lexeme.clone())
40
- }
41
- Some(token) if token.kind == TokenKind::Number => {
42
- parser.advance();
43
- Value::Number(token.lexeme.parse().unwrap_or(0.0))
44
- }
45
- Some(token) if token.kind == TokenKind::LBrace => {
46
- parser.advance(); // consume '{'
47
- let mut map = HashMap::new();
48
-
49
- while let Some(key_token) = parser.peek_clone() {
50
- if key_token.kind == TokenKind::RBrace {
51
- parser.advance(); // consume '}'
52
- break;
53
- }
54
-
55
- if key_token.kind != TokenKind::Identifier {
56
- return Statement::error(
57
- token,
58
- "Expected key identifier in map".to_string()
59
- );
60
- }
61
- parser.advance();
62
- let key = key_token.lexeme.clone();
63
-
64
- if !parser.match_token(TokenKind::Colon) {
65
- let message = format!("Expected ':' after key '{}'", key);
66
- return Statement::error(token, message);
67
- }
68
-
69
- let val = match parser.peek_clone() {
70
- Some(t) if t.kind == TokenKind::Number => {
71
- parser.advance();
72
- Value::Number(t.lexeme.parse().unwrap_or(0.0))
73
- }
74
- Some(t) if t.kind == TokenKind::String => {
75
- parser.advance();
76
- Value::String(t.lexeme.clone())
77
- }
78
- Some(t) if t.kind == TokenKind::Identifier => {
79
- parser.advance();
80
- Value::Identifier(t.lexeme.clone())
81
- }
82
- _ => { Value::Null }
83
- };
84
-
85
- if val == Value::Null {
86
- let message = format!("Invalid value for key '{}'", key);
87
- return Statement::error(token, message);
88
- }
89
-
90
- map.insert(key, val);
91
-
92
- if let Some(t) = parser.peek() {
93
- if t.kind == TokenKind::Comma {
94
- parser.advance(); // skip comma
95
- }
96
- }
97
- }
98
-
99
- Value::Map(map)
100
- }
101
- other => {
102
- let message = format!("Unexpected value token in let: {:?}", other);
103
- return Statement::error(current_token, message);
104
- }
105
- };
106
-
107
- return Statement {
108
- kind: StatementKind::Let { name: identifier },
109
- value,
110
- indent: current_token.indent,
111
- line: current_token.line,
112
- column: current_token.column,
113
- };
114
- } else if current_token.lexeme == "group" {
115
- parser.advance(); // consume "group"
116
-
117
- let Some(identifier_token) = parser.peek_clone() else {
118
- return Statement::error(current_token, "Expected identifier after 'group'".to_string());
119
- };
120
-
121
- if
122
- identifier_token.kind != TokenKind::Identifier &&
123
- identifier_token.kind != TokenKind::String
124
- {
125
- return Statement::error(identifier_token, "Expected valid identifier".to_string());
126
- }
127
-
128
- parser.advance(); // consume identifier
129
-
130
- let Some(colon_token) = parser.peek_clone() else {
131
- return Statement::error(
132
- identifier_token,
133
- "Expected ':' after group identifier".to_string()
134
- );
135
- };
136
-
137
- if colon_token.kind != TokenKind::Colon {
138
- return Statement::error(
139
- colon_token.clone(),
140
- "Expected ':' after group identifier".to_string()
141
- );
142
- }
143
-
144
- parser.advance(); // consume ':'
145
-
146
- let base_indent = current_token.indent;
147
-
148
- // Clone without consuming tokens
149
- let mut index = parser.token_index;
150
- let mut tokens_inside_group = Vec::new();
151
-
152
- while index < parser.tokens.len() {
153
- let token = parser.tokens[index].clone();
154
-
155
- if token.indent <= base_indent && token.kind != TokenKind::Newline {
156
- break;
157
- }
158
-
159
- tokens_inside_group.push(token);
160
- index += 1;
161
- }
162
-
163
- // Advance index once to skip the processed tokens
164
- parser.token_index = index;
165
-
166
- let body = parser.parse_block(tokens_inside_group, global_store);
167
-
168
- let mut value_map = HashMap::new();
169
- value_map.insert("identifier".to_string(), Value::String(identifier_token.lexeme.clone()));
170
- value_map.insert("body".to_string(), Value::Block(body));
171
-
172
- return Statement {
173
- kind: StatementKind::Group,
174
- value: Value::Map(value_map),
175
- indent: current_token.indent,
176
- line: current_token.line,
177
- column: current_token.column,
178
- };
179
- } else if current_token.lexeme == "call" {
180
- parser.advance(); // consume "call"
181
-
182
- let identifier = if let Some(token) = parser.peek_clone() {
183
- if token.kind == TokenKind::Identifier {
184
- parser.advance();
185
- token.lexeme.clone()
186
- } else {
187
- return Statement::error(token, "Expected identifier after 'call'".to_string());
188
- }
189
- } else {
190
- return Statement::error(current_token, "Expected identifier after 'call'".to_string());
191
- };
192
-
193
- return Statement {
194
- kind: StatementKind::Call,
195
- value: Value::String(identifier),
196
- indent: current_token.indent,
197
- line: current_token.line,
198
- column: current_token.column,
199
- };
200
- } else if current_token.lexeme == "spawn" {
201
- parser.advance(); // consume "spawn"
202
-
203
- let identifier = if let Some(token) = parser.peek_clone() {
204
- if token.kind == TokenKind::Identifier {
205
- parser.advance();
206
- token.lexeme.clone()
207
- } else {
208
- return Statement::error(token, "Expected identifier after 'spawn'".to_string());
209
- }
210
- } else {
211
- return Statement::error(current_token, "Expected identifier after 'spawn'".to_string());
212
- };
213
-
214
- return Statement {
215
- kind: StatementKind::Spawn,
216
- value: Value::String(identifier),
217
- indent: current_token.indent,
218
- line: current_token.line,
219
- column: current_token.column,
220
- };
221
- } else if current_token.lexeme == "sleep" {
222
- parser.advance(); // consume "sleep"
223
-
224
- let duration = if let Some(token) = parser.peek_clone() {
225
- if token.kind == TokenKind::Number {
226
- parser.advance();
227
- token.lexeme.parse().unwrap_or(0.0)
228
- } else {
229
- return Statement::error(token, "Expected number after 'sleep'".to_string());
230
- }
231
- } else {
232
- return Statement::error(current_token, "Expected number after 'sleep'".to_string());
233
- };
234
-
235
- return Statement {
236
- kind: StatementKind::Sleep,
237
- value: Value::Number(duration),
238
- indent: current_token.indent,
239
- line: current_token.line,
240
- column: current_token.column,
241
- };
242
- } else {
243
- // Unknown identifier handling
244
- Statement {
245
- kind: StatementKind::Unknown,
246
- value: Value::String(current_token.lexeme.clone()),
247
- indent: current_token.indent,
248
- line: current_token.line,
249
- column: current_token.column,
250
- };
251
- }
252
-
253
- parser.advance(); // unknown identifier fallback
254
-
255
- Statement {
256
- kind: StatementKind::Unknown,
257
- value: Value::String(current_token.lexeme.clone()),
258
- indent: current_token.indent,
259
- line: current_token.line,
260
- column: current_token.column,
261
- }
262
- }