Skip to main content

arora_module_core/
resolve.rs

1use crate::{ImportAsset, ModuleDeclarationError};
2use arora_registry::local::ROOT_ID;
3use arora_registry::{get_primitive, Module, ModuleFrozen, ReadableRegistry, RegistryError};
4use arora_types::module::low::Header;
5use arora_types::module::{
6    high::{
7        ExportSymbol as HighExportSymbol, ImportSymbol as HighImportSymbol,
8        ModuleDefinition as HighModuleDefinition, Parameter as HighParameter,
9        TypeRef as HighTypeRef,
10    },
11    low::{
12        ExportSymbol as LowExportSymbol, ImportSymbol as LowImportSymbol,
13        Parameter as LowParameter, TypeRef as LowTypeRef,
14    },
15};
16use arora_types::record::Selector;
17use arora_types::record::{
18    module::unfrozen::{Export, Function, Parameter},
19    ty::{UnfrozenArray, UnfrozenScalar, UnfrozenTy},
20};
21use arora_types::record::{Freeze, Resolver, UnfrozenReference, VersionReq};
22use std::collections::HashSet;
23use std::{collections::HashMap, str::FromStr};
24use uuid::Uuid;
25
26pub async fn resolve_type_id(
27    name: &str,
28    registry: &mut dyn ReadableRegistry,
29) -> Result<Uuid, ModuleDeclarationError> {
30    Ok(match Uuid::parse_str(name) {
31        Ok(id) => id,
32        Err(_) => registry
33            .resolve_path(name)
34            .await
35            .map_err(ModuleDeclarationError::RegistryError)?,
36    })
37}
38
39pub async fn resolve_module_id(
40    name: &str,
41    registry: &mut dyn ReadableRegistry,
42) -> Result<Uuid, ModuleDeclarationError> {
43    Ok(match Uuid::parse_str(name) {
44        Ok(id) => id,
45        Err(_) => registry
46            .resolve_path(name)
47            .await
48            .map_err(ModuleDeclarationError::RegistryError)?,
49    })
50}
51
52pub async fn resolve_high_type_ref(
53    type_ref: &HighTypeRef,
54    registry: &mut dyn ReadableRegistry,
55) -> Result<UnfrozenTy, ModuleDeclarationError> {
56    match type_ref {
57        HighTypeRef::Scalar { id } => {
58            let selector = Selector::from_str(id).map_err(ModuleDeclarationError::Generic)?;
59            if let Some(primitive) = get_primitive(&selector) {
60                Ok(UnfrozenTy::Primitive(primitive.into()))
61            } else {
62                Ok(UnfrozenTy::UnfrozenScalar(UnfrozenScalar {
63                    reference: unfrozen_reference_from_name(id, registry).await?,
64                }))
65            }
66        }
67        HighTypeRef::Array { id } => {
68            let selector = Selector::from_str(id).map_err(ModuleDeclarationError::Generic)?;
69            if let Some(primitive) = get_primitive(&selector) {
70                Ok(UnfrozenTy::Primitive(primitive.into()))
71            } else {
72                Ok(UnfrozenTy::UnfrozenArray(UnfrozenArray {
73                    reference: unfrozen_reference_from_name(id, registry).await?,
74                }))
75            }
76        }
77        _ => Err(ModuleDeclarationError::Generic(format!(
78            "Unsupported type ref: {:?}",
79            type_ref
80        ))),
81    }
82}
83
84pub async fn resolve_low_type_ref(
85    type_ref: &LowTypeRef,
86) -> Result<UnfrozenTy, ModuleDeclarationError> {
87    match type_ref {
88        LowTypeRef::Scalar { id } => {
89            let selector = Selector::Id(id.to_owned());
90            if let Some(primitive) = get_primitive(&selector) {
91                Ok(UnfrozenTy::Primitive(primitive.into()))
92            } else {
93                Ok(UnfrozenTy::UnfrozenScalar(UnfrozenScalar {
94                    reference: unfrozen_reference_from_id(id).await?,
95                }))
96            }
97        }
98        LowTypeRef::Array { id } => {
99            let selector = Selector::Id(id.to_owned());
100            if let Some(primitive) = get_primitive(&selector) {
101                Ok(UnfrozenTy::Primitive(primitive.into()))
102            } else {
103                Ok(UnfrozenTy::UnfrozenArray(UnfrozenArray {
104                    reference: unfrozen_reference_from_id(id).await?,
105                }))
106            }
107        }
108        _ => Err(ModuleDeclarationError::Generic(format!(
109            "Unsupported type ref: {:?}",
110            type_ref
111        ))),
112    }
113}
114
115async fn unfrozen_reference_from_name(
116    name_or_id: &str,
117    registry: &mut dyn ReadableRegistry,
118) -> Result<UnfrozenReference, ModuleDeclarationError> {
119    Ok(UnfrozenReference {
120        id: resolve_type_id(name_or_id, registry).await?,
121        version_req: VersionReq::parse("*").unwrap(),
122    })
123}
124
125async fn unfrozen_reference_from_id(
126    id: &Uuid,
127) -> Result<UnfrozenReference, ModuleDeclarationError> {
128    Ok(UnfrozenReference {
129        id: id.to_owned(),
130        version_req: VersionReq::parse("*").unwrap(),
131    })
132}
133
134pub async fn resolve_high_parameter(
135    parameter: HighParameter,
136    registry: &mut dyn ReadableRegistry,
137) -> Result<Parameter, ModuleDeclarationError> {
138    Ok(Parameter {
139        name: parameter.name,
140        ty: resolve_high_type_ref(&parameter.ty, registry).await?,
141        mutable: parameter.mutable,
142    })
143}
144
145pub async fn resolve_low_parameter(
146    parameter: LowParameter,
147) -> Result<Parameter, ModuleDeclarationError> {
148    Ok(Parameter {
149        name: parameter.name,
150        ty: resolve_low_type_ref(&parameter.ty).await?,
151        mutable: parameter.mutable,
152    })
153}
154
155pub async fn resolve_high_import(
156    symbol: HighImportSymbol,
157    registry: &mut dyn ReadableRegistry,
158) -> Result<Export, ModuleDeclarationError> {
159    Ok(match symbol {
160        HighImportSymbol::Function(function) => {
161            let mut parameters = HashMap::new();
162            let mut parameter_ordering = Vec::new();
163            for parameter in function.parameters {
164                let parameter_id = parameter.id.to_owned();
165                let resolved_parameter = resolve_high_parameter(parameter, registry).await?;
166                parameters.insert(parameter_id.to_owned(), resolved_parameter);
167                parameter_ordering.push(parameter_id);
168            }
169            Export {
170                name: function.name,
171                kind: arora_types::record::module::unfrozen::ExportKind::Function(Function {
172                    parameters,
173                    return_ty: resolve_high_type_ref(&function.ret, registry).await?,
174                    parameter_ordering,
175                }),
176            }
177        }
178    })
179}
180
181pub async fn resolve_low_import(symbol: LowImportSymbol) -> Result<Export, ModuleDeclarationError> {
182    Ok(match symbol {
183        LowImportSymbol::Function(function) => {
184            let mut parameters = HashMap::new();
185            let mut parameter_ordering = Vec::new();
186            for parameter in function.parameters {
187                let parameter_id = parameter.id.to_owned();
188                let resolved_parameter = resolve_low_parameter(parameter).await?;
189                parameters.insert(parameter_id.to_owned(), resolved_parameter);
190                parameter_ordering.push(parameter_id);
191            }
192            Export {
193                name: function.name,
194                kind: arora_types::record::module::unfrozen::ExportKind::Function(Function {
195                    parameters,
196                    return_ty: resolve_low_type_ref(&function.ret).await?,
197                    parameter_ordering,
198                }),
199            }
200        }
201    })
202}
203
204pub async fn resolve_high_export(
205    symbol: HighExportSymbol,
206    registry: &mut dyn ReadableRegistry,
207) -> Result<Export, ModuleDeclarationError> {
208    Ok(match symbol {
209        HighExportSymbol::Function(function) => {
210            let mut parameters = HashMap::new();
211            let mut parameter_ordering = Vec::new();
212            for parameter in function.parameters {
213                let parameter_id = parameter.id.to_owned();
214                let resolved_parameter = resolve_high_parameter(parameter, registry).await?;
215                parameters.insert(parameter_id.to_owned(), resolved_parameter);
216                parameter_ordering.push(parameter_id);
217            }
218            Export {
219                name: function.name,
220                kind: arora_types::record::module::unfrozen::ExportKind::Function(Function {
221                    parameters,
222                    return_ty: resolve_high_type_ref(&function.ret, registry).await?,
223                    parameter_ordering,
224                }),
225            }
226        }
227    })
228}
229
230pub async fn resolve_low_export(symbol: LowExportSymbol) -> Result<Export, ModuleDeclarationError> {
231    Ok(match symbol {
232        LowExportSymbol::Function(function) => {
233            let mut parameters = HashMap::new();
234            let mut parameter_ordering = Vec::new();
235            for parameter in function.parameters {
236                let parameter_id = parameter.id.to_owned();
237                let resolved_parameter = resolve_low_parameter(parameter).await?;
238                parameters.insert(parameter_id.to_owned(), resolved_parameter);
239                parameter_ordering.push(parameter_id);
240            }
241            Export {
242                name: function.name,
243                kind: arora_types::record::module::unfrozen::ExportKind::Function(Function {
244                    parameters,
245                    return_ty: resolve_low_type_ref(&function.ret).await?,
246                    parameter_ordering,
247                }),
248            }
249        }
250    })
251}
252
253pub async fn resolve_high_module<R: ReadableRegistry + Resolver>(
254    module_definition: HighModuleDefinition,
255    registry: &mut R,
256) -> Result<ModuleAndImports, ModuleDeclarationError> {
257    let mut dependencies = HashSet::new();
258
259    let mut imports = Vec::new();
260    for import in module_definition.imports {
261        let HighImportSymbol::Function(import_function) = import.clone();
262        let import_module_id = resolve_module_id(import_function.module.as_str(), registry).await?;
263        let import_module_selector = Selector::Id(import_module_id);
264        let import_module_version = registry
265            .resolve_tag(&import_module_selector, &semver::VersionReq::STAR)
266            .await
267            .map_err(ModuleDeclarationError::RegistryError)?;
268        let import_module = registry
269            .get_module(&import_module_selector, &semver::VersionReq::STAR)
270            .await
271            .map_err(ModuleDeclarationError::RegistryError)?;
272        dependencies.insert(UnfrozenReference {
273            id: import_module_id,
274            version_req: VersionReq::parse("*").unwrap(),
275        });
276        let import_id = import_function.id.to_owned();
277        let resolved_import = resolve_high_import(import, registry).await?;
278        let mut import_deps = HashSet::new();
279        resolved_import.dependencies(&mut import_deps);
280        dependencies.extend(import_deps.into_iter().cloned());
281        imports.push(ImportAsset {
282            module_id: import_module_id,
283            tag: import_module_version,
284            module_name: import_module.name.clone(),
285            id: import_id,
286            import: resolved_import.freeze(registry).await.map_err(|e| {
287                ModuleDeclarationError::RegistryError(RegistryError::Generic {
288                    message: format!("error freezing import {}: {}", import_id, e),
289                })
290            })?,
291        });
292    }
293
294    let mut exports = HashMap::new();
295    for export in module_definition.exports {
296        let HighExportSymbol::Function(export_function) = export.clone();
297        let resolved_export = resolve_high_export(export, registry).await?;
298        let mut export_deps = HashSet::new();
299        resolved_export.dependencies(&mut export_deps);
300        dependencies.extend(export_deps.into_iter().cloned());
301        exports.insert(export_function.id, resolved_export);
302    }
303
304    let module = Module {
305        parent: ROOT_ID.to_owned(),
306        name: module_definition.name,
307        executable: None,
308        exports,
309        dependencies: dependencies.into_iter().collect(),
310    };
311    Ok(ModuleAndImports {
312        module: module.freeze(registry).await.map_err(|e| {
313            ModuleDeclarationError::RegistryError(RegistryError::Generic {
314                message: format!("error freezing module {}: {}", module_definition.id, e),
315            })
316        })?,
317        imports,
318    })
319}
320
321pub async fn resolve_low_module<R: ReadableRegistry + Resolver>(
322    module_header: Header,
323    registry: &mut R,
324) -> Result<ModuleAndImports, ModuleDeclarationError> {
325    let mut dependencies = HashSet::new();
326
327    let mut imports = Vec::new();
328    for import in module_header.imports {
329        let LowImportSymbol::Function(import_function) = import.clone();
330        let import_module_id = import_function.module;
331        let import_module_selector = Selector::Id(import_module_id);
332        let import_module_version = registry
333            .resolve_tag(&import_module_selector, &semver::VersionReq::STAR)
334            .await
335            .map_err(ModuleDeclarationError::RegistryError)?;
336        let import_module = registry
337            .get_module(&Selector::Id(import_module_id), &semver::VersionReq::STAR)
338            .await
339            .map_err(ModuleDeclarationError::RegistryError)?;
340        dependencies.insert(UnfrozenReference {
341            id: import_module_id,
342            version_req: VersionReq::parse("*").unwrap(),
343        });
344        let import_id = import_function.id.to_owned();
345        let resolved_import = resolve_low_import(import).await?;
346        let mut import_deps = HashSet::new();
347        resolved_import.dependencies(&mut import_deps);
348        dependencies.extend(import_deps.into_iter().cloned());
349        imports.push(ImportAsset {
350            module_id: import_module_id,
351            tag: import_module_version,
352            module_name: import_module.name.clone(),
353            id: import_id.to_owned(),
354            import: resolved_import.freeze(registry).await.map_err(|e| {
355                ModuleDeclarationError::RegistryError(RegistryError::Generic {
356                    message: format!("error freezing import {}: {}", import_id, e),
357                })
358            })?,
359        });
360    }
361
362    let mut exports = HashMap::new();
363    for export in module_header.exports {
364        let LowExportSymbol::Function(export_function) = export.clone();
365        let resolved_export = resolve_low_export(export).await?;
366        let mut export_deps = HashSet::new();
367        resolved_export.dependencies(&mut export_deps);
368        dependencies.extend(export_deps.into_iter().cloned());
369        exports.insert(export_function.id, resolved_export);
370    }
371    let module = Module {
372        parent: ROOT_ID.to_owned(),
373        name: module_header.name,
374        executable: None,
375        exports,
376        dependencies: dependencies.into_iter().collect(),
377    };
378    Ok(ModuleAndImports {
379        module: module.freeze(registry).await.map_err(|e| {
380            ModuleDeclarationError::RegistryError(RegistryError::Generic {
381                message: format!("error freezing module {}: {}", module_header.id, e),
382            })
383        })?,
384        imports,
385    })
386}
387
388pub struct ModuleAndImports {
389    pub module: ModuleFrozen,
390    pub imports: Vec<ImportAsset>,
391}