@@ -5,8 +5,9 @@ use std::collections::{HashMap, VecDeque};
55use std:: path:: { Path , PathBuf } ;
66use std:: sync:: Arc ;
77
8- use crate :: error:: ErrorCollector ;
9- use crate :: parse:: { self , ParseFromStrWithErrors } ;
8+ use crate :: error:: { ErrorCollector , Span } ;
9+ use crate :: parse:: { self , ParseFromStrWithErrors , Visibility } ;
10+ use crate :: str:: Identifier ;
1011use crate :: LibConfig ;
1112
1213/// Represents a single, isolated file in the SimplicityHL project.
@@ -22,13 +23,22 @@ pub struct Module {
2223pub struct ProjectGraph {
2324 /// Arena Pattern: the data itself lives here.
2425 /// A flat vector guarantees that module data is stored contiguously in memory.
25- pub modules : Vec < Module > ,
26+ pub ( self ) modules : Vec < Module > ,
27+
28+ /// The configuration environment.
29+ /// Used to resolve xternal library dependencies and invoke their associated functions.
30+ pub config : Arc < LibConfig > ,
2631
2732 /// Fast lookup: File Path -> Module ID.
2833 /// A reverse index mapping absolute file paths to their internal IDs.
2934 /// This solves the duplication problem, ensuring each file is only parsed once.
3035 pub lookup : HashMap < PathBuf , usize > ,
3136
37+ /// Fast lookup: Module ID -> File Path.
38+ /// A direct index mapping internal IDs back to their absolute file paths.
39+ /// This serves as the exact inverse of the `lookup` map.
40+ pub paths : Vec < PathBuf > ,
41+
3242 /// The Adjacency List: Defines the Directed acyclic Graph (DAG) of imports.
3343 ///
3444 /// The Key (`usize`) is the ID of a "Parent" module (the file doing the importing).
@@ -39,6 +49,18 @@ pub struct ProjectGraph {
3949 pub dependencies : HashMap < usize , Vec < usize > > ,
4050}
4151
52+ #[ derive( Clone , Debug ) ]
53+ pub struct Resolution {
54+ pub visibility : Visibility ,
55+ }
56+
57+ pub struct Program {
58+ //pub graph: ProjectGraph,
59+ pub items : Arc < [ parse:: Item ] > ,
60+ pub scope_items : Vec < HashMap < Identifier , Resolution > > ,
61+ pub span : Span ,
62+ }
63+
4264#[ derive( Debug ) ]
4365pub enum C3Error {
4466 CycleDetected ( Vec < usize > ) ,
@@ -91,15 +113,16 @@ fn merge(mut seqs: Vec<Vec<usize>>) -> Option<Vec<usize>> {
91113}
92114
93115impl ProjectGraph {
94- pub fn new ( lib_cfg : & LibConfig , root_program : & parse:: Program ) -> Result < Self , String > {
116+ pub fn new ( config : Arc < LibConfig > , root_program : & parse:: Program ) -> Result < Self , String > {
95117 let mut modules: Vec < Module > = vec ! [ Module {
96118 parsed_program: root_program. clone( ) ,
97119 } ] ;
98120 let mut lookup: HashMap < PathBuf , usize > = HashMap :: new ( ) ;
121+ let mut paths: Vec < PathBuf > = vec ! [ config. root_path. clone( ) ] ;
99122 let mut dependencies: HashMap < usize , Vec < usize > > = HashMap :: new ( ) ;
100123
101124 let root_id = 0 ;
102- lookup. insert ( lib_cfg . root_path . clone ( ) , root_id) ;
125+ lookup. insert ( config . root_path . clone ( ) , root_id) ;
103126 dependencies. insert ( root_id, Vec :: new ( ) ) ;
104127
105128 // Implementation of the standard BFS algorithm with memoization and queue
@@ -112,7 +135,7 @@ impl ProjectGraph {
112135
113136 for elem in current_program. items ( ) {
114137 if let parse:: Item :: Use ( use_decl) = elem {
115- if let Ok ( path) = lib_cfg . get_full_path ( use_decl) {
138+ if let Ok ( path) = config . get_full_path ( use_decl) {
116139 pending_imports. push ( path) ;
117140 }
118141 }
@@ -140,6 +163,7 @@ impl ProjectGraph {
140163 parsed_program : program,
141164 } ) ;
142165 lookup. insert ( path. clone ( ) , last_ind) ;
166+ paths. push ( path. clone ( ) ) ;
143167 dependencies. entry ( curr_id) . or_default ( ) . push ( last_ind) ;
144168
145169 queue. push_back ( last_ind) ;
@@ -148,7 +172,9 @@ impl ProjectGraph {
148172
149173 Ok ( Self {
150174 modules,
175+ config,
151176 lookup,
177+ paths,
152178 dependencies,
153179 } )
154180 }
@@ -202,4 +228,115 @@ impl ProjectGraph {
202228
203229 Ok ( result)
204230 }
231+
232+ fn process_use_item (
233+ scope_items : & mut [ HashMap < Identifier , Resolution > ] ,
234+ file_id : usize ,
235+ ind : usize ,
236+ elem : & Identifier ,
237+ use_decl_visibility : Visibility ,
238+ ) -> Result < ( ) , String > {
239+ if matches ! (
240+ scope_items[ ind] [ elem] . visibility,
241+ parse:: Visibility :: Private
242+ ) {
243+ return Err ( format ! (
244+ "Function {} is private and cannot be used." ,
245+ elem. as_inner( )
246+ ) ) ;
247+ }
248+
249+ scope_items[ file_id] . insert (
250+ elem. clone ( ) ,
251+ Resolution {
252+ visibility : use_decl_visibility,
253+ } ,
254+ ) ;
255+
256+ Ok ( ( ) )
257+ }
258+
259+ fn register_def (
260+ items : & mut Vec < parse:: Item > ,
261+ scope : & mut HashMap < Identifier , Resolution > ,
262+ item : & parse:: Item ,
263+ name : Identifier ,
264+ vis : & parse:: Visibility ,
265+ ) {
266+ items. push ( item. clone ( ) ) ;
267+ scope. insert (
268+ name,
269+ Resolution {
270+ visibility : vis. clone ( ) ,
271+ } ,
272+ ) ;
273+ }
274+
275+ // TODO: @LesterEvSe, consider processing more than one error at a time
276+ fn build_program ( & self , order : & Vec < usize > ) -> Result < Program , String > {
277+ let mut items: Vec < parse:: Item > = Vec :: new ( ) ;
278+ let mut scope_items: Vec < HashMap < Identifier , Resolution > > =
279+ vec ! [ HashMap :: new( ) ; order. len( ) ] ;
280+
281+ for & file_id in order {
282+ let program_items = self . modules [ file_id] . parsed_program . items ( ) ;
283+
284+ for elem in program_items {
285+ match elem {
286+ parse:: Item :: Use ( use_decl) => {
287+ let full_path = self . config . get_full_path ( use_decl) ?;
288+ let ind = self . lookup [ & full_path] ;
289+ let visibility = use_decl. visibility ( ) ;
290+
291+ let use_targets = match use_decl. items ( ) {
292+ parse:: UseItems :: Single ( elem) => std:: slice:: from_ref ( elem) ,
293+ parse:: UseItems :: List ( elems) => elems. as_slice ( ) ,
294+ } ;
295+
296+ for target in use_targets {
297+ ProjectGraph :: process_use_item (
298+ & mut scope_items,
299+ file_id,
300+ ind,
301+ target,
302+ visibility. clone ( ) ,
303+ ) ?;
304+ }
305+ }
306+ parse:: Item :: TypeAlias ( alias) => {
307+ Self :: register_def (
308+ & mut items,
309+ & mut scope_items[ file_id] ,
310+ elem,
311+ alias. name ( ) . clone ( ) . into ( ) ,
312+ alias. visibility ( ) ,
313+ ) ;
314+ }
315+ parse:: Item :: Function ( function) => {
316+ Self :: register_def (
317+ & mut items,
318+ & mut scope_items[ file_id] ,
319+ elem,
320+ function. name ( ) . clone ( ) . into ( ) ,
321+ function. visibility ( ) ,
322+ ) ;
323+ }
324+ parse:: Item :: Module => { }
325+ }
326+ }
327+ }
328+
329+ Ok ( Program {
330+ items : items. into ( ) ,
331+ scope_items,
332+ span : * self . modules [ 0 ] . parsed_program . as_ref ( ) ,
333+ } )
334+ }
335+
336+ pub fn resolve_complication_order ( & self ) -> Result < Program , String > {
337+ // TODO: @LesterEvSe, resolve errors more appropriately
338+ let mut order = self . c3_linearize ( ) . unwrap ( ) ;
339+ order. reverse ( ) ;
340+ self . build_program ( & order)
341+ }
205342}
0 commit comments