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

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 (61) hide show
  1. package/Cargo.toml +1 -1
  2. package/README.md +29 -10
  3. package/docs/CHANGELOG.md +22 -2
  4. package/docs/ROADMAP.md +2 -2
  5. package/docs/SYNTAX.md +41 -7
  6. package/docs/TODO.md +3 -3
  7. package/examples/condition.deva +24 -0
  8. package/examples/index.deva +4 -5
  9. package/examples/variables.deva +1 -1
  10. package/out-tsc/bin/devalang.exe +0 -0
  11. package/package.json +1 -1
  12. package/project-version.json +3 -3
  13. package/rust/cli/build.rs +6 -1
  14. package/rust/core/audio/evaluator.rs +31 -0
  15. package/rust/core/audio/interpreter/call.rs +42 -0
  16. package/rust/core/audio/interpreter/condition.rs +65 -0
  17. package/rust/core/audio/interpreter/driver.rs +204 -0
  18. package/rust/core/audio/interpreter/let_.rs +19 -0
  19. package/rust/core/audio/interpreter/load.rs +18 -0
  20. package/rust/core/audio/interpreter/loop_.rs +59 -0
  21. package/rust/core/audio/interpreter/mod.rs +11 -0
  22. package/rust/core/audio/interpreter/sleep.rs +36 -0
  23. package/rust/core/audio/interpreter/spawn.rs +65 -0
  24. package/rust/core/audio/interpreter/tempo.rs +16 -0
  25. package/rust/core/audio/interpreter/trigger.rs +69 -0
  26. package/rust/core/audio/loader/mod.rs +1 -0
  27. package/rust/core/audio/{loader.rs → loader/trigger.rs} +3 -1
  28. package/rust/core/audio/mod.rs +2 -1
  29. package/rust/core/audio/{render.rs → renderer.rs} +6 -2
  30. package/rust/core/builder/mod.rs +1 -1
  31. package/rust/core/debugger/lexer.rs +1 -1
  32. package/rust/core/debugger/mod.rs +1 -0
  33. package/rust/core/debugger/store.rs +25 -0
  34. package/rust/core/error/mod.rs +1 -1
  35. package/rust/core/lexer/handler/driver.rs +215 -0
  36. package/rust/core/lexer/handler/identifier.rs +2 -0
  37. package/rust/core/lexer/handler/mod.rs +3 -227
  38. package/rust/core/lexer/handler/operator.rs +44 -0
  39. package/rust/core/lexer/mod.rs +1 -1
  40. package/rust/core/lexer/token.rs +36 -9
  41. package/rust/core/parser/driver.rs +312 -0
  42. package/rust/core/parser/handler/at.rs +3 -7
  43. package/rust/core/parser/handler/bank.rs +5 -2
  44. package/rust/core/parser/handler/condition.rs +74 -0
  45. package/rust/core/parser/handler/dot.rs +1 -1
  46. package/rust/core/parser/handler/identifier.rs +38 -36
  47. package/rust/core/parser/handler/loop_.rs +1 -1
  48. package/rust/core/parser/handler/mod.rs +2 -1
  49. package/rust/core/parser/handler/tempo.rs +1 -1
  50. package/rust/core/parser/mod.rs +3 -237
  51. package/rust/core/parser/statement.rs +29 -36
  52. package/rust/core/preprocessor/loader.rs +7 -6
  53. package/rust/core/preprocessor/processor.rs +1 -1
  54. package/rust/core/preprocessor/resolver/call.rs +53 -0
  55. package/rust/core/preprocessor/resolver/condition.rs +66 -0
  56. package/rust/core/preprocessor/resolver/driver.rs +182 -0
  57. package/rust/core/preprocessor/resolver/group.rs +89 -84
  58. package/rust/core/preprocessor/resolver/mod.rs +5 -153
  59. package/rust/core/preprocessor/resolver/spawn.rs +53 -0
  60. package/rust/core/audio/interpreter.rs +0 -317
  61. package/rust/core/lexer/handler/equal.rs +0 -32
