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