devalang_core/core/preprocessor/resolver/
group.rs

1use 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    // Check for the presence of the identifier field
29    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    // Ensure the identifier does not already exist
42    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    // Resolve statements in the body
52    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    // Build a complete Statement for the group
61    let resolved_group_stmt = Statement {
62        kind: StatementKind::Group,
63        value: Value::Map(resolved_map.clone()),
64        ..stmt.clone()
65    };
66
67    // Store the Statement directly in the global variable_table
68    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}