1- use super :: Filter ;
1+ use std:: collections:: HashMap ;
2+
3+ use crate :: { arena:: Handle , graph:: File , json:: Filter } ;
24use serde:: { Deserialize , Serialize } ;
35
46#[ derive( Serialize , Deserialize , PartialEq , Eq , Debug ) ]
@@ -9,8 +11,194 @@ pub struct StackGraph {
911}
1012
1113impl StackGraph {
12- pub fn reconstruct ( & self ) -> crate :: graph:: StackGraph {
13- todo ! ( )
14+ pub fn load_into ( & self , graph : & mut crate :: graph:: StackGraph ) -> Result < ( ) , ( ) > {
15+ // load files into the stack-graph, create a mapping between file <-> handle
16+ if self
17+ . files
18+ . data
19+ . iter ( )
20+ . any ( |f| graph. get_file ( f. as_str ( ) ) . is_some ( ) )
21+ {
22+ return Err ( ( ) ) ;
23+ }
24+ let mut file_handle_map: HashMap < & str , Handle < File > > = HashMap :: default ( ) ;
25+ for f in self . files . data . iter ( ) {
26+ let handle = graph. add_file ( f. as_str ( ) ) . unwrap ( ) ;
27+ file_handle_map. insert ( f. as_str ( ) , handle) ;
28+ }
29+
30+ // load nodes into stack-graph
31+ for n in self . nodes . data . as_slice ( ) {
32+ match n {
33+ Node :: DropScopes {
34+ id :
35+ NodeID {
36+ file : Some ( f) ,
37+ local_id,
38+ } ,
39+ ..
40+ } => {
41+ if let Some ( file_handle) = file_handle_map. get ( f. as_str ( ) ) {
42+ let node_id = crate :: graph:: NodeID :: new_in_file ( * file_handle, * local_id) ;
43+ graph. add_drop_scopes_node ( node_id) ;
44+ }
45+ }
46+ Node :: JumpTo { .. } => { }
47+ Node :: PopScopedSymbol {
48+ id :
49+ NodeID {
50+ file : Some ( f) ,
51+ local_id,
52+ } ,
53+ symbol,
54+ is_definition,
55+ ..
56+ } => {
57+ if let Some ( file_handle) = file_handle_map. get ( f. as_str ( ) ) {
58+ let node_id = crate :: graph:: NodeID :: new_in_file ( * file_handle, * local_id) ;
59+ let symbol_handle = graph. add_symbol ( symbol. as_str ( ) ) ;
60+ graph. add_pop_scoped_symbol_node ( node_id, symbol_handle, * is_definition) ;
61+ }
62+ }
63+ Node :: PopSymbol {
64+ id :
65+ NodeID {
66+ file : Some ( f) ,
67+ local_id,
68+ } ,
69+ symbol,
70+ is_definition,
71+ ..
72+ } => {
73+ if let Some ( file_handle) = file_handle_map. get ( f. as_str ( ) ) {
74+ let node_id = crate :: graph:: NodeID :: new_in_file ( * file_handle, * local_id) ;
75+ let symbol_handle = graph. add_symbol ( symbol. as_str ( ) ) ;
76+ graph. add_pop_symbol_node ( node_id, symbol_handle, * is_definition) ;
77+ }
78+ }
79+ Node :: PushScopedSymbol {
80+ id :
81+ NodeID {
82+ file : Some ( f) ,
83+ local_id,
84+ } ,
85+ symbol,
86+ scope :
87+ NodeID {
88+ file : Some ( scope_f) ,
89+ local_id : scope_local_id,
90+ } ,
91+ is_reference,
92+ ..
93+ } => {
94+ if let Some ( file_handle) = file_handle_map. get ( f. as_str ( ) ) {
95+ if let Some ( scope_file_handle) = file_handle_map. get ( scope_f. as_str ( ) ) {
96+ let node_id =
97+ crate :: graph:: NodeID :: new_in_file ( * file_handle, * local_id) ;
98+
99+ let scope_id = crate :: graph:: NodeID :: new_in_file (
100+ * scope_file_handle,
101+ * scope_local_id,
102+ ) ;
103+
104+ let symbol_handle = graph. add_symbol ( symbol. as_str ( ) ) ;
105+
106+ graph. add_push_scoped_symbol_node (
107+ node_id,
108+ symbol_handle,
109+ scope_id,
110+ * is_reference,
111+ ) ;
112+ }
113+ }
114+ }
115+ Node :: PushSymbol {
116+ id :
117+ NodeID {
118+ file : Some ( f) ,
119+ local_id,
120+ } ,
121+ symbol,
122+ is_reference,
123+ ..
124+ } => {
125+ if let Some ( file_handle) = file_handle_map. get ( f. as_str ( ) ) {
126+ let node_id = crate :: graph:: NodeID :: new_in_file ( * file_handle, * local_id) ;
127+ let symbol_handle = graph. add_symbol ( symbol. as_str ( ) ) ;
128+ graph. add_push_symbol_node ( node_id, symbol_handle, * is_reference) ;
129+ }
130+ }
131+ Node :: Root { .. } => { }
132+ Node :: Scope {
133+ id :
134+ NodeID {
135+ file : Some ( f) ,
136+ local_id,
137+ } ,
138+ is_exported,
139+ ..
140+ } => {
141+ if let Some ( file_handle) = file_handle_map. get ( f. as_str ( ) ) {
142+ let node_id = crate :: graph:: NodeID :: new_in_file ( * file_handle, * local_id) ;
143+ graph. add_scope_node ( node_id, * is_exported) ;
144+ }
145+ }
146+ _ => { }
147+ }
148+ }
149+
150+ // load edges into stack-graph
151+ for Edge {
152+ source,
153+ sink,
154+ precedence,
155+ } in self . edges . data . as_slice ( )
156+ {
157+ let source_file_handle = source
158+ . file
159+ . as_ref ( )
160+ . and_then ( |f| file_handle_map. get ( f. as_str ( ) ) ) ;
161+ let sink_file_handle = sink
162+ . file
163+ . as_ref ( )
164+ . and_then ( |f| file_handle_map. get ( f. as_str ( ) ) ) ;
165+ let convert = |n : & NodeID | {
166+ if n. is_root ( ) {
167+ crate :: graph:: NodeID :: root ( )
168+ } else if n. is_jump_to ( ) {
169+ crate :: graph:: NodeID :: jump_to ( )
170+ } else {
171+ panic ! ( )
172+ }
173+ } ;
174+ let ( source_id, sink_id) = match ( source_file_handle, sink_file_handle) {
175+ ( Some ( a) , Some ( b) ) => {
176+ let source_node_id = crate :: graph:: NodeID :: new_in_file ( * a, source. local_id ) ;
177+ let sink_node_id = crate :: graph:: NodeID :: new_in_file ( * b, source. local_id ) ;
178+ ( source_node_id, sink_node_id)
179+ }
180+ ( Some ( a) , None ) => {
181+ let source_node_id = crate :: graph:: NodeID :: new_in_file ( * a, source. local_id ) ;
182+ let sink_node_id = convert ( & sink) ;
183+ ( source_node_id, sink_node_id)
184+ }
185+ ( None , Some ( b) ) => {
186+ let source_node_id = convert ( & source) ;
187+ let sink_node_id = crate :: graph:: NodeID :: new_in_file ( * b, source. local_id ) ;
188+ ( source_node_id, sink_node_id)
189+ }
190+ ( None , None ) => {
191+ let source_node_id = convert ( & source) ;
192+ let sink_node_id = convert ( & sink) ;
193+ ( source_node_id, sink_node_id)
194+ }
195+ } ;
196+
197+ if let ( Some ( a) , Some ( b) ) = ( graph. node_for_id ( source_id) , graph. node_for_id ( sink_id) ) {
198+ graph. add_edge ( a, b, * precedence) ;
199+ }
200+ }
201+ Ok ( ( ) )
14202 }
15203}
16204
@@ -27,23 +215,21 @@ pub struct Nodes {
27215}
28216
29217#[ derive( Serialize , Deserialize , PartialEq , Eq , Debug ) ]
30- #[ serde( tag = "type" ) ]
218+ #[ serde( tag = "type" , rename_all = "snake_case" ) ]
31219pub enum Node {
32- #[ serde( rename = "drop_scopes" ) ]
33220 DropScopes {
34221 id : NodeID ,
35222 source_info : Option < SourceInfo > ,
36223 debug_info : Option < DebugInfo > ,
37224 } ,
38225
39- #[ serde( rename = "jump_to " ) ]
226+ #[ serde( rename = "jump_to_scope " ) ]
40227 JumpTo {
41228 id : NodeID ,
42229 source_info : Option < SourceInfo > ,
43230 debug_info : Option < DebugInfo > ,
44231 } ,
45232
46- #[ serde( rename = "pop_scoped_symbol" ) ]
47233 PopScopedSymbol {
48234 id : NodeID ,
49235 symbol : String ,
@@ -52,7 +238,6 @@ pub enum Node {
52238 debug_info : Option < DebugInfo > ,
53239 } ,
54240
55- #[ serde( rename = "pop_symbol" ) ]
56241 PopSymbol {
57242 id : NodeID ,
58243 symbol : String ,
@@ -61,7 +246,6 @@ pub enum Node {
61246 debug_info : Option < DebugInfo > ,
62247 } ,
63248
64- #[ serde( rename = "push_scoped_symbol" ) ]
65249 PushScopedSymbol {
66250 id : NodeID ,
67251 symbol : String ,
@@ -71,7 +255,6 @@ pub enum Node {
71255 debug_info : Option < DebugInfo > ,
72256 } ,
73257
74- #[ serde( rename = "push_symbol" ) ]
75258 PushSymbol {
76259 id : NodeID ,
77260 symbol : String ,
@@ -80,14 +263,12 @@ pub enum Node {
80263 debug_info : Option < DebugInfo > ,
81264 } ,
82265
83- #[ serde( rename = "root" ) ]
84266 Root {
85267 id : NodeID ,
86268 source_info : Option < SourceInfo > ,
87269 debug_info : Option < DebugInfo > ,
88270 } ,
89271
90- #[ serde( rename = "scope" ) ]
91272 Scope {
92273 id : NodeID ,
93274 is_exported : bool ,
@@ -120,6 +301,16 @@ pub struct NodeID {
120301 local_id : u32 ,
121302}
122303
304+ impl NodeID {
305+ fn is_root ( & self ) -> bool {
306+ self . local_id == crate :: graph:: NodeID :: root ( ) . local_id ( )
307+ }
308+
309+ fn is_jump_to ( & self ) -> bool {
310+ self . local_id == crate :: graph:: NodeID :: jump_to ( ) . local_id ( )
311+ }
312+ }
313+
123314#[ derive( Serialize , Deserialize , PartialEq , Eq , Debug ) ]
124315#[ serde( transparent) ]
125316pub struct Edges {
@@ -165,7 +356,7 @@ impl crate::graph::StackGraph {
165356 fn filter_source_info < ' a > (
166357 & self ,
167358 _filter : & ' a dyn Filter ,
168- handle : super :: Handle < super :: Node > ,
359+ handle : Handle < super :: Node > ,
169360 ) -> Option < SourceInfo > {
170361 self . source_info ( handle) . map ( |info| SourceInfo {
171362 span : info. span . clone ( ) ,
@@ -176,7 +367,7 @@ impl crate::graph::StackGraph {
176367 fn filter_debug_info < ' a > (
177368 & self ,
178369 _filter : & ' a dyn Filter ,
179- handle : super :: Handle < super :: Node > ,
370+ handle : Handle < super :: Node > ,
180371 ) -> Option < DebugInfo > {
181372 self . debug_info ( handle) . map ( |info| DebugInfo {
182373 data : info
@@ -383,4 +574,56 @@ mod test {
383574
384575 assert_eq ! ( observed, expected) ;
385576 }
577+
578+ #[ test]
579+ fn reconstruct ( ) {
580+ let json_data = serde_json:: json!( {
581+ "files" : [
582+ "index.ts"
583+ ] ,
584+ "nodes" : [ {
585+ "type" : "root" ,
586+ "id" : {
587+ "local_id" : 1
588+ } ,
589+ "source_info" : {
590+ "span" : {
591+ "start" : {
592+ "line" : 0 ,
593+ "column" : {
594+ "utf8_offset" : 0 ,
595+ "utf16_offset" : 0 ,
596+ "grapheme_offset" : 0
597+ }
598+ } ,
599+ "end" : {
600+ "line" : 0 ,
601+ "column" : {
602+ "utf8_offset" : 0 ,
603+ "utf16_offset" : 0 ,
604+ "grapheme_offset" : 0
605+ }
606+ }
607+ }
608+ } ,
609+ "debug_info" : [ ]
610+ } ] ,
611+ "edges" : [ {
612+ "source" : {
613+ "local_id" : 1
614+ } ,
615+ "sink" : {
616+ "file" : "index.ts" ,
617+ "local_id" : 0
618+ } ,
619+ "precedence" : 0
620+ } ] } ) ;
621+ let observed = serde_json:: from_value :: < super :: StackGraph > ( json_data) . unwrap ( ) ;
622+ let mut sg = crate :: graph:: StackGraph :: new ( ) ;
623+ observed. load_into ( & mut sg) . unwrap ( ) ;
624+
625+ // always 2 nodes: root and jump
626+ assert_eq ! ( sg. iter_nodes( ) . count( ) , 2 ) ;
627+ assert_eq ! ( sg. iter_files( ) . count( ) , 1 ) ;
628+ }
386629}
0 commit comments