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