@devaloop/devalang 0.0.1-alpha.1 → 0.0.1-alpha.11
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 +9 -0
- package/Cargo.toml +15 -6
- package/README.md +79 -81
- package/docs/CHANGELOG.md +213 -0
- package/docs/ROADMAP.md +11 -8
- package/docs/TODO.md +32 -29
- package/examples/bank.deva +9 -0
- package/examples/condition.deva +20 -0
- package/examples/duration.deva +9 -0
- package/examples/group.deva +12 -0
- package/examples/index.deva +12 -5
- package/examples/loop.deva +16 -0
- package/examples/samples/hat-808.wav +0 -0
- package/examples/synth.deva +14 -0
- package/examples/variables.deva +9 -0
- package/out-tsc/bin/devalang.exe +0 -0
- package/out-tsc/scripts/version/fetch.js +1 -5
- package/package.json +5 -4
- package/project-version.json +3 -3
- package/rust/cli/bank.rs +455 -0
- package/rust/cli/build.rs +114 -28
- package/rust/cli/check.rs +96 -103
- package/rust/cli/driver.rs +280 -0
- package/rust/cli/init.rs +79 -0
- package/rust/cli/install.rs +17 -0
- package/rust/cli/mod.rs +8 -1
- package/rust/cli/play.rs +193 -0
- package/rust/cli/template.rs +57 -0
- package/rust/cli/update.rs +4 -0
- package/rust/common/cdn.rs +11 -0
- package/rust/common/mod.rs +1 -0
- package/rust/config/driver.rs +76 -0
- package/rust/config/loader.rs +110 -0
- package/rust/config/mod.rs +2 -0
- package/rust/core/audio/engine.rs +242 -0
- package/rust/core/audio/evaluator.rs +31 -0
- package/rust/core/audio/interpreter/arrow_call.rs +142 -0
- package/rust/core/audio/interpreter/call.rs +70 -0
- package/rust/core/audio/interpreter/condition.rs +69 -0
- package/rust/core/audio/interpreter/driver.rs +236 -0
- package/rust/core/audio/interpreter/let_.rs +19 -0
- package/rust/core/audio/interpreter/load.rs +18 -0
- package/rust/core/audio/interpreter/loop_.rs +67 -0
- package/rust/core/audio/interpreter/mod.rs +12 -0
- package/rust/core/audio/interpreter/sleep.rs +36 -0
- package/rust/core/audio/interpreter/spawn.rs +84 -0
- package/rust/core/audio/interpreter/tempo.rs +16 -0
- package/rust/core/audio/interpreter/trigger.rs +102 -0
- package/rust/core/audio/loader/mod.rs +1 -0
- package/rust/core/audio/loader/trigger.rs +64 -0
- package/rust/core/audio/mod.rs +6 -0
- package/rust/core/audio/player.rs +54 -0
- package/rust/core/audio/renderer.rs +54 -0
- package/rust/core/builder/mod.rs +70 -27
- package/rust/core/debugger/lexer.rs +27 -0
- package/rust/core/debugger/mod.rs +13 -49
- package/rust/core/debugger/preprocessor.rs +27 -0
- package/rust/core/debugger/store.rs +25 -0
- package/rust/core/error/mod.rs +60 -0
- package/rust/core/lexer/handler/arrow.rs +31 -0
- package/rust/core/lexer/handler/at.rs +21 -0
- package/rust/core/lexer/handler/brace.rs +41 -0
- package/rust/core/lexer/handler/colon.rs +21 -0
- package/rust/core/lexer/handler/comment.rs +30 -0
- package/rust/core/lexer/handler/dot.rs +21 -0
- package/rust/core/lexer/handler/driver.rs +241 -0
- package/rust/core/lexer/handler/identifier.rs +41 -0
- package/rust/core/lexer/handler/indent.rs +52 -0
- package/rust/core/lexer/handler/mod.rs +15 -0
- package/rust/core/lexer/handler/newline.rs +23 -0
- package/rust/core/lexer/handler/number.rs +31 -0
- package/rust/core/lexer/handler/operator.rs +44 -0
- package/rust/core/lexer/handler/slash.rs +21 -0
- package/rust/core/lexer/handler/string.rs +63 -0
- package/rust/core/lexer/mod.rs +37 -319
- package/rust/core/lexer/token.rs +87 -0
- package/rust/core/mod.rs +6 -2
- package/rust/core/parser/driver.rs +339 -0
- package/rust/core/parser/handler/arrow_call.rs +151 -0
- package/rust/core/parser/handler/at.rs +162 -0
- package/rust/core/parser/handler/bank.rs +41 -0
- package/rust/core/parser/handler/condition.rs +74 -0
- package/rust/core/parser/handler/dot.rs +178 -0
- package/rust/core/parser/handler/identifier/call.rs +41 -0
- package/rust/core/parser/handler/identifier/group.rs +75 -0
- package/rust/core/parser/handler/identifier/let_.rs +133 -0
- package/rust/core/parser/handler/identifier/mod.rs +51 -0
- package/rust/core/parser/handler/identifier/sleep.rs +33 -0
- package/rust/core/parser/handler/identifier/spawn.rs +41 -0
- package/rust/core/parser/handler/identifier/synth.rs +65 -0
- package/rust/core/parser/handler/loop_.rs +72 -0
- package/rust/core/parser/handler/mod.rs +8 -0
- package/rust/core/parser/handler/tempo.rs +47 -0
- package/rust/core/parser/mod.rs +3 -200
- package/rust/core/parser/statement.rs +96 -0
- package/rust/core/preprocessor/loader.rs +308 -0
- package/rust/core/preprocessor/mod.rs +2 -24
- package/rust/core/preprocessor/module.rs +42 -56
- package/rust/core/preprocessor/processor.rs +76 -0
- package/rust/core/preprocessor/resolver/bank.rs +41 -51
- package/rust/core/preprocessor/resolver/call.rs +123 -0
- package/rust/core/preprocessor/resolver/condition.rs +92 -0
- package/rust/core/preprocessor/resolver/driver.rs +232 -0
- package/rust/core/preprocessor/resolver/group.rs +61 -0
- package/rust/core/preprocessor/resolver/let_.rs +31 -0
- package/rust/core/preprocessor/resolver/loop_.rs +76 -67
- package/rust/core/preprocessor/resolver/mod.rs +12 -111
- package/rust/core/preprocessor/resolver/spawn.rs +58 -0
- package/rust/core/preprocessor/resolver/synth.rs +50 -0
- package/rust/core/preprocessor/resolver/tempo.rs +40 -61
- package/rust/core/preprocessor/resolver/trigger.rs +90 -154
- package/rust/core/preprocessor/resolver/value.rs +78 -0
- package/rust/core/shared/bank.rs +21 -0
- package/rust/core/shared/duration.rs +9 -0
- package/rust/core/shared/mod.rs +3 -0
- package/rust/core/shared/value.rs +29 -0
- package/rust/core/store/export.rs +28 -0
- package/rust/core/store/global.rs +39 -0
- package/rust/core/store/import.rs +28 -0
- package/rust/core/store/mod.rs +4 -0
- package/rust/core/store/variable.rs +28 -0
- package/rust/core/utils/mod.rs +2 -0
- package/rust/core/utils/path.rs +31 -0
- package/rust/core/utils/validation.rs +37 -0
- package/rust/installer/bank.rs +55 -0
- package/rust/installer/mod.rs +1 -0
- package/rust/lib.rs +162 -1
- package/rust/main.rs +104 -31
- package/rust/utils/file.rs +35 -0
- package/rust/utils/installer.rs +56 -0
- package/rust/utils/logger.rs +108 -34
- package/rust/utils/mod.rs +5 -3
- package/rust/utils/{loader.rs → spinner.rs} +2 -0
- package/rust/utils/watcher.rs +33 -0
- package/templates/minimal/.devalang +5 -0
- package/templates/minimal/README.md +202 -0
- package/templates/minimal/src/index.deva +2 -0
- package/templates/welcome/.devalang +5 -0
- package/templates/welcome/README.md +202 -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/typescript/scripts/version/fetch.ts +1 -6
- package/docs/COMMANDS.md +0 -31
- package/docs/SYNTAX.md +0 -148
- package/examples/exported.deva +0 -7
- package/rust/audio/mod.rs +0 -1
- package/rust/cli/new.rs +0 -1
- package/rust/core/parser/at.rs +0 -142
- package/rust/core/parser/bank.rs +0 -42
- package/rust/core/parser/dot.rs +0 -107
- package/rust/core/parser/identifer.rs +0 -91
- package/rust/core/parser/loop_.rs +0 -62
- package/rust/core/parser/tempo.rs +0 -42
- package/rust/core/parser/variable.rs +0 -129
- package/rust/core/preprocessor/dependencies.rs +0 -54
- package/rust/core/preprocessor/resolver/at.rs +0 -24
- package/rust/core/types/cli.rs +0 -160
- package/rust/core/types/mod.rs +0 -7
- package/rust/core/types/module.rs +0 -41
- package/rust/core/types/parser.rs +0 -73
- package/rust/core/types/statement.rs +0 -105
- package/rust/core/types/store.rs +0 -116
- package/rust/core/types/token.rs +0 -83
- package/rust/core/types/variable.rs +0 -32
- package/rust/runner/executer.rs +0 -44
- package/rust/runner/mod.rs +0 -1
- package/rust/utils/path.rs +0 -46
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
use crate::core::{
|
|
2
|
+
lexer::token::{ Token, TokenKind },
|
|
3
|
+
parser::{
|
|
4
|
+
handler::{
|
|
5
|
+
arrow_call::parse_arrow_call,
|
|
6
|
+
at::parse_at_token,
|
|
7
|
+
bank::parse_bank_token,
|
|
8
|
+
condition::parse_condition_token,
|
|
9
|
+
dot::parse_dot_token,
|
|
10
|
+
identifier::parse_identifier_token,
|
|
11
|
+
loop_::parse_loop_token,
|
|
12
|
+
tempo::parse_tempo_token,
|
|
13
|
+
},
|
|
14
|
+
statement::Statement,
|
|
15
|
+
},
|
|
16
|
+
shared::value::Value,
|
|
17
|
+
store::global::GlobalStore,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
#[derive(Debug, Clone, PartialEq)]
|
|
21
|
+
pub struct Parser {
|
|
22
|
+
pub resolve_modules: bool,
|
|
23
|
+
pub tokens: Vec<Token>,
|
|
24
|
+
pub token_index: usize,
|
|
25
|
+
pub current_module: String,
|
|
26
|
+
pub previous: Option<Token>,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
impl Parser {
|
|
30
|
+
pub fn new() -> Self {
|
|
31
|
+
Parser {
|
|
32
|
+
resolve_modules: false,
|
|
33
|
+
tokens: Vec::new(),
|
|
34
|
+
token_index: 0,
|
|
35
|
+
current_module: String::new(),
|
|
36
|
+
previous: None,
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
pub fn set_current_module(&mut self, module_path: String) {
|
|
41
|
+
self.current_module = module_path;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
pub fn advance(&mut self) -> Option<&Token> {
|
|
45
|
+
if self.is_eof() {
|
|
46
|
+
return None;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
self.previous = self.tokens.get(self.token_index).cloned();
|
|
50
|
+
self.token_index += 1;
|
|
51
|
+
|
|
52
|
+
self.tokens.get(self.token_index - 1)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
pub fn peek_is(&self, expected: &str) -> bool {
|
|
56
|
+
self.peek().map_or(false, |t| t.lexeme == expected)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
pub fn peek_nth(&self, n: usize) -> Option<&Token> {
|
|
60
|
+
if self.token_index + n < self.tokens.len() {
|
|
61
|
+
self.tokens.get(self.token_index + n)
|
|
62
|
+
} else {
|
|
63
|
+
None
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
pub fn peek_nth_kind(&self, n: usize) -> Option<TokenKind> {
|
|
68
|
+
self.peek_nth(n).map(|t| t.kind.clone())
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
pub fn advance_if(&mut self, kind: TokenKind) -> bool {
|
|
72
|
+
if self.match_token(kind) { true } else { false }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
pub fn match_token(&mut self, kind: TokenKind) -> bool {
|
|
76
|
+
if let Some(tok) = self.peek() {
|
|
77
|
+
if tok.kind == kind {
|
|
78
|
+
self.advance();
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
false
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
pub fn previous_clone(&self) -> Option<Token> {
|
|
86
|
+
self.previous.clone()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
pub fn parse_block(
|
|
90
|
+
&self,
|
|
91
|
+
tokens: Vec<Token>,
|
|
92
|
+
global_store: &mut GlobalStore
|
|
93
|
+
) -> Vec<Statement> {
|
|
94
|
+
let mut inner_parser = Parser {
|
|
95
|
+
resolve_modules: self.resolve_modules,
|
|
96
|
+
tokens,
|
|
97
|
+
token_index: 0,
|
|
98
|
+
current_module: self.current_module.clone(),
|
|
99
|
+
previous: None,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
inner_parser.parse_tokens(inner_parser.tokens.clone(), global_store)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
pub fn parse_tokens(
|
|
106
|
+
&mut self,
|
|
107
|
+
tokens: Vec<Token>,
|
|
108
|
+
global_store: &mut GlobalStore
|
|
109
|
+
) -> Vec<Statement> {
|
|
110
|
+
self.tokens = tokens;
|
|
111
|
+
self.token_index = 0;
|
|
112
|
+
|
|
113
|
+
let mut statements = Vec::new();
|
|
114
|
+
|
|
115
|
+
while !self.is_eof() {
|
|
116
|
+
let token = match self.peek() {
|
|
117
|
+
Some(t) => t.clone(),
|
|
118
|
+
None => {
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
let statement = match &token.kind {
|
|
124
|
+
TokenKind::At => parse_at_token(self, global_store),
|
|
125
|
+
TokenKind::Identifier => {
|
|
126
|
+
if let Some(next) = self.peek_nth(1).cloned() {
|
|
127
|
+
if next.kind == TokenKind::Arrow {
|
|
128
|
+
parse_arrow_call(self, global_store)
|
|
129
|
+
} else {
|
|
130
|
+
parse_identifier_token(self, global_store)
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
parse_identifier_token(self, global_store)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
TokenKind::Dot => parse_dot_token(self, global_store),
|
|
137
|
+
TokenKind::Tempo => parse_tempo_token(self, global_store),
|
|
138
|
+
TokenKind::Bank => parse_bank_token(self, global_store),
|
|
139
|
+
TokenKind::Loop => parse_loop_token(self, global_store),
|
|
140
|
+
TokenKind::If => parse_condition_token(self, global_store),
|
|
141
|
+
|
|
142
|
+
| TokenKind::Else // Ignore else, already handled in `parse_condition_token`
|
|
143
|
+
| TokenKind::Comment
|
|
144
|
+
| TokenKind::Equals
|
|
145
|
+
| TokenKind::Colon
|
|
146
|
+
| TokenKind::Number
|
|
147
|
+
| TokenKind::String
|
|
148
|
+
| TokenKind::LBrace
|
|
149
|
+
| TokenKind::RBrace
|
|
150
|
+
| TokenKind::Comma
|
|
151
|
+
| TokenKind::Newline
|
|
152
|
+
| TokenKind::Dedent
|
|
153
|
+
| TokenKind::Indent => {
|
|
154
|
+
self.advance();
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
TokenKind::EOF => {
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
_ => {
|
|
163
|
+
println!("Unhandled token: {:?}", token);
|
|
164
|
+
self.advance();
|
|
165
|
+
Statement::unknown()
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
statements.push(statement);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
statements
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
pub fn check_token(&self, kind: TokenKind) -> bool {
|
|
176
|
+
self.peek().map_or(false, |t| t.kind == kind)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
pub fn peek_kind(&self) -> Option<TokenKind> {
|
|
180
|
+
self.peek().map(|t| t.kind.clone())
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
pub fn parse_map_value(&mut self) -> Option<Value> {
|
|
184
|
+
if !self.match_token(TokenKind::LBrace) {
|
|
185
|
+
return None;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
let mut map = std::collections::HashMap::new();
|
|
189
|
+
|
|
190
|
+
while !self.check_token(TokenKind::RBrace) && !self.is_eof() {
|
|
191
|
+
let key = if let Some(token) = self.advance() {
|
|
192
|
+
token.lexeme.clone()
|
|
193
|
+
} else {
|
|
194
|
+
break;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
if !self.match_token(TokenKind::Colon) {
|
|
198
|
+
println!("Expected ':' after map key '{}'", key);
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
let value = if let Some(token) = self.peek_clone() {
|
|
203
|
+
match token.kind {
|
|
204
|
+
TokenKind::String => {
|
|
205
|
+
self.advance();
|
|
206
|
+
Value::String(token.lexeme.clone())
|
|
207
|
+
}
|
|
208
|
+
TokenKind::Number => {
|
|
209
|
+
self.advance();
|
|
210
|
+
Value::Number(token.lexeme.parse().unwrap_or(0.0))
|
|
211
|
+
}
|
|
212
|
+
TokenKind::Identifier => {
|
|
213
|
+
self.advance();
|
|
214
|
+
Value::Identifier(token.lexeme.clone())
|
|
215
|
+
}
|
|
216
|
+
_ => {
|
|
217
|
+
println!("Unexpected token in map value: {:?}", token);
|
|
218
|
+
Value::Null
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
} else {
|
|
222
|
+
Value::Null
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
map.insert(key, value);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if !self.match_token(TokenKind::RBrace) {
|
|
229
|
+
println!("Expected '}}' at end of map");
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
Some(Value::Map(map))
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
pub fn peek(&self) -> Option<&Token> {
|
|
236
|
+
self.tokens.get(self.token_index)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
pub fn peek_clone(&self) -> Option<Token> {
|
|
240
|
+
self.tokens.get(self.token_index).cloned()
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
pub fn expect(&mut self, kind: TokenKind) -> Result<&Token, String> {
|
|
244
|
+
let tok = self.advance().ok_or("Unexpected end of input")?;
|
|
245
|
+
if tok.kind == kind {
|
|
246
|
+
Ok(tok)
|
|
247
|
+
} else {
|
|
248
|
+
Err(format!("Expected {:?}, got {:?}", kind, tok.kind))
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
pub fn collect_block_tokens(&mut self, base_indent: usize) -> Vec<Token> {
|
|
253
|
+
let mut tokens = Vec::new();
|
|
254
|
+
|
|
255
|
+
while let Some(tok) = self.peek() {
|
|
256
|
+
if tok.indent <= base_indent && tok.kind != TokenKind::Newline {
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
tokens.push(self.advance().unwrap().clone());
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
tokens
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
pub fn collect_until<F>(&mut self, condition: F) -> Vec<Token> where F: Fn(&Token) -> bool {
|
|
266
|
+
let mut collected = Vec::new();
|
|
267
|
+
while let Some(token) = self.peek() {
|
|
268
|
+
if token.kind == TokenKind::Newline || token.kind == TokenKind::Indent {
|
|
269
|
+
self.advance(); // Skip newlines and indents
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
if token.kind == TokenKind::EOF {
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
if condition(token) {
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
collected.push(self.advance().unwrap().clone());
|
|
279
|
+
}
|
|
280
|
+
collected
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
pub fn is_eof(&self) -> bool {
|
|
284
|
+
self.token_index >= self.tokens.len()
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
pub fn parse_block_until_next_else(
|
|
288
|
+
&mut self,
|
|
289
|
+
base_indent: usize,
|
|
290
|
+
global_store: &mut GlobalStore
|
|
291
|
+
) -> Vec<Statement> {
|
|
292
|
+
let mut block_tokens = Vec::new();
|
|
293
|
+
|
|
294
|
+
while let Some(tok) = self.peek() {
|
|
295
|
+
// Stop if we encounter an 'else' at same indent level
|
|
296
|
+
if tok.lexeme == "else" && tok.indent == base_indent {
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
block_tokens.push(self.advance().unwrap().clone());
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
self.parse_block(block_tokens, global_store)
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
pub fn parse_condition_until_colon(&mut self) -> Option<Value> {
|
|
306
|
+
let tokens = self.collect_until(|t| t.kind == TokenKind::Colon);
|
|
307
|
+
if tokens.is_empty() {
|
|
308
|
+
return None;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
let condition = tokens
|
|
312
|
+
.iter()
|
|
313
|
+
.map(|t| t.lexeme.clone())
|
|
314
|
+
.collect::<Vec<_>>()
|
|
315
|
+
.join(" ");
|
|
316
|
+
|
|
317
|
+
Some(Value::String(condition))
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
pub fn parse_block_until_else_or_dedent(
|
|
321
|
+
&mut self,
|
|
322
|
+
base_indent: usize,
|
|
323
|
+
global_store: &mut GlobalStore
|
|
324
|
+
) -> Vec<Statement> {
|
|
325
|
+
let mut tokens = Vec::new();
|
|
326
|
+
|
|
327
|
+
while let Some(tok) = self.peek() {
|
|
328
|
+
if tok.lexeme == "else" && tok.indent == base_indent {
|
|
329
|
+
break;
|
|
330
|
+
}
|
|
331
|
+
if tok.indent < base_indent && tok.kind != TokenKind::Newline {
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
tokens.push(self.advance().unwrap().clone());
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
self.parse_block(tokens, global_store)
|
|
338
|
+
}
|
|
339
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
use crate::core::{
|
|
2
|
+
lexer::token::TokenKind,
|
|
3
|
+
parser::{ driver::Parser, statement::{ Statement, StatementKind } },
|
|
4
|
+
shared::value::Value,
|
|
5
|
+
store::global::GlobalStore,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
pub fn parse_arrow_call(parser: &mut Parser, global_store: &mut GlobalStore) -> Statement {
|
|
9
|
+
let Some(target_token) = parser.peek_clone() else {
|
|
10
|
+
return Statement::unknown();
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
if target_token.kind != TokenKind::Identifier {
|
|
14
|
+
parser.advance(); // consume target token
|
|
15
|
+
return Statement::unknown();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let Some(arrow_token) = parser.peek_nth(1).cloned() else {
|
|
19
|
+
parser.advance(); // consume arrow token
|
|
20
|
+
return Statement {
|
|
21
|
+
kind: StatementKind::Unknown,
|
|
22
|
+
value: Value::String(target_token.lexeme.clone()),
|
|
23
|
+
indent: target_token.indent,
|
|
24
|
+
line: target_token.line,
|
|
25
|
+
column: target_token.column,
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
if arrow_token.kind != TokenKind::Arrow {
|
|
30
|
+
parser.advance(); // consume method token
|
|
31
|
+
return Statement {
|
|
32
|
+
kind: StatementKind::Unknown,
|
|
33
|
+
value: Value::String(target_token.lexeme.clone()),
|
|
34
|
+
indent: target_token.indent,
|
|
35
|
+
line: target_token.line,
|
|
36
|
+
column: target_token.column,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// We have a valid arrow call, so we consume the arrow token
|
|
41
|
+
let Some(method_token) = parser.peek_nth(2).cloned() else {
|
|
42
|
+
parser.advance();
|
|
43
|
+
return Statement::unknown();
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
if method_token.kind != TokenKind::Identifier {
|
|
47
|
+
parser.advance();
|
|
48
|
+
return Statement::unknown();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Consume the tokens for target, arrow, and method
|
|
52
|
+
parser.advance(); // target
|
|
53
|
+
parser.advance(); // ->
|
|
54
|
+
parser.advance(); // method
|
|
55
|
+
|
|
56
|
+
let mut args = Vec::new();
|
|
57
|
+
|
|
58
|
+
while let Some(token) = parser.peek_clone() {
|
|
59
|
+
if token.kind == TokenKind::Newline || token.kind == TokenKind::EOF {
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
parser.advance();
|
|
64
|
+
|
|
65
|
+
let value = match token.kind {
|
|
66
|
+
TokenKind::Identifier => Value::Identifier(token.lexeme.clone()),
|
|
67
|
+
TokenKind::String => Value::String(token.lexeme.clone()),
|
|
68
|
+
TokenKind::Number => Value::Number(token.lexeme.parse::<f32>().unwrap_or(0.0)),
|
|
69
|
+
TokenKind::LBrace => {
|
|
70
|
+
// Handle map literal
|
|
71
|
+
let mut map = std::collections::HashMap::new();
|
|
72
|
+
while let Some(inner_token) = parser.peek_clone() {
|
|
73
|
+
if inner_token.kind == TokenKind::RBrace {
|
|
74
|
+
parser.advance(); // consume RBrace
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
if inner_token.kind == TokenKind::Newline || inner_token.kind == TokenKind::EOF {
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
parser.advance(); // consume key token
|
|
81
|
+
let key = inner_token.lexeme.clone();
|
|
82
|
+
|
|
83
|
+
if let Some(colon_token) = parser.peek_clone() {
|
|
84
|
+
if colon_token.kind == TokenKind::Colon {
|
|
85
|
+
parser.advance(); // consume colon
|
|
86
|
+
if let Some(value_token) = parser.peek_clone() {
|
|
87
|
+
parser.advance(); // consume value token
|
|
88
|
+
let value = match value_token.kind {
|
|
89
|
+
TokenKind::Identifier =>
|
|
90
|
+
Value::Identifier(value_token.lexeme.clone()),
|
|
91
|
+
TokenKind::String => Value::String(value_token.lexeme.clone()),
|
|
92
|
+
TokenKind::Number => {
|
|
93
|
+
if let Some(TokenKind::Slash) = parser.peek_kind() {
|
|
94
|
+
parser.advance(); // consume slash
|
|
95
|
+
if let Some(denominator_token) = parser.peek_clone() {
|
|
96
|
+
if denominator_token.kind == TokenKind::Number {
|
|
97
|
+
parser.advance(); // consume denominator
|
|
98
|
+
let denominator =
|
|
99
|
+
denominator_token.lexeme.clone();
|
|
100
|
+
Value::Beat(
|
|
101
|
+
format!(
|
|
102
|
+
"{}/{}",
|
|
103
|
+
value_token.lexeme,
|
|
104
|
+
denominator
|
|
105
|
+
)
|
|
106
|
+
)
|
|
107
|
+
} else {
|
|
108
|
+
Value::Unknown
|
|
109
|
+
}
|
|
110
|
+
} else {
|
|
111
|
+
Value::Unknown
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
// Regular number without slash
|
|
115
|
+
Value::Number(
|
|
116
|
+
value_token.lexeme.parse::<f32>().unwrap_or(0.0)
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
TokenKind::Boolean =>
|
|
121
|
+
Value::Boolean(
|
|
122
|
+
value_token.lexeme.parse::<bool>().unwrap_or(false)
|
|
123
|
+
),
|
|
124
|
+
|
|
125
|
+
_ => Value::Unknown,
|
|
126
|
+
};
|
|
127
|
+
map.insert(key, value);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
Value::Map(map)
|
|
133
|
+
}
|
|
134
|
+
_ => Value::Unknown,
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
args.push(value);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
Statement {
|
|
141
|
+
kind: StatementKind::ArrowCall {
|
|
142
|
+
target: target_token.lexeme.clone(),
|
|
143
|
+
method: method_token.lexeme.clone(),
|
|
144
|
+
args,
|
|
145
|
+
},
|
|
146
|
+
value: Value::Null,
|
|
147
|
+
indent: target_token.indent,
|
|
148
|
+
line: target_token.line,
|
|
149
|
+
column: target_token.column,
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
use crate::core::{
|
|
2
|
+
lexer::token::TokenKind,
|
|
3
|
+
parser::{ driver::Parser, statement::{ Statement, StatementKind } },
|
|
4
|
+
shared::value::Value,
|
|
5
|
+
store::global::GlobalStore,
|
|
6
|
+
};
|
|
7
|
+
pub fn parse_at_token(parser: &mut Parser, global_store: &mut GlobalStore) -> Statement {
|
|
8
|
+
parser.advance(); // consume '@'
|
|
9
|
+
|
|
10
|
+
let Some(token) = parser.peek_clone() else {
|
|
11
|
+
return Statement::unknown();
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
let keyword = token.lexeme.as_str();
|
|
15
|
+
|
|
16
|
+
match keyword {
|
|
17
|
+
"import" => {
|
|
18
|
+
parser.advance(); // consume 'import'
|
|
19
|
+
|
|
20
|
+
if !parser.match_token(TokenKind::LBrace) {
|
|
21
|
+
return Statement::error(token, "Expected '{{' after 'import'".to_string());
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let mut names = Vec::new();
|
|
25
|
+
while let Some(token) = parser.peek() {
|
|
26
|
+
match &token.kind {
|
|
27
|
+
TokenKind::Identifier => {
|
|
28
|
+
names.push(token.lexeme.clone());
|
|
29
|
+
parser.advance();
|
|
30
|
+
}
|
|
31
|
+
TokenKind::Comma => {
|
|
32
|
+
parser.advance();
|
|
33
|
+
}
|
|
34
|
+
TokenKind::RBrace => {
|
|
35
|
+
parser.advance();
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
_ => {
|
|
39
|
+
let message = format!(
|
|
40
|
+
"Unexpected token in import list: {:?}",
|
|
41
|
+
token.kind.clone()
|
|
42
|
+
);
|
|
43
|
+
return Statement::error(token.clone(), message);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let Some(from_token) = parser.peek_clone() else {
|
|
49
|
+
return Statement::error(token, "Expected 'from' after import list".to_string());
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
if from_token.lexeme != "from" {
|
|
53
|
+
return Statement::error(token, "Expected keyword 'from'".to_string());
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
parser.advance(); // consume 'from'
|
|
57
|
+
|
|
58
|
+
let Some(source_token) = parser.peek() else {
|
|
59
|
+
return Statement::error(token, "Expected string after 'from'".to_string());
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
if source_token.kind != TokenKind::String {
|
|
63
|
+
return Statement::error(token, "Expected string after 'from'".to_string());
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let source = source_token.lexeme.clone();
|
|
67
|
+
parser.advance(); // consume string
|
|
68
|
+
|
|
69
|
+
Statement {
|
|
70
|
+
kind: StatementKind::Import { names, source },
|
|
71
|
+
value: Value::Null,
|
|
72
|
+
indent: token.indent,
|
|
73
|
+
line: token.line,
|
|
74
|
+
column: token.column,
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
"export" => {
|
|
79
|
+
parser.advance(); // consume 'export'
|
|
80
|
+
|
|
81
|
+
parser.advance(); // consume '{'
|
|
82
|
+
|
|
83
|
+
let names_tokens = parser.collect_until(|t| TokenKind::RBrace == t.kind);
|
|
84
|
+
let mut names: Vec<String> = Vec::new();
|
|
85
|
+
|
|
86
|
+
for token in names_tokens {
|
|
87
|
+
if token.kind == TokenKind::Identifier {
|
|
88
|
+
names.push(token.lexeme.clone());
|
|
89
|
+
} else if token.kind == TokenKind::Comma {
|
|
90
|
+
continue; // Ignore commas
|
|
91
|
+
} else if token.kind == TokenKind::RBrace {
|
|
92
|
+
break; // Stop at the closing brace
|
|
93
|
+
} else {
|
|
94
|
+
return Statement::error(token, "Unexpected token in export list".to_string());
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
Statement {
|
|
99
|
+
kind: StatementKind::Export {
|
|
100
|
+
names: names.clone(),
|
|
101
|
+
source: parser.current_module.clone(),
|
|
102
|
+
},
|
|
103
|
+
value: Value::Null,
|
|
104
|
+
indent: token.indent,
|
|
105
|
+
line: token.line,
|
|
106
|
+
column: token.column,
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
"load" => {
|
|
111
|
+
parser.advance(); // consume 'load'
|
|
112
|
+
|
|
113
|
+
// Exemple : @load "preset.mydeva"
|
|
114
|
+
let Some(path_token) = parser.peek() else {
|
|
115
|
+
return Statement::error(token, "Expected string after 'load'".to_string());
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
if path_token.kind != TokenKind::String {
|
|
119
|
+
return Statement::error(token, "Expected string after 'load'".to_string());
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
let path = path_token.lexeme.clone();
|
|
123
|
+
|
|
124
|
+
parser.advance(); // consume string
|
|
125
|
+
parser.advance(); // consume 'as'
|
|
126
|
+
|
|
127
|
+
let Some(as_token) = parser.peek_clone() else {
|
|
128
|
+
return Statement::error(
|
|
129
|
+
token,
|
|
130
|
+
"Expected 'as' after path in load statement".to_string()
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
if as_token.kind != TokenKind::Identifier {
|
|
135
|
+
return Statement::error(
|
|
136
|
+
token,
|
|
137
|
+
"Expected identifier after 'as' in load statement".to_string()
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
let alias = as_token.lexeme.clone();
|
|
142
|
+
|
|
143
|
+
parser.advance(); // consume identifier
|
|
144
|
+
|
|
145
|
+
Statement {
|
|
146
|
+
kind: StatementKind::Load {
|
|
147
|
+
source: path,
|
|
148
|
+
alias,
|
|
149
|
+
},
|
|
150
|
+
value: Value::Null,
|
|
151
|
+
indent: token.indent,
|
|
152
|
+
line: token.line,
|
|
153
|
+
column: token.column,
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
_ => {
|
|
158
|
+
let message = format!("Unknown keyword after '@' : {}", keyword);
|
|
159
|
+
Statement::error(token, message)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
use crate::core::{
|
|
2
|
+
lexer::token::TokenKind,
|
|
3
|
+
parser::{ statement::{ Statement, StatementKind }, driver::Parser },
|
|
4
|
+
shared::value::Value,
|
|
5
|
+
store::global::GlobalStore,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
pub fn parse_bank_token(parser: &mut Parser, _global_store: &mut GlobalStore) -> Statement {
|
|
9
|
+
parser.advance(); // consume 'bank'
|
|
10
|
+
|
|
11
|
+
let Some(bank_token) = parser.previous_clone() else {
|
|
12
|
+
return Statement::unknown();
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
let bank_value = if let Some(token) = parser.peek_clone() {
|
|
16
|
+
match token.kind {
|
|
17
|
+
TokenKind::Identifier => {
|
|
18
|
+
parser.advance();
|
|
19
|
+
Value::Identifier(token.lexeme.clone())
|
|
20
|
+
}
|
|
21
|
+
TokenKind::Number => {
|
|
22
|
+
parser.advance();
|
|
23
|
+
Value::Number(token.lexeme.parse::<f32>().unwrap_or(0.0))
|
|
24
|
+
}
|
|
25
|
+
_ => Value::Unknown,
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
return Statement::error(
|
|
29
|
+
bank_token,
|
|
30
|
+
"Expected identifier or number after 'bank'".to_string()
|
|
31
|
+
);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
Statement {
|
|
35
|
+
kind: StatementKind::Bank,
|
|
36
|
+
value: bank_value,
|
|
37
|
+
indent: bank_token.indent,
|
|
38
|
+
line: bank_token.line,
|
|
39
|
+
column: bank_token.column,
|
|
40
|
+
}
|
|
41
|
+
}
|