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

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 (86) hide show
  1. package/Cargo.toml +1 -1
  2. package/README.md +31 -16
  3. package/docs/CHANGELOG.md +49 -2
  4. package/docs/ROADMAP.md +2 -2
  5. package/docs/SYNTAX.md +41 -7
  6. package/docs/TODO.md +3 -3
  7. package/examples/condition.deva +20 -0
  8. package/examples/group.deva +3 -3
  9. package/examples/index.deva +9 -8
  10. package/examples/loop.deva +10 -8
  11. package/examples/synth.deva +14 -0
  12. package/examples/variables.deva +2 -2
  13. package/out-tsc/bin/devalang.exe +0 -0
  14. package/out-tsc/scripts/version/fetch.js +1 -5
  15. package/package.json +1 -1
  16. package/project-version.json +3 -3
  17. package/rust/cli/build.rs +6 -1
  18. package/rust/core/audio/engine.rs +89 -12
  19. package/rust/core/audio/evaluator.rs +31 -0
  20. package/rust/core/audio/interpreter/arrow_call.rs +129 -0
  21. package/rust/core/audio/interpreter/call.rs +64 -0
  22. package/rust/core/audio/interpreter/condition.rs +69 -0
  23. package/rust/core/audio/interpreter/driver.rs +216 -0
  24. package/rust/core/audio/interpreter/let_.rs +19 -0
  25. package/rust/core/audio/interpreter/load.rs +18 -0
  26. package/rust/core/audio/interpreter/loop_.rs +67 -0
  27. package/rust/core/audio/interpreter/mod.rs +12 -0
  28. package/rust/core/audio/interpreter/sleep.rs +36 -0
  29. package/rust/core/audio/interpreter/spawn.rs +66 -0
  30. package/rust/core/audio/interpreter/tempo.rs +16 -0
  31. package/rust/core/audio/interpreter/trigger.rs +69 -0
  32. package/rust/core/audio/loader/mod.rs +1 -0
  33. package/rust/core/audio/{loader.rs → loader/trigger.rs} +3 -1
  34. package/rust/core/audio/mod.rs +2 -1
  35. package/rust/core/audio/renderer.rs +54 -0
  36. package/rust/core/builder/mod.rs +1 -1
  37. package/rust/core/debugger/lexer.rs +1 -1
  38. package/rust/core/debugger/mod.rs +1 -0
  39. package/rust/core/debugger/store.rs +25 -0
  40. package/rust/core/error/mod.rs +1 -1
  41. package/rust/core/lexer/handler/arrow.rs +31 -0
  42. package/rust/core/lexer/handler/driver.rs +226 -0
  43. package/rust/core/lexer/handler/identifier.rs +3 -0
  44. package/rust/core/lexer/handler/mod.rs +4 -227
  45. package/rust/core/lexer/handler/operator.rs +44 -0
  46. package/rust/core/lexer/mod.rs +25 -4
  47. package/rust/core/lexer/token.rs +40 -9
  48. package/rust/core/parser/driver.rs +331 -0
  49. package/rust/core/parser/handler/arrow_call.rs +126 -0
  50. package/rust/core/parser/handler/at.rs +3 -7
  51. package/rust/core/parser/handler/bank.rs +5 -2
  52. package/rust/core/parser/handler/condition.rs +74 -0
  53. package/rust/core/parser/handler/dot.rs +1 -1
  54. package/rust/core/parser/handler/identifier/call.rs +41 -0
  55. package/rust/core/parser/handler/identifier/group.rs +75 -0
  56. package/rust/core/parser/handler/identifier/let_.rs +133 -0
  57. package/rust/core/parser/handler/identifier/mod.rs +51 -0
  58. package/rust/core/parser/handler/identifier/sleep.rs +33 -0
  59. package/rust/core/parser/handler/identifier/spawn.rs +41 -0
  60. package/rust/core/parser/handler/identifier/synth.rs +65 -0
  61. package/rust/core/parser/handler/loop_.rs +25 -19
  62. package/rust/core/parser/handler/mod.rs +3 -1
  63. package/rust/core/parser/handler/tempo.rs +1 -1
  64. package/rust/core/parser/mod.rs +3 -237
  65. package/rust/core/parser/statement.rs +36 -35
  66. package/rust/core/preprocessor/loader.rs +64 -49
  67. package/rust/core/preprocessor/module.rs +3 -6
  68. package/rust/core/preprocessor/processor.rs +13 -4
  69. package/rust/core/preprocessor/resolver/call.rs +123 -0
  70. package/rust/core/preprocessor/resolver/condition.rs +92 -0
  71. package/rust/core/preprocessor/resolver/driver.rs +227 -0
  72. package/rust/core/preprocessor/resolver/group.rs +35 -87
  73. package/rust/core/preprocessor/resolver/let_.rs +31 -0
  74. package/rust/core/preprocessor/resolver/loop_.rs +62 -116
  75. package/rust/core/preprocessor/resolver/mod.rs +9 -153
  76. package/rust/core/preprocessor/resolver/spawn.rs +58 -0
  77. package/rust/core/preprocessor/resolver/synth.rs +50 -0
  78. package/rust/core/preprocessor/resolver/trigger.rs +51 -50
  79. package/rust/core/preprocessor/resolver/value.rs +78 -0
  80. package/rust/core/utils/path.rs +17 -32
  81. package/rust/core/utils/validation.rs +30 -28
  82. package/typescript/scripts/version/fetch.ts +1 -6
  83. package/rust/core/audio/interpreter.rs +0 -317
  84. package/rust/core/audio/render.rs +0 -53
  85. package/rust/core/lexer/handler/equal.rs +0 -32
  86. package/rust/core/parser/handler/identifier.rs +0 -260
