@@ -9,17 +9,19 @@ use miniscript::iter::{Tree, TreeLike};
99use simplicity:: jet:: Elements ;
1010
1111use crate :: debug:: { CallTracker , DebugSymbols , TrackedCallName } ;
12+ use crate :: driver:: FileResolutions ;
1213use crate :: error:: { Error , RichError , Span , WithSpan } ;
1314use crate :: num:: { NonZeroPow2Usize , Pow2Usize } ;
1415use crate :: parse:: MatchPattern ;
1516use crate :: pattern:: Pattern ;
17+ use crate :: resolution:: SourceName ;
1618use crate :: str:: { AliasName , FunctionName , Identifier , ModuleName , WitnessName } ;
1719use crate :: types:: {
1820 AliasedType , ResolvedType , StructuralType , TypeConstructible , TypeDeconstructible , UIntType ,
1921} ;
2022use crate :: value:: { UIntValue , Value } ;
2123use crate :: witness:: { Parameters , WitnessTypes , WitnessValues } ;
22- use crate :: { impl_eq_hash, parse} ;
24+ use crate :: { driver , impl_eq_hash, parse} ;
2325
2426/// A program consists of the main function.
2527///
@@ -520,8 +522,12 @@ impl TreeLike for ExprTree<'_> {
520522/// 2. Resolving type aliases
521523/// 3. Assigning types to each witness expression
522524/// 4. Resolving calls to custom functions
523- #[ derive( Clone , Debug , Eq , PartialEq , Default ) ]
525+ #[ derive( Clone , Debug , Eq , PartialEq ) ]
524526struct Scope {
527+ resolutions : Arc < [ FileResolutions ] > ,
528+ paths : Arc < [ SourceName ] > ,
529+ file_id : usize , // ID of the file from which the function is called.
530+
525531 variables : Vec < HashMap < Identifier , ResolvedType > > ,
526532 aliases : HashMap < AliasName , ResolvedType > ,
527533 parameters : HashMap < WitnessName , ResolvedType > ,
@@ -531,7 +537,44 @@ struct Scope {
531537 call_tracker : CallTracker ,
532538}
533539
540+ impl Default for Scope {
541+ fn default ( ) -> Self {
542+ Self {
543+ resolutions : Arc :: from ( [ ] ) ,
544+ paths : Arc :: from ( [ ] ) ,
545+ file_id : 0 ,
546+ variables : Vec :: new ( ) ,
547+ aliases : HashMap :: new ( ) ,
548+ parameters : HashMap :: new ( ) ,
549+ witnesses : HashMap :: new ( ) ,
550+ functions : HashMap :: new ( ) ,
551+ is_main : false ,
552+ call_tracker : CallTracker :: default ( ) ,
553+ }
554+ }
555+ }
556+
534557impl Scope {
558+ pub fn new ( resolutions : Arc < [ FileResolutions ] > , paths : Arc < [ SourceName ] > ) -> Self {
559+ Self {
560+ resolutions,
561+ paths,
562+ file_id : 0 ,
563+ variables : Vec :: new ( ) ,
564+ aliases : HashMap :: new ( ) ,
565+ parameters : HashMap :: new ( ) ,
566+ witnesses : HashMap :: new ( ) ,
567+ functions : HashMap :: new ( ) ,
568+ is_main : false ,
569+ call_tracker : CallTracker :: default ( ) ,
570+ }
571+ }
572+
573+ /// Access to current function file id.
574+ pub fn file_id ( & self ) -> usize {
575+ self . file_id
576+ }
577+
535578 /// Check if the current scope is topmost.
536579 pub fn is_topmost ( & self ) -> bool {
537580 self . variables . is_empty ( )
@@ -542,6 +585,11 @@ impl Scope {
542585 self . variables . push ( HashMap :: new ( ) ) ;
543586 }
544587
588+ pub fn push_function_scope ( & mut self , file_id : usize ) {
589+ self . push_scope ( ) ;
590+ self . file_id = file_id;
591+ }
592+
545593 /// Push the scope of the main function onto the stack.
546594 ///
547595 /// ## Panics
@@ -564,6 +612,11 @@ impl Scope {
564612 self . variables . pop ( ) . expect ( "Stack is empty" ) ;
565613 }
566614
615+ pub fn pop_function_scope ( & mut self , previous_file_id : usize ) {
616+ self . pop_scope ( ) ;
617+ self . file_id = previous_file_id;
618+ }
619+
567620 /// Pop the scope of the main function from the stack.
568621 ///
569622 /// ## Panics
@@ -693,9 +746,39 @@ impl Scope {
693746 }
694747 }
695748
696- /// Get the definition of a custom function.
697- pub fn get_function ( & self , name : & FunctionName ) -> Option < & CustomFunction > {
698- self . functions . get ( name)
749+ /// Get the definition of a custom function with visibility and existence checks.
750+ ///
751+ /// # Errors
752+ ///
753+ /// - `Error::FileNotFound`: The specified `file_id` does not exist in the resolutions.
754+ /// - `Error::FunctionUndefined`: The function is not found in the file's scope OR not defined globally.
755+ /// - `Error::FunctionIsPrivate`: The function exists but is private (and thus not accessible).
756+ pub fn get_function ( & self , name : & FunctionName ) -> Result < & CustomFunction , Error > {
757+ // The order of the errors is important!
758+ let function = self
759+ . functions
760+ . get ( name)
761+ . ok_or_else ( || Error :: FunctionUndefined ( name. clone ( ) ) ) ?;
762+
763+ let source_name = self . paths [ self . file_id ] . clone ( ) ;
764+
765+ let file_scope = match source_name {
766+ SourceName :: Real ( path) => self
767+ . resolutions
768+ . get ( self . file_id )
769+ . ok_or ( Error :: FileNotFound ( path) ) ?,
770+ SourceName :: Virtual ( _) => {
771+ return Ok ( function) ;
772+ }
773+ } ;
774+
775+ let identifier: Identifier = name. clone ( ) . into ( ) ;
776+
777+ if file_scope. contains_key ( & identifier) {
778+ Ok ( function)
779+ } else {
780+ Err ( Error :: FunctionIsPrivate ( name. clone ( ) ) )
781+ }
699782 }
700783
701784 /// Track a call expression with its span.
@@ -718,9 +801,10 @@ trait AbstractSyntaxTree: Sized {
718801}
719802
720803impl Program {
721- pub fn analyze ( from : & parse:: Program ) -> Result < Self , RichError > {
804+ // TODO: Add visibility check inside program
805+ pub fn analyze ( from : & driver:: Program ) -> Result < Self , RichError > {
722806 let unit = ResolvedType :: unit ( ) ;
723- let mut scope = Scope :: default ( ) ;
807+ let mut scope = Scope :: new ( Arc :: from ( from . resolutions ( ) ) , Arc :: from ( from . paths ( ) ) ) ;
724808 let items = from
725809 . items ( )
726810 . iter ( )
@@ -746,36 +830,37 @@ impl Program {
746830}
747831
748832impl AbstractSyntaxTree for Item {
749- type From = parse :: Item ;
833+ type From = driver :: Item ;
750834
751835 fn analyze ( from : & Self :: From , ty : & ResolvedType , scope : & mut Scope ) -> Result < Self , RichError > {
752836 assert ! ( ty. is_unit( ) , "Items cannot return anything" ) ;
753837 assert ! ( scope. is_topmost( ) , "Items live in the topmost scope only" ) ;
754838
755839 match from {
756- parse :: Item :: TypeAlias ( alias) => {
840+ driver :: Item :: TypeAlias ( alias) => {
757841 scope
758842 . insert_alias ( alias. name ( ) . clone ( ) , alias. ty ( ) . clone ( ) )
759843 . with_span ( alias) ?;
760844 Ok ( Self :: TypeAlias )
761845 }
762- parse :: Item :: Function ( function) => {
846+ driver :: Item :: Function ( function) => {
763847 Function :: analyze ( function, ty, scope) . map ( Self :: Function )
764848 }
765- parse:: Item :: Use ( _) => todo ! ( ) ,
766- parse:: Item :: Module => Ok ( Self :: Module ) ,
849+ driver:: Item :: Module => Ok ( Self :: Module ) ,
767850 }
768851 }
769852}
770853
771854impl AbstractSyntaxTree for Function {
772- type From = parse :: Function ;
855+ type From = driver :: Function ;
773856
774857 fn analyze ( from : & Self :: From , ty : & ResolvedType , scope : & mut Scope ) -> Result < Self , RichError > {
775858 assert ! ( ty. is_unit( ) , "Function definitions cannot return anything" ) ;
776859 assert ! ( scope. is_topmost( ) , "Items live in the topmost scope only" ) ;
860+ let previous_file_id = scope. file_id ( ) ;
777861
778862 if from. name ( ) . as_inner ( ) != "main" {
863+ let file_id = from. file_id ( ) ;
779864 let params = from
780865 . params ( )
781866 . iter ( )
@@ -792,12 +877,12 @@ impl AbstractSyntaxTree for Function {
792877 . map ( |aliased| scope. resolve ( aliased) . with_span ( from) )
793878 . transpose ( ) ?
794879 . unwrap_or_else ( ResolvedType :: unit) ;
795- scope. push_scope ( ) ;
880+ scope. push_function_scope ( file_id ) ;
796881 for param in params. iter ( ) {
797882 scope. insert_variable ( param. identifier ( ) . clone ( ) , param. ty ( ) . clone ( ) ) ;
798883 }
799884 let body = Expression :: analyze ( from. body ( ) , & ret, scope) . map ( Arc :: new) ?;
800- scope. pop_scope ( ) ;
885+ scope. pop_function_scope ( previous_file_id ) ;
801886 debug_assert ! ( scope. is_topmost( ) ) ;
802887 let function = CustomFunction { params, body } ;
803888 scope
@@ -1322,14 +1407,9 @@ impl AbstractSyntaxTree for CallName {
13221407 . get_function ( name)
13231408 . cloned ( )
13241409 . map ( Self :: Custom )
1325- . ok_or ( Error :: FunctionUndefined ( name. clone ( ) ) )
13261410 . with_span ( from) ,
13271411 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) ?;
1412+ let function = scope. get_function ( name) . cloned ( ) . with_span ( from) ?;
13331413 // A function that is used in a array fold has the signature:
13341414 // fn f(element: E, accumulator: A) -> A
13351415 if function. params ( ) . len ( ) != 2 || function. params ( ) [ 1 ] . ty ( ) != function. body ( ) . ty ( )
@@ -1340,11 +1420,7 @@ impl AbstractSyntaxTree for CallName {
13401420 }
13411421 }
13421422 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) ?;
1423+ let function = scope. get_function ( name) . cloned ( ) . with_span ( from) ?;
13481424 // A function that is used in a list fold has the signature:
13491425 // fn f(element: E, accumulator: A) -> A
13501426 if function. params ( ) . len ( ) != 2 || function. params ( ) [ 1 ] . ty ( ) != function. body ( ) . ty ( )
@@ -1355,11 +1431,7 @@ impl AbstractSyntaxTree for CallName {
13551431 }
13561432 }
13571433 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) ?;
1434+ let function = scope. get_function ( name) . cloned ( ) . with_span ( from) ?;
13631435 // A function that is used in a for-while loop has the signature:
13641436 // fn f(accumulator: A, readonly_context: C, counter: u{N}) -> Either<B, A>
13651437 // where
@@ -1435,6 +1507,9 @@ fn analyze_named_module(
14351507 from : & parse:: ModuleProgram ,
14361508) -> Result < HashMap < WitnessName , Value > , RichError > {
14371509 let unit = ResolvedType :: unit ( ) ;
1510+
1511+ // IMPORTANT! If modules allow imports, then we need to consider
1512+ // passing the resolution conetxt by calling `Scope::new(resolutions)`
14381513 let mut scope = Scope :: default ( ) ;
14391514 let items = from
14401515 . items ( )
0 commit comments