@devaloop/devalang 0.0.1-alpha.1 → 0.0.1-alpha.10

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 (155) hide show
  1. package/.devalang +4 -0
  2. package/Cargo.toml +49 -45
  3. package/README.md +127 -46
  4. package/docs/CHANGELOG.md +172 -0
  5. package/docs/COMMANDS.md +60 -6
  6. package/docs/CONFIG.md +30 -0
  7. package/docs/ROADMAP.md +10 -7
  8. package/docs/SYNTAX.md +100 -18
  9. package/docs/TODO.md +31 -28
  10. package/examples/condition.deva +20 -0
  11. package/examples/group.deva +12 -0
  12. package/examples/index.deva +13 -4
  13. package/examples/loop.deva +16 -0
  14. package/examples/samples/hat-808.wav +0 -0
  15. package/examples/synth.deva +14 -0
  16. package/examples/variables.deva +9 -0
  17. package/out-tsc/bin/devalang.exe +0 -0
  18. package/out-tsc/scripts/version/fetch.js +1 -5
  19. package/package.json +5 -4
  20. package/project-version.json +3 -3
  21. package/rust/cli/build.rs +114 -28
  22. package/rust/cli/check.rs +96 -103
  23. package/rust/cli/init.rs +79 -0
  24. package/rust/cli/mod.rs +203 -1
  25. package/rust/cli/play.rs +193 -0
  26. package/rust/cli/template.rs +57 -0
  27. package/rust/config/loader.rs +13 -0
  28. package/rust/config/mod.rs +16 -0
  29. package/rust/core/audio/engine.rs +214 -0
  30. package/rust/core/audio/evaluator.rs +31 -0
  31. package/rust/core/audio/interpreter/arrow_call.rs +129 -0
  32. package/rust/core/audio/interpreter/call.rs +70 -0
  33. package/rust/core/audio/interpreter/condition.rs +69 -0
  34. package/rust/core/audio/interpreter/driver.rs +236 -0
  35. package/rust/core/audio/interpreter/let_.rs +19 -0
  36. package/rust/core/audio/interpreter/load.rs +18 -0
  37. package/rust/core/audio/interpreter/loop_.rs +67 -0
  38. package/rust/core/audio/interpreter/mod.rs +12 -0
  39. package/rust/core/audio/interpreter/sleep.rs +36 -0
  40. package/rust/core/audio/interpreter/spawn.rs +84 -0
  41. package/rust/core/audio/interpreter/tempo.rs +16 -0
  42. package/rust/core/audio/interpreter/trigger.rs +69 -0
  43. package/rust/core/audio/loader/mod.rs +1 -0
  44. package/rust/core/audio/loader/trigger.rs +52 -0
  45. package/rust/core/audio/mod.rs +6 -0
  46. package/rust/core/audio/player.rs +54 -0
  47. package/rust/core/audio/renderer.rs +54 -0
  48. package/rust/core/builder/mod.rs +70 -27
  49. package/rust/core/debugger/lexer.rs +27 -0
  50. package/rust/core/debugger/mod.rs +13 -49
  51. package/rust/core/debugger/preprocessor.rs +27 -0
  52. package/rust/core/debugger/store.rs +25 -0
  53. package/rust/core/error/mod.rs +60 -0
  54. package/rust/core/lexer/handler/arrow.rs +31 -0
  55. package/rust/core/lexer/handler/at.rs +21 -0
  56. package/rust/core/lexer/handler/brace.rs +41 -0
  57. package/rust/core/lexer/handler/colon.rs +21 -0
  58. package/rust/core/lexer/handler/comment.rs +30 -0
  59. package/rust/core/lexer/handler/dot.rs +21 -0
  60. package/rust/core/lexer/handler/driver.rs +230 -0
  61. package/rust/core/lexer/handler/identifier.rs +41 -0
  62. package/rust/core/lexer/handler/indent.rs +52 -0
  63. package/rust/core/lexer/handler/mod.rs +14 -0
  64. package/rust/core/lexer/handler/newline.rs +23 -0
  65. package/rust/core/lexer/handler/number.rs +31 -0
  66. package/rust/core/lexer/handler/operator.rs +44 -0
  67. package/rust/core/lexer/handler/string.rs +63 -0
  68. package/rust/core/lexer/mod.rs +37 -319
  69. package/rust/core/lexer/token.rs +86 -0
  70. package/rust/core/mod.rs +6 -2
  71. package/rust/core/parser/driver.rs +331 -0
  72. package/rust/core/parser/handler/arrow_call.rs +126 -0
  73. package/rust/core/parser/handler/at.rs +162 -0
  74. package/rust/core/parser/handler/bank.rs +41 -0
  75. package/rust/core/parser/handler/condition.rs +74 -0
  76. package/rust/core/parser/handler/dot.rs +112 -0
  77. package/rust/core/parser/handler/identifier/call.rs +41 -0
  78. package/rust/core/parser/handler/identifier/group.rs +75 -0
  79. package/rust/core/parser/handler/identifier/let_.rs +133 -0
  80. package/rust/core/parser/handler/identifier/mod.rs +51 -0
  81. package/rust/core/parser/handler/identifier/sleep.rs +33 -0
  82. package/rust/core/parser/handler/identifier/spawn.rs +41 -0
  83. package/rust/core/parser/handler/identifier/synth.rs +65 -0
  84. package/rust/core/parser/handler/loop_.rs +72 -0
  85. package/rust/core/parser/handler/mod.rs +8 -0
  86. package/rust/core/parser/handler/tempo.rs +47 -0
  87. package/rust/core/parser/mod.rs +3 -200
  88. package/rust/core/parser/statement.rs +96 -0
  89. package/rust/core/preprocessor/loader.rs +229 -0
  90. package/rust/core/preprocessor/mod.rs +2 -24
  91. package/rust/core/preprocessor/module.rs +42 -56
  92. package/rust/core/preprocessor/processor.rs +76 -0
  93. package/rust/core/preprocessor/resolver/bank.rs +41 -51
  94. package/rust/core/preprocessor/resolver/call.rs +123 -0
  95. package/rust/core/preprocessor/resolver/condition.rs +92 -0
  96. package/rust/core/preprocessor/resolver/driver.rs +227 -0
  97. package/rust/core/preprocessor/resolver/group.rs +61 -0
  98. package/rust/core/preprocessor/resolver/let_.rs +31 -0
  99. package/rust/core/preprocessor/resolver/loop_.rs +76 -67
  100. package/rust/core/preprocessor/resolver/mod.rs +12 -111
  101. package/rust/core/preprocessor/resolver/spawn.rs +58 -0
  102. package/rust/core/preprocessor/resolver/synth.rs +50 -0
  103. package/rust/core/preprocessor/resolver/tempo.rs +40 -61
  104. package/rust/core/preprocessor/resolver/trigger.rs +90 -154
  105. package/rust/core/preprocessor/resolver/value.rs +78 -0
  106. package/rust/core/shared/duration.rs +8 -0
  107. package/rust/core/shared/mod.rs +2 -0
  108. package/rust/core/shared/value.rs +28 -0
  109. package/rust/core/store/export.rs +28 -0
  110. package/rust/core/store/global.rs +39 -0
  111. package/rust/core/store/import.rs +28 -0
  112. package/rust/core/store/mod.rs +4 -0
  113. package/rust/core/store/variable.rs +28 -0
  114. package/rust/core/utils/mod.rs +2 -0
  115. package/rust/core/utils/path.rs +31 -0
  116. package/rust/core/utils/validation.rs +37 -0
  117. package/rust/lib.rs +161 -1
  118. package/rust/main.rs +46 -30
  119. package/rust/utils/file.rs +35 -0
  120. package/rust/utils/logger.rs +108 -34
  121. package/rust/utils/mod.rs +3 -2
  122. package/rust/utils/{loader.rs → spinner.rs} +2 -0
  123. package/rust/utils/watcher.rs +33 -0
  124. package/templates/minimal/.devalang +5 -0
  125. package/templates/minimal/README.md +202 -0
  126. package/templates/minimal/src/index.deva +2 -0
  127. package/templates/welcome/.devalang +5 -0
  128. package/templates/welcome/README.md +202 -0
  129. package/templates/welcome/samples/kick-808.wav +0 -0
  130. package/templates/welcome/src/index.deva +13 -0
  131. package/templates/welcome/src/variables.deva +5 -0
  132. package/typescript/scripts/version/fetch.ts +1 -6
  133. package/examples/exported.deva +0 -7
  134. package/rust/audio/mod.rs +0 -1
  135. package/rust/cli/new.rs +0 -1
  136. package/rust/core/parser/at.rs +0 -142
  137. package/rust/core/parser/bank.rs +0 -42
  138. package/rust/core/parser/dot.rs +0 -107
  139. package/rust/core/parser/identifer.rs +0 -91
  140. package/rust/core/parser/loop_.rs +0 -62
  141. package/rust/core/parser/tempo.rs +0 -42
  142. package/rust/core/parser/variable.rs +0 -129
  143. package/rust/core/preprocessor/dependencies.rs +0 -54
  144. package/rust/core/preprocessor/resolver/at.rs +0 -24
  145. package/rust/core/types/cli.rs +0 -160
  146. package/rust/core/types/mod.rs +0 -7
  147. package/rust/core/types/module.rs +0 -41
  148. package/rust/core/types/parser.rs +0 -73
  149. package/rust/core/types/statement.rs +0 -105
  150. package/rust/core/types/store.rs +0 -116
  151. package/rust/core/types/token.rs +0 -83
  152. package/rust/core/types/variable.rs +0 -32
  153. package/rust/runner/executer.rs +0 -44
  154. package/rust/runner/mod.rs +0 -1
  155. package/rust/utils/path.rs +0 -46