@@ -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,40 @@ 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
- // Trigger statements
40
- Trigger {
41
- entity: String,
42
- duration: Duration,
43
- // params: Vec<TokenParam>,
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
  },
47
+ ArrowCall {
48
+ target: String,
49
+ method: String,
50
+ args: Vec<Value>,
51
+ },
50
52
 
51
- // Loop statements
52
- Loop,
53
+ // ───── Instruments ─────
54
+ Synth,
53
55
 
54
- // Group statements
55
- Group,
56
-
57
- // Special statements
56
+ // ───── Playback / Scheduling ─────
57
+ Trigger {
58
+ entity: String,
59
+ duration: Duration,
60
+ },
61
+ Sleep,
58
62
  Call,
59
63
  Spawn,
60
- Sleep,
61
-
62
- // Conditional statements
63
- // If
64
-
65
- // Keyword statements
66
- Tempo,
67
- Bank,
64
+ Loop,
65
+
66
+ // ───── Structure & Logic ─────
67
+ Group,
68
68
 
69
- // At (@) statements
69
+ // ───── Module System ─────
70
70
  Include(String),
71
71
  Export {
72
72
  names: Vec<String>,
@@ -76,20 +76,21 @@ pub enum StatementKind {
76
76
  names: Vec<String>,
77
77
  source: String,
78
78
  },
79
- Load {
80
- source: String,
81
- alias: String,
82
- },
83
79
 
84
- // Error & Unknown statements
85
- Unknown,
86
- Error {
87
- message: String,
88
- },
80
+ // ───── Conditions ─────
81
+ If,
82
+ Else,
83
+ ElseIf,
89
84
 
90
- // Empty or ignored statements
85
+ // ───── Internal / Utility ─────
91
86
  Comment,
92
87
  Indent,
93
88
  Dedent,
94
89
  NewLine,
95
- }
90
+
91
+ // ───── Error Handling ─────
92
+ Unknown,
93
+ Error {
94
+ message: String,
95
+ },
96
+ }
@@ -1,30 +1,39 @@
1
- use std::collections::HashMap;
1
+ use std::{ collections::HashMap, path::Path };
2
2
  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
+ use crate::core::utils::path::resolve_relative_path;
17
18
 
18
19
  pub struct ModuleLoader {
19
20
  pub entry: String,
20
21
  pub output: String,
22
+ pub base_dir: String,
21
23
  }
22
24
 
