@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.
- package/Cargo.toml +1 -1
- package/README.md +29 -10
- package/docs/CHANGELOG.md +22 -2
- package/docs/ROADMAP.md +2 -2
- package/docs/SYNTAX.md +41 -7
- package/docs/TODO.md +3 -3
- package/examples/condition.deva +24 -0
- package/examples/index.deva +4 -5
- package/examples/variables.deva +1 -1
- package/out-tsc/bin/devalang.exe +0 -0
- package/package.json +1 -1
- package/project-version.json +3 -3
- package/rust/cli/build.rs +6 -1
- package/rust/core/audio/evaluator.rs +31 -0
- package/rust/core/audio/interpreter/call.rs +42 -0
- package/rust/core/audio/interpreter/condition.rs +65 -0
- package/rust/core/audio/interpreter/driver.rs +204 -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 +59 -0
- package/rust/core/audio/interpreter/mod.rs +11 -0
- package/rust/core/audio/interpreter/sleep.rs +36 -0
- package/rust/core/audio/interpreter/spawn.rs +65 -0
- package/rust/core/audio/interpreter/tempo.rs +16 -0
- package/rust/core/audio/interpreter/trigger.rs +69 -0
- package/rust/core/audio/loader/mod.rs +1 -0
- package/rust/core/audio/{loader.rs → loader/trigger.rs} +3 -1
- package/rust/core/audio/mod.rs +2 -1
- package/rust/core/audio/{render.rs → renderer.rs} +6 -2
- package/rust/core/builder/mod.rs +1 -1
- package/rust/core/debugger/lexer.rs +1 -1
- package/rust/core/debugger/mod.rs +1 -0
- package/rust/core/debugger/store.rs +25 -0
- package/rust/core/error/mod.rs +1 -1
- package/rust/core/lexer/handler/driver.rs +215 -0
- package/rust/core/lexer/handler/identifier.rs +2 -0
- package/rust/core/lexer/handler/mod.rs +3 -227
- package/rust/core/lexer/handler/operator.rs +44 -0
- package/rust/core/lexer/mod.rs +1 -1
- package/rust/core/lexer/token.rs +36 -9
- package/rust/core/parser/driver.rs +312 -0
- package/rust/core/parser/handler/at.rs +3 -7
- package/rust/core/parser/handler/bank.rs +5 -2
- package/rust/core/parser/handler/condition.rs +74 -0
- package/rust/core/parser/handler/dot.rs +1 -1
- package/rust/core/parser/handler/identifier.rs +38 -36
- package/rust/core/parser/handler/loop_.rs +1 -1
- package/rust/core/parser/handler/mod.rs +2 -1
- package/rust/core/parser/handler/tempo.rs +1 -1
- package/rust/core/parser/mod.rs +3 -237
- package/rust/core/parser/statement.rs +29 -36
- package/rust/core/preprocessor/loader.rs +7 -6
- package/rust/core/preprocessor/processor.rs +1 -1
- package/rust/core/preprocessor/resolver/call.rs +53 -0
- package/rust/core/preprocessor/resolver/condition.rs +66 -0
- package/rust/core/preprocessor/resolver/driver.rs +182 -0
- package/rust/core/preprocessor/resolver/group.rs +89 -84
- package/rust/core/preprocessor/resolver/mod.rs +5 -153
- package/rust/core/preprocessor/resolver/spawn.rs +53 -0
- package/rust/core/audio/interpreter.rs +0 -317
- package/rust/core/lexer/handler/equal.rs +0 -32
package/rust/core/parser/mod.rs
CHANGED
|
@@ -1,238 +1,4 @@
|
|
|
1
|
-
pub mod
|
|
2
|
-
pub mod handler;
|
|
3
|
-
|
|
4
|
-
use crate::core::{
|
|
5
|
-
lexer::token::{ Token, TokenKind },
|
|
6
|
-
parser::{
|
|
7
|
-
handler::{
|
|
8
|
-
at::parse_at_token,
|
|
9
|
-
bank::parse_bank_token,
|
|
10
|
-
dot::parse_dot_token,
|
|
11
|
-
identifier::parse_identifier_token,
|
|
12
|
-
loop_::parse_loop_token,
|
|
13
|
-
tempo::parse_tempo_token,
|
|
14
|
-
},
|
|
15
|
-
statement::{ Statement, StatementKind },
|
|
16
|
-
},
|
|
17
|
-
shared::value::Value,
|
|
18
|
-
store::global::GlobalStore,
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
#[derive(Debug, Clone, PartialEq)]
|
|
22
|
-
pub struct Parser {
|
|
23
|
-
pub resolve_modules: bool,
|
|
24
|
-
pub tokens: Vec<Token>,
|
|
25
|
-
pub token_index: usize,
|
|
26
|
-
pub current_module: String,
|
|
27
|
-
pub previous: Option<Token>,
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
impl Parser {
|
|
31
|
-
pub fn new() -> Self {
|
|
32
|
-
Parser {
|
|
33
|
-
resolve_modules: false,
|
|
34
|
-
tokens: Vec::new(),
|
|
35
|
-
token_index: 0,
|
|
36
|
-
current_module: String::new(),
|
|
37
|
-
previous: None,
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
pub fn set_current_module(&mut self, module_path: String) {
|
|
42
|
-
self.current_module = module_path;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
pub fn advance(&mut self) -> Option<&Token> {
|
|
46
|
-
if self.is_eof() {
|
|
47
|
-
return None;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
self.previous = self.tokens.get(self.token_index).cloned(); // mémorise avant de bouger
|
|
51
|
-
self.token_index += 1;
|
|
52
|
-
|
|
53
|
-
self.tokens.get(self.token_index - 1)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
pub fn match_token(&mut self, kind: TokenKind) -> bool {
|
|
57
|
-
if let Some(tok) = self.peek() {
|
|
58
|
-
if tok.kind == kind {
|
|
59
|
-
self.advance();
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
false
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
pub fn previous_clone(&self) -> Option<Token> {
|
|
67
|
-
self.previous.clone()
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
pub fn parse_block(
|
|
71
|
-
&self,
|
|
72
|
-
tokens: Vec<Token>,
|
|
73
|
-
global_store: &mut GlobalStore
|
|
74
|
-
) -> Vec<Statement> {
|
|
75
|
-
let mut inner_parser = Parser {
|
|
76
|
-
resolve_modules: self.resolve_modules,
|
|
77
|
-
tokens,
|
|
78
|
-
token_index: 0,
|
|
79
|
-
current_module: self.current_module.clone(),
|
|
80
|
-
previous: None,
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
inner_parser.parse_tokens(inner_parser.tokens.clone(), global_store)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
pub fn parse_tokens(
|
|
87
|
-
&mut self,
|
|
88
|
-
tokens: Vec<Token>,
|
|
89
|
-
global_store: &mut GlobalStore
|
|
90
|
-
) -> Vec<Statement> {
|
|
91
|
-
self.tokens = tokens;
|
|
92
|
-
self.token_index = 0;
|
|
93
|
-
|
|
94
|
-
let mut statements = Vec::new();
|
|
95
|
-
|
|
96
|
-
while !self.is_eof() {
|
|
97
|
-
let token = match self.peek() {
|
|
98
|
-
Some(t) => t.clone(),
|
|
99
|
-
None => {
|
|
100
|
-
break;
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
let mut statement = match &token.kind {
|
|
105
|
-
TokenKind::At => parse_at_token(self, global_store),
|
|
106
|
-
TokenKind::Identifier => parse_identifier_token(self, global_store),
|
|
107
|
-
TokenKind::Dot => parse_dot_token(self, global_store),
|
|
108
|
-
TokenKind::Tempo => parse_tempo_token(self, global_store),
|
|
109
|
-
TokenKind::Bank => parse_bank_token(self, global_store),
|
|
110
|
-
TokenKind::Loop => parse_loop_token(self, global_store),
|
|
111
|
-
|
|
112
|
-
| TokenKind::Comment
|
|
113
|
-
| TokenKind::Equals
|
|
114
|
-
| TokenKind::Colon
|
|
115
|
-
| TokenKind::Number
|
|
116
|
-
| TokenKind::String
|
|
117
|
-
| TokenKind::LBrace
|
|
118
|
-
| TokenKind::RBrace
|
|
119
|
-
| TokenKind::Comma
|
|
120
|
-
| TokenKind::Newline
|
|
121
|
-
| TokenKind::Dedent
|
|
122
|
-
| TokenKind::Indent => {
|
|
123
|
-
self.advance();
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
TokenKind::EOF => {
|
|
128
|
-
break;
|
|
129
|
-
}
|
|
1
|
+
pub mod driver;
|
|
130
2
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
self.advance();
|
|
134
|
-
Statement::unknown()
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
statements.push(statement);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
statements
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
pub fn check_token(&self, kind: TokenKind) -> bool {
|
|
145
|
-
self.peek().map_or(false, |t| t.kind == kind)
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
pub fn parse_map_value(&mut self) -> Option<Value> {
|
|
149
|
-
if !self.match_token(TokenKind::LBrace) {
|
|
150
|
-
return None;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
let mut map = std::collections::HashMap::new();
|
|
154
|
-
|
|
155
|
-
while !self.check_token(TokenKind::RBrace) && !self.is_eof() {
|
|
156
|
-
let key = if let Some(token) = self.advance() {
|
|
157
|
-
token.lexeme.clone()
|
|
158
|
-
} else {
|
|
159
|
-
break;
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
if !self.match_token(TokenKind::Colon) {
|
|
163
|
-
println!("Expected ':' after map key '{}'", key);
|
|
164
|
-
break;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
let value = if let Some(token) = self.peek_clone() {
|
|
168
|
-
match token.kind {
|
|
169
|
-
TokenKind::String => {
|
|
170
|
-
self.advance();
|
|
171
|
-
Value::String(token.lexeme.clone())
|
|
172
|
-
}
|
|
173
|
-
TokenKind::Number => {
|
|
174
|
-
self.advance();
|
|
175
|
-
Value::Number(token.lexeme.parse().unwrap_or(0.0))
|
|
176
|
-
}
|
|
177
|
-
TokenKind::Identifier => {
|
|
178
|
-
self.advance();
|
|
179
|
-
Value::Identifier(token.lexeme.clone())
|
|
180
|
-
}
|
|
181
|
-
_ => {
|
|
182
|
-
println!("Unexpected token in map value: {:?}", token);
|
|
183
|
-
Value::Null
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
} else {
|
|
187
|
-
Value::Null
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
map.insert(key, value);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if !self.match_token(TokenKind::RBrace) {
|
|
194
|
-
println!("Expected '}}' at end of map");
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
Some(Value::Map(map))
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
pub fn peek(&self) -> Option<&Token> {
|
|
201
|
-
self.tokens.get(self.token_index)
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
pub fn peek_clone(&self) -> Option<Token> {
|
|
205
|
-
self.tokens.get(self.token_index).cloned()
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
pub fn expect(&mut self, kind: TokenKind) -> Result<&Token, String> {
|
|
209
|
-
let tok = self.advance().ok_or("Unexpected end of input")?;
|
|
210
|
-
if tok.kind == kind {
|
|
211
|
-
Ok(tok)
|
|
212
|
-
} else {
|
|
213
|
-
Err(format!("Expected {:?}, got {:?}", kind, tok.kind))
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
pub fn collect_until<F>(&mut self, condition: F) -> Vec<Token> where F: Fn(&Token) -> bool {
|
|
218
|
-
let mut collected = Vec::new();
|
|
219
|
-
while let Some(token) = self.peek() {
|
|
220
|
-
if token.kind == TokenKind::Newline || token.kind == TokenKind::Indent {
|
|
221
|
-
self.advance(); // Skip newlines and indents
|
|
222
|
-
continue;
|
|
223
|
-
}
|
|
224
|
-
if token.kind == TokenKind::EOF {
|
|
225
|
-
break;
|
|
226
|
-
}
|
|
227
|
-
if condition(token) {
|
|
228
|
-
break;
|
|
229
|
-
}
|
|
230
|
-
collected.push(self.advance().unwrap().clone());
|
|
231
|
-
}
|
|
232
|
-
collected
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
pub fn is_eof(&self) -> bool {
|
|
236
|
-
self.token_index >= self.tokens.len()
|
|
237
|
-
}
|
|
238
|
-
}
|
|
3
|
+
pub mod statement;
|
|
4
|
+
pub mod handler;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
use serde::{ Deserialize, Serialize };
|
|
2
|
-
|
|
3
2
|
use crate::core::{ lexer::token::Token, shared::{ duration::Duration, value::Value } };
|
|
4
3
|
|
|
5
4
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
@@ -34,39 +33,32 @@ impl Statement {
|
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
#[derive(Debug, Serialize, Clone, Deserialize, PartialEq)]
|
|
37
|
-
/// Represents the kind of a statement
|
|
38
36
|
pub enum StatementKind {
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
// ───── Core Instructions ─────
|
|
38
|
+
Tempo,
|
|
39
|
+
Bank,
|
|
40
|
+
Load {
|
|
41
|
+
source: String,
|
|
42
|
+
alias: String,
|
|
44
43
|
},
|
|
45
|
-
|
|
46
|
-
// Variable statements
|
|
47
44
|
Let {
|
|
48
45
|
name: String,
|
|
49
46
|
},
|
|
50
47
|
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
// Special statements
|
|
48
|
+
// ───── Playback / Scheduling ─────
|
|
49
|
+
Trigger {
|
|
50
|
+
entity: String,
|
|
51
|
+
duration: Duration,
|
|
52
|
+
},
|
|
53
|
+
Sleep,
|
|
58
54
|
Call,
|
|
59
55
|
Spawn,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// Keyword statements
|
|
66
|
-
Tempo,
|
|
67
|
-
Bank,
|
|
56
|
+
Loop,
|
|
57
|
+
|
|
58
|
+
// ───── Structure & Logic ─────
|
|
59
|
+
Group,
|
|
68
60
|
|
|
69
|
-
//
|
|
61
|
+
// ───── Module System ─────
|
|
70
62
|
Include(String),
|
|
71
63
|
Export {
|
|
72
64
|
names: Vec<String>,
|
|
@@ -76,20 +68,21 @@ pub enum StatementKind {
|
|
|
76
68
|
names: Vec<String>,
|
|
77
69
|
source: String,
|
|
78
70
|
},
|
|
79
|
-
Load {
|
|
80
|
-
source: String,
|
|
81
|
-
alias: String,
|
|
82
|
-
},
|
|
83
71
|
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
},
|
|
72
|
+
// ───── Conditions ─────
|
|
73
|
+
If,
|
|
74
|
+
Else,
|
|
75
|
+
ElseIf,
|
|
89
76
|
|
|
90
|
-
//
|
|
77
|
+
// ───── Internal / Utility ─────
|
|
91
78
|
Comment,
|
|
92
79
|
Indent,
|
|
93
80
|
Dedent,
|
|
94
81
|
NewLine,
|
|
95
|
-
|
|
82
|
+
|
|
83
|
+
// ───── Error Handling ─────
|
|
84
|
+
Unknown,
|
|
85
|
+
Error {
|
|
86
|
+
message: String,
|
|
87
|
+
},
|
|
88
|
+
}
|
|
@@ -3,17 +3,17 @@ use crate::{
|
|
|
3
3
|
core::{
|
|
4
4
|
error::ErrorHandler,
|
|
5
5
|
lexer::{ token::Token, Lexer },
|
|
6
|
-
parser::{ statement::{ Statement, StatementKind }, Parser },
|
|
7
|
-
preprocessor::{
|
|
8
|
-
module::Module,
|
|
9
|
-
processor::process_modules,
|
|
10
|
-
resolver::{ resolve_all_modules, resolve_and_flatten_all_modules },
|
|
11
|
-
},
|
|
6
|
+
parser::{ statement::{ Statement, StatementKind }, driver::Parser },
|
|
7
|
+
preprocessor::{ module::Module, processor::process_modules },
|
|
12
8
|
store::global::GlobalStore,
|
|
13
9
|
utils::path::normalize_path,
|
|
14
10
|
},
|
|
15
11
|
utils::logger::Logger,
|
|
16
12
|
};
|
|
13
|
+
use crate::core::preprocessor::resolver::driver::{
|
|
14
|
+
resolve_all_modules,
|
|
15
|
+
resolve_and_flatten_all_modules,
|
|
16
|
+
};
|
|
17
17
|
|
|
18
18
|
pub struct ModuleLoader {
|
|
19
19
|
pub entry: String,
|
|
@@ -93,6 +93,7 @@ impl ModuleLoader {
|
|
|
93
93
|
global_store: &mut GlobalStore
|
|
94
94
|
) -> (HashMap<String, Vec<Token>>, HashMap<String, Vec<Statement>>) {
|
|
95
95
|
// SECTION Load the entry module and its dependencies
|
|
96
|
+
|
|
96
97
|
let tokens_by_module = self.load_module_recursively(&self.entry, global_store);
|
|
97
98
|
|
|
98
99
|
// SECTION Process and resolve modules
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
use std::collections::HashMap;
|
|
2
2
|
|
|
3
3
|
use crate::core::{
|
|
4
|
-
parser::{ statement::StatementKind, Parser },
|
|
4
|
+
parser::{ statement::StatementKind, driver::Parser },
|
|
5
5
|
preprocessor::{ loader::ModuleLoader, resolver::group },
|
|
6
6
|
shared::value::Value,
|
|
7
7
|
store::global::GlobalStore,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
use crate::{
|
|
2
|
+
core::{
|
|
3
|
+
parser::statement::{Statement, StatementKind},
|
|
4
|
+
preprocessor::module::Module,
|
|
5
|
+
shared::value::Value,
|
|
6
|
+
store::global::GlobalStore,
|
|
7
|
+
},
|
|
8
|
+
utils::logger::Logger,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
pub fn resolve_call(
|
|
12
|
+
stmt: &Statement,
|
|
13
|
+
module: &Module,
|
|
14
|
+
_path: &str,
|
|
15
|
+
_global_store: &GlobalStore,
|
|
16
|
+
) -> Statement {
|
|
17
|
+
let logger = Logger::new();
|
|
18
|
+
|
|
19
|
+
let Value::String(name) = &stmt.value else {
|
|
20
|
+
return type_error(&logger, module, stmt, "Call expects a group name as string.".to_string());
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
match module.variable_table.variables.get(name) {
|
|
24
|
+
Some(Value::Map(group_stmt)) => Statement {
|
|
25
|
+
kind: StatementKind::Call,
|
|
26
|
+
value: Value::Map(group_stmt.clone()),
|
|
27
|
+
..stmt.clone()
|
|
28
|
+
},
|
|
29
|
+
Some(other) => type_error(
|
|
30
|
+
&logger,
|
|
31
|
+
module,
|
|
32
|
+
stmt,
|
|
33
|
+
format!("Expected a group for '{}', but found {:?}", name, other),
|
|
34
|
+
),
|
|
35
|
+
None => type_error(
|
|
36
|
+
&logger,
|
|
37
|
+
module,
|
|
38
|
+
stmt,
|
|
39
|
+
format!("Group '{}' not found in module '{}'", name, module.path),
|
|
40
|
+
),
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
fn type_error(logger: &Logger, module: &Module, stmt: &Statement, message: String) -> Statement {
|
|
45
|
+
let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
|
|
46
|
+
logger.log_error_with_stacktrace(&message, &stacktrace);
|
|
47
|
+
|
|
48
|
+
Statement {
|
|
49
|
+
kind: StatementKind::Error { message },
|
|
50
|
+
value: Value::Null,
|
|
51
|
+
..stmt.clone()
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
use crate::{
|
|
2
|
+
core::{
|
|
3
|
+
parser::statement::{ Statement, StatementKind },
|
|
4
|
+
preprocessor::{module::Module, resolver::driver::resolve_statement},
|
|
5
|
+
shared::value::Value,
|
|
6
|
+
store::global::GlobalStore,
|
|
7
|
+
},
|
|
8
|
+
utils::logger::Logger,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
pub fn resolve_condition(
|
|
12
|
+
stmt: &Statement,
|
|
13
|
+
module: &Module,
|
|
14
|
+
path: &str,
|
|
15
|
+
global_store: &GlobalStore
|
|
16
|
+
) -> Statement {
|
|
17
|
+
let logger = Logger::new();
|
|
18
|
+
|
|
19
|
+
let Value::Map(condition_map) = &stmt.value else {
|
|
20
|
+
return type_error(&logger, module, stmt, "Expected a map in condition statement".to_string());
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
let mut resolved_map = condition_map.clone();
|
|
24
|
+
|
|
25
|
+
// Body resolution
|
|
26
|
+
if let Some(Value::Block(body)) = condition_map.get("body") {
|
|
27
|
+
let resolved_body = body
|
|
28
|
+
.iter()
|
|
29
|
+
.map(|s| resolve_statement(s, module, path, global_store))
|
|
30
|
+
.collect::<Vec<_>>();
|
|
31
|
+
|
|
32
|
+
resolved_map.insert("body".to_string(), Value::Block(resolved_body));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Next resolution
|
|
36
|
+
if let Some(Value::Map(next)) = condition_map.get("next") {
|
|
37
|
+
let next_stmt = Statement {
|
|
38
|
+
kind: StatementKind::If,
|
|
39
|
+
value: Value::Map(next.clone()),
|
|
40
|
+
..stmt.clone()
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
let resolved_next = resolve_condition(&next_stmt, module, path, global_store);
|
|
44
|
+
|
|
45
|
+
if let Value::Map(resolved_next_map) = resolved_next.value {
|
|
46
|
+
resolved_map.insert("next".to_string(), Value::Map(resolved_next_map));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
Statement {
|
|
51
|
+
kind: StatementKind::If,
|
|
52
|
+
value: Value::Map(resolved_map),
|
|
53
|
+
..stmt.clone()
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
fn type_error(logger: &Logger, module: &Module, stmt: &Statement, message: String) -> Statement {
|
|
58
|
+
let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
|
|
59
|
+
logger.log_error_with_stacktrace(&message, &stacktrace);
|
|
60
|
+
|
|
61
|
+
Statement {
|
|
62
|
+
kind: StatementKind::Error { message },
|
|
63
|
+
value: Value::Null,
|
|
64
|
+
..stmt.clone()
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
use crate::{
|
|
3
|
+
core::{
|
|
4
|
+
parser::statement::{ self, Statement, StatementKind },
|
|
5
|
+
preprocessor::{
|
|
6
|
+
loader::ModuleLoader,
|
|
7
|
+
module::Module,
|
|
8
|
+
resolver::{
|
|
9
|
+
bank::resolve_bank, call::resolve_call, condition::resolve_condition, group::resolve_group, loop_::resolve_loop, spawn::resolve_spawn, tempo::resolve_tempo, trigger::resolve_trigger
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
shared::{ duration::Duration, value::Value },
|
|
13
|
+
store::global::GlobalStore,
|
|
14
|
+
utils::validation::{ is_valid_entity, is_valid_identifier },
|
|
15
|
+
},
|
|
16
|
+
utils::logger::Logger,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
pub fn resolve_all_modules(module_loader: &ModuleLoader, global_store: &mut GlobalStore) {
|
|
20
|
+
for module in global_store.clone().modules.values_mut() {
|
|
21
|
+
resolve_imports(module_loader, global_store);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
pub fn resolve_statement(
|
|
26
|
+
stmt: &Statement,
|
|
27
|
+
module: &Module,
|
|
28
|
+
path: &str,
|
|
29
|
+
global_store: &GlobalStore
|
|
30
|
+
) -> Statement {
|
|
31
|
+
match &stmt.kind {
|
|
32
|
+
StatementKind::Trigger { entity, duration } => {
|
|
33
|
+
resolve_trigger(
|
|
34
|
+
&mut stmt.clone(),
|
|
35
|
+
entity,
|
|
36
|
+
&mut duration.clone(),
|
|
37
|
+
module,
|
|
38
|
+
path,
|
|
39
|
+
global_store
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
StatementKind::If => { resolve_condition(stmt, module, path, global_store) }
|
|
44
|
+
|
|
45
|
+
StatementKind::Group => { resolve_group(stmt, module, path, global_store) }
|
|
46
|
+
|
|
47
|
+
StatementKind::Call => { resolve_call(stmt, module, path, global_store) }
|
|
48
|
+
|
|
49
|
+
StatementKind::Spawn => { resolve_spawn(stmt, module, path, global_store) }
|
|
50
|
+
|
|
51
|
+
// TODO: Handle other statement kinds if necessary
|
|
52
|
+
// ...
|
|
53
|
+
|
|
54
|
+
_ => stmt.clone(),
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
pub fn resolve_imports(module_loader: &ModuleLoader, global_store: &mut GlobalStore) {
|
|
59
|
+
for (module_path, module) in global_store.clone().modules.iter_mut() {
|
|
60
|
+
for (name, source_path) in &module.import_table.imports {
|
|
61
|
+
match source_path {
|
|
62
|
+
Value::String(source_path) => {
|
|
63
|
+
if let Some(source_module) = global_store.modules.get(source_path) {
|
|
64
|
+
if let Some(value) = source_module.export_table.get_export(name) {
|
|
65
|
+
module.variable_table.set(name.clone(), value.clone());
|
|
66
|
+
} else {
|
|
67
|
+
println!(
|
|
68
|
+
"[warn] '{module_path}': '{name}' not found in exports of '{source_path}'"
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
println!(
|
|
73
|
+
"[warn] '{module_path}': cannot find source module '{source_path}'"
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
_ => {
|
|
78
|
+
println!(
|
|
79
|
+
"[warn] '{module_path}': expected string for import source, found {:?}",
|
|
80
|
+
source_path
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
pub fn resolve_and_flatten_all_modules(
|
|
89
|
+
global_store: &mut GlobalStore
|
|
90
|
+
) -> HashMap<String, Vec<Statement>> {
|
|
91
|
+
let logger = Logger::new();
|
|
92
|
+
let snapshot = global_store.clone();
|
|
93
|
+
|
|
94
|
+
// 1. Imports resolution
|
|
95
|
+
for (module_path, module) in global_store.modules.iter_mut() {
|
|
96
|
+
for (name, source_path) in &module.import_table.imports {
|
|
97
|
+
if let Value::String(source_path_str) = source_path {
|
|
98
|
+
match snapshot.modules.get(source_path_str) {
|
|
99
|
+
Some(source_module) => {
|
|
100
|
+
if let Some(value) = source_module.export_table.get_export(name) {
|
|
101
|
+
module.variable_table.set(name.clone(), value.clone());
|
|
102
|
+
} else {
|
|
103
|
+
logger.log_error_with_stacktrace(
|
|
104
|
+
&format!("'{name}' not found in exports of '{source_path_str}'"),
|
|
105
|
+
module_path
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
None => {
|
|
110
|
+
logger.log_error_with_stacktrace(
|
|
111
|
+
&format!("Cannot find source module '{source_path_str}'"),
|
|
112
|
+
module_path
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
logger.log_error_with_stacktrace(
|
|
118
|
+
&format!("Expected string for import source, found {:?}", source_path),
|
|
119
|
+
module_path
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 2. Statements resolution
|
|
126
|
+
let mut resolved_map: HashMap<String, Vec<Statement>> = HashMap::new();
|
|
127
|
+
let store_snapshot = global_store.clone();
|
|
128
|
+
|
|
129
|
+
for (path, module) in &store_snapshot.modules {
|
|
130
|
+
let mut resolved = Vec::new();
|
|
131
|
+
|
|
132
|
+
for stmt in &module.statements {
|
|
133
|
+
let mut stmt = stmt.clone();
|
|
134
|
+
|
|
135
|
+
match &stmt.kind {
|
|
136
|
+
StatementKind::Trigger { entity, duration } => {
|
|
137
|
+
let resolved_stmt = resolve_trigger(
|
|
138
|
+
&stmt,
|
|
139
|
+
entity.as_str(),
|
|
140
|
+
&mut duration.clone(),
|
|
141
|
+
&module,
|
|
142
|
+
&path,
|
|
143
|
+
&store_snapshot
|
|
144
|
+
);
|
|
145
|
+
resolved.push(resolved_stmt);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
StatementKind::Loop => {
|
|
149
|
+
let resolved_stmt = resolve_loop(&stmt, &module, &path, &store_snapshot);
|
|
150
|
+
resolved.push(resolved_stmt);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
StatementKind::Bank => {
|
|
154
|
+
let resolved_stmt = resolve_bank(&stmt, &module, &path, &store_snapshot);
|
|
155
|
+
resolved.push(resolved_stmt);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
StatementKind::Tempo => {
|
|
159
|
+
let resolved_stmt = resolve_tempo(&stmt, &module, &path, &store_snapshot);
|
|
160
|
+
resolved.push(resolved_stmt);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
StatementKind::Import { .. } | StatementKind::Export { .. } => {
|
|
164
|
+
resolved.push(stmt.clone());
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
StatementKind::Group => {
|
|
168
|
+
let resolved_stmt = resolve_group(&stmt, &module, &path, &store_snapshot);
|
|
169
|
+
resolved.push(resolved_stmt);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
_ => {
|
|
173
|
+
resolved.push(stmt);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
resolved_map.insert(path.clone(), resolved);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
resolved_map
|
|
182
|
+
}
|