@@ -1,70 +1,56 @@
1
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 } },
2
+ lexer::token::Token,
3
+ parser::statement::Statement,
4
+ store::{ export::ExportTable, import::ImportTable, variable::VariableTable },
9
5
  };
10
6
 
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);
7
+ #[derive(Debug, Clone)]
8
+ pub struct Module {
9
+ pub path: String,
10
+ pub resolved: bool,
11
+ pub tokens: Vec<Token>,
12
+ pub statements: Vec<Statement>,
13
+ pub variable_table: VariableTable,
14
+ pub export_table: ExportTable,
15
+ pub import_table: ImportTable,
16
+ pub content: String,
17
+ pub current_dir: String,
18
+ }
14
19
 
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);
20
+ impl Module {
21
+ pub fn new(path: &str) -> Self {
22
+ Module {
23
+ path: path.to_string(),
24
+ tokens: Vec::new(),
25
+ statements: Vec::new(),
26
+ variable_table: VariableTable::new(),
27
+ export_table: ExportTable::new(),
28
+ import_table: ImportTable::new(),
29
+ resolved: false,
30
+ content: String::new(),
31
+ current_dir: String::new(),
18
32
  }
19
33
  }
20
34
 
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
- }
35
+ pub fn is_resolved(&self) -> bool {
36
+ self.resolved
33
37
  }