23
25
  impl ModuleLoader {
24
26
  pub fn new(entry: &str, output: &str) -> Self {
27
+ let base_dir = Path::new(entry)
28
+ .parent()
29
+ .unwrap_or(Path::new(""))
30
+ .to_string_lossy()
31
+ .replace('\\', "/");
32
+
25
33
  Self {
26
34
  entry: entry.to_string(),
27
35
  output: output.to_string(),
36
+ base_dir: base_dir,
28
37
  }
29
38
  }
30
39
 
@@ -39,13 +48,12 @@ impl ModuleLoader {
39
48
  let mut module = Module::new(&entry_path);
40
49
  module.content = content.to_string();
41
50
 
42
- println!("Loading module from raw source: {}", normalized_entry_path);
43
-
44
51
  global_store.insert_module(normalized_entry_path.to_string(), module);
45
52
 
46
53
  Self {
47
54
  entry: normalized_entry_path.to_string(),
48
55
  output: output_path.to_string(),
56
+ base_dir: "".to_string(),
49
57
  }
50
58
  }
51
59
 
@@ -93,6 +101,7 @@ impl ModuleLoader {
93
101
  global_store: &mut GlobalStore
94
102
  ) -> (HashMap<String, Vec<Token>>, HashMap<String, Vec<Statement>>) {
95
103
  // SECTION Load the entry module and its dependencies
104
+
96
105
  let tokens_by_module = self.load_module_recursively(&self.entry, global_store);
97
106
 
98
107
  // SECTION Process and resolve modules
@@ -107,72 +116,78 @@ impl ModuleLoader {
107
116
  #[cfg(feature = "cli")]
108
117
  fn load_module_recursively(
109
118
  &self,
110
- path: &str,
119
+ raw_path: &str,
111
120
  global_store: &mut GlobalStore
112
121
  ) -> HashMap<String, Vec<Token>> {
113
- if global_store.modules.contains_key(path) {
122
+ let path = normalize_path(raw_path);
123
+
124
+ // Check if already loaded
125
+ if global_store.modules.contains_key(&path) {
114
126
  return HashMap::new();
115
127
  }
116
128
 
117
129
  let lexer = Lexer::new();
118
- let tokens = lexer.lex_tokens(path);
130
+ let tokens = lexer.lex_tokens(&path);
119
131
 
120
132
  let mut parser = Parser::new();
121
- parser.set_current_module(path.to_string());
133
+ parser.set_current_module(path.clone());
122
134
 
123
135
  let statements = parser.parse_tokens(tokens.clone(), global_store);
124
136
 
125
- // SECTION Error handling
137
+ // Error handling
126
138
  let mut error_handler = ErrorHandler::new();
127
139
  error_handler.detect_from_statements(&mut parser, &statements);
128
140
 
129
- error_handler.has_errors().then(|| {
141
+ if error_handler.has_errors() {
130
142
  let logger = Logger::new();
131
- let errors = error_handler.get_errors();
132
-
133
- for error in errors {
134
- let stacktrace = format!("{}:{}:{}", path, error.line, error.column);
135
- logger.log_error_with_stacktrace(&error.message, &stacktrace);
143
+ for error in error_handler.get_errors() {
144
+ let trace = format!("{}:{}:{}", path, error.line, error.column);
145
+ logger.log_error_with_stacktrace(&error.message, &trace);
136
146
  }
137
- });
147
+ }
138
148
 
139
- // SECTION Module creation
140
- let mut module = Module::new(path);
149
+ // Insert module into store
150
+ let mut module = Module::new(&path);
141
151
  module.tokens = tokens.clone();
142
152
  module.statements = statements.clone();
153
+ global_store.insert_module(path.clone(), module);
143
154
 
144
- global_store.insert_module(path.to_string(), module);
155
+ // Load dependencies
156
+ self.load_module_imports(&path, global_store);
145
157
 
146
- // Then load the imports recursively
147
- self.load_module_imports(&path.to_string(), global_store);
148
-
149
- // Return all tokens by module
150
- let mut tokens_by_module = HashMap::new();
151
-
152
- global_store.modules.iter().for_each(|(path, module)| {
153
- tokens_by_module.insert(path.clone(), module.tokens.clone());
154
- });
155
-
156
- tokens_by_module
158
+ // Return tokens per module
159
+ global_store.modules
160
+ .iter()
161
+ .map(|(p, m)| (p.clone(), m.tokens.clone()))
162
+ .collect()
157
163
  }
158
164
 
159
165
  #[cfg(feature = "cli")]
160
166
  fn load_module_imports(&self, path: &String, global_store: &mut GlobalStore) {
161
- let imports = global_store.modules
162
- .get(path)
163
- .unwrap()
164
- .statements.iter()
165
- .filter_map(|stmt| {
166
- if let StatementKind::Import { source, .. } = &stmt.kind {
167
- Some(source.clone())
168
- } else {
169
- None
167
+ let import_paths: Vec<String> = {
168
+ let current_module = match global_store.modules.get(path) {
169
+ Some(module) => module,
170
+ None => {
171
+ eprintln!("[warn] Cannot resolve imports: module '{}' not found in store", path);
172
+ return;
170
173
  }
171
- })
172
- .collect::<Vec<_>>();
173
-
174
- for import_path in imports {
175
- self.load_module_recursively(&import_path, global_store);
174
+ };
175
+
176
+ current_module.statements
177
+ .iter()
178
+ .filter_map(|stmt| {
179
+ if let StatementKind::Import { source, .. } = &stmt.kind {
180
+ Some(source.clone())
181
+ } else {
182
+ None
183
+ }
184
+ })
185
+ .collect()
186
+ };
187
+
188
+ for import_path in import_paths {
189
+ let resolved = resolve_relative_path(path, &import_path);
190
+ self.load_module_recursively(&resolved, global_store);
176
191
  }
177
192
  }
178
193
  }
@@ -1,12 +1,7 @@
1
1
  use crate::core::{
2
2
  lexer::token::Token,
3
3
  parser::statement::Statement,
4
- store::{
5
- export::ExportTable,
6
- global::GlobalStore,
7
- import::ImportTable,
8
- variable::VariableTable,
9
- },
4
+ store::{ export::ExportTable, import::ImportTable, variable::VariableTable },
10
5
  };
11
6
 
12
7
  #[derive(Debug, Clone)]
@@ -19,6 +14,7 @@ pub struct Module {
19
14
  pub export_table: ExportTable,
20
15
  pub import_table: ImportTable,
21
16
  pub content: String,
17
+ pub current_dir: String,
22
18
  }
23
19
 
24
20
  impl Module {
@@ -32,6 +28,7 @@ impl Module {
32
28
  import_table: ImportTable::new(),
33
29
  resolved: false,
34
30
  content: String::new(),
31
+ current_dir: String::new(),
35
32
  }
36
33
  }
37
34
 
@@ -1,10 +1,11 @@
1
- use std::collections::HashMap;
1
+ use std::{ collections::HashMap, path::Path };
2
2
 
3
3
  use crate::core::{
4
- parser::{ statement::StatementKind, Parser },
4
+ parser::{ driver::Parser, statement::StatementKind },
5
5
  preprocessor::{ loader::ModuleLoader, resolver::group },
6
6
  shared::value::Value,
7
7
  store::global::GlobalStore,
8
+ utils::path::{normalize_path, resolve_relative_path},
8
9
  };
9
10
 
10
11
  pub fn process_modules(module_loader: &ModuleLoader, global_store: &mut GlobalStore) {
@@ -16,9 +17,13 @@ pub fn process_modules(module_loader: &ModuleLoader, global_store: &mut GlobalSt
16
17
  }
17
18
 
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
+
19
24
  module.variable_table.variables.insert(
20
25
  alias.clone(),
21
- Value::Sample(source.clone())
26
+ Value::Sample(resolved_path)
22
27
  );
23
28
  }
24
29
 
@@ -31,8 +36,12 @@ pub fn process_modules(module_loader: &ModuleLoader, global_store: &mut GlobalSt
31
36
  }
32
37
 
33
38
  StatementKind::Import { names, source } => {
39
+ let resolved = resolve_relative_path(&module.path, source);
34
40
  for name in names {
35
- module.import_table.add_import(name.clone(), Value::String(source.clone()));
41
+ module.import_table.add_import(
42
+ name.clone(),
43
+ Value::String(resolved.clone())
44
+ );
36
45
  }
37
46
  }
38
47
 
@@ -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
+ }