swamp_script_semantic/
modules.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/script
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use crate::ns::{ResolvedModuleNamespace, ResolvedModuleNamespaceRef};
6use crate::{
7    ConstantId, ResolvedConstant, ResolvedConstantRef, ResolvedDefinition, ResolvedExpression,
8    SemanticError,
9};
10use seq_map::SeqMap;
11use seq_set::SeqSet;
12use std::cell::RefCell;
13use std::collections::{HashMap, VecDeque};
14use std::fmt::{Debug, Formatter};
15use std::rc::Rc;
16
17#[derive(Debug)]
18pub struct ResolvedModules {
19    pub modules: HashMap<Vec<String>, ResolvedModuleRef>,
20    pub constants: Vec<ResolvedConstantRef>,
21    pub constants_in_eval_order: Vec<ResolvedConstantRef>,
22}
23
24impl Default for ResolvedModules {
25    fn default() -> Self {
26        Self::new()
27    }
28}
29
30pub struct ResolvedModule {
31    pub definitions: Vec<ResolvedDefinition>,
32    pub expression: Option<ResolvedExpression>,
33    pub namespace: ResolvedModuleNamespaceRef,
34}
35
36impl Debug for ResolvedModule {
37    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
38        for resolved_def in &self.definitions {
39            writeln!(f, "{resolved_def:?}")?;
40        }
41
42        if !self.definitions.is_empty() && self.expression.is_some() {
43            writeln!(f, "---\n")?;
44        }
45
46        if let Some(resolved_expression) = &self.expression {
47            match resolved_expression {
48                ResolvedExpression::Block(expressions) => {
49                    for expression in expressions {
50                        writeln!(f, "{expression:?}")?;
51                    }
52                }
53                _ => writeln!(f, "{resolved_expression:?}")?,
54            }
55        }
56
57        Ok(())
58    }
59}
60
61pub type ResolvedModuleRef = Rc<RefCell<ResolvedModule>>;
62
63impl ResolvedModule {
64    pub fn new(module_path: &[String]) -> Self {
65        let ns_ref = Rc::new(RefCell::new(ResolvedModuleNamespace::new(module_path)));
66        Self {
67            definitions: Vec::new(),
68            namespace: ns_ref,
69            expression: None,
70        }
71    }
72}
73
74impl ResolvedModules {
75    pub fn new() -> Self {
76        Self {
77            modules: HashMap::new(),
78            constants: Vec::new(),
79            constants_in_eval_order: Vec::new(),
80        }
81    }
82    pub fn add(&mut self, module: ResolvedModuleRef) {
83        self.modules.insert(
84            module.clone().borrow().namespace.borrow().path.clone(),
85            module,
86        );
87    }
88
89    pub fn add_constant(&mut self, resolved_constant: ResolvedConstant) -> ResolvedConstantRef {
90        let id = self.constants.len();
91        let mut copy = resolved_constant;
92        copy.id = id as ConstantId;
93        let constant_ref = Rc::new(copy);
94        self.constants.push(constant_ref.clone());
95
96        constant_ref
97    }
98
99    pub fn finalize(&mut self) -> Result<(), SemanticError> {
100        self.constants_in_eval_order = self.eval_ordered_constants()?;
101
102        Ok(())
103    }
104
105    fn eval_ordered_constants(&self) -> Result<Vec<ResolvedConstantRef>, SemanticError> {
106        Self::topological_sort_constants(&self.constants)
107    }
108
109    pub fn topological_sort_constants(
110        constants: &[ResolvedConstantRef],
111    ) -> Result<Vec<ResolvedConstantRef>, SemanticError> {
112        let mut id_to_constant: SeqMap<ConstantId, ResolvedConstantRef> = SeqMap::new();
113        for const_ref in constants {
114            id_to_constant
115                .insert(const_ref.id, Rc::clone(const_ref))
116                .map_err(|_| SemanticError::DuplicateConstantId(const_ref.id))?;
117        }
118
119        let mut adjacency: SeqMap<ConstantId, SeqSet<ConstantId>> = SeqMap::new();
120        let mut number_of_dependencies: SeqMap<ConstantId, usize> = SeqMap::new();
121
122        for const_ref in constants {
123            number_of_dependencies
124                .insert(const_ref.id, 0)
125                .map_err(|_| SemanticError::DuplicateConstantId(const_ref.id))?;
126
127            let mut deps = SeqSet::new();
128            const_ref.expr.collect_constant_dependencies(&mut deps);
129
130            for dep_id in &deps {
131                assert!(id_to_constant.contains_key(dep_id));
132
133                if let Some(dependents) = adjacency.get_mut(dep_id) {
134                    dependents.insert(const_ref.id);
135                } else {
136                    let mut dependents = SeqSet::new();
137                    dependents.insert(const_ref.id);
138                    adjacency
139                        .insert(*dep_id, dependents)
140                        .map_err(|_| SemanticError::DuplicateConstantId(const_ref.id))?;
141                }
142
143                let dependency_count = number_of_dependencies
144                    .get_mut(&const_ref.id)
145                    .expect("dependency count should have been inserted earlier");
146                *dependency_count += 1;
147            }
148        }
149
150        let mut queue: VecDeque<ConstantId> = number_of_dependencies
151            .iter()
152            .filter_map(|(id, &dependency_count)| {
153                if dependency_count == 0 {
154                    Some(*id)
155                } else {
156                    None
157                }
158            })
159            .collect();
160
161        let mut sorted_constants: Vec<ResolvedConstantRef> = Vec::new();
162
163        while let Some(current_id) = queue.pop_front() {
164            let current_const = id_to_constant
165                .get(&current_id)
166                .expect("should have a id to constant lookup");
167
168            sorted_constants.push(Rc::clone(current_const));
169
170            if let Some(dependents) = adjacency.get(&current_id) {
171                for dependent_id in dependents {
172                    let dependency_count = number_of_dependencies
173                        .get_mut(dependent_id)
174                        .expect("should have number of dependencies");
175                    assert!(*dependency_count > 0);
176                    *dependency_count -= 1;
177                    if *dependency_count == 0 {
178                        queue.push_back(*dependent_id);
179                    }
180                }
181            }
182        }
183
184        if sorted_constants.len() != constants.len() {
185            let unsorted_ids: Vec<ConstantId> = constants
186                .iter()
187                .map(|c| c.id)
188                .filter(|id| !sorted_constants.iter().any(|c| c.id == *id))
189                .collect();
190
191            return Err(SemanticError::CircularConstantDependency(unsorted_ids));
192        }
193
194        Ok(sorted_constants)
195    }
196
197    pub fn add_empty_module(&mut self, module_path: &[String]) -> ResolvedModuleRef {
198        let ns_ref = Rc::new(RefCell::new(ResolvedModuleNamespace::new(module_path)));
199        let module = ResolvedModule {
200            definitions: vec![],
201            expression: None,
202            namespace: ns_ref,
203        };
204        let module_ref = Rc::new(RefCell::new(module));
205
206        self.modules
207            .insert(Vec::from(module_path), module_ref.clone());
208
209        module_ref
210    }
211
212    #[must_use]
213    pub fn contains_key(&self, module_path: &[String]) -> bool {
214        self.modules.contains_key(module_path)
215    }
216
217    #[must_use]
218    pub fn get(&self, module_path: &[String]) -> Option<ResolvedModuleRef> {
219        self.modules.get(module_path).cloned()
220    }
221}