@@ -0,0 +1,312 @@
1
+ use crate::core::{
2
+ lexer::token::{ Token, TokenKind },
3
+ parser::{
4
+ handler::{
5
+ at::parse_at_token,
6
+ bank::parse_bank_token,
7
+ condition::parse_condition_token,
8
+ dot::parse_dot_token,
9
+ identifier::parse_identifier_token,
10
+ loop_::parse_loop_token,
11
+ tempo::parse_tempo_token,
12
+ },
13
+ statement::{ Statement, StatementKind },
14
+ },
15
+ shared::value::Value,
16
+ store::global::GlobalStore,
17
+ };
18
+
19
+ #[derive(Debug, Clone, PartialEq)]
20
+ pub struct Parser {
21
+ pub resolve_modules: bool,
22
+ pub tokens: Vec<Token>,
23
+ pub token_index: usize,
24
+ pub current_module: String,
25
+ pub previous: Option<Token>,
26
+ }
27
+
28
+ impl Parser {
29
+ pub fn new() -> Self {
30
+ Parser {
31
+ resolve_modules: false,
32
+ tokens: Vec::new(),
33
+ token_index: 0,
34
+ current_module: String::new(),
35
+ previous: None,
36
+ }
37
+ }
38
+
39
+ pub fn set_current_module(&mut self, module_path: String) {
40
+ self.current_module = module_path;
41
+ }
42
+
43
+ pub fn advance(&mut self) -> Option<&Token> {
44
+ if self.is_eof() {
45
+ return None;
46
+ }
47
+
48
+ self.previous = self.tokens.get(self.token_index).cloned(); // mémorise avant de bouger
49
+ self.token_index += 1;
50
+
51
+ self.tokens.get(self.token_index - 1)
52
+ }
53
+
54
+ pub fn peek_is(&self, expected: &str) -> bool {
55
+ self.peek().map_or(false, |t| t.lexeme == expected)
56
+ }
57
+
58
+ pub fn advance_if(&mut self, kind: TokenKind) -> bool {
59
+ if self.match_token(kind) { true } else { false }
60
+ }
61
+
62
+ pub fn match_token(&mut self, kind: TokenKind) -> bool {
63
+ if let Some(tok) = self.peek() {
64
+ if tok.kind == kind {
65
+ self.advance();
66
+ return true;
67
+ }
68
+ }
69
+ false
70
+ }
71
+
72
+ pub fn previous_clone(&self) -> Option<Token> {
73
+ self.previous.clone()
74
+ }
75
+
76
+ pub fn parse_block(
77
+ &self,
78
+ tokens: Vec<Token>,
79
+ global_store: &mut GlobalStore
80
+ ) -> Vec<Statement> {
81
+ let mut inner_parser = Parser {
82
+ resolve_modules: self.resolve_modules,
83
+ tokens,
84
+ token_index: 0,
85
+ current_module: self.current_module.clone(),
86
+ previous: None,
87
+ };
88
+
89
+ inner_parser.parse_tokens(inner_parser.tokens.clone(), global_store)
90
+ }
91
+
92
+ pub fn parse_tokens(
93
+ &mut self,
94
+ tokens: Vec<Token>,
95
+ global_store: &mut GlobalStore
96
+ ) -> Vec<Statement> {
97
+ self.tokens = tokens;
98
+ self.token_index = 0;
99
+
100
+ let mut statements = Vec::new();
101
+
102
+ while !self.is_eof() {
103
+ let token = match self.peek() {
104
+ Some(t) => t.clone(),
105
+ None => {
106
+ break;
107
+ }
108
+ };
109
+
110
+ let mut statement = match &token.kind {
111
+ TokenKind::At => parse_at_token(self, global_store),
112
+ TokenKind::Identifier => parse_identifier_token(self, global_store),
113
+ TokenKind::Dot => parse_dot_token(self, global_store),
114
+ TokenKind::Tempo => parse_tempo_token(self, global_store),
115
+ TokenKind::Bank => parse_bank_token(self, global_store),
116
+ TokenKind::Loop => parse_loop_token(self, global_store),
117
+ TokenKind::If => parse_condition_token(self, global_store),
118
+
119
+ | TokenKind::Else // Ignore else, already handled in `parse_condition_token`
120
+ | TokenKind::Comment
121
+ | TokenKind::Equals
122
+ | TokenKind::Colon
123
+ | TokenKind::Number
124
+ | TokenKind::String
125
+ | TokenKind::LBrace
126
+ | TokenKind::RBrace
127
+ | TokenKind::Comma
128
+ | TokenKind::Newline
129
+ | TokenKind::Dedent
130
+ | TokenKind::Indent => {
131
+ self.advance();
132
+ continue;
133
+ }
134
+
135
+ TokenKind::EOF => {
136
+ break;
137
+ }
138
+
139
+ _ => {
140
+ println!("Unhandled token: {:?}", token);
141
+ self.advance();
142
+ Statement::unknown()
143
+ }
144
+ };
145
+
146
+ statements.push(statement);
147
+ }
148
+
149
+ statements
150
+ }
151
+
152
+ pub fn check_token(&self, kind: TokenKind) -> bool {
153
+ self.peek().map_or(false, |t| t.kind == kind)
154
+ }
155
+
156
+ pub fn parse_map_value(&mut self) -> Option<Value> {
157
+ if !self.match_token(TokenKind::LBrace) {
158
+ return None;
159
+ }
160
+
161
+ let mut map = std::collections::HashMap::new();
162
+
163
+ while !self.check_token(TokenKind::RBrace) && !self.is_eof() {
164
+ let key = if let Some(token) = self.advance() {
165
+ token.lexeme.clone()
166
+ } else {
167
+ break;
168
+ };
169
+
170
+ if !self.match_token(TokenKind::Colon) {
171
+ println!("Expected ':' after map key '{}'", key);
172
+ break;
173
+ }
174
+
175
+ let value = if let Some(token) = self.peek_clone() {
176
+ match token.kind {
177
+ TokenKind::String => {
178
+ self.advance();
179
+ Value::String(token.lexeme.clone())
180
+ }
181
+ TokenKind::Number => {
182
+ self.advance();
183
+ Value::Number(token.lexeme.parse().unwrap_or(0.0))
184
+ }
185
+ TokenKind::Identifier => {
186
+ self.advance();
187
+ Value::Identifier(token.lexeme.clone())
188
+ }
189
+ _ => {
190
+ println!("Unexpected token in map value: {:?}", token);
191
+ Value::Null
192
+ }
193
+ }
194
+ } else {
195
+ Value::Null
196
+ };
197
+
198
+ map.insert(key, value);
199
+ }
200
+
201
+ if !self.match_token(TokenKind::RBrace) {
202
+ println!("Expected '}}' at end of map");
203
+ }
204
+
205
+ Some(Value::Map(map))
206
+ }
207
+
208
+ pub fn peek(&self) -> Option<&Token> {
209
+ self.tokens.get(self.token_index)
210
+ }
211
+
212
+ pub fn peek_clone(&self) -> Option<Token> {
213
+ self.tokens.get(self.token_index).cloned()
214
+ }
215
+
216
+ pub fn expect(&mut self, kind: TokenKind) -> Result<&Token, String> {
217
+ let tok = self.advance().ok_or("Unexpected end of input")?;
218
+ if tok.kind == kind {
219
+ Ok(tok)
220
+ } else {
221
+ Err(format!("Expected {:?}, got {:?}", kind, tok.kind))
222
+ }
223
+ }
224
+
225
+ pub fn collect_block_tokens(&mut self, base_indent: usize) -> Vec<Token> {
226
+ let mut tokens = Vec::new();
227
+
228
+ while let Some(tok) = self.peek() {
229
+ if tok.indent <= base_indent && tok.kind != TokenKind::Newline {
230
+ break;
231
+ }
232
+ tokens.push(self.advance().unwrap().clone());
233
+ }
234
+
235
+ tokens
236
+ }
237
+
238
+ pub fn collect_until<F>(&mut self, condition: F) -> Vec<Token> where F: Fn(&Token) -> bool {
239
+ let mut collected = Vec::new();
240
+ while let Some(token) = self.peek() {
241
+ if token.kind == TokenKind::Newline || token.kind == TokenKind::Indent {
242
+ self.advance(); // Skip newlines and indents
243
+ continue;
244
+ }
245
+ if token.kind == TokenKind::EOF {
246
+ break;
247
+ }
248
+ if condition(token) {
249
+ break;
250
+ }
251
+ collected.push(self.advance().unwrap().clone());
252
+ }
253
+ collected
254
+ }
255
+
256
+ pub fn is_eof(&self) -> bool {
257
+ self.token_index >= self.tokens.len()
258
+ }
259
+
260
+ pub fn parse_block_until_next_else(
261
+ &mut self,
262
+ base_indent: usize,
263
+ global_store: &mut GlobalStore
264
+ ) -> Vec<Statement> {
265
+ let mut block_tokens = Vec::new();
266
+
267
+ while let Some(tok) = self.peek() {
268
+ // Stop if we encounter an 'else' at same indent level
269
+ if tok.lexeme == "else" && tok.indent == base_indent {
270
+ break;
271
+ }
272
+ block_tokens.push(self.advance().unwrap().clone());
273
+ }
274
+
275
+ self.parse_block(block_tokens, global_store)
276
+ }
277
+
278
+ pub fn parse_condition_until_colon(&mut self) -> Option<Value> {
279
+ let tokens = self.collect_until(|t| t.kind == TokenKind::Colon);
280
+ if tokens.is_empty() {
281
+ return None;
282
+ }
283
+
284
+ let condition = tokens
285
+ .iter()
286
+ .map(|t| t.lexeme.clone())
287
+ .collect::<Vec<_>>()
288
+ .join(" ");
289
+
290
+ Some(Value::String(condition))
291
+ }
292
+
293
+ pub fn parse_block_until_else_or_dedent(
294
+ &mut self,
295
+ base_indent: usize,
296
+ global_store: &mut GlobalStore
297
+ ) -> Vec<Statement> {
298
+ let mut tokens = Vec::new();
299
+
300
+ while let Some(tok) = self.peek() {
301
+ if tok.lexeme == "else" && tok.indent == base_indent {
302
+ break;
303
+ }
304
+ if tok.indent < base_indent && tok.kind != TokenKind::Newline {
305
+ break;
306
+ }
307
+ tokens.push(self.advance().unwrap().clone());
308
+ }
309
+
310
+ self.parse_block(tokens, global_store)
311
+ }
312
+ }
@@ -1,14 +1,10 @@
1
1
  use crate::core::{
2
- lexer::token::{ Token, TokenKind },
3
- parser::{
4
- handler::identifier::parse_identifier_token,
5
- statement::{ Statement, StatementKind },
6
- Parser,
7
- },
2
+ lexer::token::TokenKind,
3
+ parser::{ driver::Parser, statement::{ Statement, StatementKind } },
8
4
  shared::value::Value,
9
5
  store::global::GlobalStore,
10
6
  };
