@devaloop/devalang 0.0.1-alpha.8 → 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 (59) hide show
  1. package/Cargo.toml +1 -1
  2. package/README.md +4 -8
  3. package/docs/CHANGELOG.md +27 -0
  4. package/examples/condition.deva +8 -12
  5. package/examples/group.deva +3 -3
  6. package/examples/index.deva +10 -8
  7. package/examples/loop.deva +10 -8
  8. package/examples/synth.deva +14 -0
  9. package/examples/variables.deva +1 -1
  10. package/out-tsc/bin/devalang.exe +0 -0
  11. package/out-tsc/scripts/version/fetch.js +1 -5
  12. package/package.json +1 -1
  13. package/project-version.json +3 -3
  14. package/rust/core/audio/engine.rs +89 -12
  15. package/rust/core/audio/interpreter/arrow_call.rs +129 -0
  16. package/rust/core/audio/interpreter/call.rs +29 -7
  17. package/rust/core/audio/interpreter/condition.rs +5 -1
  18. package/rust/core/audio/interpreter/driver.rs +41 -29
  19. package/rust/core/audio/interpreter/loop_.rs +11 -3
  20. package/rust/core/audio/interpreter/mod.rs +1 -0
  21. package/rust/core/audio/interpreter/spawn.rs +43 -42
  22. package/rust/core/audio/interpreter/trigger.rs +1 -1
  23. package/rust/core/audio/renderer.rs +15 -18
  24. package/rust/core/lexer/handler/arrow.rs +31 -0
  25. package/rust/core/lexer/handler/driver.rs +12 -1
  26. package/rust/core/lexer/handler/identifier.rs +1 -0
  27. package/rust/core/lexer/handler/mod.rs +1 -0
  28. package/rust/core/lexer/mod.rs +24 -3
  29. package/rust/core/lexer/token.rs +4 -0
  30. package/rust/core/parser/driver.rs +23 -4
  31. package/rust/core/parser/handler/arrow_call.rs +126 -0
  32. package/rust/core/parser/handler/identifier/call.rs +41 -0
  33. package/rust/core/parser/handler/identifier/group.rs +75 -0
  34. package/rust/core/parser/handler/identifier/let_.rs +133 -0
  35. package/rust/core/parser/handler/identifier/mod.rs +51 -0
  36. package/rust/core/parser/handler/identifier/sleep.rs +33 -0
  37. package/rust/core/parser/handler/identifier/spawn.rs +41 -0
  38. package/rust/core/parser/handler/identifier/synth.rs +65 -0
  39. package/rust/core/parser/handler/loop_.rs +24 -18
  40. package/rust/core/parser/handler/mod.rs +2 -1
  41. package/rust/core/parser/statement.rs +8 -0
  42. package/rust/core/preprocessor/loader.rs +57 -43
  43. package/rust/core/preprocessor/module.rs +3 -6
  44. package/rust/core/preprocessor/processor.rs +13 -4
  45. package/rust/core/preprocessor/resolver/call.rs +99 -29
  46. package/rust/core/preprocessor/resolver/condition.rs +38 -12
  47. package/rust/core/preprocessor/resolver/driver.rs +74 -29
  48. package/rust/core/preprocessor/resolver/group.rs +24 -81
  49. package/rust/core/preprocessor/resolver/let_.rs +31 -0
  50. package/rust/core/preprocessor/resolver/loop_.rs +62 -116
  51. package/rust/core/preprocessor/resolver/mod.rs +5 -1
  52. package/rust/core/preprocessor/resolver/spawn.rs +41 -36
  53. package/rust/core/preprocessor/resolver/synth.rs +50 -0
  54. package/rust/core/preprocessor/resolver/trigger.rs +51 -50
  55. package/rust/core/preprocessor/resolver/value.rs +78 -0
  56. package/rust/core/utils/path.rs +17 -32
  57. package/rust/core/utils/validation.rs +30 -28
  58. package/typescript/scripts/version/fetch.ts +1 -6
  59. package/rust/core/parser/handler/identifier.rs +0 -262
@@ -3,101 +3,33 @@ use std::collections::HashMap;
3
3
  use crate::{
4
4
  core::{
5
5
  parser::statement::{ Statement, StatementKind },
6
- preprocessor::{ module::Module, resolver::{condition::resolve_condition, trigger::resolve_trigger} },
6
+ preprocessor::{ module::Module, resolver::driver::resolve_statement },
7
7
  shared::value::Value,
8
- store::global::GlobalStore,
8
+ store::{ global::GlobalStore, variable::VariableTable },
9
9
  },
10
- utils::logger::Logger,
10
+ utils::logger::{ LogLevel, Logger },
11
11
  };
