Init each unique import once; code modules run their top-level, native ones just bind. `in_progress` catches cycles cleanly. */
(&mut self, chunk: &SSAChunk, in_progress: &mut crate::util::fx::FxHashSet<String>)
| 189 | |
| 190 | /* Init each unique import once; code modules run their top-level, native ones just bind. `in_progress` catches cycles cleanly. */ |
| 191 | fn init_modules(&mut self, chunk: &SSAChunk, in_progress: &mut crate::util::fx::FxHashSet<String>) -> Result<(), VmErr> { |
| 192 | for entry in &chunk.imports { |
| 193 | if self.module_table.contains_key(&entry.spec) { continue; } |
| 194 | if !in_progress.insert(entry.spec.clone()) { |
| 195 | return Err(VmErr::Runtime("circular import")); |
| 196 | } |
| 197 | match &entry.kind { |
| 198 | ImportKind::Native { funcs, classes, consts } => { |
| 199 | let mut attrs: Vec<(String, Val)> = Vec::with_capacity(funcs.len() + classes.len() + consts.len()); |
| 200 | for b in funcs { |
| 201 | let val = self.heap.alloc(HeapObj::Extern(b.clone()))?; |
| 202 | attrs.push((b.name.clone(), val)); |
| 203 | } |
| 204 | // Materialise each constant by invoking its export once and binding the result as an attr. |
| 205 | for c in consts { |
| 206 | let func = c.func.clone(); |
| 207 | let val = func(&mut self.heap, &[], None)?; |
| 208 | attrs.push((c.name.clone(), val)); |
| 209 | } |
| 210 | // Synthesise a HeapObj::Class per native class; each method becomes an Extern Val on the class. |
| 211 | for c in classes { |
| 212 | let mut methods: Vec<(String, Val)> = Vec::with_capacity(c.methods.len()); |
| 213 | for m in &c.methods { |
| 214 | let mval = self.heap.alloc(HeapObj::Extern(m.clone()))?; |
| 215 | methods.push((m.name.clone(), mval)); |
| 216 | } |
| 217 | let cls_val = self.heap.alloc(HeapObj::Class(c.name.clone(), Vec::new(), alloc::rc::Rc::new(core::cell::RefCell::new(methods))))?; |
| 218 | attrs.push((c.name.clone(), cls_val)); |
| 219 | } |
| 220 | let val = self.heap.alloc(HeapObj::Module(entry.spec.clone(), attrs))?; |
| 221 | self.module_table.insert(entry.spec.clone(), val); |
| 222 | } |
| 223 | ImportKind::Code(sub_chunk) => { |
| 224 | self.init_modules(sub_chunk, in_progress)?; |
| 225 | let mut sub_slots = self.fill_builtins(&sub_chunk.names); |
| 226 | // Set `__name__` to the module spec so `if __name__ == "__main__":` works. |
| 227 | let spec_val = self.heap.alloc(HeapObj::Str(entry.spec.clone()))?; |
| 228 | for (i, name) in sub_chunk.names.iter().enumerate() { |
| 229 | if ssa_strip(name) == "__name__" { |
| 230 | sub_slots[i] = spec_val; |
| 231 | } |
| 232 | } |
| 233 | self.exec(sub_chunk, &mut sub_slots)?; |
| 234 | let attrs = collect_module_attrs(sub_chunk, &sub_slots); |
| 235 | let val = self.heap.alloc(HeapObj::Module(entry.spec.clone(), attrs))?; |
| 236 | self.module_table.insert(entry.spec.clone(), val); |
| 237 | } |
| 238 | } |
| 239 | in_progress.remove(&entry.spec); |
| 240 | } |
| 241 | Ok(()) |
| 242 | } |
| 243 | } |
no test coverage detected