1use crate::expr_arena::CallTypeNode;
2use crate::parser::{PackageName, TypeParameter};
3use crate::type_parameter::InterfaceName;
4use crate::wit_type::{TypeEnum, TypeVariant, WitExport, WitType};
5use crate::{
6 CallType, DynamicParsedFunctionName, DynamicParsedFunctionReference, FunctionTypeRegistry,
7 InferredType, ParsedFunctionSite, RegistryKey, RegistryValue, SemVer,
8};
9use std::collections::BTreeMap;
10use std::convert::TryFrom;
11use std::fmt::{Debug, Display, Formatter};
12
13#[derive(Debug, Hash, Clone, Eq, PartialEq, Ord, PartialOrd, Default)]
19pub struct FunctionDictionary {
20 pub name_and_types: Vec<(FunctionName, FunctionType)>,
21}
22
23impl FunctionDictionary {
24 pub fn get(&self, function_name: &FunctionName) -> Option<&FunctionType> {
25 self.name_and_types.iter().find_map(|(name, ftype)| {
26 if name == function_name {
27 Some(ftype)
28 } else {
29 None
30 }
31 })
32 }
33
34 pub fn get_all_variants(&self) -> Vec<TypeVariant> {
35 self.name_and_types
36 .iter()
37 .filter_map(|(_, ftype)| ftype.as_type_variant())
38 .collect()
39 }
40
41 pub fn get_all_enums(&self) -> Vec<TypeEnum> {
42 self.name_and_types
43 .iter()
44 .filter_map(|(_, ftype)| ftype.as_type_enum())
45 .collect()
46 }
47
48 pub fn get_enum_info(&self, identifier_name: &str) -> Option<TypeEnum> {
49 self.name_and_types.iter().find_map(|(f, ftype)| match f {
50 FunctionName::Enum(name) => {
51 if name == identifier_name {
52 ftype.as_type_enum()
53 } else {
54 None
55 }
56 }
57 _ => None,
58 })
59 }
60 pub fn get_variant_info(&self, identifier_name: &str) -> Vec<TypeVariant> {
61 self.name_and_types
62 .iter()
63 .filter_map(|(f, ftype)| match f {
64 FunctionName::Variant(name) => {
65 if name == identifier_name {
66 ftype.as_type_variant()
67 } else {
68 None
69 }
70 }
71 _ => None,
72 })
73 .collect::<Vec<_>>()
74 }
75
76 pub fn function_names(&self) -> Vec<String> {
77 self.name_and_types
78 .iter()
79 .map(|(f, _)| f.name())
80 .collect::<Vec<_>>()
81 }
82}
83
84#[derive(Debug, Hash, Clone, Eq, PartialEq, PartialOrd, Ord)]
91pub struct ResourceMethodDictionary {
92 pub map: BTreeMap<FullyQualifiedResourceMethod, FunctionType>,
93}
94
95impl From<&ResourceMethodDictionary> for FunctionDictionary {
96 fn from(value: &ResourceMethodDictionary) -> Self {
97 FunctionDictionary {
98 name_and_types: value
99 .map
100 .iter()
101 .map(|(key, value)| (FunctionName::ResourceMethod(key.clone()), value.clone()))
102 .collect(),
103 }
104 }
105}
106
107impl FunctionDictionary {
108 pub fn from_exports(exports: &[WitExport]) -> Result<FunctionDictionary, String> {
109 let registry = FunctionTypeRegistry::from_export_metadata(exports);
110 Self::from_function_type_registry(®istry)
111 }
112
113 pub fn from_function_type_registry(
114 registry: &FunctionTypeRegistry,
115 ) -> Result<FunctionDictionary, String> {
116 let mut map = vec![];
117
118 for (key, value) in registry.types.iter() {
119 match value {
120 RegistryValue::Function {
121 parameter_types,
122 return_type,
123 } => match key {
124 RegistryKey::FunctionName(function_name) => {
125 let function_name = resolve_function_name(None, None, function_name)?;
126
127 map.push((
128 function_name,
129 FunctionType {
130 parameter_types: parameter_types.iter().map(|x| x.into()).collect(),
131 return_type: return_type.as_ref().map(|x| x.into()),
132 },
133 ));
134 }
135
136 RegistryKey::FunctionNameWithInterface {
137 interface_name,
138 function_name,
139 } => {
140 let type_parameter = TypeParameter::from_text(interface_name.as_str())?;
141
142 let interface_name = type_parameter.get_interface_name();
143 let package_name = type_parameter.get_package_name();
144
145 let function_name =
146 resolve_function_name(package_name, interface_name, function_name)?;
147
148 map.push((
149 function_name,
150 FunctionType {
151 parameter_types: parameter_types.iter().map(|x| x.into()).collect(),
152 return_type: return_type.as_ref().map(|x| x.into()),
153 },
154 ));
155 }
156 },
157
158 RegistryValue::Variant {
159 parameter_types,
160 variant_type,
161 } => match key {
162 RegistryKey::FunctionName(name) => {
163 let function_name = FunctionName::Variant(name.to_string());
164 let cases = variant_type
165 .cases
166 .iter()
167 .map(|x| (x.name.clone(), x.typ.as_ref().map(InferredType::from)))
168 .collect::<Vec<_>>();
169
170 map.push((
171 function_name,
172 FunctionType {
173 parameter_types: parameter_types.iter().map(|x| x.into()).collect(),
174 return_type: Some(InferredType::variant(cases)),
175 },
176 ));
177 }
178 RegistryKey::FunctionNameWithInterface { .. } => {}
179 },
180
181 RegistryValue::Value(value) => match value {
182 WitType::Enum(type_enum) => match key {
183 RegistryKey::FunctionName(name) => {
184 let function_name = FunctionName::Enum(name.to_string());
185
186 map.push((
187 function_name,
188 FunctionType {
189 parameter_types: vec![],
190 return_type: Some(InferredType::enum_(type_enum.cases.clone())),
191 },
192 ));
193 }
194 RegistryKey::FunctionNameWithInterface { .. } => {}
195 },
196 WitType::Variant(variant_type) => match key {
197 RegistryKey::FunctionName(name) => {
198 let function_name = FunctionName::Variant(name.to_string());
199
200 let cases = variant_type
201 .cases
202 .iter()
203 .map(|x| (x.name.clone(), x.typ.as_ref().map(InferredType::from)))
204 .collect::<Vec<_>>();
205
206 map.push((
207 function_name,
208 FunctionType {
209 parameter_types: vec![],
210 return_type: Some(InferredType::variant(cases)),
211 },
212 ));
213 }
214 RegistryKey::FunctionNameWithInterface { .. } => {}
215 },
216
217 _ => {}
218 },
219 };
220 }
221
222 Ok(FunctionDictionary {
223 name_and_types: map,
224 })
225 }
226}
227
228fn resolve_function_name(
229 package_name: Option<PackageName>,
230 interface_name: Option<InterfaceName>,
231 function_name: &str,
232) -> Result<FunctionName, String> {
233 match get_resource_name(function_name) {
234 Some(resource_name) => Ok(FunctionName::ResourceConstructor(
235 FullyQualifiedResourceConstructor {
236 package_name,
237 interface_name,
238 resource_name,
239 },
240 )),
241 None => match get_resource_method_name(function_name) {
242 Ok(Some((constructor, method))) => {
243 Ok(FunctionName::ResourceMethod(FullyQualifiedResourceMethod {
244 package_name,
245 interface_name,
246 resource_name: constructor,
247 method_name: method,
248 static_function: false,
249 }))
250 }
251 Ok(None) => match get_resource_static_method_name(function_name) {
252 Ok(Some((constructor, method))) => {
253 Ok(FunctionName::ResourceMethod(FullyQualifiedResourceMethod {
254 package_name,
255 interface_name,
256 resource_name: constructor,
257 method_name: method,
258 static_function: true,
259 }))
260 }
261 Ok(None) => Ok(FunctionName::Function(FullyQualifiedFunctionName {
262 package_name,
263 interface_name,
264 function_name: function_name.to_string(),
265 })),
266
267 Err(e) => Err(format!("invalid resource static method call. {e}")),
268 },
269
270 Err(e) => Err(format!("invalid resource method call. {e}")),
271 },
272 }
273}
274
275fn get_resource_name(function_name: &str) -> Option<String> {
276 if function_name.trim().starts_with("[constructor]") {
277 Some(
278 function_name
279 .trim_start_matches("[constructor]")
280 .to_string(),
281 )
282 } else {
283 None
284 }
285}
286
287fn get_resource_static_method_name(
288 function_name: &str,
289) -> Result<Option<(String, String)>, String> {
290 if function_name.starts_with("[static]") {
291 let constructor_and_method = function_name.trim_start_matches("[static]").to_string();
292 let mut constructor_and_method = constructor_and_method.split('.');
293 let constructor = constructor_and_method.next();
294 let method = constructor_and_method.next();
295
296 match (constructor, method) {
297 (Some(constructor), Some(method)) => {
298 Ok(Some((constructor.to_string(), method.to_string())))
299 }
300 _ => Err(format!("Invalid resource method name: {function_name}")),
301 }
302 } else {
303 Ok(None)
304 }
305}
306
307fn get_resource_method_name(function_name: &str) -> Result<Option<(String, String)>, String> {
308 if function_name.starts_with("[method]") {
309 let constructor_and_method = function_name.trim_start_matches("[method]").to_string();
310 let mut constructor_and_method = constructor_and_method.split('.');
311 let constructor = constructor_and_method.next();
312 let method = constructor_and_method.next();
313
314 match (constructor, method) {
315 (Some(constructor), Some(method)) => {
316 Ok(Some((constructor.to_string(), method.to_string())))
317 }
318 _ => Err(format!("Invalid resource method name: {function_name}")),
319 }
320 } else if function_name.starts_with("[drop]") {
321 let constructor = function_name.trim_start_matches("[drop]").to_string();
322 Ok(Some((constructor, "drop".to_string())))
323 } else {
324 Ok(None)
325 }
326}
327
328#[derive(Debug, Hash, Clone, Eq, PartialEq, Ord, PartialOrd)]
329pub enum FunctionName {
330 Variant(String),
331 Enum(String),
332 Function(FullyQualifiedFunctionName),
333 ResourceConstructor(FullyQualifiedResourceConstructor),
334 ResourceMethod(FullyQualifiedResourceMethod),
335}
336
337impl Display for FunctionName {
338 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
339 write!(f, "{}", self.name())
340 }
341}
342
343impl FunctionName {
344 pub fn from_dynamic_parsed_function_name(
345 function_name: &DynamicParsedFunctionName,
346 ) -> FunctionName {
347 let site = &function_name.site;
348 let (package_name, interface_name) = match site {
349 ParsedFunctionSite::Global => (None, None),
350
351 ParsedFunctionSite::Interface { name } => (
352 None,
353 Some(InterfaceName {
354 name: name.clone(),
355 version: None,
356 }),
357 ),
358 ParsedFunctionSite::PackagedInterface {
359 namespace,
360 package,
361 interface,
362 version,
363 } => (
364 Some(PackageName {
365 namespace: namespace.clone(),
366 package_name: package.clone(),
367 version: None,
368 }),
369 Some(InterfaceName {
370 name: interface.clone(),
371 version: version.as_ref().map(|v| v.0.to_string()),
372 }),
373 ),
374 };
375
376 match &function_name.function {
377 DynamicParsedFunctionReference::Function { function } => {
378 FunctionName::Function(FullyQualifiedFunctionName {
379 package_name,
380 interface_name,
381 function_name: function.clone(),
382 })
383 }
384 DynamicParsedFunctionReference::RawResourceConstructor { resource } => {
385 FunctionName::ResourceConstructor(FullyQualifiedResourceConstructor {
386 package_name,
387 interface_name,
388 resource_name: resource.clone(),
389 })
390 }
391 DynamicParsedFunctionReference::RawResourceDrop { resource } => {
392 FunctionName::ResourceMethod(FullyQualifiedResourceMethod {
393 package_name,
394 interface_name,
395 resource_name: resource.clone(),
396 method_name: "drop".to_string(),
397 static_function: false,
398 })
399 }
400 DynamicParsedFunctionReference::RawResourceMethod { resource, method } => {
401 FunctionName::ResourceMethod(FullyQualifiedResourceMethod {
402 package_name,
403 interface_name,
404 resource_name: resource.clone(),
405 method_name: method.clone(),
406 static_function: false,
407 })
408 }
409 DynamicParsedFunctionReference::RawResourceStaticMethod { resource, method } => {
410 FunctionName::ResourceMethod(FullyQualifiedResourceMethod {
411 package_name,
412 interface_name,
413 resource_name: resource.clone(),
414 method_name: method.clone(),
415 static_function: true,
416 })
417 }
418 }
419 }
420
421 pub fn from_call_type(call_type: &CallType) -> Option<FunctionName> {
422 match call_type {
423 CallType::VariantConstructor(variant_name) => {
424 Some(FunctionName::Variant(variant_name.clone()))
425 }
426 CallType::EnumConstructor(enum_name) => Some(FunctionName::Enum(enum_name.clone())),
427 CallType::Function { function_name, .. } => {
428 Some(Self::from_dynamic_parsed_function_name(function_name))
429 }
430 CallType::InstanceCreation(_) => None,
431 }
432 }
433
434 pub fn from_call_type_node(call_type: &CallTypeNode) -> Option<FunctionName> {
437 match call_type {
438 CallTypeNode::VariantConstructor(variant_name) => {
439 Some(FunctionName::Variant(variant_name.clone()))
440 }
441 CallTypeNode::EnumConstructor(enum_name) => Some(FunctionName::Enum(enum_name.clone())),
442 CallTypeNode::Function { function_name, .. } => {
443 Some(Self::from_dynamic_parsed_function_name(function_name))
444 }
445 CallTypeNode::InstanceCreation(_) => None,
446 }
447 }
448
449 pub fn interface_name(&self) -> Option<InterfaceName> {
450 match self {
451 FunctionName::Function(fqfn) => fqfn.interface_name.clone(),
452 FunctionName::ResourceConstructor(fqfn) => fqfn.interface_name.clone(),
453 FunctionName::ResourceMethod(resource_method) => resource_method.interface_name.clone(),
454 FunctionName::Variant(_) => None,
455 FunctionName::Enum(_) => None,
456 }
457 }
458
459 pub fn package_name(&self) -> Option<PackageName> {
460 match self {
461 FunctionName::Function(fqfn) => fqfn.package_name.clone(),
462 FunctionName::ResourceConstructor(fqfn) => fqfn.package_name.clone(),
463 FunctionName::ResourceMethod(fqfn) => fqfn.package_name.clone(),
464 FunctionName::Variant(_) => None,
465 FunctionName::Enum(_) => None,
466 }
467 }
468
469 pub fn name(&self) -> String {
470 match self {
471 FunctionName::Function(fqfn) => fqfn.function_name.to_string(),
472 FunctionName::ResourceConstructor(fqfn) => fqfn.resource_name.to_string(),
473 FunctionName::ResourceMethod(fqfn) => fqfn.method_name.to_string(),
474 FunctionName::Variant(name) => name.clone(),
475 FunctionName::Enum(name) => name.clone(),
476 }
477 }
478}
479
480#[derive(Debug, Hash, Clone, Eq, PartialEq, Ord, PartialOrd)]
481pub struct FullyQualifiedResourceConstructor {
482 pub package_name: Option<PackageName>,
483 pub interface_name: Option<InterfaceName>,
484 pub resource_name: String,
485}
486
487impl FullyQualifiedResourceConstructor {
488 pub fn parsed_function_site(&self) -> ParsedFunctionSite {
489 if let Some(package_name) = &self.package_name {
490 let interface_name = self.interface_name.clone().unwrap();
491
492 ParsedFunctionSite::PackagedInterface {
493 namespace: package_name.namespace.clone(),
494 package: package_name.package_name.clone(),
495 interface: self
496 .interface_name
497 .as_ref()
498 .map_or_else(|| "".to_string(), |i| i.name.clone()),
499 version: interface_name
500 .version
501 .map(|x| SemVer(semver::Version::parse(&x).unwrap())),
502 }
503 } else if let Some(interface_name) = &self.interface_name {
504 ParsedFunctionSite::Interface {
505 name: interface_name.name.clone(),
506 }
507 } else {
508 ParsedFunctionSite::Global
509 }
510 }
511}
512
513#[derive(Debug, Hash, Clone, Eq, PartialEq, Ord, PartialOrd)]
514pub struct FullyQualifiedFunctionName {
515 pub package_name: Option<PackageName>,
516 pub interface_name: Option<InterfaceName>,
517 pub function_name: String,
518}
519
520#[derive(Debug, Hash, Clone, Eq, PartialEq, Ord, PartialOrd)]
521pub struct FullyQualifiedResourceMethod {
522 pub package_name: Option<PackageName>,
523 pub interface_name: Option<InterfaceName>,
524 pub resource_name: String,
525 pub method_name: String,
526 pub static_function: bool,
527}
528
529impl FullyQualifiedResourceMethod {
530 pub fn get_constructor(&self) -> FullyQualifiedResourceConstructor {
531 FullyQualifiedResourceConstructor {
532 package_name: self.package_name.clone(),
533 interface_name: self.interface_name.clone(),
534 resource_name: self.resource_name.clone(),
535 }
536 }
537
538 pub fn dynamic_parsed_function_name(&self) -> Result<DynamicParsedFunctionName, String> {
541 let mut dynamic_parsed_str = String::new();
542
543 if let Some(package) = &self.package_name {
545 dynamic_parsed_str.push_str(&package.to_string());
546 dynamic_parsed_str.push('/');
547 }
548
549 if let Some(interface) = &self.interface_name {
550 dynamic_parsed_str.push_str(&interface.to_string());
551 dynamic_parsed_str.push('.');
552 }
553
554 dynamic_parsed_str.push('{');
555 if self.static_function {
556 dynamic_parsed_str.push_str("[static]");
557 } else {
558 dynamic_parsed_str.push_str("[method]");
559 }
560
561 dynamic_parsed_str.push_str(&self.resource_name);
562 dynamic_parsed_str.push('.');
563 dynamic_parsed_str.push_str(&self.method_name);
564 dynamic_parsed_str.push('}');
565
566 DynamicParsedFunctionName::parse(dynamic_parsed_str)
567 }
568
569 pub fn method_name(&self) -> &String {
570 &self.method_name
571 }
572}
573
574impl Display for FullyQualifiedFunctionName {
575 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
576 if let Some(package_name) = &self.package_name {
577 write!(f, "{package_name}")?
578 }
579
580 if let Some(interface_name) = &self.interface_name {
581 write!(f, "/{interface_name}.")?;
582 write!(f, "{{{}}}", self.function_name)
583 } else {
584 write!(f, "{}", self.function_name)
585 }
586 }
587}
588
589#[derive(Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
590pub struct FunctionType {
591 pub parameter_types: Vec<InferredType>,
592 pub return_type: Option<InferredType>,
593}
594
595impl FunctionType {
596 pub fn as_type_variant(&self) -> Option<TypeVariant> {
597 let analysed_type = WitType::try_from(&self.return_type.clone()?).ok()?;
598
599 match analysed_type {
600 WitType::Variant(type_variant) => Some(type_variant),
601 _ => None,
602 }
603 }
604
605 pub fn as_type_enum(&self) -> Option<TypeEnum> {
606 let analysed_type = WitType::try_from(&self.return_type.clone()?).ok()?;
607 match analysed_type {
608 WitType::Enum(type_enum) => Some(type_enum),
609 _ => None,
610 }
611 }
612
613 pub fn parameter_types(&self) -> Vec<WitType> {
614 self.parameter_types
615 .iter()
616 .map(|x| WitType::try_from(x).unwrap())
617 .collect()
618 }
619
620 pub fn return_type(&self) -> Option<WitType> {
621 self.return_type
622 .clone()
623 .map(|x| WitType::try_from(&x).unwrap())
624 }
625}