12
12
 
13
13
  pub fn resolve_group(
14
14
  stmt: &Statement,
15
15
  module: &Module,
16
16
  path: &str,
17
- global_store: &GlobalStore
17
+ global_store: &mut GlobalStore
18
18
  ) -> Statement {
19
19
  let logger = Logger::new();
20
20
 
21
- let Value::Map(value_map) = &stmt.value else {
22
- return type_error(&logger, module, stmt, "Expected a map for group statement".to_string());
21
+ let Value::Map(group_map) = &stmt.value else {
22
+ return type_error(&logger, module, stmt, "Expected a map in group statement".to_string());
23
23
  };
24
24
 
25
- let group_name = match value_map.get("identifier") {
26
- Some(Value::String(name)) => name.clone(),
27
- Some(other) => {
28
- return type_error(
29
- &logger,
30
- module,
31
- stmt,
32
- format!("Group name must be a string, found {:?}", other)
33
- );
34
- }
35
- None => {
36
- return type_error(&logger, module, stmt, "Group name is required".to_string());
37
- }
38
- };
39
-
40
- let resolved_body = match value_map.get("body") {
41
- Some(Value::Block(statements)) => {
42
- let mut resolved = Vec::new();
43
-
44
- for stmt in statements {
45
- match &stmt.kind {
46
- StatementKind::Trigger { entity, duration } => {
47
- let resolved_trigger = resolve_trigger(
48
- &mut stmt.clone(),
49
- entity,
50
- &mut duration.clone(),
51
- module,
52
- path,
53
- global_store
54
- );
55
-
56
- resolved.push(resolved_trigger);
57
- }
58
-
59
- StatementKind::If => {
60
- let resolved_condition = resolve_condition(
61
- &mut stmt.clone(),
62
- module,
63
- path,
64
- global_store
65
- );
66
-
67
- resolved.push(resolved_condition);
68
- }
69
-
70
- _ => {
71
- println!("Unhandled group body statement: {:?}", stmt);
72
- }
73
- }
74
- }
75
-
76
- Value::Block(resolved)
77
- }
25
+ let mut resolved_map = group_map.clone();
78
26
 
79
- Some(other) => {
80
- return type_error(
81
- &logger,
82
- module,
83
- stmt,
84
- format!("Unexpected value for group body: {:?}", other)
85
- );
86
- }
87
-
88
- None => {
89
- return type_error(
90
- &logger,
91
- module,
92
- stmt,
93
- "Missing 'body' key in group statement".to_string()
94
- );
95
- }
96
- };
97
-
98
- let mut resolved_map = HashMap::new();
99
- resolved_map.insert("identifier".to_string(), Value::String(group_name));
100
- resolved_map.insert("body".to_string(), resolved_body);
27
+ if let Some(Value::Block(body)) = group_map.get("body") {
28
+ let resolved_body = resolve_block_statements(body, module, path, global_store);
29
+ resolved_map.insert("body".to_string(), Value::Block(resolved_body));
30
+ } else {
31
+ logger.log_message(LogLevel::Warning, "group without a body");
32
+ }
101
33
 
102
34
  Statement {
103
35
  kind: StatementKind::Group,
@@ -106,6 +38,17 @@ pub fn resolve_group(
106
38
  }
107
39
  }
108
40
 
41
+ fn resolve_block_statements(
42
+ body: &[Statement],
43
+ module: &Module,
44
+ path: &str,
45
+ global_store: &mut GlobalStore
46
+ ) -> Vec<Statement> {
47
+ body.iter()
48
+ .map(|stmt| resolve_statement(stmt, module, path, global_store))
49
+ .collect()
50
+ }
51
+
109
52
  fn type_error(logger: &Logger, module: &Module, stmt: &Statement, message: String) -> Statement {
110
53
  let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
111
54
  logger.log_error_with_stacktrace(&message, &stacktrace);
@@ -0,0 +1,31 @@
1
+ use crate::
2
+ core::{
3
+ parser::statement:: Statement ,
4
+ preprocessor::{
5
+ module::Module,
6
+ resolver:: value::resolve_value ,
7
+ },
8
+ store:: global::GlobalStore ,
9
+ }
10
+ ;
11
+
12
+ pub fn resolve_let(
13
+ stmt: &Statement,
14
+ name: &str,
15
+ module: &Module,
16
+ path: &str,
17
+ global_store: &mut GlobalStore
18
+ ) -> Statement {
19
+ let resolved_value = resolve_value(&stmt.value, module, global_store);
20
+
21
+ if let Some(current_mod) = global_store.modules.get_mut(path) {
22
+ current_mod.variable_table.set(name.to_string(), resolved_value.clone());
23
+ } else {
24
+ eprintln!("[resolve_statement] ❌ Module path not found: {path}");
25
+ }
26
+
27
+ Statement {
28
+ value: resolved_value,
29
+ ..stmt.clone()
30
+ }
31
+ }
@@ -3,7 +3,10 @@ use std::collections::HashMap;
3
3
  use crate::{
4
4
  core::{
5
5
  parser::statement::{ Statement, StatementKind },
6
- preprocessor::{ module::Module, resolver::trigger::resolve_trigger },
6
+ preprocessor::{
7
+ module::Module,
8
+ resolver::{ driver::resolve_statement, value::resolve_value },
9
+ },
7
10
  shared::value::Value,
8
11
  store::global::GlobalStore,
9
12
  },
@@ -14,132 +17,75 @@ pub fn resolve_loop(
14
17
  stmt: &Statement,
15
18
  module: &Module,
16
19
  path: &str,
17
- global_store: &GlobalStore
20
+ global_store: &mut GlobalStore
18
21
  ) -> Statement {
19
22
  let logger = Logger::new();
20
23
 
21
- if let Value::Map(value_map) = &stmt.value {
22
- let iterator_value = match value_map.get("iterator") {
23
- Some(Value::Identifier(ident)) => {
24
- match module.variable_table.get(ident) {
25
- Some(Value::Number(n)) => Value::Number(*n),
26
- Some(_) => {
27
- log_type_error(
28
- &logger,
29
- module,
30
- stmt,
31
- format!("Loop iterator '{ident}' must resolve to a number")
32
- );
33
- Value::Null
34
- }
35
- None => {
36
- // Value is not a variable so we assume it's a number
37
- if let Ok(n) = ident.parse::<f32>() {
38
- Value::Number(n)
39
- } else {
40
- log_type_error(
41
- &logger,
42
- module,
43
- stmt,
44
- format!("Loop iterator '{ident}' is not a valid number")
45
- );
46
- Value::Null
47
- }
48
- }
49
- }
50
- }
51
- Some(Value::Number(n)) => Value::Number(*n),
52
- Some(other) => {
53
- log_type_error(
54
- &logger,
55
- module,
56
- stmt,
57
- format!("Unexpected value for loop iterator: {:?}", other)
58
- );
59
- Value::Null
60
- }
61
- None => {
62
- log_type_error(
63
- &logger,
64
- module,
65
- stmt,
66
- "Missing 'iterator' key in loop statement map".to_string()
67
- );
68
- Value::Null
69
- }
70
- };
24
+ let resolved_value = resolve_value(&stmt.value, module, global_store);
71
25
 
72
- let body_value = match value_map.get("body") {
73
- Some(Value::Block(block)) => {
74
- let mut resolved_block = Vec::new();
75
- for ref statement in block.clone() {
76
- match &statement.kind {
77
- StatementKind::Trigger { entity, duration } => {
78
- let resolved = resolve_trigger(
79
- &mut statement.clone(),
80
- &entity,
81
- &mut duration.clone(),
82
- module,
83
- path,
84
- global_store
85
- );
86
- resolved_block.push(resolved);
87
- }
88
- _ => {
89
- println!("Unhandled loop body statement: {:?}", statement);
90
- }
91
- }
92
- }
93
- Value::Block(resolved_block)
94
- }
95
- Some(other) => {
96
- log_type_error(
97
- &logger,
98
- module,
99
- stmt,
100
- format!("Unexpected value for loop body: {:?}", other)
101
- );
102
- Value::Null
103
- }
104
- None => {
105
- log_type_error(
106
- &logger,
107
- module,
108
- stmt,
109
- "Missing 'body' key in loop statement map".to_string()
110
- );
111
- Value::Null
112
- }
113
- };
26
+ let Value::Map(value_map) = &resolved_value else {
27
+ return error_stmt(&logger, module, stmt, "Expected a map for loop value");
28
+ };
114
29
 
115
- let mut resolved_map = HashMap::new();
116
- resolved_map.insert("iterator".to_string(), iterator_value);
117
- resolved_map.insert("body".to_string(), body_value);
30
+ let mut resolved_map: HashMap<String, Value> = HashMap::new();
31
+ for (key, val) in value_map {
32
+ resolved_map.insert(key.clone(), resolve_value(val, module, global_store));
33
+ }
118
34
 
119
- Statement {
120
- kind: StatementKind::Loop,
121
- value: Value::Map(resolved_map),
122
- ..stmt.clone()
35
+ let iterator_value = match resolved_map.get("iterator") {
36
+ Some(Value::Number(n)) => Value::Number(*n),
37
+ Some(other) => {
38
+ error_value(
39
+ &logger,
40
+ module,
41
+ stmt,
42
+ &format!("Loop iterator must be a number, found: {:?}", other)
43
+ );
44
+ Value::Number(1.0)
45
+ }
46
+ None => {
47
+ error_value(&logger, module, stmt, "Missing 'iterator' in loop");
48
+ Value::Number(1.0)
123
49
  }
124
- } else {
125
- log_type_error(
126
- &logger,
127
- module,
128
- stmt,
129
- format!("Expected a map for loop value, found {:?}", stmt.value)
130
- );
50
+ };
131
51
 
132
- Statement {
133
- kind: StatementKind::Error {
134
- message: "Expected a map for loop value".to_string(),
135
- },
136
- value: Value::Null,
137
- ..stmt.clone()
52
+ let body_value = match resolved_map.remove("body") {
53
+ Some(Value::Block(stmts)) => {
54
+ let resolved = stmts
55
+ .iter()
56
+ .map(|s| resolve_statement(s, module, path, global_store))
57
+ .collect();
58
+ Value::Block(resolved)
138
59
  }
60
+ _ => {
61
+ error_value(&logger, module, stmt, "Invalid or missing loop body");
62
+ Value::Block(vec![])
63
+ }
64
+ };
65
+
66
+ let mut final_map = HashMap::new();
67
+ final_map.insert("iterator".to_string(), iterator_value);
68
+ final_map.insert("body".to_string(), body_value);
69
+
70
+ Statement {
71
+ kind: StatementKind::Loop,
72
+ value: Value::Map(final_map),
73
+ ..stmt.clone()
139
74
  }
140
75
  }
141
76
 
142
- fn log_type_error(logger: &Logger, module: &Module, stmt: &Statement, message: String) {
77
+ fn error_value(logger: &Logger, module: &Module, stmt: &Statement, msg: &str) {
143
78
  let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
144
- logger.log_error_with_stacktrace(&message, &stacktrace);
79
+ logger.log_error_with_stacktrace(msg, &stacktrace);
80
+ }
81
+
82
+ fn error_stmt(logger: &Logger, module: &Module, stmt: &Statement, msg: &str) -> Statement {
83
+ error_value(logger, module, stmt, msg);
84
+ Statement {
85
+ kind: StatementKind::Error {
86
+ message: msg.to_string(),
87
+ },
88
+ value: Value::Null,
89
+ ..stmt.clone()
90
+ }
145
91
  }
@@ -1,5 +1,7 @@
1
1
  pub mod driver;
2
2
 
3
+ pub mod value;
4
+
3
5
  pub mod trigger;
4
6
  pub mod loop_;
5
7
  pub mod bank;
@@ -7,4 +9,6 @@ pub mod tempo;
7
9
  pub mod group;
8
10
  pub mod condition;
9
11
  pub mod spawn;
10
- pub mod call;
12
+ pub mod call;
13
+ pub mod synth;
14
+ pub mod let_;
@@ -1,53 +1,58 @@
1
1
  use crate::{
2
2
  core::{
3
- parser::statement::{Statement, StatementKind},
4
- preprocessor::module::Module,
3
+ parser::statement::{ Statement, StatementKind },
4
+ preprocessor::{
5
+ module::Module,
6
+ resolver::driver::resolve_statement,
7
+ resolver::value::resolve_value,
8
+ },
5
9
  shared::value::Value,
6
10
  store::global::GlobalStore,
7
11
  },
8
- utils::logger::Logger,
12
+ utils::logger::{ Logger, LogLevel },
9
13
  };
10
14
 
11
15
  pub fn resolve_spawn(
12
16
  stmt: &Statement,
13
17
  module: &Module,
14
- _path: &str,
15
- _global_store: &GlobalStore,
18
+ path: &str,
19
+ global_store: &mut GlobalStore
16
20
  ) -> Statement {
17
21
  let logger = Logger::new();
18
22
 
19
- let Value::String(name) = &stmt.value else {
20
- return type_error(&logger, module, stmt, "Spawn expects a group name as string.".to_string());
21
- };
23
+ let resolved_value = resolve_value(&stmt.value, module, global_store);
22
24
 
23
- match module.variable_table.variables.get(name) {
24
- Some(Value::Map(group_stmt)) => Statement {
25
- kind: StatementKind::Spawn,
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
- }
25
+ match resolved_value {
26
+ Value::Map(mut map) => {
27
+ if let Some(Value::Block(stmts)) = map.get("body") {
28
+ let resolved_block = stmts
29
+ .iter()
30
+ .map(|s| resolve_statement(s, module, path, global_store))
31
+ .collect();
32
+ map.insert("body".to_string(), Value::Block(resolved_block));
33
+ }
34
+
35
+ Statement {
36
+ kind: StatementKind::Spawn,
37
+ value: Value::Map(map),
38
+ ..stmt.clone()
39
+ }
40
+ }
43
41
 
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);
42
+ _ => {
43
+ let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
44
+ logger.log_message(
45
+ LogLevel::Error,
46
+ &format!("Expected a map in spawn statement\n → at {stacktrace}")
47
+ );
47
48
 
48
- Statement {
49
- kind: StatementKind::Error { message },
50
- value: Value::Null,
51
- ..stmt.clone()
49
+ Statement {
50
+ kind: StatementKind::Error {
51
+ message: "Invalid spawn value".to_string(),
52
+ },
53
+ value: Value::Null,
54
+ ..stmt.clone()
55
+ }
56
+ }
52
57
  }
53
- }
58
+ }
@@ -0,0 +1,50 @@
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::{ LogLevel, Logger },
9
+ };
10
+
11
+ pub fn resolve_synth(
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(synth_map) = &stmt.value else {
20
+ return type_error(&logger, module, stmt, "Expected a map in synth statement".to_string());
21
+ };
22
+
23
+ let mut resolved_map = synth_map.clone();
24
+
25
+ if let Some(Value::Block(body)) = synth_map.get("body") {
26
+ let resolved_body = body.iter()
27
+ .map(|s| resolve_statement(s, module, path, global_store))
28
+ .collect::<Vec<_>>();
29
+ resolved_map.insert("body".to_string(), Value::Block(resolved_body));
30
+ } else {
31
+ logger.log_message(LogLevel::Warning, "synth without a body");
32
+ }
33
+
34
+ Statement {
35
+ kind: StatementKind::Synth,
36
+ value: Value::Map(resolved_map),
37
+ ..stmt.clone()
38
+ }
39
+ }
40
+
41
+ fn type_error(logger: &Logger, module: &Module, stmt: &Statement, message: String) -> Statement {
42
+ let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
43
+ logger.log_error_with_stacktrace(&message, &stacktrace);
44
+
45
+ Statement {
46
+ kind: StatementKind::Error { message },
47
+ value: Value::Null,
48
+ ..stmt.clone()
49
+ }
50
+ }
@@ -6,7 +6,6 @@ use crate::{
6
6
  preprocessor::module::Module,
7
7
  shared::{ duration::Duration, value::Value },
8
8
  store::global::GlobalStore,
9
- utils::validation::is_valid_entity,
10
9
  },
11
10
  utils::logger::Logger,
12
11
  };
@@ -24,30 +23,17 @@ pub fn resolve_trigger(
24
23
  let mut final_duration = duration.clone();
25
24
  let mut final_value = stmt.value.clone();
26
25
 
27
- if !is_valid_entity(entity, module, global_store) {
28
- let message = format!("Invalid entity '{}', expected a valid identifier", entity);
29
- let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
30
- logger.log_error_with_stacktrace(&message, &stacktrace);
31
-
32
- return Statement {
33
- kind: stmt.kind.clone(),
34
- value: Value::Null,
35
- line: stmt.line,
36
- column: stmt.column,
37
- indent: stmt.indent,
38
- };
39
- }
40
-
26
+ // Duration resolution
41
27
  if let Duration::Identifier(ident) = duration {
42
- if let Some(val) = module.variable_table.get(ident) {
28
+ if let Some(val) = resolve_identifier(ident, module, global_store) {
43
29
  match val {
44
- Value::Number(num) => {
45
- final_duration = Duration::Number(*num);
30
+ Value::Number(n) => {
31
+ final_duration = Duration::Number(n);
46
32
  }
47
33
  Value::String(s) => {
48
- final_duration = Duration::Identifier(s.clone());
34
+ final_duration = Duration::Identifier(s);
49
35
  }
50
- Value::Identifier(id) if id == "auto" => {
36
+ Value::Identifier(s) if s == "auto" => {
51
37
  final_duration = Duration::Auto;
52
38
  }
53
39
  _ => {}
@@ -55,50 +41,34 @@ pub fn resolve_trigger(
55
41
  }
56
42
  }
57
43
 
44
+ // Params value resolution
58
45
  final_value = match &stmt.value {
59
46
  Value::Identifier(ident) => {
60
- match module.variable_table.get(ident) {
61
- Some(val) => val.clone(),
62
- None => {
63
- let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
64
- let message = format!(
65
- "'{path}': value identifier '{ident}' not found in variable table"
66
- );
67
- logger.log_error_with_stacktrace(&message, &stacktrace);
68
- Value::Null
69
- }
70
- }
47
+ resolve_identifier(ident, module, global_store).unwrap_or_else(|| {
48
+ logger.log_error_with_stacktrace(
49
+ &format!("'{path}': value identifier '{ident}' not found"),
50
+ &format!("{}:{}:{}", module.path, stmt.line, stmt.column)
51
+ );
52
+ Value::Null
53
+ })
71
54
  }
72
55
  Value::Map(map) => {
73
56
  let mut resolved_map = HashMap::new();
74
- for (k, v) in map.iter() {
75
- let resolved_v = match v {
57
+ for (k, v) in map {
58
+ let resolved = match v {
76
59
  Value::Identifier(id) => {
77
- module.variable_table.get(id).cloned().unwrap_or(Value::Null)
60
+ resolve_identifier(id, module, global_store).unwrap_or(Value::Null)
78
61
  }
79
62
  other => other.clone(),
80
63
  };
81
- resolved_map.insert(k.clone(), resolved_v);
64
+ resolved_map.insert(k.clone(), resolved);
82
65
  }
83
66
  Value::Map(resolved_map)
84
67
  }
85
68
  other => other.clone(),
86
69
  };
87
70
 
88
- if let StatementKind::Trigger { entity, .. } = &stmt.kind {
89
- return Statement {
90
- kind: StatementKind::Trigger {
91
- entity: entity.to_string(),
92
- duration: final_duration,
93
- },
94
- value: final_value,
95
- line: stmt.line,
96
- column: stmt.column,
97
- indent: stmt.indent,
98
- };
99
- }
100
-
101
- return Statement {
71
+ Statement {
102
72
  kind: StatementKind::Trigger {
103
73
  entity: entity.to_string(),
104
74
  duration: final_duration,
@@ -107,5 +77,36 @@ pub fn resolve_trigger(
107
77
  line: stmt.line,
108
78
  column: stmt.column,
109
79
  indent: stmt.indent,
110
- };
80
+ }
81
+ }
82
+
83
+ fn resolve_identifier(ident: &str, module: &Module, global_store: &GlobalStore) -> Option<Value> {
84
+ if let Some(val) = module.variable_table.get(ident) {
85
+ return Some(resolve_value(val, module, global_store));
86
+ }
87
+
88
+ for (_, other_mod) in &global_store.modules {
89
+ if let Some(val) = other_mod.export_table.get_export(ident) {
90
+ return Some(resolve_value(val, other_mod, global_store));
91
+ }
92
+ }
93
+
94
+ None
95
+ }
96
+
97
+ fn resolve_value(val: &Value, module: &Module, global_store: &GlobalStore) -> Value {
98
+ match val {
99
+ Value::Identifier(inner) =>
100
+ resolve_identifier(inner, module, global_store).unwrap_or(
101
+ Value::Identifier(inner.clone())
102
+ ),
103
+ Value::Map(map) => {
104
+ let mut resolved = HashMap::new();
105
+ for (k, v) in map {
106
+ resolved.insert(k.clone(), resolve_value(v, module, global_store));
107
+ }
108
+ Value::Map(resolved)
109
+ }
110
+ other => other.clone(),
111
+ }
111
112
  }