1use crate::ast::{
2 EnumDef, EnumVariant, FieldOwnership, FunctionDef, FunctionParam, ImplBlock, Span, StructDef,
3 StructField, TraitBound, TraitDef, TraitMethod, Type, TypeKind, Visibility,
4};
5use crate::typechecker::{FunctionSignature, TypeChecker};
6use crate::vm::VM;
7use crate::Result;
8use hashbrown::HashMap;
9use std::collections::BTreeMap;
10
11#[derive(Clone, Default)]
13pub struct ExternRegistry {
14 structs: Vec<StructDef>,
15 enums: Vec<EnumDef>,
16 traits: Vec<TraitDef>,
17 impls: Vec<ImplBlock>,
18 functions: Vec<FunctionDef>,
19}
20
21impl ExternRegistry {
22 pub fn new() -> Self {
23 Self::default()
24 }
25
26 pub fn add_struct(&mut self, def: StructDef) -> &mut Self {
27 self.structs.push(def);
28 self
29 }
30
31 pub fn add_enum(&mut self, def: EnumDef) -> &mut Self {
32 self.enums.push(def);
33 self
34 }
35
36 pub fn add_trait(&mut self, def: TraitDef) -> &mut Self {
37 self.traits.push(def);
38 self
39 }
40
41 pub fn add_impl(&mut self, impl_block: ImplBlock) -> &mut Self {
42 self.impls.push(impl_block);
43 self
44 }
45
46 pub fn add_function(&mut self, func: FunctionDef) -> &mut Self {
47 self.functions.push(func);
48 self
49 }
50
51 pub fn extend(&mut self, other: &ExternRegistry) {
52 self.structs.extend(other.structs.iter().cloned());
53 self.enums.extend(other.enums.iter().cloned());
54 self.traits.extend(other.traits.iter().cloned());
55 self.impls.extend(other.impls.iter().cloned());
56 self.functions.extend(other.functions.iter().cloned());
57 }
58
59 pub fn register_with_typechecker(&self, checker: &mut TypeChecker) -> Result<()> {
60 for def in &self.structs {
61 checker.register_external_struct(def.clone())?;
62 }
63 for def in &self.enums {
64 checker.register_external_enum(def.clone())?;
65 }
66 for def in &self.traits {
67 checker.register_external_trait(def.clone())?;
68 }
69 for func in &self.functions {
70 checker.register_external_function(function_signature_for(func))?;
71 }
72 for impl_block in &self.impls {
73 checker.register_external_impl(impl_block.clone())?;
74 }
75 Ok(())
76 }
77
78 pub fn register_with_vm(&self, vm: &mut VM) {
79 self.register_struct_layouts(vm);
80 self.register_type_stubs(vm);
81 }
82
83 pub fn register_struct_layouts(&self, vm: &mut VM) {
84 let prefix = vm.export_prefix();
85 let mut struct_map: HashMap<String, StructDef> = HashMap::new();
86 for def in &self.structs {
87 let canonical = canonicalize_struct(def, prefix.as_deref());
88 struct_map.insert(canonical.name.clone(), canonical);
89 }
90 if !struct_map.is_empty() {
91 vm.register_structs(&struct_map);
92 }
93 }
94
95 pub fn register_type_stubs(&self, vm: &mut VM) {
96 if self.structs.is_empty()
97 && self.enums.is_empty()
98 && self.traits.is_empty()
99 && self.impls.is_empty()
100 {
101 return;
102 }
103 let prefix = vm.export_prefix();
104 vm.register_type_stubs(self.module_stubs_with_prefix(prefix.as_deref()));
105 }
106
107 pub fn module_stubs(&self) -> Vec<ModuleStub> {
108 self.module_stubs_with_prefix(None)
109 }
110
111 fn module_stubs_with_prefix(&self, prefix: Option<&str>) -> Vec<ModuleStub> {
112 let mut modules: BTreeMap<String, ModuleStub> = BTreeMap::new();
113 for def in &self.structs {
114 let canonical = canonicalize_struct(def, prefix);
115 if let Some((module, name)) = module_and_name(&canonical.name) {
116 let entry = modules.entry(module.clone()).or_insert_with(|| ModuleStub {
117 module,
118 ..ModuleStub::default()
119 });
120 entry.struct_defs.push(format_struct_def(name, &canonical));
121 }
122 }
123 for def in &self.enums {
124 let canonical = canonicalize_enum(def, prefix);
125 if let Some((module, name)) = module_and_name(&canonical.name) {
126 let entry = modules.entry(module.clone()).or_insert_with(|| ModuleStub {
127 module,
128 ..ModuleStub::default()
129 });
130 entry.enum_defs.push(format_enum_def(name, &canonical));
131 }
132 }
133 for def in &self.traits {
134 let canonical = canonicalize_trait(def, prefix);
135 if let Some((module, name)) = module_and_name(&canonical.name) {
136 let entry = modules.entry(module.clone()).or_insert_with(|| ModuleStub {
137 module,
138 ..ModuleStub::default()
139 });
140 entry.trait_defs.push(format_trait_def(name, &canonical));
141 }
142 }
143 for def in &self.impls {
144 let canonical = canonicalize_impl(def, prefix);
145 if let Some(module) = impl_module(&canonical) {
146 modules.entry(module.clone()).or_insert_with(|| ModuleStub {
147 module,
148 ..ModuleStub::default()
149 });
150 }
151 }
152 modules.into_values().collect()
153 }
154
155 pub fn structs(&self) -> impl Iterator<Item = &StructDef> {
156 self.structs.iter()
157 }
158
159 pub fn enums(&self) -> impl Iterator<Item = &EnumDef> {
160 self.enums.iter()
161 }
162}
163
164#[derive(Clone, Debug, Default)]
165pub struct ModuleStub {
166 pub module: String,
167 pub struct_defs: Vec<String>,
168 pub enum_defs: Vec<String>,
169 pub trait_defs: Vec<String>,
170}
171
172impl ModuleStub {
173 pub fn is_empty(&self) -> bool {
174 self.struct_defs.is_empty() && self.enum_defs.is_empty() && self.trait_defs.is_empty()
175 }
176}
177
178#[derive(Clone)]
179pub struct StructBuilder {
180 def: StructDef,
181}
182
183impl StructBuilder {
184 pub fn new(name: impl Into<String>) -> Self {
185 StructBuilder {
186 def: StructDef {
187 name: name.into(),
188 type_params: Vec::new(),
189 trait_bounds: Vec::new(),
190 fields: Vec::new(),
191 visibility: Visibility::Public,
192 },
193 }
194 }
195
196 pub fn visibility(mut self, visibility: Visibility) -> Self {
197 self.def.visibility = visibility;
198 self
199 }
200
201 pub fn type_param(mut self, name: impl Into<String>) -> Self {
202 self.def.type_params.push(name.into());
203 self
204 }
205
206 pub fn trait_bound(mut self, bound: TraitBound) -> Self {
207 self.def.trait_bounds.push(bound);
208 self
209 }
210
211 pub fn field(mut self, field: StructField) -> Self {
212 self.def.fields.push(field);
213 self
214 }
215
216 pub fn finish(self) -> StructDef {
217 self.def
218 }
219}
220
221#[derive(Clone)]
222pub struct EnumBuilder {
223 def: EnumDef,
224}
225
226impl EnumBuilder {
227 pub fn new(name: impl Into<String>) -> Self {
228 EnumBuilder {
229 def: EnumDef {
230 name: name.into(),
231 type_params: Vec::new(),
232 trait_bounds: Vec::new(),
233 variants: Vec::new(),
234 visibility: Visibility::Public,
235 },
236 }
237 }
238
239 pub fn visibility(mut self, visibility: Visibility) -> Self {
240 self.def.visibility = visibility;
241 self
242 }
243
244 pub fn type_param(mut self, name: impl Into<String>) -> Self {
245 self.def.type_params.push(name.into());
246 self
247 }
248
249 pub fn trait_bound(mut self, bound: TraitBound) -> Self {
250 self.def.trait_bounds.push(bound);
251 self
252 }
253
254 pub fn variant(mut self, variant: EnumVariant) -> Self {
255 self.def.variants.push(variant);
256 self
257 }
258
259 pub fn finish(self) -> EnumDef {
260 self.def
261 }
262}
263
264#[derive(Clone)]
265pub struct TraitBuilder {
266 def: TraitDef,
267}
268
269impl TraitBuilder {
270 pub fn new(name: impl Into<String>) -> Self {
271 TraitBuilder {
272 def: TraitDef {
273 name: name.into(),
274 type_params: Vec::new(),
275 methods: Vec::new(),
276 visibility: Visibility::Public,
277 },
278 }
279 }
280
281 pub fn visibility(mut self, visibility: Visibility) -> Self {
282 self.def.visibility = visibility;
283 self
284 }
285
286 pub fn type_param(mut self, name: impl Into<String>) -> Self {
287 self.def.type_params.push(name.into());
288 self
289 }
290
291 pub fn method(mut self, method: TraitMethod) -> Self {
292 self.def.methods.push(method);
293 self
294 }
295
296 pub fn finish(self) -> TraitDef {
297 self.def
298 }
299}
300
301#[derive(Clone)]
302pub struct ImplBuilder {
303 block: ImplBlock,
304}
305
306impl ImplBuilder {
307 pub fn new(target_type: Type) -> Self {
308 ImplBuilder {
309 block: ImplBlock {
310 type_params: Vec::new(),
311 trait_name: None,
312 target_type,
313 methods: Vec::new(),
314 where_clause: Vec::new(),
315 },
316 }
317 }
318
319 pub fn for_trait(mut self, trait_name: impl Into<String>) -> Self {
320 self.block.trait_name = Some(trait_name.into());
321 self
322 }
323
324 pub fn type_param(mut self, name: impl Into<String>) -> Self {
325 self.block.type_params.push(name.into());
326 self
327 }
328
329 pub fn where_bound(mut self, bound: TraitBound) -> Self {
330 self.block.where_clause.push(bound);
331 self
332 }
333
334 pub fn method(mut self, method: FunctionDef) -> Self {
335 self.block.methods.push(method);
336 self
337 }
338
339 pub fn finish(self) -> ImplBlock {
340 self.block
341 }
342}
343
344#[derive(Clone)]
345pub struct TraitMethodBuilder {
346 method: TraitMethod,
347}
348
349impl TraitMethodBuilder {
350 pub fn new(name: impl Into<String>) -> Self {
351 TraitMethodBuilder {
352 method: TraitMethod {
353 name: name.into(),
354 type_params: Vec::new(),
355 params: Vec::new(),
356 return_type: None,
357 default_impl: None,
358 },
359 }
360 }
361
362 pub fn type_param(mut self, name: impl Into<String>) -> Self {
363 self.method.type_params.push(name.into());
364 self
365 }
366
367 pub fn param(mut self, param: FunctionParam) -> Self {
368 self.method.params.push(param);
369 self
370 }
371
372 pub fn return_type(mut self, ty: Type) -> Self {
373 self.method.return_type = Some(ty);
374 self
375 }
376
377 pub fn finish(self) -> TraitMethod {
378 self.method
379 }
380}
381
382#[derive(Clone)]
383pub struct FunctionBuilder {
384 function: FunctionDef,
385}
386
387impl FunctionBuilder {
388 pub fn new(name: impl Into<String>) -> Self {
389 let name = name.into();
390 FunctionBuilder {
391 function: FunctionDef {
392 name,
393 type_params: Vec::new(),
394 trait_bounds: Vec::new(),
395 params: Vec::new(),
396 return_type: None,
397 body: Vec::new(),
398 is_method: false,
399 visibility: Visibility::Public,
400 },
401 }
402 }
403
404 pub fn visibility(mut self, visibility: Visibility) -> Self {
405 self.function.visibility = visibility;
406 self
407 }
408
409 pub fn type_param(mut self, name: impl Into<String>) -> Self {
410 self.function.type_params.push(name.into());
411 self
412 }
413
414 pub fn trait_bound(mut self, bound: TraitBound) -> Self {
415 self.function.trait_bounds.push(bound);
416 self
417 }
418
419 pub fn param(mut self, param: FunctionParam) -> Self {
420 if param.is_self {
421 self.function.is_method = true;
422 }
423 self.function.params.push(param);
424 self
425 }
426
427 pub fn return_type(mut self, ty: Type) -> Self {
428 self.function.return_type = Some(ty);
429 self
430 }
431
432 pub fn finish(self) -> FunctionDef {
433 self.function
434 }
435}
436
437pub fn struct_field_decl(name: impl Into<String>, ty: Type) -> StructField {
438 StructField {
439 name: name.into(),
440 ty,
441 visibility: Visibility::Public,
442 ownership: FieldOwnership::Strong,
443 weak_target: None,
444 }
445}
446
447pub fn weak_struct_field_decl(name: impl Into<String>, ty: Type) -> StructField {
448 let span = ty.span;
449 let option = Type::new(TypeKind::Option(Box::new(ty.clone())), span);
450 StructField {
451 name: name.into(),
452 ty: option,
453 visibility: Visibility::Public,
454 ownership: FieldOwnership::Weak,
455 weak_target: Some(ty),
456 }
457}
458
459pub fn private_struct_field_decl(name: impl Into<String>, ty: Type) -> StructField {
460 StructField {
461 name: name.into(),
462 ty,
463 visibility: Visibility::Private,
464 ownership: FieldOwnership::Strong,
465 weak_target: None,
466 }
467}
468
469pub fn enum_variant(name: impl Into<String>) -> EnumVariant {
470 EnumVariant {
471 name: name.into(),
472 fields: None,
473 }
474}
475
476pub fn enum_variant_with(
477 name: impl Into<String>,
478 fields: impl IntoIterator<Item = Type>,
479) -> EnumVariant {
480 EnumVariant {
481 name: name.into(),
482 fields: Some(fields.into_iter().collect()),
483 }
484}
485
486pub fn trait_bound(
487 param: impl Into<String>,
488 traits: impl IntoIterator<Item = String>,
489) -> TraitBound {
490 TraitBound {
491 type_param: param.into(),
492 traits: traits.into_iter().collect(),
493 }
494}
495
496pub fn function_param(name: impl Into<String>, ty: Type) -> FunctionParam {
497 FunctionParam {
498 name: name.into(),
499 ty,
500 is_self: false,
501 }
502}
503
504pub fn self_param(ty: Option<Type>) -> FunctionParam {
505 FunctionParam {
506 name: "self".to_string(),
507 ty: ty.unwrap_or_else(|| Type::new(TypeKind::Infer, Span::dummy())),
508 is_self: true,
509 }
510}
511
512pub fn type_named(name: impl Into<String>) -> Type {
513 Type::new(TypeKind::Named(name.into()), Span::dummy())
514}
515
516pub fn type_unit() -> Type {
517 Type::new(TypeKind::Unit, Span::dummy())
518}
519
520pub fn type_unknown() -> Type {
521 Type::new(TypeKind::Unknown, Span::dummy())
522}
523
524fn function_signature_for(func: &FunctionDef) -> (String, FunctionSignature) {
525 let params: Vec<Type> = func.params.iter().map(|p| p.ty.clone()).collect();
526 let return_type = func
527 .return_type
528 .clone()
529 .unwrap_or_else(|| Type::new(TypeKind::Unit, Span::dummy()));
530 (
531 func.name.clone(),
532 FunctionSignature {
533 params,
534 return_type,
535 is_method: func.is_method,
536 },
537 )
538}
539
540fn module_and_name(name: &str) -> Option<(String, String)> {
541 if let Some((module, rest)) = name.rsplit_once("::") {
542 return Some((module.replace("::", "."), rest.to_string()));
543 }
544 if let Some((module, rest)) = name.rsplit_once('.') {
545 return Some((module.to_string(), rest.to_string()));
546 }
547 None
548}
549
550fn impl_module(impl_block: &ImplBlock) -> Option<String> {
551 match &impl_block.target_type.kind {
552 TypeKind::Named(name) => module_and_name(name).map(|(module, _)| module),
553 TypeKind::GenericInstance { name, .. } => module_and_name(name).map(|(module, _)| module),
554 _ => None,
555 }
556}
557
558fn format_struct_def(name: String, def: &StructDef) -> String {
559 let mut out = String::new();
560 if matches!(def.visibility, Visibility::Public) {
561 out.push_str("pub ");
562 }
563 out.push_str("struct ");
564 out.push_str(&name);
565 if !def.type_params.is_empty() {
566 out.push('<');
567 out.push_str(&def.type_params.join(", "));
568 out.push('>');
569 }
570 out.push('\n');
571 for field in &def.fields {
572 out.push_str(" ");
573 if matches!(field.visibility, Visibility::Public) {
574 out.push_str("pub ");
575 }
576 out.push_str(&field.name);
577 out.push_str(": ");
578 match field.ownership {
579 FieldOwnership::Weak => {
580 out.push_str("ref ");
581 if let Some(target) = &field.weak_target {
582 out.push_str(&format_type(target));
583 } else {
584 out.push_str(&format_type(&field.ty));
585 }
586 }
587 FieldOwnership::Strong => {
588 out.push_str(&format_type(&field.ty));
589 }
590 }
591 out.push('\n');
592 }
593 out.push_str("end\n");
594 out
595}
596
597fn format_enum_def(name: String, def: &EnumDef) -> String {
598 let mut out = String::new();
599 if matches!(def.visibility, Visibility::Public) {
600 out.push_str("pub ");
601 }
602 out.push_str("enum ");
603 out.push_str(&name);
604 if !def.type_params.is_empty() {
605 out.push('<');
606 out.push_str(&def.type_params.join(", "));
607 out.push('>');
608 }
609 out.push('\n');
610 for variant in &def.variants {
611 out.push_str(" ");
612 out.push_str(&variant.name);
613 if let Some(fields) = &variant.fields {
614 let parts: Vec<String> = fields.iter().map(format_type).collect();
615 out.push('(');
616 out.push_str(&parts.join(", "));
617 out.push(')');
618 }
619 out.push('\n');
620 }
621 out.push_str("end\n");
622 out
623}
624
625fn format_trait_def(name: String, def: &TraitDef) -> String {
626 let mut out = String::new();
627 if matches!(def.visibility, Visibility::Public) {
628 out.push_str("pub ");
629 }
630 out.push_str("trait ");
631 out.push_str(&name);
632 if !def.type_params.is_empty() {
633 out.push('<');
634 out.push_str(&def.type_params.join(", "));
635 out.push('>');
636 }
637 out.push('\n');
638 for method in &def.methods {
639 out.push_str(" ");
640 out.push_str(&format_trait_method(method));
641 out.push('\n');
642 }
643 out.push_str("end\n");
644 out
645}
646
647fn format_trait_method(method: &TraitMethod) -> String {
648 let mut out = String::new();
649 out.push_str("function ");
650 out.push_str(&method.name);
651 if !method.type_params.is_empty() {
652 out.push('<');
653 out.push_str(&method.type_params.join(", "));
654 out.push('>');
655 }
656 out.push('(');
657 out.push_str(
658 &method
659 .params
660 .iter()
661 .map(format_param_signature)
662 .collect::<Vec<_>>()
663 .join(", "),
664 );
665 out.push(')');
666 if let Some(ret) = &method.return_type {
667 if !matches!(ret.kind, TypeKind::Unit) {
668 out.push_str(": ");
669 out.push_str(&format_type(ret));
670 }
671 }
672 out
673}
674
675fn format_param_signature(param: &FunctionParam) -> String {
676 if param.is_self {
677 return "self".to_string();
678 }
679 if matches!(param.ty.kind, TypeKind::Infer) {
680 param.name.clone()
681 } else {
682 format!("{}: {}", param.name, format_type(¶m.ty))
683 }
684}
685
686fn format_type(ty: &Type) -> String {
687 match &ty.kind {
688 TypeKind::Named(name) => {
689 let (_, simple) =
690 module_and_name(name).unwrap_or_else(|| (String::new(), name.clone()));
691 if simple.is_empty() {
692 name.clone()
693 } else {
694 simple
695 }
696 }
697 TypeKind::GenericInstance { name, type_args } => {
698 let (_, simple) =
699 module_and_name(name).unwrap_or_else(|| (String::new(), name.clone()));
700 let args = type_args
701 .iter()
702 .map(format_type)
703 .collect::<Vec<_>>()
704 .join(", ");
705 format!("{}<{}>", simple, args)
706 }
707 _ => format!("{}", ty),
708 }
709}
710
711fn canonicalize_struct(def: &StructDef, prefix: Option<&str>) -> StructDef {
712 let mut cloned = def.clone();
713 cloned.name = canonicalize_simple_name(&cloned.name, prefix);
714 for field in &mut cloned.fields {
715 field.ty = canonicalize_type(&field.ty, prefix);
716 if let Some(target) = &field.weak_target {
717 field.weak_target = Some(canonicalize_type(target, prefix));
718 }
719 }
720 cloned
721}
722
723fn canonicalize_enum(def: &EnumDef, prefix: Option<&str>) -> EnumDef {
724 let mut cloned = def.clone();
725 cloned.name = canonicalize_simple_name(&cloned.name, prefix);
726 for variant in &mut cloned.variants {
727 if let Some(fields) = &mut variant.fields {
728 for field in fields {
729 *field = canonicalize_type(field, prefix);
730 }
731 }
732 }
733 cloned
734}
735
736fn canonicalize_trait(def: &TraitDef, prefix: Option<&str>) -> TraitDef {
737 let mut cloned = def.clone();
738 cloned.name = canonicalize_simple_name(&cloned.name, prefix);
739 for method in &mut cloned.methods {
740 for param in &mut method.params {
741 param.ty = canonicalize_type(¶m.ty, prefix);
742 }
743 if let Some(ret) = method.return_type.clone() {
744 method.return_type = Some(canonicalize_type(&ret, prefix));
745 }
746 }
747 cloned
748}
749
750fn canonicalize_impl(def: &ImplBlock, prefix: Option<&str>) -> ImplBlock {
751 let mut cloned = def.clone();
752 cloned.target_type = canonicalize_type(&cloned.target_type, prefix);
753 let struct_name = match &cloned.target_type.kind {
754 TypeKind::Named(name) => name.clone(),
755 TypeKind::GenericInstance { name, .. } => name.clone(),
756 _ => cloned.target_type.to_string(),
757 };
758 if let Some(trait_name) = &cloned.trait_name {
759 cloned.trait_name = Some(canonicalize_simple_name(trait_name, prefix));
760 }
761 for method in &mut cloned.methods {
762 for param in &mut method.params {
763 param.ty = canonicalize_type(¶m.ty, prefix);
764 }
765 if let Some(ret) = method.return_type.clone() {
766 method.return_type = Some(canonicalize_type(&ret, prefix));
767 }
768 if let Some((_, rest)) = method.name.split_once(':') {
769 method.name = format!("{}:{}", struct_name, rest);
770 } else if let Some((_, rest)) = method.name.split_once('.') {
771 method.name = format!("{}.{}", struct_name, rest);
772 } else {
773 method.name = format!("{}:{}", struct_name, method.name);
774 }
775 #[cfg(debug_assertions)]
776 eprintln!("canonicalized method name -> {}", method.name);
777 }
778 cloned
779}
780
781fn canonicalize_type(ty: &Type, prefix: Option<&str>) -> Type {
782 use TypeKind as TK;
783 let mut canonical = ty.clone();
784 canonical.kind = match &ty.kind {
785 TK::Named(name) => TK::Named(canonicalize_simple_name(name, prefix)),
786 TK::GenericInstance { name, type_args } => TK::GenericInstance {
787 name: canonicalize_simple_name(name, prefix),
788 type_args: type_args
789 .iter()
790 .map(|arg| canonicalize_type(arg, prefix))
791 .collect(),
792 },
793 TK::Array(inner) => TK::Array(Box::new(canonicalize_type(inner, prefix))),
794 TK::Option(inner) => TK::Option(Box::new(canonicalize_type(inner, prefix))),
795 TK::Result(ok, err) => TK::Result(
796 Box::new(canonicalize_type(ok, prefix)),
797 Box::new(canonicalize_type(err, prefix)),
798 ),
799 TK::Ref(inner) => TK::Ref(Box::new(canonicalize_type(inner, prefix))),
800 TK::MutRef(inner) => TK::MutRef(Box::new(canonicalize_type(inner, prefix))),
801 TK::Map(key, value) => TK::Map(
802 Box::new(canonicalize_type(key, prefix)),
803 Box::new(canonicalize_type(value, prefix)),
804 ),
805 TK::Tuple(elements) => TK::Tuple(
806 elements
807 .iter()
808 .map(|element| canonicalize_type(element, prefix))
809 .collect(),
810 ),
811 TK::Union(types) => TK::Union(
812 types
813 .iter()
814 .map(|variant| canonicalize_type(variant, prefix))
815 .collect(),
816 ),
817 other => other.clone(),
818 };
819 canonical
820}
821
822fn canonicalize_simple_name(name: &str, prefix: Option<&str>) -> String {
823 if name.is_empty() {
824 return name.to_string();
825 }
826 if is_qualified_name(name) {
827 return name.replace("::", ".");
828 }
829 if let Some(prefix) = prefix {
830 if prefix.is_empty() {
831 return name.to_string();
832 }
833 return format!("{}.{}", prefix, name);
834 }
835 name.to_string()
836}
837
838fn is_qualified_name(name: &str) -> bool {
839 name.contains('.') || name.contains("::")
840}