34
38
 
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(());
39
+ pub fn set_resolved(&mut self, resolved: bool) {
40
+ self.resolved = resolved;
44
41
  }
45
42
 
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
- };
43
+ pub fn add_token(&mut self, token: Token) {
44
+ self.tokens.push(token);
45
+ }
66
46
 
67
- global_store.insert_module(path.to_string(), module.clone());
47
+ pub fn add_statement(&mut self, statement: Statement) {
48
+ self.statements.push(statement);
49
+ }
68
50
 
69
- Ok(())
51
+ pub fn from_existing(path: &str, content: String) -> Self {
52
+ let mut module = Module::new(path);
53
+ module.content = content;
54
+ module
55
+ }
70
56
  }
@@ -0,0 +1,76 @@
1
+ use std::{ collections::HashMap, path::Path };
2
+
3
+ use crate::core::{
4
+ parser::{ driver::Parser, statement::StatementKind },
5
+ preprocessor::{ loader::ModuleLoader, resolver::group },
6
+ shared::value::Value,
7
+ store::global::GlobalStore,
8
+ utils::path::{normalize_path, resolve_relative_path},
9
+ };
10
+
11
+ pub fn process_modules(module_loader: &ModuleLoader, global_store: &mut GlobalStore) {
12
+ for module in global_store.modules.values_mut() {
13
+ for stmt in &module.statements {
14
+ match &stmt.kind {
15
+ StatementKind::Let { name } => {
16
+ module.variable_table.variables.insert(name.clone(), stmt.value.clone());
17
+ }
18
+
19
+ StatementKind::Load { source, alias } => {
20
+ let module_dir = Path::new(&module.path).parent().unwrap_or(Path::new(""));
21
+
22
+ let resolved_path = normalize_path(&module_dir.join(source));
23
+
24
+ module.variable_table.variables.insert(
25
+ alias.clone(),
26
+ Value::Sample(resolved_path)
27
+ );
28
+ }
29
+
30
+ StatementKind::Export { names, source } => {
31
+ for name in names {
32
+ if let Some(val) = module.variable_table.get(name) {
33
+ module.export_table.add_export(name.clone(), val.clone());
34
+ }
35
+ }
36
+ }
37
+
38
+ StatementKind::Import { names, source } => {
39
+ let resolved = resolve_relative_path(&module.path, source);
40
+ for name in names {
41
+ module.import_table.add_import(
42
+ name.clone(),
43
+ Value::String(resolved.clone())
44
+ );
45
+ }
46
+ }
47
+
48
+ StatementKind::Group => {
49
+ if let Value::Map(map) = &stmt.value {
50
+ if
51
+ let (Some(Value::String(name)), Some(Value::Block(body))) = (
52
+ map.get("identifier"),
53
+ map.get("body"),
54
+ )
55
+ {
56
+ let mut stored_map = HashMap::new();
57
+
58
+ stored_map.insert(
59
+ "identifier".to_string(),
60
+ Value::String(name.clone())
61
+ );
62
+
63
+ stored_map.insert("body".to_string(), Value::Block(body.clone()));
64
+
65
+ module.variable_table.set(name.to_string(), Value::Map(stored_map));
66
+ } else {
67
+ eprintln!("❌ Invalid group definition: {:?}", stmt.value);
68
+ }
69
+ }
70
+ }
71
+
72
+ _ => {}
73
+ }
74
+ }
75
+ }
76
+ }
@@ -1,59 +1,49 @@
1
- use crate::core::{parser::parse_with_resolving_with_module, types::{
2
- module::Module,
3
- statement::{ Statement, StatementKind, StatementResolved, StatementResolvedValue },
4
- variable::VariableValue,
5
- }};
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
+ };
6
10
 
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
- };
11
+ pub fn resolve_bank(
12
+ stmt: &Statement,
13
+ module: &Module,
14
+ path: &str,
15
+ _global_store: &GlobalStore
16
+ ) -> Statement {
17
+ let mut new_stmt = stmt.clone();
18
+ let logger = Logger::new();
29
19
 
30
- StatementResolved {
31
- kind: StatementKind::Bank,
32
- value: statement_value,
33
- indent: stmt.indent,
34
- line: stmt.line,
35
- column: stmt.column,
36
- }
20
+ match &stmt.value {
21
+ Value::Identifier(ident) => {
22
+ if let Some(val) = module.variable_table.get(ident) {
23
+ new_stmt.value = val.clone();
37
24
  } 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
- }
25
+ let message = format!("Bank identifier '{ident}' not found in variable table");
26
+ logger.log_error_with_stacktrace(&message, &module.path);
27
+ new_stmt.kind = StatementKind::Error {
28
+ message: message.clone(),
29
+ };
30
+ new_stmt.value = Value::Null;
46
31
  }
47
32
  }
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
- }
33
+
34
+ Value::String(_) => {}
35
+
36
+ Value::Number(_) => {}
37
+
38
+ other => {
39
+ let message = format!("Expected a string or identifier for bank, found {:?}", other);
40
+ logger.log_error_with_stacktrace(&message, &module.path);
41
+ new_stmt.kind = StatementKind::Error {
42
+ message: "Expected a string or identifier for bank".to_string(),
43
+ };
44
+ new_stmt.value = Value::Null;
57
45
  }
