1use crate::model::lor::{Error, Resolved, Resolver, Unresolved};
2use crate::model::{Asn, Definition, LitOrRef, LiteralValue, Model, Target, Type, ValueReference};
3
4#[derive(Default)]
5pub struct MultiModuleResolver {
6 models: Vec<Model<Asn<Unresolved>>>,
7}
8
9impl MultiModuleResolver {
10 pub fn push(&mut self, model: Model<Asn<Unresolved>>) {
11 self.models.push(model);
12 }
13
14 pub fn try_resolve_all(&self) -> Result<Vec<Model<Asn<Resolved>>>, Error> {
15 self.models
16 .iter()
17 .map(|model| {
18 ResolveScope {
19 model,
20 scope: &self.models,
21 }
22 .try_resolve()
23 })
24 .collect::<_>()
25 }
26}
27
28pub(crate) struct ResolveScope<'a> {
29 model: &'a Model<Asn<Unresolved>>,
30 scope: &'a [Model<Asn<Unresolved>>],
31}
32
33impl<'a> From<&'a Model<Asn<Unresolved>>> for ResolveScope<'a> {
34 fn from(model: &'a Model<Asn<Unresolved>>) -> Self {
35 Self {
36 model,
37 scope: core::slice::from_ref(model),
38 }
39 }
40}
41
42impl<'a> ResolveScope<'a> {
43 pub(crate) fn try_resolve(&self) -> Result<Model<Asn<Resolved>>, Error> {
44 let mut result = Model::<Asn<Resolved>> {
45 name: self.model.name.clone(),
46 oid: self.model.oid.clone(),
47 imports: self.model.imports.clone(),
48 definitions: Vec::with_capacity(self.model.definitions.len()),
49 value_references: Vec::with_capacity(self.model.value_references.len()),
50 };
51
52 for vr in &self.model.value_references {
54 result.value_references.push(ValueReference {
55 name: vr.name.clone(),
56 role: vr.role.try_resolve(self)?,
57 value: vr.value.clone(),
58 })
59 }
60
61 for Definition(name, asn) in &self.model.definitions {
62 result
63 .definitions
64 .push(Definition(name.clone(), asn.try_resolve(self)?))
65 }
66
67 Ok(result)
68 }
69
70 fn model_with_imported_item(&self, item: &str) -> Option<&'a Model<Asn<Unresolved>>> {
71 self.model
72 .imports
73 .iter()
74 .find(|i| i.what.iter().any(|what| what.eq(item)))
75 .and_then(|import| {
76 self.scope.iter().find(|m| {
77 (m.oid.is_some() && m.oid.eq(&import.from_oid)) || m.name.eq(&import.from)
78 })
79 })
80 }
81
82 fn value_reference(
83 &self,
84 name: &str,
85 ) -> Option<&'a ValueReference<<Asn<Unresolved> as Target>::ValueReferenceType>> {
86 self.model
87 .value_references
88 .iter()
89 .find(|vr| vr.name.eq(name))
90 .or_else(|| {
91 self.model_with_imported_item(name).and_then(|model| {
92 ResolveScope {
93 model,
94 scope: self.scope,
95 }
96 .value_reference(name)
97 })
98 })
99 }
100
101 fn definition(&self, name: &str) -> Option<&'a Definition<Asn<Unresolved>>> {
102 self.model
103 .definitions
104 .iter()
105 .find(|def| def.name().eq(name))
106 .or_else(|| {
107 self.model_with_imported_item(name).and_then(|model| {
108 ResolveScope {
109 model,
110 scope: self.scope,
111 }
112 .definition(name)
113 })
114 })
115 }
116}
117
118impl Resolver<usize> for ResolveScope<'_> {
119 fn resolve(&self, lor: &LitOrRef<usize>) -> Result<usize, Error> {
120 match lor {
121 LitOrRef::Lit(lit) => Ok(*lit),
122 LitOrRef::Ref(name) => {
123 match self.value_reference(name).map(|vr| vr.value.to_integer()) {
124 Some(Some(value)) => Ok(value as usize),
125 Some(None) => Err(Error::FailedToParseLiteral(format!("name: {}", name))),
126 None => Err(Error::FailedToResolveReference(name.clone())),
127 }
128 }
129 }
130 }
131}
132
133impl Resolver<i64> for ResolveScope<'_> {
134 fn resolve(&self, lor: &LitOrRef<i64>) -> Result<i64, Error> {
135 match lor {
136 LitOrRef::Lit(lit) => Ok(*lit),
137 LitOrRef::Ref(name) => match self.value_reference(name).map(|vr| vr.value.to_integer())
138 {
139 Some(Some(value)) => Ok(value),
140 Some(None) => Err(Error::FailedToParseLiteral(format!("name: {}", name))),
141 None => Err(Error::FailedToResolveReference(name.clone())),
142 },
143 }
144 }
145}
146
147impl Resolver<LiteralValue> for ResolveScope<'_> {
148 fn resolve(&self, lor: &LitOrRef<LiteralValue>) -> Result<LiteralValue, Error> {
149 match lor {
150 LitOrRef::Lit(lit) => Ok(lit.clone()),
151 LitOrRef::Ref(name) => self
152 .value_reference(name)
153 .map(|vr| vr.value.clone())
154 .ok_or_else(|| Error::FailedToResolveReference(name.clone())),
155 }
156 }
157}
158
159impl Resolver<Type<Unresolved>> for ResolveScope<'_> {
160 fn resolve(&self, lor: &LitOrRef<Type<Unresolved>>) -> Result<Type<Unresolved>, Error> {
161 match lor {
162 LitOrRef::Lit(lit) => Ok(lit.clone()),
163 LitOrRef::Ref(name) => self
164 .definition(name)
165 .map(|def| def.1.r#type.clone())
166 .ok_or_else(|| Error::FailedToResolveType(name.clone())),
167 }
168 }
169}