devalang_core/core/preprocessor/resolver/
group.rs

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