58
46
  }
47
+
48
+ new_stmt
59
49
  }
@@ -0,0 +1,123 @@
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, LogLevel },
9
+ };
10
+
11
+ pub fn resolve_call(
12
+ stmt: &Statement,
13
+ module: &Module,
14
+ path: &str,
15
+ global_store: &mut GlobalStore
16
+ ) -> Statement {
17
+ let logger = Logger::new();
18
+
19
+ match &stmt.value {
20
+ Value::Identifier(ident) => {
21
+ match module.variable_table.get(ident) {
22
+ Some(Value::String(group_name)) =>
23
+ resolve_group_by_name(group_name, stmt, module, path, global_store, &logger),
24
+ Some(Value::Map(group_map)) =>
25
+ resolved_call(stmt, group_map, module, path, global_store),
26
+ Some(other) =>
27
+ error_stmt(
28
+ &logger,
29
+ module,
30
+ stmt,
31
+ &format!(
32
+ "Identifier '{ident}' must resolve to a group name or map, found {:?}",
33
+ other
34
+ )
35
+ ),
36
+ None =>
37
+ error_stmt(
38
+ &logger,
39
+ module,
40
+ stmt,
41
+ &format!("Identifier '{ident}' not found in variable table")
42
+ ),
43
+ }
44
+ }
45
+
46
+ Value::String(name) =>
47
+ resolve_group_by_name(name, stmt, module, path, global_store, &logger),
48
+
49
+ Value::Map(group_map) => resolved_call(stmt, group_map, module, path, global_store),
50
+
51
+ other =>
52
+ error_stmt(
53
+ &logger,
54
+ module,
55
+ stmt,
56
+ &format!("Call expects a group name as string or identifier, found {:?}", other)
57
+ ),
58
+ }
59
+ }
60
+
61
+ fn resolve_group_by_name(
62
+ name: &str,
63
+ stmt: &Statement,
64
+ module: &Module,
65
+ path: &str,
66
+ global_store: &mut GlobalStore,
67
+ logger: &Logger
68
+ ) -> Statement {
69
+ match module.variable_table.get(name) {
70
+ Some(Value::Map(group_map)) => resolved_call(stmt, group_map, module, path, global_store),
71
+ Some(other) =>
72
+ error_stmt(
73
+ logger,
74
+ module,
75
+ stmt,
76
+ &format!("Expected a group for '{}', but found {:?}", name, other)
77
+ ),
78
+ None =>
79
+ error_stmt(
80
+ logger,
81
+ module,
82
+ stmt,
83
+ &format!("Group '{}' not found in module '{}'", name, module.path)
84
+ ),
85
+ }
86
+ }
87
+
88
+ fn resolved_call(
89
+ stmt: &Statement,
90
+ group_map: &std::collections::HashMap<String, Value>,
91
+ module: &Module,
92
+ path: &str,
93
+ global_store: &mut GlobalStore
94
+ ) -> Statement {
95
+ let mut cloned_map = group_map.clone();
96
+
97
+ if let Some(Value::Block(stmts)) = group_map.get("body") {
98
+ let resolved = stmts
99
+ .iter()
100
+ .map(|s| resolve_statement(s, module, path, global_store))
101
+ .collect();
102
+ cloned_map.insert("body".to_string(), Value::Block(resolved));
103
+ }
104
+
105
+ Statement {
106
+ kind: StatementKind::Call,
107
+ value: Value::Map(cloned_map),
108
+ ..stmt.clone()
109
+ }
110
+ }
111
+
112
+ fn error_stmt(logger: &Logger, module: &Module, stmt: &Statement, message: &str) -> Statement {
113
+ let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
114
+ logger.log_message(LogLevel::Error, &format!("{message}\n → at {stacktrace}"));
115
+
116
+ Statement {
117
+ kind: StatementKind::Error {
118
+ message: message.to_string(),
119
+ },
120
+ value: Value::Null,
121
+ ..stmt.clone()
122
+ }
123
+ }
@@ -0,0 +1,92 @@
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: &mut 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
+ // Main body resolution
26
+ if let Some(Value::Block(body)) = condition_map.get("body") {
27
+ let resolved_body = resolve_block_statements(body, module, path, global_store);
28
+ resolved_map.insert("body".to_string(), Value::Block(resolved_body));
29
+ }
30
+
31
+ // Recursive resolution of next condition
32
+ if let Some(Value::Map(next_map)) = condition_map.get("next") {
33
+ let next_stmt = Statement {
34
+ kind: StatementKind::If,
35
+ value: Value::Map(next_map.clone()),
36
+ ..stmt.clone()
37
+ };
38
+
39
+ let resolved_next = resolve_condition(&next_stmt, module, path, global_store);
40
+
41
+ if let Value::Map(mut resolved_next_map) = resolved_next.value {
42
+ // Body next resolution
43
+ if let Some(Value::Block(body)) = resolved_next_map.get("body") {
44
+ let resolved_body = resolve_block_statements(body, module, path, global_store);
45
+ resolved_next_map.insert("body".to_string(), Value::Block(resolved_body));
46
+ }
47
+
48
+ resolved_map.insert("next".to_string(), Value::Map(resolved_next_map));
49
+ }
50
+ }
51
+
52
+ Statement {
53
+ kind: StatementKind::If,
54
+ value: Value::Map(resolved_map),
55
+ ..stmt.clone()
56
+ }
57
+ }
58
+
59
+ fn resolve_block_statements(
60
+ body: &[Statement],
61
+ module: &Module,
62
+ path: &str,
63
+ global_store: &mut GlobalStore,
64
+ ) -> Vec<Statement> {
65
+ body.iter()
66
+ .flat_map(|stmt| {
67
+ let resolved = resolve_statement(stmt, module, path, global_store);
68
+
69
+ if let StatementKind::Call = resolved.kind {
70
+ if let Value::Block(inner) = &resolved.value {
71
+ return inner
72
+ .iter()
73
+ .map(|s| resolve_statement(s, module, path, global_store))
74
+ .collect();
75
+ }
76
+ }
77
+
78
+ vec![resolved]
79
+ })
80
+ .collect()
81
+ }
82
+
83
+ fn type_error(logger: &Logger, module: &Module, stmt: &Statement, message: String) -> Statement {
84
+ let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
85
+ logger.log_error_with_stacktrace(&message, &stacktrace);
86
+
87
+ Statement {
88
+ kind: StatementKind::Error { message },
89
+ value: Value::Null,
90
+ ..stmt.clone()
91
+ }
92
+ }