11use crate :: lang:: interface:: FrozenInterfaceValue ;
2- use crate :: lang:: module:: find_moved_span;
2+ use crate :: lang:: module:: { find_moved_span, ModulePath } ;
33use crate :: lang:: physical:: PhysicalValue ;
44use crate :: lang:: symbol:: SymbolValue ;
5- use crate :: lang:: test_bench:: FrozenTestBenchValue ;
65use crate :: lang:: type_info:: TypeInfo ;
76use crate :: moved:: { collect_existing_paths, scoped_path, Remapper } ;
87use crate :: { Diagnostic , Diagnostics , WithDiagnostics } ;
@@ -16,10 +15,9 @@ use serde::{Deserialize, Serialize};
1615use serde_json:: { Map as JsonMap , Number as JsonNumber , Value as JsonValue } ;
1716use starlark:: errors:: EvalSeverity ;
1817use starlark:: values:: list:: ListRef ;
19- use starlark:: values:: FrozenValue ;
20- use starlark:: values:: { dict:: DictRef , Value , ValueLike } ;
21- use std:: collections:: HashMap ;
18+ use starlark:: values:: { dict:: DictRef , FrozenValue , Value , ValueLike } ;
2219use std:: collections:: HashSet ;
20+ use std:: collections:: { BTreeMap , HashMap } ;
2321use std:: path:: { Path , PathBuf } ;
2422
2523/// Convert a [`FrozenModuleValue`] to a [`Schematic`].
@@ -32,6 +30,8 @@ pub(crate) struct ModuleConverter {
3230 comp_models : Vec < ( InstanceRef , FrozenSpiceModelValue ) > ,
3331 // Mapping <module instance ref> -> <module value> for position processing
3432 module_instances : Vec < ( InstanceRef , FrozenModuleValue ) > ,
33+ // Module tree for looking up children
34+ module_tree : BTreeMap < ModulePath , FrozenModuleValue > ,
3535}
3636
3737/// Module signature information to be serialized as JSON
@@ -147,27 +147,49 @@ impl ModuleConverter {
147147 net_to_properties : HashMap :: new ( ) ,
148148 comp_models : Vec :: new ( ) ,
149149 module_instances : Vec :: new ( ) ,
150+ module_tree : BTreeMap :: new ( ) ,
150151 }
151152 }
152153
153- pub ( crate ) fn build ( mut self , module : & FrozenModuleValue ) -> crate :: WithDiagnostics < Schematic > {
154+ pub ( crate ) fn build (
155+ mut self ,
156+ module_tree : BTreeMap < ModulePath , FrozenModuleValue > ,
157+ ) -> crate :: WithDiagnostics < Schematic > {
158+ let root_module = module_tree. get ( & ModulePath :: root ( ) ) . unwrap ( ) ;
154159 let root_instance_ref = InstanceRef :: new (
155- ModuleRef :: new ( module . source_path ( ) , module . name ( ) ) ,
160+ ModuleRef :: new ( root_module . source_path ( ) , "<root>" ) ,
156161 Vec :: new ( ) ,
157162 ) ;
163+ self . schematic . set_root_ref ( root_instance_ref) ;
158164
159- if let Err ( err) = self . add_module_at ( module, & root_instance_ref) {
160- let mut diagnostics = Diagnostics :: default ( ) ;
161- diagnostics. push ( err. into ( ) ) ;
162- return WithDiagnostics {
163- output : None ,
164- diagnostics,
165- } ;
165+ for ( path, module) in module_tree. iter ( ) {
166+ let instance_ref = InstanceRef :: new (
167+ ModuleRef :: new ( root_module. source_path ( ) , root_module. path ( ) . name ( ) ) ,
168+ path. segments . clone ( ) ,
169+ ) ;
170+ if let Err ( err) = self . add_module_at ( module, & instance_ref) {
171+ let mut diagnostics = Diagnostics :: default ( ) ;
172+ diagnostics. push ( err. into ( ) ) ;
173+ return WithDiagnostics {
174+ output : None ,
175+ diagnostics,
176+ } ;
177+ }
178+
179+ // Link child to parent module
180+ if let Some ( parent_path) = path. parent ( ) {
181+ let parent_ref = InstanceRef :: new (
182+ ModuleRef :: new ( root_module. source_path ( ) , root_module. path ( ) . name ( ) ) ,
183+ parent_path. segments . clone ( ) ,
184+ ) ;
185+ if let Some ( parent_inst) = self . schematic . instances . get_mut ( & parent_ref) {
186+ parent_inst. add_child ( module. path ( ) . name ( ) , instance_ref. clone ( ) ) ;
187+ }
188+ }
166189 }
167- self . schematic . set_root_ref ( root_instance_ref) ;
168190
169191 // Propagate impedance from DiffPair interfaces to P/N nets (before creating Net objects)
170- propagate_diffpair_impedance ( module , & mut self . net_to_properties ) ;
192+ propagate_diffpair_impedance ( & mut self . net_to_properties , & self . module_tree ) ;
171193
172194 // Create Net objects directly using the names recorded per-module.
173195 // Ensure global uniqueness and stable creation order by sorting names.
@@ -193,7 +215,7 @@ impl ModuleConverter {
193215 diagnostics. push ( Diagnostic :: new (
194216 format ! ( "Duplicate net name: {name}" ) ,
195217 EvalSeverity :: Error ,
196- Path :: new ( module . source_path ( ) ) ,
218+ Path :: new ( root_module . source_path ( ) ) ,
197219 ) ) ;
198220 return WithDiagnostics {
199221 output : None ,
@@ -273,45 +295,6 @@ impl ModuleConverter {
273295 }
274296 }
275297
276- fn add_instance_at (
277- & mut self ,
278- instance_ref : & InstanceRef ,
279- value : FrozenValue ,
280- ) -> anyhow:: Result < ( ) > {
281- if let Some ( module_value) = value. downcast_ref :: < FrozenModuleValue > ( ) {
282- self . add_module_at ( module_value, instance_ref)
283- } else if let Some ( component_value) = value. downcast_ref :: < FrozenComponentValue > ( ) {
284- self . add_component_at ( component_value, instance_ref)
285- } else if value. downcast_ref :: < FrozenTestBenchValue > ( ) . is_some ( ) {
286- // Skip TestBench values - they're not part of the schematic
287- Ok ( ( ) )
288- } else if value
289- . downcast_ref :: < crate :: lang:: electrical_check:: FrozenElectricalCheck > ( )
290- . is_some ( )
291- {
292- // Skip ElectricalCheck values - they're not part of the schematic
293- Ok ( ( ) )
294- } else {
295- Err ( anyhow:: anyhow!( "Unexpected value in module: {}" , value) )
296- }
297- }
298-
299- fn value_name ( & self , value : & FrozenValue ) -> anyhow:: Result < String > {
300- if let Some ( module_value) = value. downcast_ref :: < FrozenModuleValue > ( ) {
301- Ok ( module_value. name ( ) . to_string ( ) )
302- } else if let Some ( component_value) = value. downcast_ref :: < FrozenComponentValue > ( ) {
303- Ok ( component_value. name ( ) . to_string ( ) )
304- } else if let Some ( testbench) = value. downcast_ref :: < FrozenTestBenchValue > ( ) {
305- Ok ( testbench. name ( ) . to_string ( ) )
306- } else if let Some ( check) =
307- value. downcast_ref :: < crate :: lang:: electrical_check:: FrozenElectricalCheck > ( )
308- {
309- Ok ( check. name . clone ( ) )
310- } else {
311- Err ( anyhow:: anyhow!( "Unexpected value in module: {}" , value) )
312- }
313- }
314-
315298 fn add_module_at (
316299 & mut self ,
317300 module : & FrozenModuleValue ,
@@ -417,13 +400,11 @@ impl ModuleConverter {
417400 self . net_to_name . insert ( * net_id, final_name) ;
418401 }
419402
420- // Recurse into children, but don't pass any properties down.
421- // Each module/component should only have its own properties.
422- for child in module. children ( ) . iter ( ) {
423- let child_name = self . value_name ( child) ?;
424- let child_inst_ref = instance_ref. append ( child_name. clone ( ) ) ;
425- self . add_instance_at ( & child_inst_ref, * child) ?;
426- inst. add_child ( child_name. clone ( ) , child_inst_ref. clone ( ) ) ;
403+ // Add direct child components
404+ for component in module. components ( ) {
405+ let child_ref = instance_ref. append ( component. name ( ) . to_string ( ) ) ;
406+ self . add_component_at ( component, & child_ref) ?;
407+ inst. add_child ( component. name ( ) . to_string ( ) , child_ref. clone ( ) ) ;
427408 }
428409
429410 // Add instance to schematic.
@@ -824,20 +805,14 @@ impl ModuleConverter {
824805
825806/// Propagate impedance from DiffPair interfaces to P/N nets
826807fn propagate_diffpair_impedance (
827- module : & FrozenModuleValue ,
828808 net_props : & mut HashMap < NetId , HashMap < String , AttributeValue > > ,
809+ tree : & BTreeMap < ModulePath , FrozenModuleValue > ,
829810) {
830- // Check signature for interfaces
831- for param in module. signature ( ) . iter ( ) . filter ( |p| !p. is_config ) {
832- if let Some ( val) = param. actual_value {
833- propagate_from_value ( val. to_value ( ) , net_props) ;
834- }
835- }
836-
837- // Recurse into children
838- for child in module. children ( ) . iter ( ) {
839- if let Some ( m) = child. downcast_ref :: < FrozenModuleValue > ( ) {
840- propagate_diffpair_impedance ( m, net_props) ;
811+ for module in tree. values ( ) {
812+ for param in module. signature ( ) . iter ( ) . filter ( |p| !p. is_config ) {
813+ if let Some ( val) = param. actual_value {
814+ propagate_from_value ( val. to_value ( ) , net_props) ;
815+ }
841816 }
842817 }
843818}
@@ -884,11 +859,6 @@ fn propagate_from_value(
884859 }
885860}
886861
887- pub trait ToSchematic {
888- fn to_schematic ( & self ) -> anyhow:: Result < Schematic > ;
889- fn to_schematic_with_diagnostics ( & self ) -> crate :: WithDiagnostics < Schematic > ;
890- }
891-
892862fn to_attribute_value ( v : starlark:: values:: FrozenValue ) -> anyhow:: Result < AttributeValue > {
893863 // Handle scalars first
894864 if let Some ( s) = v. downcast_frozen_str ( ) {
@@ -923,19 +893,3 @@ fn to_attribute_value(v: starlark::values::FrozenValue) -> anyhow::Result<Attrib
923893 // Any other type – fall back to string representation
924894 Ok ( AttributeValue :: String ( v. to_string ( ) ) )
925895}
926-
927- impl ToSchematic for FrozenModuleValue {
928- fn to_schematic ( & self ) -> anyhow:: Result < Schematic > {
929- let result = self . to_schematic_with_diagnostics ( ) ;
930- match result. output {
931- Some ( schematic) if !result. diagnostics . has_errors ( ) => Ok ( schematic) ,
932- Some ( _) => Err ( anyhow:: anyhow!( "Schematic conversion had errors" ) ) ,
933- None => Err ( anyhow:: anyhow!( "Schematic conversion failed" ) ) ,
934- }
935- }
936-
937- fn to_schematic_with_diagnostics ( & self ) -> crate :: WithDiagnostics < Schematic > {
938- let converter = ModuleConverter :: new ( ) ;
939- converter. build ( self )
940- }
941- }
0 commit comments