Skip to content
This repository was archived by the owner on Sep 9, 2025. It is now read-only.

Commit fc67b4b

Browse files
oppiliappanHendrik van Antwerpen
authored andcommitted
implement load_from on filtered stack-graphs
1 parent 34ec1a6 commit fc67b4b

File tree

1 file changed

+257
-14
lines changed

1 file changed

+257
-14
lines changed

stack-graphs/src/filtered_stack_graph.rs

Lines changed: 257 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use super::Filter;
1+
use std::collections::HashMap;
2+
3+
use crate::{arena::Handle, graph::File, json::Filter};
24
use serde::{Deserialize, Serialize};
35

46
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
@@ -9,8 +11,194 @@ pub struct StackGraph {
911
}
1012

1113
impl 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")]
31219
pub 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)]
125316
pub 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

Comments
 (0)