@@ -9,6 +9,7 @@ use miniscript::iter::{Tree, TreeLike};
99use simplicity:: jet:: Elements ;
1010
1111use crate :: debug:: { CallTracker , DebugSymbols , TrackedCallName } ;
12+ use crate :: driver:: ProgramResolutions ;
1213use crate :: error:: { Error , RichError , Span , WithSpan } ;
1314use crate :: num:: { NonZeroPow2Usize , Pow2Usize } ;
1415use crate :: parse:: MatchPattern ;
@@ -19,7 +20,7 @@ use crate::types::{
1920} ;
2021use crate :: value:: { UIntValue , Value } ;
2122use crate :: witness:: { Parameters , WitnessTypes , WitnessValues } ;
22- use crate :: { impl_eq_hash, parse} ;
23+ use crate :: { driver , impl_eq_hash, parse, SourceName } ;
2324
2425/// A program consists of the main function.
2526///
@@ -520,8 +521,12 @@ impl TreeLike for ExprTree<'_> {
520521/// 2. Resolving type aliases
521522/// 3. Assigning types to each witness expression
522523/// 4. Resolving calls to custom functions
523- #[ derive( Clone , Debug , Eq , PartialEq , Default ) ]
524+ #[ derive( Clone , Debug , Eq , PartialEq ) ]
524525struct Scope {
526+ resolutions : ProgramResolutions ,
527+ paths : Arc < [ SourceName ] > ,
528+ file_id : usize , // ID of the file from which the function is called.
529+
525530 variables : Vec < HashMap < Identifier , ResolvedType > > ,
526531 aliases : HashMap < AliasName , ResolvedType > ,
527532 parameters : HashMap < WitnessName , ResolvedType > ,
@@ -531,7 +536,44 @@ struct Scope {
531536 call_tracker : CallTracker ,
532537}
533538
539+ impl Default for Scope {
540+ fn default ( ) -> Self {
541+ Self {
542+ resolutions : Arc :: from ( [ ] ) ,
543+ paths : Arc :: from ( [ ] ) ,
544+ file_id : 0 ,
545+ variables : Vec :: new ( ) ,
546+ aliases : HashMap :: new ( ) ,
547+ parameters : HashMap :: new ( ) ,
548+ witnesses : HashMap :: new ( ) ,
549+ functions : HashMap :: new ( ) ,
550+ is_main : false ,
551+ call_tracker : CallTracker :: default ( ) ,
552+ }
553+ }
554+ }
555+
534556impl Scope {
557+ pub fn new ( resolutions : ProgramResolutions , paths : Arc < [ SourceName ] > ) -> Self {
558+ Self {
559+ resolutions,
560+ paths,
561+ file_id : 0 ,
562+ variables : Vec :: new ( ) ,
563+ aliases : HashMap :: new ( ) ,
564+ parameters : HashMap :: new ( ) ,
565+ witnesses : HashMap :: new ( ) ,
566+ functions : HashMap :: new ( ) ,
567+ is_main : false ,
568+ call_tracker : CallTracker :: default ( ) ,
569+ }
570+ }
571+
572+ /// Access to current function file id.
573+ pub fn file_id ( & self ) -> usize {
574+ self . file_id
575+ }
576+
535577 /// Check if the current scope is topmost.
536578 pub fn is_topmost ( & self ) -> bool {
537579 self . variables . is_empty ( )
@@ -542,6 +584,11 @@ impl Scope {
542584 self . variables . push ( HashMap :: new ( ) ) ;
543585 }
544586
587+ pub fn push_function_scope ( & mut self , file_id : usize ) {
588+ self . push_scope ( ) ;
589+ self . file_id = file_id;
590+ }
591+
545592 /// Push the scope of the main function onto the stack.
546593 ///
547594 /// ## Panics
@@ -564,6 +611,11 @@ impl Scope {
564611 self . variables . pop ( ) . expect ( "Stack is empty" ) ;
565612 }
566613
614+ pub fn pop_function_scope ( & mut self , previous_file_id : usize ) {
615+ self . pop_scope ( ) ;
616+ self . file_id = previous_file_id;
617+ }
618+
567619 /// Pop the scope of the main function from the stack.
568620 ///
569621 /// ## Panics
@@ -693,9 +745,39 @@ impl Scope {
693745 }
694746 }
695747
696- /// Get the definition of a custom function.
697- pub fn get_function ( & self , name : & FunctionName ) -> Option < & CustomFunction > {
698- self . functions . get ( name)
748+ /// Get the definition of a custom function with visibility and existence checks.
749+ ///
750+ /// # Errors
751+ ///
752+ /// - `Error::FileNotFound`: The specified `file_id` does not exist in the resolutions.
753+ /// - `Error::FunctionUndefined`: The function is not found in the file's scope OR not defined globally.
754+ /// - `Error::FunctionIsPrivate`: The function exists but is private (and thus not accessible).
755+ pub fn get_function ( & self , name : & FunctionName ) -> Result < & CustomFunction , Error > {
756+ // The order of the errors is important!
757+ let function = self
758+ . functions
759+ . get ( name)
760+ . ok_or_else ( || Error :: FunctionUndefined ( name. clone ( ) ) ) ?;
761+
762+ let source_name = self . paths [ self . file_id ] . clone ( ) ;
763+
764+ let file_scope = match source_name {
765+ SourceName :: Real ( path) => self
766+ . resolutions
767+ . get ( self . file_id )
768+ . ok_or ( Error :: FileNotFound ( path) ) ?,
769+ SourceName :: Virtual ( _) => {
770+ return Ok ( function) ;
771+ }
772+ } ;
773+
774+ let identifier: Identifier = name. clone ( ) . into ( ) ;
775+
776+ if file_scope. contains_key ( & identifier) {
777+ Ok ( function)
778+ } else {
779+ Err ( Error :: FunctionIsPrivate ( name. clone ( ) ) )
780+ }
699781 }
700782
701783 /// Track a call expression with its span.
@@ -718,9 +800,10 @@ trait AbstractSyntaxTree: Sized {
718800}
719801
720802impl Program {
721- pub fn analyze ( from : & parse:: Program ) -> Result < Self , RichError > {
803+ // TODO: Add visibility check inside program
804+ pub fn analyze ( from : & driver:: Program ) -> Result < Self , RichError > {
722805 let unit = ResolvedType :: unit ( ) ;
723- let mut scope = Scope :: default ( ) ;
806+ let mut scope = Scope :: new ( Arc :: from ( from . resolutions ( ) ) , Arc :: from ( from . paths ( ) ) ) ;
724807 let items = from
725808 . items ( )
726809 . iter ( )
@@ -746,36 +829,37 @@ impl Program {
746829}
747830
748831impl AbstractSyntaxTree for Item {
749- type From = parse :: Item ;
832+ type From = driver :: Item ;
750833
751834 fn analyze ( from : & Self :: From , ty : & ResolvedType , scope : & mut Scope ) -> Result < Self , RichError > {
752835 assert ! ( ty. is_unit( ) , "Items cannot return anything" ) ;
753836 assert ! ( scope. is_topmost( ) , "Items live in the topmost scope only" ) ;
754837
755838 match from {
756- parse :: Item :: TypeAlias ( alias) => {
839+ driver :: Item :: TypeAlias ( alias) => {
757840 scope
758841 . insert_alias ( alias. name ( ) . clone ( ) , alias. ty ( ) . clone ( ) )
759842 . with_span ( alias) ?;
760843 Ok ( Self :: TypeAlias )
761844 }
762- parse :: Item :: Function ( function) => {
845+ driver :: Item :: Function ( function) => {
763846 Function :: analyze ( function, ty, scope) . map ( Self :: Function )
764847 }
765- parse:: Item :: Use ( _) => todo ! ( ) ,
766- parse:: Item :: Module => Ok ( Self :: Module ) ,
848+ driver:: Item :: Module => Ok ( Self :: Module ) ,
767849 }
768850 }
769851}
770852
771853impl AbstractSyntaxTree for Function {
772- type From = parse :: Function ;
854+ type From = driver :: Function ;
773855
774856 fn analyze ( from : & Self :: From , ty : & ResolvedType , scope : & mut Scope ) -> Result < Self , RichError > {
775857 assert ! ( ty. is_unit( ) , "Function definitions cannot return anything" ) ;
776858 assert ! ( scope. is_topmost( ) , "Items live in the topmost scope only" ) ;
859+ let previous_file_id = scope. file_id ( ) ;
777860
778861 if from. name ( ) . as_inner ( ) != "main" {
862+ let file_id = from. file_id ( ) ;
779863 let params = from
780864 . params ( )
781865 . iter ( )
@@ -792,12 +876,12 @@ impl AbstractSyntaxTree for Function {
792876 . map ( |aliased| scope. resolve ( aliased) . with_span ( from) )
793877 . transpose ( ) ?
794878 . unwrap_or_else ( ResolvedType :: unit) ;
795- scope. push_scope ( ) ;
879+ scope. push_function_scope ( file_id ) ;
796880 for param in params. iter ( ) {
797881 scope. insert_variable ( param. identifier ( ) . clone ( ) , param. ty ( ) . clone ( ) ) ;
798882 }
799883 let body = Expression :: analyze ( from. body ( ) , & ret, scope) . map ( Arc :: new) ?;
800- scope. pop_scope ( ) ;
884+ scope. pop_function_scope ( previous_file_id ) ;
801885 debug_assert ! ( scope. is_topmost( ) ) ;
802886 let function = CustomFunction { params, body } ;
803887 scope
@@ -1322,14 +1406,9 @@ impl AbstractSyntaxTree for CallName {
13221406 . get_function ( name)
13231407 . cloned ( )
13241408 . map ( Self :: Custom )
1325- . ok_or ( Error :: FunctionUndefined ( name. clone ( ) ) )
13261409 . with_span ( from) ,
13271410 parse:: CallName :: ArrayFold ( name, size) => {
1328- let function = scope
1329- . get_function ( name)
1330- . cloned ( )
1331- . ok_or ( Error :: FunctionUndefined ( name. clone ( ) ) )
1332- . with_span ( from) ?;
1411+ let function = scope. get_function ( name) . cloned ( ) . with_span ( from) ?;
13331412 // A function that is used in a array fold has the signature:
13341413 // fn f(element: E, accumulator: A) -> A
13351414 if function. params ( ) . len ( ) != 2 || function. params ( ) [ 1 ] . ty ( ) != function. body ( ) . ty ( )
@@ -1340,11 +1419,7 @@ impl AbstractSyntaxTree for CallName {
13401419 }
13411420 }
13421421 parse:: CallName :: Fold ( name, bound) => {
1343- let function = scope
1344- . get_function ( name)
1345- . cloned ( )
1346- . ok_or ( Error :: FunctionUndefined ( name. clone ( ) ) )
1347- . with_span ( from) ?;
1422+ let function = scope. get_function ( name) . cloned ( ) . with_span ( from) ?;
13481423 // A function that is used in a list fold has the signature:
13491424 // fn f(element: E, accumulator: A) -> A
13501425 if function. params ( ) . len ( ) != 2 || function. params ( ) [ 1 ] . ty ( ) != function. body ( ) . ty ( )
@@ -1355,11 +1430,7 @@ impl AbstractSyntaxTree for CallName {
13551430 }
13561431 }
13571432 parse:: CallName :: ForWhile ( name) => {
1358- let function = scope
1359- . get_function ( name)
1360- . cloned ( )
1361- . ok_or ( Error :: FunctionUndefined ( name. clone ( ) ) )
1362- . with_span ( from) ?;
1433+ let function = scope. get_function ( name) . cloned ( ) . with_span ( from) ?;
13631434 // A function that is used in a for-while loop has the signature:
13641435 // fn f(accumulator: A, readonly_context: C, counter: u{N}) -> Either<B, A>
13651436 // where
@@ -1435,6 +1506,9 @@ fn analyze_named_module(
14351506 from : & parse:: ModuleProgram ,
14361507) -> Result < HashMap < WitnessName , Value > , RichError > {
14371508 let unit = ResolvedType :: unit ( ) ;
1509+
1510+ // IMPORTANT! If modules allow imports, then we need to consider
1511+ // passing the resolution conetxt by calling `Scope::new(resolutions)`
14381512 let mut scope = Scope :: default ( ) ;
14391513 let items = from
14401514 . items ( )
0 commit comments