11
- pub fn parse_at_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
7
+ pub fn parse_at_token(parser: &mut Parser, global_store: &mut GlobalStore) -> Statement {
12
8
  parser.advance(); // consume '@'
13
9
 
14
10
  let Some(token) = parser.peek_clone() else {
@@ -1,6 +1,6 @@
1
1
  use crate::core::{
2
2
  lexer::token::TokenKind,
3
- parser::{ statement::{ Statement, StatementKind }, Parser },
3
+ parser::{ statement::{ Statement, StatementKind }, driver::Parser },
4
4
  shared::value::Value,
5
5
  store::global::GlobalStore,
6
6
  };
@@ -25,7 +25,10 @@ pub fn parse_bank_token(parser: &mut Parser, _global_store: &mut GlobalStore) ->
25
25
  _ => Value::Unknown,
26
26
  }
27
27
  } else {
28
- return Statement::error(bank_token, "Expected identifier or number after 'bank'".to_string());
28
+ return Statement::error(
29
+ bank_token,
30
+ "Expected identifier or number after 'bank'".to_string()
31
+ );
29
32
  };
30
33
 
31
34
  Statement {
@@ -0,0 +1,74 @@
1
+ use std::collections::HashMap;
2
+ use crate::core::{
3
+ lexer::token::TokenKind,
4
+ parser::{statement::{Statement, StatementKind}, driver::Parser},
5
+ shared::value::Value,
6
+ store::global::GlobalStore,
7
+ };
8
+
9
+ pub fn parse_condition_token(parser: &mut Parser, global_store: &mut GlobalStore) -> Statement {
10
+ parser.advance(); // consume 'if'
11
+ let Some(if_token) = parser.previous_clone() else {
12
+ return Statement::unknown();
13
+ };
14
+
15
+ let Some(condition) = parser.parse_condition_until_colon() else {
16
+ return Statement::error(if_token, "Expected condition after 'if'".to_string());
17
+ };
18
+
19
+ parser.advance_if(TokenKind::Colon);
20
+ let base_indent = if_token.indent;
21
+
22
+ let if_body = parser.parse_block_until_else_or_dedent(base_indent, global_store);
23
+
24
+ let mut root_map = HashMap::new();
25
+ root_map.insert("condition".to_string(), condition);
26
+ root_map.insert("body".to_string(), Value::Block(if_body));
27
+
28
+ let mut current = &mut root_map;
29
+
30
+ // Loop for else / else if
31
+ while let Some(tok) = parser.peek_clone() {
32
+ // Only continue if we see `else` at same indent level
33
+ if tok.lexeme != "else" || tok.indent != base_indent {
34
+ break;
35
+ }
36
+
37
+ parser.advance(); // consume 'else'
38
+
39
+ // Check if it's an 'else if'
40
+ let next_condition = if parser.peek_is("if") {
41
+ parser.advance(); // consume 'if'
42
+ let Some(cond) = parser.parse_condition_until_colon() else {
43
+ return Statement::error(tok.clone(), "Expected condition after 'else if'".to_string());
44
+ };
45
+ parser.advance_if(TokenKind::Colon);
46
+ Some(cond)
47
+ } else {
48
+ parser.advance_if(TokenKind::Colon);
49
+ None
50
+ };
51
+
52
+ let body = parser.parse_block_until_else_or_dedent(base_indent, global_store);
53
+
54
+ let mut next_map = HashMap::new();
55
+ if let Some(cond) = next_condition {
56
+ next_map.insert("condition".to_string(), cond);
57
+ }
58
+ next_map.insert("body".to_string(), Value::Block(body));
59
+
60
+ current.insert("next".to_string(), Value::Map(next_map));
61
+ current = match current.get_mut("next") {
62
+ Some(Value::Map(map)) => map,
63
+ _ => break,
64
+ };
65
+ }
66
+
67
+ Statement {
68
+ kind: StatementKind::If,
69
+ value: Value::Map(root_map),
70
+ indent: if_token.indent,
71
+ line: if_token.line,
72
+ column: if_token.column,
73
+ }
74
+ }
@@ -1,6 +1,6 @@
1
1
  use crate::core::{
2
2
  lexer::token::TokenKind,
3
- parser::{ statement::{ Statement, StatementKind }, Parser },
3
+ parser::{ statement::{ Statement, StatementKind }, driver::Parser },
4
4
  shared::{ duration::Duration, value::Value },
5
5
  store::global::GlobalStore,
6
6
  };
@@ -1,6 +1,6 @@
1
1
  use crate::core::{
2
2
  lexer::token::{ Token, TokenKind },
3
- parser::{ statement::{ Statement, StatementKind }, Parser },
3
+ parser::{ statement::{ Statement, StatementKind }, driver::Parser },
4
4
  shared::value::Value,
5
5
  store::global::GlobalStore,
6
6
  };
@@ -114,58 +114,60 @@ pub fn parse_identifier_token(parser: &mut Parser, global_store: &mut GlobalStor
114
114
  } else if current_token.lexeme == "group" {
115
115
  parser.advance(); // consume "group"
116
116
 
117
- let identifier = if let Some(token) = parser.peek_clone() {
118
- if token.kind == TokenKind::String {
119
- parser.advance();
120
- token.lexeme.clone()
121
- } else if token.kind == TokenKind::Identifier {
122
- parser.advance();
123
- token.lexeme.clone()
124
- } else {
125
- return Statement::error(
126
- token,
127
- "Expected string or identifier after 'group'".to_string()
128
- );
129
- }
130
- } else {
131
- return Statement::error(current_token, "Expected string after 'group'".to_string());
117
+ let Some(identifier_token) = parser.peek_clone() else {
118
+ return Statement::error(current_token, "Expected identifier after 'group'".to_string());
132
119
  };
133
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
+
134
130
  let Some(colon_token) = parser.peek_clone() else {
135
131
  return Statement::error(
136
- current_token,
132
+ identifier_token,
137
133
  "Expected ':' after group identifier".to_string()
138
134
  );
139
135
  };
140
136
 
141
137
  if colon_token.kind != TokenKind::Colon {
142
- let message = format!(
143
- "Expected ':' after group identifier, got {:?}",
144
- colon_token.kind
138
+ return Statement::error(
139
+ colon_token.clone(),
140
+ "Expected ':' after group identifier".to_string()
145
141
  );
146
- return Statement::error(colon_token.clone(), message);
147
142
  }
148
143
 
149
- let tokens = parser.collect_until(
150
- |t| (t.kind == TokenKind::Dedent || t.kind == TokenKind::EOF)
151
- );
152
- let group_body = parser.parse_block(tokens.clone(), global_store);
144
+ parser.advance(); // consume ':'
153
145
 
154
- // Peek for dedent
155
- if let Some(token) = parser.peek() {
156
- if token.kind == TokenKind::Dedent {
157
- parser.advance();
158
- } else {
159
- // Unexpected token after group body
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;
160
157
  }
161
- } else {
162
- // EOF or unexpected end of input
158
+
159
+ tokens_inside_group.push(token);
160
+ index += 1;
163
161
  }
164
162
 
165
- let mut value_map = HashMap::new();
163
+ // Advance index once to skip the processed tokens
164
+ parser.token_index = index;
166
165
 
167
- value_map.insert("identifier".to_string(), Value::String(identifier));
168
- value_map.insert("body".to_string(), Value::Block(group_body.clone()));
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));
169
171
 
170
172
  return Statement {
171
173
  kind: StatementKind::Group,
@@ -2,7 +2,7 @@ use std::collections::HashMap;
2
2
 
3
3
  use crate::core::{
4
4
  lexer::{ token::TokenKind },
5
- parser::{ statement::{ Statement, StatementKind }, Parser },
5
+ parser::{ statement::{ Statement, StatementKind }, driver::Parser },
6
6
  shared::value::Value,
7
7
  store::global::GlobalStore,
8
8
  };
@@ -3,4 +3,5 @@ pub mod identifier;
3
3
  pub mod dot;
4
4
  pub mod tempo;
5
5
  pub mod bank;
6
- pub mod loop_;
6
+ pub mod loop_;
7
+ pub mod condition;
@@ -1,6 +1,6 @@
1
1
  use crate::core::{
2
2
  lexer::token::TokenKind,
3
- parser::{ statement::{ Statement, StatementKind }, Parser },
3
+ parser::{ statement::{ Statement, StatementKind }, driver::Parser },
4
4
  shared::value::Value,
5
5
  store::global::GlobalStore,
6
6
  };