devalang_core/core/preprocessor/resolver/
group.rs1use 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
11pub fn resolve_group(
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(group_map) = &stmt.value else {
20 return type_error(
21 &logger,
22 module,
23 stmt,
24 "Expected a map in group statement".to_string(),
25 );
26 };
27
28 let identifier = match group_map.get("identifier") {
30 Some(Value::String(id)) => id.clone(),
31 _ => {
32 return type_error(
33 &logger,
34 module,
35 stmt,
36 "Group statement must have an 'identifier' field".to_string(),
37 );
38 }
39 };
40
41 if global_store.variables.variables.contains_key(&identifier) {
43 return type_error(
44 &logger,
45 module,
46 stmt,
47 format!("Group identifier '{}' already exists", identifier),
48 );
49 }
50
51 let mut resolved_map = group_map.clone();
53 if let Some(Value::Block(body)) = group_map.get("body") {
54 let resolved_body = resolve_block_statements(body, module, path, global_store);
55 resolved_map.insert("body".to_string(), Value::Block(resolved_body));
56 } else {
57 logger.log_message(LogLevel::Warning, "Group without a body");
58 }
59
60 let resolved_group_stmt = Statement {
62 kind: StatementKind::Group,
63 value: Value::Map(resolved_map.clone()),
64 ..stmt.clone()
65 };
66
67 global_store.variables.variables.insert(
69 identifier.clone(),
70 Value::Statement(Box::new(resolved_group_stmt.clone())),
71 );
72
73 resolved_group_stmt
74}
75
76fn resolve_block_statements(
77 body: &[Statement],
78 module: &Module,
79 path: &str,
80 global_store: &mut GlobalStore,
81) -> Vec<Statement> {
82 body.iter()
83 .map(|stmt| resolve_statement(stmt, module, path, global_store))
84 .collect()
85}
86
87fn type_error(logger: &Logger, module: &Module, stmt: &Statement, message: String) -> Statement {
88 let stacktrace = format!("{}:{}:{}", module.path, stmt.line, stmt.column);
89 logger.log_error_with_stacktrace(&message, &stacktrace);
90
91 Statement {
92 kind: StatementKind::Error { message },
93 value: Value::Null,
94 ..stmt.clone()
95 }
96}