@@ -2,16 +2,17 @@ use std::collections::{HashMap, VecDeque};
22use std:: path:: { Path , PathBuf } ;
33use std:: sync:: Arc ;
44
5- use crate :: error:: ErrorCollector ;
6- use crate :: parse:: { self , Item , ParseFromStrWithErrors , Program , UseDecl } ;
5+ use crate :: error:: { ErrorCollector , Span } ;
6+ use crate :: parse:: { self , ParseFromStrWithErrors , UseDecl , Visibility } ;
7+ use crate :: str:: Identifier ;
78use crate :: LibConfig ;
89
910/// Graph Node: One file = One module
1011#[ derive( Debug , Clone ) ]
11- pub struct Module {
12+ struct Module {
1213 /// Parsed AST (your `parse::Program`)
1314 /// Using Option to first create the node, then add the AST
14- pub parsed_program : Program ,
15+ pub parsed_program : parse :: Program ,
1516}
1617
1718/// The Dependency Graph itself
@@ -22,11 +23,24 @@ pub struct ProjectGraph {
2223 /// Fast lookup: Path -> ID
2324 /// Solves the duplicate problem (so as not to parse a.simf twice)
2425 pub lookup : HashMap < PathBuf , usize > ,
26+ pub paths : Vec < PathBuf > ,
2527
2628 /// Adjacency list: Who depends on whom
2729 pub dependencies : HashMap < usize , Vec < usize > > ,
2830}
2931
32+ #[ derive( Clone , Debug ) ]
33+ pub struct Resolution {
34+ pub visibility : Visibility ,
35+ }
36+
37+ pub struct Program {
38+ //pub graph: ProjectGraph,
39+ pub items : Arc < [ parse:: Item ] > ,
40+ pub scope_items : Vec < HashMap < Identifier , Resolution > > ,
41+ pub span : Span ,
42+ }
43+
3044#[ derive( Debug ) ]
3145pub enum C3Error {
3246 CycleDetected ( Vec < usize > ) ,
@@ -66,11 +80,12 @@ fn parse_and_get_program(prog_file: &Path) -> Result<parse::Program, String> {
6680}
6781
6882impl ProjectGraph {
69- pub fn new ( lib_cfg : & LibConfig , root_program : & Program ) -> Result < Self , String > {
83+ pub fn new ( lib_cfg : & LibConfig , root_program : & parse :: Program ) -> Result < Self , String > {
7084 let mut modules: Vec < Module > = vec ! [ Module {
7185 parsed_program: root_program. clone( ) ,
7286 } ] ;
7387 let mut lookup: HashMap < PathBuf , usize > = HashMap :: new ( ) ;
88+ let mut paths: Vec < PathBuf > = vec ! [ lib_cfg. root_path. clone( ) ] ;
7489 let mut dependencies: HashMap < usize , Vec < usize > > = HashMap :: new ( ) ;
7590
7691 let root_id = 0 ;
@@ -86,7 +101,7 @@ impl ProjectGraph {
86101 let current_program = & modules[ curr_id] . parsed_program ;
87102
88103 for elem in current_program. items ( ) {
89- if let Item :: Use ( use_decl) = elem {
104+ if let parse :: Item :: Use ( use_decl) = elem {
90105 if let Ok ( path) = get_full_path ( & lib_cfg. libraries , use_decl) {
91106 pending_imports. push ( path) ;
92107 }
@@ -112,6 +127,7 @@ impl ProjectGraph {
112127 parsed_program : program,
113128 } ) ;
114129 lookup. insert ( path. clone ( ) , last_ind) ;
130+ paths. push ( path. clone ( ) ) ;
115131 dependencies. entry ( curr_id) . or_default ( ) . push ( last_ind) ;
116132
117133 queue. push_back ( last_ind) ;
@@ -121,6 +137,7 @@ impl ProjectGraph {
121137 Ok ( Self {
122138 modules,
123139 lookup,
140+ paths,
124141 dependencies,
125142 } )
126143 }
@@ -148,9 +165,7 @@ impl ProjectGraph {
148165
149166 if visiting. contains ( & module) {
150167 let cycle_start = visiting. iter ( ) . position ( |m| * m == module) . unwrap ( ) ;
151- return Err ( C3Error :: CycleDetected (
152- visiting[ cycle_start..] . to_vec ( ) ,
153- ) ) ;
168+ return Err ( C3Error :: CycleDetected ( visiting[ cycle_start..] . to_vec ( ) ) ) ;
154169 }
155170
156171 visiting. push ( module) ;
@@ -167,8 +182,7 @@ impl ProjectGraph {
167182 seqs. push ( parents. clone ( ) ) ;
168183
169184 let mut result = vec ! [ module] ;
170- let merged = merge ( seqs)
171- . ok_or ( C3Error :: InconsistentLinearization { module } ) ?;
185+ let merged = merge ( seqs) . ok_or ( C3Error :: InconsistentLinearization { module } ) ?;
172186
173187 result. extend ( merged) ;
174188
@@ -177,6 +191,113 @@ impl ProjectGraph {
177191
178192 Ok ( result)
179193 }
194+
195+ // TODO: @Sdoba16 to implement
196+ fn build_ordering ( & self ) { }
197+
198+ fn process_use_item (
199+ scope_items : & mut [ HashMap < Identifier , Resolution > ] ,
200+ file_id : usize ,
201+ ind : usize ,
202+ elem : & Identifier ,
203+ use_decl_visibility : Visibility ,
204+ ) -> Result < ( ) , String > {
205+ if matches ! (
206+ scope_items[ ind] [ elem] . visibility,
207+ parse:: Visibility :: Private
208+ ) {
209+ return Err ( format ! (
210+ "Function {} is private and cannot be used." ,
211+ elem. as_inner( )
212+ ) ) ;
213+ }
214+
215+ scope_items[ file_id] . insert (
216+ elem. clone ( ) ,
217+ Resolution {
218+ visibility : use_decl_visibility,
219+ } ,
220+ ) ;
221+
222+ Ok ( ( ) )
223+ }
224+
225+ // TODO: Change. Consider processing more than one errro at a time
226+ fn build_program ( & self , order : & Vec < usize > ) -> Result < Program , String > {
227+ let mut items: Vec < parse:: Item > = Vec :: new ( ) ;
228+ let mut scope_items: Vec < HashMap < Identifier , Resolution > > = Vec :: new ( ) ;
229+
230+ for file_id in order {
231+ scope_items. push ( HashMap :: new ( ) ) ;
232+
233+ for elem in self . modules [ * file_id] . parsed_program . items ( ) {
234+ match elem {
235+ // If the function is private, we don't add it to the current scope.
236+ // If the function is public, we add it as public if we have 'pub use', or as private if we only have 'use'.
237+ // We can do this because all Items in the Arc<[Item]> array will be defined in advance.
238+ parse:: Item :: Use ( use_decl) => {
239+ let ind = self . lookup [ & use_decl. path_buf ( ) ] ;
240+
241+ match use_decl. items ( ) {
242+ parse:: UseItems :: Single ( elem) => {
243+ ProjectGraph :: process_use_item (
244+ & mut scope_items,
245+ * file_id,
246+ ind,
247+ elem,
248+ use_decl. visibility ( ) . clone ( ) ,
249+ ) ?;
250+ }
251+ parse:: UseItems :: List ( elems) => {
252+ for elem in elems {
253+ ProjectGraph :: process_use_item (
254+ & mut scope_items,
255+ * file_id,
256+ ind,
257+ elem,
258+ use_decl. visibility ( ) . clone ( ) ,
259+ ) ?;
260+ }
261+ }
262+ }
263+ }
264+ parse:: Item :: TypeAlias ( alias) => {
265+ items. push ( elem. clone ( ) ) ;
266+ scope_items[ * file_id] . insert (
267+ Identifier :: from ( alias. name ( ) . clone ( ) ) ,
268+ Resolution {
269+ visibility : alias. visibility ( ) . clone ( ) ,
270+ } ,
271+ ) ;
272+ }
273+ parse:: Item :: Function ( function) => {
274+ items. push ( elem. clone ( ) ) ;
275+ scope_items[ * file_id] . insert (
276+ Identifier :: from ( function. name ( ) . clone ( ) ) ,
277+ Resolution {
278+ visibility : function. visibility ( ) . clone ( ) ,
279+ } ,
280+ ) ;
281+ }
282+ parse:: Item :: Module => { }
283+ }
284+ }
285+ }
286+
287+ Ok ( Program {
288+ items : items. into ( ) ,
289+ scope_items,
290+ span : self . modules [ 0 ] . parsed_program . as_ref ( ) . clone ( ) ,
291+ } )
292+ }
293+
294+ pub fn resolve_complication_order ( & self ) -> Result < Program , String > {
295+ // TODO: Resolve errors more appropriately
296+ let mut order = self . c3_linearize ( ) . unwrap ( ) ;
297+ order. reverse ( ) ;
298+ // self.build_ordering();
299+ self . build_program ( & order)
300+ }
180301}
181302
182303fn merge ( mut seqs : Vec < Vec < usize > > ) -> Option < Vec < usize > > {
@@ -219,8 +340,7 @@ mod tests {
219340 use std:: path:: Path ;
220341 use tempfile:: TempDir ;
221342
222- // --- Helper to setup environment ---
223-
343+ // ProjectGraph::new tests
224344 // Creates a file with specific content in the temp directory
225345 fn create_simf_file ( dir : & Path , rel_path : & str , content : & str ) -> PathBuf {
226346 let full_path = dir. join ( rel_path) ;
@@ -238,7 +358,7 @@ mod tests {
238358
239359 // Helper to mock the initial root program parsing
240360 // (Assuming your parser works via a helper function)
241- fn parse_root ( path : & Path ) -> Program {
361+ fn parse_root ( path : & Path ) -> parse :: Program {
242362 parse_and_get_program ( path) . expect ( "Root parsing failed" )
243363 }
244364
@@ -273,10 +393,8 @@ mod tests {
273393
274394 #[ test]
275395 fn test_c3_simple_import ( ) {
276-
277396 let temp_dir = TempDir :: new ( ) . unwrap ( ) ;
278- let root_path =
279- create_simf_file ( temp_dir. path ( ) , "root.simf" , "use std::math::some_func;" ) ;
397+ let root_path = create_simf_file ( temp_dir. path ( ) , "root.simf" , "use std::math::some_func;" ) ;
280398 create_simf_file ( temp_dir. path ( ) , "libs/std/math.simf" , "" ) ;
281399
282400 let mut lib_map = HashMap :: new ( ) ;
@@ -377,12 +495,9 @@ mod tests {
377495
378496 let order = graph. c3_linearize ( ) . expect ( "C3 failed" ) ;
379497
380- assert_eq ! (
381- order, vec![ 0 , 1 , 2 , 3 ] ,
382- ) ;
498+ assert_eq ! ( order, vec![ 0 , 1 , 2 , 3 ] , ) ;
383499 }
384500
385-
386501 #[ test]
387502 fn test_cyclic_dependency ( ) {
388503 // Setup:
@@ -409,8 +524,6 @@ mod tests {
409524 let config = LibConfig :: new ( lib_map, & a_path) ;
410525 let graph = ProjectGraph :: new ( & config, & root_program) . expect ( "Graph build failed" ) ;
411526
412- println ! ( "Graph dependencies: {:?}" , graph. dependencies) ;
413- println ! ( "lookup: {:?}" , graph. lookup) ;
414527 assert_eq ! ( graph. modules. len( ) , 2 , "Should only have A and B" ) ;
415528
416529 // A depends on B
@@ -449,7 +562,6 @@ mod tests {
449562 matches ! ( order, C3Error :: CycleDetected ( _) ) ;
450563 }
451564
452-
453565 #[ test]
454566 fn test_missing_file_error ( ) {
455567 // Setup:
@@ -497,5 +609,4 @@ mod tests {
497609 "Root should have no resolved dependencies"
498610 ) ;
499611 }
500-
501612}
0 commit comments