@devaloop/devalang 0.0.1-alpha.1
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 +45 -0
- package/LICENSE +21 -0
- package/README.md +161 -0
- package/docs/COMMANDS.md +31 -0
- package/docs/ROADMAP.md +27 -0
- package/docs/SYNTAX.md +148 -0
- package/docs/TODO.md +66 -0
- package/examples/exported.deva +7 -0
- package/examples/index.deva +9 -0
- package/examples/samples/kick-808.wav +0 -0
- package/out-tsc/bin/devalang.exe +0 -0
- package/out-tsc/bin/index.js +13 -0
- package/out-tsc/index.js +2 -0
- package/out-tsc/scripts/postbuild.js +11 -0
- package/out-tsc/scripts/version/bump.js +52 -0
- package/out-tsc/scripts/version/fetch.js +34 -0
- package/out-tsc/scripts/version/index.js +32 -0
- package/out-tsc/scripts/version/sync.js +32 -0
- package/package.json +43 -0
- package/project-version.json +6 -0
- package/rust/audio/mod.rs +1 -0
- package/rust/cli/build.rs +51 -0
- package/rust/cli/check.rs +124 -0
- package/rust/cli/mod.rs +3 -0
- package/rust/cli/new.rs +1 -0
- package/rust/core/builder/mod.rs +37 -0
- package/rust/core/debugger/mod.rs +57 -0
- package/rust/core/lexer/mod.rs +333 -0
- package/rust/core/mod.rs +6 -0
- package/rust/core/parser/at.rs +142 -0
- package/rust/core/parser/bank.rs +42 -0
- package/rust/core/parser/dot.rs +107 -0
- package/rust/core/parser/identifer.rs +91 -0
- package/rust/core/parser/loop_.rs +62 -0
- package/rust/core/parser/mod.rs +201 -0
- package/rust/core/parser/tempo.rs +42 -0
- package/rust/core/parser/variable.rs +129 -0
- package/rust/core/preprocessor/dependencies.rs +54 -0
- package/rust/core/preprocessor/mod.rs +26 -0
- package/rust/core/preprocessor/module.rs +70 -0
- package/rust/core/preprocessor/resolver/at.rs +24 -0
- package/rust/core/preprocessor/resolver/bank.rs +59 -0
- package/rust/core/preprocessor/resolver/loop_.rs +82 -0
- package/rust/core/preprocessor/resolver/mod.rs +113 -0
- package/rust/core/preprocessor/resolver/tempo.rs +70 -0
- package/rust/core/preprocessor/resolver/trigger.rs +176 -0
- package/rust/core/types/cli.rs +160 -0
- package/rust/core/types/mod.rs +7 -0
- package/rust/core/types/module.rs +41 -0
- package/rust/core/types/parser.rs +73 -0
- package/rust/core/types/statement.rs +105 -0
- package/rust/core/types/store.rs +116 -0
- package/rust/core/types/token.rs +83 -0
- package/rust/core/types/variable.rs +32 -0
- package/rust/lib.rs +1 -0
- package/rust/main.rs +49 -0
- package/rust/runner/executer.rs +44 -0
- package/rust/runner/mod.rs +1 -0
- package/rust/utils/loader.rs +19 -0
- package/rust/utils/logger.rs +49 -0
- package/rust/utils/mod.rs +5 -0
- package/rust/utils/path.rs +46 -0
- package/rust/utils/signature.rs +17 -0
- package/rust/utils/version.rs +15 -0
- package/tsconfig.json +113 -0
- package/typescript/bin/index.ts +14 -0
- package/typescript/index.ts +1 -0
- package/typescript/scripts/postbuild.ts +8 -0
- package/typescript/scripts/version/bump.ts +45 -0
- package/typescript/scripts/version/fetch.ts +23 -0
- package/typescript/scripts/version/index.ts +26 -0
- package/typescript/scripts/version/sync.ts +24 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
use crate::core::{
|
|
4
|
+
parser::Parser,
|
|
5
|
+
types::{
|
|
6
|
+
statement::{ Statement, StatementKind },
|
|
7
|
+
token::{ Token, TokenKind, TokenParamValue },
|
|
8
|
+
variable::VariableValue,
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
pub fn parse_let_statement(parser: &mut Parser) -> Result<Statement, String> {
|
|
13
|
+
let name_token = parser.next().ok_or("Expected variable name after 'let'")?.clone();
|
|
14
|
+
if name_token.kind != TokenKind::Identifier {
|
|
15
|
+
return Err(format!("Expected variable name, found {:?}", name_token.kind));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let variable_name = name_token.lexeme.clone();
|
|
19
|
+
|
|
20
|
+
let equal_token = parser.next().ok_or("Expected '=' after variable name")?.clone();
|
|
21
|
+
if equal_token.kind != TokenKind::Equals {
|
|
22
|
+
return Err(format!("Expected '=', found {:?} after variable name", equal_token.kind));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let value_token = parser.next().ok_or("Expected value after '='")?.clone();
|
|
26
|
+
let value = match value_token.kind {
|
|
27
|
+
TokenKind::String => VariableValue::Text(value_token.lexeme.clone()),
|
|
28
|
+
TokenKind::Number =>
|
|
29
|
+
value_token.lexeme
|
|
30
|
+
.parse::<f32>()
|
|
31
|
+
.map(VariableValue::Number)
|
|
32
|
+
.map_err(|_| "Invalid number value".to_string())?,
|
|
33
|
+
TokenKind::Boolean =>
|
|
34
|
+
value_token.lexeme
|
|
35
|
+
.parse::<bool>()
|
|
36
|
+
.map(VariableValue::Boolean)
|
|
37
|
+
.map_err(|_| "Invalid boolean value".to_string())?,
|
|
38
|
+
TokenKind::Identifier => VariableValue::Text(value_token.lexeme.clone()),
|
|
39
|
+
TokenKind::LBrace => {
|
|
40
|
+
let mut object: HashMap<String, VariableValue> = HashMap::new();
|
|
41
|
+
while let Some(next_token) = parser.next() {
|
|
42
|
+
if next_token.kind == TokenKind::RBrace {
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
if next_token.kind != TokenKind::Identifier {
|
|
46
|
+
return Err(
|
|
47
|
+
format!("Expected identifier in object, found {:?}", next_token.kind)
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
let key = next_token.lexeme.clone();
|
|
51
|
+
|
|
52
|
+
let colon_token = parser.next().ok_or("Expected ':' after object key")?.clone();
|
|
53
|
+
if colon_token.kind != TokenKind::Colon {
|
|
54
|
+
return Err(format!("Expected ':', found {:?}", colon_token.kind));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let value_token = parser.next().ok_or("Expected value after ':'")?.clone();
|
|
58
|
+
let value = match value_token.kind {
|
|
59
|
+
TokenKind::String => VariableValue::Text(value_token.lexeme.clone()),
|
|
60
|
+
TokenKind::Number =>
|
|
61
|
+
value_token.lexeme
|
|
62
|
+
.parse::<f32>()
|
|
63
|
+
.map(VariableValue::Number)
|
|
64
|
+
.map_err(|_| "Invalid number value".to_string())?,
|
|
65
|
+
TokenKind::Boolean =>
|
|
66
|
+
value_token.lexeme
|
|
67
|
+
.parse::<bool>()
|
|
68
|
+
.map(VariableValue::Boolean)
|
|
69
|
+
.map_err(|_| "Invalid boolean value".to_string())?,
|
|
70
|
+
_ => {
|
|
71
|
+
return Err(format!("Invalid object value token: {:?}", value_token.kind));
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
object.insert(key, value);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let mut variable_object_map: HashMap<String, TokenParamValue> = HashMap::new();
|
|
78
|
+
|
|
79
|
+
for (key, value) in object {
|
|
80
|
+
let token_value = match value {
|
|
81
|
+
VariableValue::Text(s) => TokenParamValue::String(s),
|
|
82
|
+
VariableValue::Number(n) => TokenParamValue::Number(n),
|
|
83
|
+
VariableValue::Boolean(b) => TokenParamValue::Boolean(b),
|
|
84
|
+
_ => {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
variable_object_map.insert(key, token_value);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
VariableValue::Map(variable_object_map)
|
|
92
|
+
}
|
|
93
|
+
_ => {
|
|
94
|
+
return Err(format!("Invalid value token: {:?}", value_token.kind));
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
parser.variable_table.variables.insert(variable_name.clone(), value.clone());
|
|
99
|
+
|
|
100
|
+
Ok(Statement {
|
|
101
|
+
kind: StatementKind::Let {
|
|
102
|
+
name: variable_name,
|
|
103
|
+
},
|
|
104
|
+
value: value,
|
|
105
|
+
indent: name_token.indent,
|
|
106
|
+
line: name_token.line,
|
|
107
|
+
column: name_token.column,
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
pub fn parse_variable_value(parser: &mut Parser, token: &Token) -> Result<VariableValue, String> {
|
|
112
|
+
match token.kind {
|
|
113
|
+
TokenKind::String => Ok(VariableValue::Text(token.lexeme.clone())),
|
|
114
|
+
TokenKind::Number => {
|
|
115
|
+
token.lexeme
|
|
116
|
+
.parse::<f32>()
|
|
117
|
+
.map(VariableValue::Number)
|
|
118
|
+
.map_err(|_| "Invalid number value".to_string())
|
|
119
|
+
}
|
|
120
|
+
TokenKind::Boolean => {
|
|
121
|
+
token.lexeme
|
|
122
|
+
.parse::<bool>()
|
|
123
|
+
.map(VariableValue::Boolean)
|
|
124
|
+
.map_err(|_| "Invalid boolean value".to_string())
|
|
125
|
+
}
|
|
126
|
+
TokenKind::Identifier => Ok(VariableValue::Text(token.lexeme.clone())),
|
|
127
|
+
_ => Err(format!("Invalid variable value token: {:?}", token.kind)),
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
use std::{ collections::{ HashSet, VecDeque }, fs };
|
|
2
|
+
|
|
3
|
+
pub fn collect_dependencies_recursively(entry_file: &str) -> Vec<String> {
|
|
4
|
+
let mut queue = VecDeque::new();
|
|
5
|
+
let mut loaded = HashSet::new();
|
|
6
|
+
|
|
7
|
+
queue.push_back(entry_file.to_string());
|
|
8
|
+
|
|
9
|
+
while let Some(file_ref) = queue.pop_front() {
|
|
10
|
+
if loaded.contains(&file_ref) {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let deps = get_direct_dependencies(&file_ref);
|
|
15
|
+
for dep in deps {
|
|
16
|
+
queue.push_back(dep.clone());
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
loaded.insert(file_ref);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
loaded.into_iter().collect()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
fn get_direct_dependencies(file: &str) -> Vec<String> {
|
|
26
|
+
let content = match fs::read_to_string(file) {
|
|
27
|
+
Ok(c) => c,
|
|
28
|
+
Err(_) => {
|
|
29
|
+
eprintln!("⚠️ Unable to read file: {}", file);
|
|
30
|
+
return vec![];
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
let mut deps = Vec::new();
|
|
35
|
+
|
|
36
|
+
for line in content.lines() {
|
|
37
|
+
let line = line.trim();
|
|
38
|
+
|
|
39
|
+
if line.starts_with("@import") {
|
|
40
|
+
if let Some(from_index) = line.find("from") {
|
|
41
|
+
let after_from = line[from_index + 4..].trim();
|
|
42
|
+
if after_from.starts_with('"') || after_from.starts_with('\'') {
|
|
43
|
+
let delimiter = after_from.chars().next().unwrap();
|
|
44
|
+
if let Some(end_quote) = after_from[1..].find(delimiter) {
|
|
45
|
+
let path = &after_from[1..=end_quote];
|
|
46
|
+
deps.push(path.to_string());
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
deps
|
|
54
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
pub mod module;
|
|
2
|
+
pub mod dependencies;
|
|
3
|
+
pub mod resolver;
|
|
4
|
+
|
|
5
|
+
use crate::core::{
|
|
6
|
+
preprocessor::{
|
|
7
|
+
dependencies::collect_dependencies_recursively,
|
|
8
|
+
module::load_module_into_global_store,
|
|
9
|
+
},
|
|
10
|
+
types::{ store::GlobalStore },
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
pub fn preprocess(entry_file: &str) -> GlobalStore {
|
|
14
|
+
println!("📦 Collecting dependencies for: {}", entry_file);
|
|
15
|
+
|
|
16
|
+
let files = collect_dependencies_recursively(entry_file);
|
|
17
|
+
let mut store = GlobalStore::default();
|
|
18
|
+
|
|
19
|
+
for file in &files {
|
|
20
|
+
if let Err(e) = load_module_into_global_store(file, &mut store) {
|
|
21
|
+
eprintln!("❌ Error while loading {}: {}", file, e);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
store
|
|
26
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
use crate::core::{
|
|
2
|
+
lexer::lex,
|
|
3
|
+
parser::{ parse_without_resolving },
|
|
4
|
+
preprocessor::{
|
|
5
|
+
collect_dependencies_recursively,
|
|
6
|
+
resolver::{ resolve_exports, resolve_imports },
|
|
7
|
+
},
|
|
8
|
+
types::{ module::Module, parser::Parser, store::{ ExportTable, GlobalStore, ImportTable } },
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
pub fn load_all_modules(entry_file: &str) -> GlobalStore {
|
|
12
|
+
let mut global_store = GlobalStore::default();
|
|
13
|
+
let files = collect_dependencies_recursively(entry_file);
|
|
14
|
+
|
|
15
|
+
for file in &files {
|
|
16
|
+
if let Err(e) = load_module_into_global_store(file, &mut global_store) {
|
|
17
|
+
eprintln!("❌ Error loading {}: {}", file, e);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
for file in &files {
|
|
22
|
+
if let Some(module) = global_store.modules.clone().get_mut(file) {
|
|
23
|
+
let imports = resolve_imports(module, &mut global_store);
|
|
24
|
+
module.import_table = imports.clone();
|
|
25
|
+
|
|
26
|
+
let global_store_module = global_store.modules.get(&file.clone().to_string());
|
|
27
|
+
if let Some(global_store_module_found) = global_store_module {
|
|
28
|
+
global_store.insert_module(file.to_string(), module.clone());
|
|
29
|
+
} else {
|
|
30
|
+
eprintln!("❌ Module {} not found in global store after import resolution", file);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
global_store
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
pub fn load_module_into_global_store(
|
|
39
|
+
path: &str,
|
|
40
|
+
global_store: &mut GlobalStore
|
|
41
|
+
) -> Result<(), String> {
|
|
42
|
+
if global_store.modules.contains_key(path) {
|
|
43
|
+
return Ok(());
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let content = std::fs::read_to_string(path).map_err(|_| format!("Cannot read file: {}", path))?;
|
|
47
|
+
|
|
48
|
+
let tokens = lex(content);
|
|
49
|
+
|
|
50
|
+
let mut parser = Parser::new(tokens.clone());
|
|
51
|
+
|
|
52
|
+
parser.current_module = path.to_string();
|
|
53
|
+
|
|
54
|
+
let raw_statements = parse_without_resolving(tokens.clone(), &mut parser, global_store);
|
|
55
|
+
|
|
56
|
+
let export_table = resolve_exports(&raw_statements, &mut parser);
|
|
57
|
+
|
|
58
|
+
let mut module = Module {
|
|
59
|
+
path: path.to_string(),
|
|
60
|
+
tokens: tokens.clone(),
|
|
61
|
+
statements: raw_statements,
|
|
62
|
+
variable_table: parser.variable_table.clone(),
|
|
63
|
+
export_table: export_table.clone(),
|
|
64
|
+
import_table: parser.import_table.clone(),
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
global_store.insert_module(path.to_string(), module.clone());
|
|
68
|
+
|
|
69
|
+
Ok(())
|
|
70
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
use crate::core::types::{
|
|
2
|
+
module::Module,
|
|
3
|
+
statement::{ Statement, StatementResolved, StatementResolvedValue },
|
|
4
|
+
variable::VariableValue,
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
pub fn resolve_load_statement(
|
|
8
|
+
stmt: &Statement,
|
|
9
|
+
source: &str,
|
|
10
|
+
alias: &str,
|
|
11
|
+
module: &mut Module
|
|
12
|
+
) -> StatementResolved {
|
|
13
|
+
let source_string = source.to_string();
|
|
14
|
+
|
|
15
|
+
module.set_variable(alias.to_string(), VariableValue::Sample(source_string.clone()));
|
|
16
|
+
|
|
17
|
+
StatementResolved {
|
|
18
|
+
kind: stmt.kind.clone(),
|
|
19
|
+
value: StatementResolvedValue::Null,
|
|
20
|
+
indent: stmt.indent,
|
|
21
|
+
line: stmt.line,
|
|
22
|
+
column: stmt.column,
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
use crate::core::{parser::parse_with_resolving_with_module, types::{
|
|
2
|
+
module::Module,
|
|
3
|
+
statement::{ Statement, StatementKind, StatementResolved, StatementResolvedValue },
|
|
4
|
+
variable::VariableValue,
|
|
5
|
+
}};
|
|
6
|
+
|
|
7
|
+
pub fn resolve_bank_statement(stmt: &Statement, module: &Module) -> StatementResolved {
|
|
8
|
+
match &stmt.value {
|
|
9
|
+
VariableValue::Text(name) => {
|
|
10
|
+
if
|
|
11
|
+
let Some(value) = module.import_table.imports
|
|
12
|
+
.get(name)
|
|
13
|
+
.or_else(|| module.variable_table.variables.get(name))
|
|
14
|
+
{
|
|
15
|
+
let statement_value: StatementResolvedValue = match value {
|
|
16
|
+
VariableValue::Array(arr) => {
|
|
17
|
+
StatementResolvedValue::Array(
|
|
18
|
+
parse_with_resolving_with_module(arr.clone(), module)
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
VariableValue::Text(text) => StatementResolvedValue::String(text.clone()),
|
|
22
|
+
VariableValue::Number(num) => StatementResolvedValue::Number(*num),
|
|
23
|
+
VariableValue::Boolean(b) => StatementResolvedValue::Boolean(*b),
|
|
24
|
+
_ => {
|
|
25
|
+
eprintln!("⚠️ Unsupported variable type for Bank: {:?}", value);
|
|
26
|
+
StatementResolvedValue::Unknown
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
StatementResolved {
|
|
31
|
+
kind: StatementKind::Bank,
|
|
32
|
+
value: statement_value,
|
|
33
|
+
indent: stmt.indent,
|
|
34
|
+
line: stmt.line,
|
|
35
|
+
column: stmt.column,
|
|
36
|
+
}
|
|
37
|
+
} else {
|
|
38
|
+
eprintln!("⚠️ Bank variable '{}' not found", name);
|
|
39
|
+
StatementResolved {
|
|
40
|
+
kind: StatementKind::Bank,
|
|
41
|
+
value: StatementResolvedValue::Unknown,
|
|
42
|
+
indent: stmt.indent,
|
|
43
|
+
line: stmt.line,
|
|
44
|
+
column: stmt.column,
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
_ => {
|
|
49
|
+
eprintln!("⚠️ Invalid value type for Bank statement: {:?}", stmt.value);
|
|
50
|
+
StatementResolved {
|
|
51
|
+
kind: StatementKind::Bank,
|
|
52
|
+
value: StatementResolvedValue::Unknown,
|
|
53
|
+
indent: stmt.indent,
|
|
54
|
+
line: stmt.line,
|
|
55
|
+
column: stmt.column,
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
use crate::core::{
|
|
2
|
+
parser::parse_without_resolving_with_module,
|
|
3
|
+
preprocessor::resolver::resolve_statement,
|
|
4
|
+
types::{
|
|
5
|
+
module::Module,
|
|
6
|
+
statement::{
|
|
7
|
+
Statement,
|
|
8
|
+
StatementIterator,
|
|
9
|
+
StatementKind,
|
|
10
|
+
StatementResolved,
|
|
11
|
+
StatementResolvedValue,
|
|
12
|
+
},
|
|
13
|
+
variable::VariableValue,
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
pub fn resolve_loop_statement(
|
|
18
|
+
loop_statement: &Statement,
|
|
19
|
+
iterator: StatementIterator,
|
|
20
|
+
module: &Module
|
|
21
|
+
) -> StatementResolved {
|
|
22
|
+
let mut resolved_iterator = StatementIterator::Unknown;
|
|
23
|
+
|
|
24
|
+
match iterator.clone() {
|
|
25
|
+
StatementIterator::Identifier(id) => {
|
|
26
|
+
if let Some(value) = module.variable_table.variables.get(&id) {
|
|
27
|
+
match value {
|
|
28
|
+
VariableValue::Array(arr) => {
|
|
29
|
+
resolved_iterator = StatementIterator::Array(
|
|
30
|
+
parse_without_resolving_with_module(arr.clone(), module)
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
VariableValue::Number(num) => {
|
|
34
|
+
resolved_iterator = StatementIterator::Number(*num);
|
|
35
|
+
}
|
|
36
|
+
_ => {
|
|
37
|
+
eprintln!("⚠️ Unsupported variable type for loop iterator: {:?}", value);
|
|
38
|
+
resolved_iterator = StatementIterator::Unknown;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
eprintln!("⚠️ Loop iterator variable '{}' not found", id);
|
|
43
|
+
resolved_iterator = StatementIterator::Unknown;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
StatementIterator::Number(num) => {
|
|
47
|
+
resolved_iterator = StatementIterator::Number(num);
|
|
48
|
+
}
|
|
49
|
+
_ => {
|
|
50
|
+
resolved_iterator = iterator.clone();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let mut resolved_body: StatementResolvedValue = StatementResolvedValue::Unknown;
|
|
55
|
+
|
|
56
|
+
match &loop_statement.value {
|
|
57
|
+
VariableValue::Array(arr) => {
|
|
58
|
+
let raw_statements = parse_without_resolving_with_module(arr.clone(), &module.clone());
|
|
59
|
+
|
|
60
|
+
let mut resolved_statements = Vec::new();
|
|
61
|
+
|
|
62
|
+
for raw_stmt in raw_statements {
|
|
63
|
+
let resolved_stmt = resolve_statement(&raw_stmt, &mut module.clone());
|
|
64
|
+
resolved_statements.push(resolved_stmt);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
resolved_body = StatementResolvedValue::Array(resolved_statements);
|
|
68
|
+
}
|
|
69
|
+
_ => {
|
|
70
|
+
resolved_body = StatementResolvedValue::Unknown;
|
|
71
|
+
eprintln!("⚠️ Unsupported value type for loop body: {:?}", loop_statement.value);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return StatementResolved {
|
|
76
|
+
kind: StatementKind::Loop { iterator: resolved_iterator },
|
|
77
|
+
value: resolved_body,
|
|
78
|
+
indent: loop_statement.indent,
|
|
79
|
+
line: loop_statement.line,
|
|
80
|
+
column: loop_statement.column,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
pub mod bank;
|
|
2
|
+
pub mod loop_;
|
|
3
|
+
pub mod tempo;
|
|
4
|
+
pub mod trigger;
|
|
5
|
+
pub mod at;
|
|
6
|
+
|
|
7
|
+
use crate::core::{
|
|
8
|
+
preprocessor::resolver::{
|
|
9
|
+
bank::resolve_bank_statement,
|
|
10
|
+
loop_::resolve_loop_statement,
|
|
11
|
+
tempo::resolve_tempo_statement,
|
|
12
|
+
trigger::resolve_trigger_statement,
|
|
13
|
+
at::{ resolve_load_statement },
|
|
14
|
+
},
|
|
15
|
+
types::{
|
|
16
|
+
module::Module,
|
|
17
|
+
parser::Parser,
|
|
18
|
+
statement::{ Statement, StatementKind, StatementResolved, StatementResolvedValue },
|
|
19
|
+
store::{ ExportTable, GlobalStore, ImportTable },
|
|
20
|
+
variable::VariableValue,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
pub fn resolve_exports(statements: &[Statement], parser: &Parser) -> ExportTable {
|
|
25
|
+
let mut export_table = parser.export_table.clone();
|
|
26
|
+
|
|
27
|
+
for stmt in statements {
|
|
28
|
+
if let StatementKind::Export = &stmt.kind {
|
|
29
|
+
if let VariableValue::Array(tokens) = &stmt.value {
|
|
30
|
+
for token in tokens {
|
|
31
|
+
let var_name = &token.lexeme;
|
|
32
|
+
if let Some(value) = parser.variable_table.variables.get(var_name) {
|
|
33
|
+
export_table.add_export(var_name.clone(), value.clone());
|
|
34
|
+
} else {
|
|
35
|
+
eprintln!("⚠️ Variable '{}' not found in scope, export skipped", var_name);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
eprintln!("⚠️ Unexpected value type in export: {:?}", stmt.value);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export_table
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
pub fn resolve_imports(module: &mut Module, global_store: &GlobalStore) -> ImportTable {
|
|
48
|
+
let mut import_table = ImportTable::default();
|
|
49
|
+
|
|
50
|
+
for stmt in &module.statements {
|
|
51
|
+
if let StatementKind::Import { names, source } = &stmt.kind {
|
|
52
|
+
if let Some(from_module) = global_store.modules.get(source) {
|
|
53
|
+
for name in names {
|
|
54
|
+
if let Some(value) = from_module.export_table.exports.get(name) {
|
|
55
|
+
module.variable_table.variables.insert(name.clone(), value.clone());
|
|
56
|
+
import_table.add_import(name.clone(), value.clone());
|
|
57
|
+
} else {
|
|
58
|
+
eprintln!("⚠️ '{}' not found in exports of '{}'", name, source);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
eprintln!("⚠️ Module '{}' not found", source);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
import_table
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
pub fn resolve_statement(stmt: &Statement, module: &mut Module) -> StatementResolved {
|
|
71
|
+
match &stmt.kind {
|
|
72
|
+
StatementKind::Loop { iterator } => {
|
|
73
|
+
resolve_loop_statement(stmt, iterator.clone(), module)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
StatementKind::Trigger { entity, duration } => {
|
|
77
|
+
resolve_trigger_statement(stmt, entity.clone(), duration.clone(), module)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
StatementKind::Bank { .. } => { resolve_bank_statement(stmt, module) }
|
|
81
|
+
|
|
82
|
+
StatementKind::Tempo { .. } => { resolve_tempo_statement(stmt, module) }
|
|
83
|
+
|
|
84
|
+
StatementKind::Load { source, alias } => {
|
|
85
|
+
resolve_load_statement(stmt, source, alias, module)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// TODO Handle other statement kinds
|
|
89
|
+
|
|
90
|
+
StatementKind::Error => {
|
|
91
|
+
StatementResolved {
|
|
92
|
+
kind: StatementKind::Error,
|
|
93
|
+
value: match stmt.value {
|
|
94
|
+
VariableValue::Text(ref msg) => StatementResolvedValue::String(msg.clone()),
|
|
95
|
+
_ => StatementResolvedValue::Unknown,
|
|
96
|
+
},
|
|
97
|
+
indent: stmt.indent,
|
|
98
|
+
line: stmt.line,
|
|
99
|
+
column: stmt.column,
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
_ => {
|
|
104
|
+
StatementResolved {
|
|
105
|
+
kind: StatementKind::Unknown,
|
|
106
|
+
value: StatementResolvedValue::Unknown,
|
|
107
|
+
indent: stmt.indent,
|
|
108
|
+
line: stmt.line,
|
|
109
|
+
column: stmt.column,
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
use crate::core::types::{module::Module, statement::{Statement, StatementKind, StatementResolved, StatementResolvedValue}, variable::VariableValue};
|
|
2
|
+
|
|
3
|
+
pub fn resolve_tempo_statement(
|
|
4
|
+
tempo_statement: &Statement,
|
|
5
|
+
module: &Module
|
|
6
|
+
) -> StatementResolved {
|
|
7
|
+
match &tempo_statement.value {
|
|
8
|
+
VariableValue::Number(num) => {
|
|
9
|
+
if *num > 0.0 {
|
|
10
|
+
StatementResolved {
|
|
11
|
+
kind: StatementKind::Tempo,
|
|
12
|
+
value: StatementResolvedValue::Number(*num),
|
|
13
|
+
indent: tempo_statement.indent,
|
|
14
|
+
line: tempo_statement.line,
|
|
15
|
+
column: tempo_statement.column,
|
|
16
|
+
}
|
|
17
|
+
} else {
|
|
18
|
+
eprintln!("⚠️ Invalid tempo value: {}", num);
|
|
19
|
+
StatementResolved {
|
|
20
|
+
kind: StatementKind::Tempo,
|
|
21
|
+
value: StatementResolvedValue::Unknown,
|
|
22
|
+
indent: tempo_statement.indent,
|
|
23
|
+
line: tempo_statement.line,
|
|
24
|
+
column: tempo_statement.column,
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
VariableValue::Text(text) => {
|
|
29
|
+
if let Some(value) = module.variable_table.variables.get(text) {
|
|
30
|
+
let variable_value: StatementResolvedValue = match value {
|
|
31
|
+
VariableValue::Number(num) if *num > 0.0 => {
|
|
32
|
+
StatementResolvedValue::Number(*num)
|
|
33
|
+
}
|
|
34
|
+
VariableValue::Text(t) => StatementResolvedValue::String(t.clone()),
|
|
35
|
+
_ => {
|
|
36
|
+
eprintln!("⚠️ Unsupported variable type for Tempo: {:?}", value);
|
|
37
|
+
StatementResolvedValue::Unknown
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
StatementResolved {
|
|
42
|
+
kind: StatementKind::Tempo,
|
|
43
|
+
value: variable_value,
|
|
44
|
+
indent: tempo_statement.indent,
|
|
45
|
+
line: tempo_statement.line,
|
|
46
|
+
column: tempo_statement.column,
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
eprintln!("⚠️ Tempo variable '{}' not found", text);
|
|
50
|
+
StatementResolved {
|
|
51
|
+
kind: StatementKind::Tempo,
|
|
52
|
+
value: StatementResolvedValue::Unknown,
|
|
53
|
+
indent: tempo_statement.indent,
|
|
54
|
+
line: tempo_statement.line,
|
|
55
|
+
column: tempo_statement.column,
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
_ => {
|
|
60
|
+
eprintln!("⚠️ Invalid value type for Tempo statement: {:?}", tempo_statement.value);
|
|
61
|
+
StatementResolved {
|
|
62
|
+
kind: StatementKind::Tempo,
|
|
63
|
+
value: StatementResolvedValue::Unknown,
|
|
64
|
+
indent: tempo_statement.indent,
|
|
65
|
+
line: tempo_statement.line,
|
|
66
|
+
column: tempo_statement.column,
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|