@@ -24,17 +24,20 @@ pub use leo_ast::{Ast, Program};
2424use leo_ast:: { NetworkName , NodeBuilder , Stub } ;
2525use leo_errors:: { CompilerError , Handler , Result } ;
2626use leo_passes:: * ;
27- use leo_span:: { Symbol , source_map:: FileName , with_session_globals} ;
27+ use leo_span:: {
28+ Symbol ,
29+ file_source:: { DiskFileSource , FileSource } ,
30+ source_map:: FileName ,
31+ with_session_globals,
32+ } ;
2833
2934use std:: {
30- ffi:: OsStr ,
3135 fs,
3236 path:: { Path , PathBuf } ,
3337 rc:: Rc ,
3438} ;
3539
3640use indexmap:: { IndexMap , IndexSet } ;
37- use walkdir:: WalkDir ;
3841
3942/// A single compiled program with its bytecode and ABI.
4043pub struct CompiledProgram {
@@ -336,30 +339,28 @@ impl Compiler {
336339 ///
337340 /// Returns `Err(CompilerError)` if reading any file fails.
338341 fn read_sources_and_modules (
342+ file_source : & impl FileSource ,
339343 entry_file_path : impl AsRef < Path > ,
340344 source_directory : impl AsRef < Path > ,
341345 ) -> Result < ( String , Vec < ( String , FileName ) > ) > {
342- // Read the contents of the main source file.
343- let source = fs:: read_to_string ( & entry_file_path)
344- . map_err ( |e| CompilerError :: file_read_error ( entry_file_path. as_ref ( ) . display ( ) . to_string ( ) , e) ) ?;
345-
346- // Walk all files under source_directory recursively, excluding the main source file itself.
347- let files = WalkDir :: new ( source_directory)
348- . into_iter ( )
349- . filter_map ( Result :: ok)
350- . filter ( |e| {
351- e. file_type ( ) . is_file ( )
352- && e. path ( ) != entry_file_path. as_ref ( )
353- && e. path ( ) . extension ( ) == Some ( OsStr :: new ( "leo" ) )
354- } )
355- . collect :: < Vec < _ > > ( ) ;
346+ let entry_file_path = entry_file_path. as_ref ( ) ;
347+ let source_directory = source_directory. as_ref ( ) ;
356348
357- // Read all module files and pair with FileName immediately
358- let mut modules = Vec :: new ( ) ;
359- for file in & files {
360- let module_source = fs:: read_to_string ( file. path ( ) )
361- . map_err ( |e| CompilerError :: file_read_error ( file. path ( ) . display ( ) . to_string ( ) , e) ) ?;
362- modules. push ( ( module_source, FileName :: Real ( file. path ( ) . into ( ) ) ) ) ;
349+ // Read the contents of the main source file.
350+ let source = file_source
351+ . read_file ( entry_file_path)
352+ . map_err ( |e| CompilerError :: file_read_error ( entry_file_path. display ( ) . to_string ( ) , e) ) ?;
353+
354+ let files = file_source
355+ . list_leo_files ( source_directory, entry_file_path)
356+ . map_err ( |e| CompilerError :: file_read_error ( source_directory. display ( ) . to_string ( ) , e) ) ?;
357+
358+ let mut modules = Vec :: with_capacity ( files. len ( ) ) ;
359+ for path in files {
360+ let module_source = file_source
361+ . read_file ( & path)
362+ . map_err ( |e| CompilerError :: file_read_error ( path. display ( ) . to_string ( ) , e) ) ?;
363+ modules. push ( ( module_source, FileName :: Real ( path) ) ) ;
363364 }
364365
365366 Ok ( ( source, modules) )
@@ -371,7 +372,17 @@ impl Compiler {
371372 entry_file_path : impl AsRef < Path > ,
372373 source_directory : impl AsRef < Path > ,
373374 ) -> Result < Compiled > {
374- let ( source, modules_owned) = Self :: read_sources_and_modules ( & entry_file_path, & source_directory) ?;
375+ self . compile_from_directory_with_file_source ( entry_file_path, source_directory, & DiskFileSource )
376+ }
377+
378+ /// Compiles a program from a source file using the given file source.
379+ pub fn compile_from_directory_with_file_source (
380+ & mut self ,
381+ entry_file_path : impl AsRef < Path > ,
382+ source_directory : impl AsRef < Path > ,
383+ file_source : & impl FileSource ,
384+ ) -> Result < Compiled > {
385+ let ( source, modules_owned) = Self :: read_sources_and_modules ( file_source, & entry_file_path, & source_directory) ?;
375386
376387 // Convert owned module sources into temporary (&str, FileName) tuples.
377388 let module_refs: Vec < ( & str , FileName ) > =
@@ -387,7 +398,17 @@ impl Compiler {
387398 entry_file_path : impl AsRef < Path > ,
388399 source_directory : impl AsRef < Path > ,
389400 ) -> Result < Program > {
390- let ( source, modules_owned) = Self :: read_sources_and_modules ( & entry_file_path, & source_directory) ?;
401+ self . parse_from_directory_with_file_source ( entry_file_path, source_directory, & DiskFileSource )
402+ }
403+
404+ /// Parses a program from a source file using the given file source.
405+ pub fn parse_from_directory_with_file_source (
406+ & mut self ,
407+ entry_file_path : impl AsRef < Path > ,
408+ source_directory : impl AsRef < Path > ,
409+ file_source : & impl FileSource ,
410+ ) -> Result < Program > {
411+ let ( source, modules_owned) = Self :: read_sources_and_modules ( file_source, & entry_file_path, & source_directory) ?;
391412
392413 // Convert owned module sources into temporary (&str, FileName) tuples.
393414 let module_refs: Vec < ( & str , FileName ) > =
@@ -495,3 +516,59 @@ impl Compiler {
495516 Ok ( ( ) )
496517 }
497518}
519+
520+ #[ cfg( test) ]
521+ mod tests {
522+ use super :: Compiler ;
523+
524+ use leo_ast:: { NetworkName , NodeBuilder } ;
525+ use leo_errors:: Handler ;
526+ use leo_span:: { Symbol , create_session_if_not_set_then, file_source:: InMemoryFileSource } ;
527+
528+ use std:: { path:: PathBuf , rc:: Rc } ;
529+
530+ use indexmap:: IndexMap ;
531+
532+ #[ test]
533+ fn parse_from_directory_in_memory_with_module ( ) {
534+ create_session_if_not_set_then ( |_| {
535+ let mut source = InMemoryFileSource :: new ( ) ;
536+ source. set (
537+ PathBuf :: from ( "/project/src/main.leo" ) ,
538+ concat ! (
539+ "program test.aleo {\n " ,
540+ " fn main() -> u32 {\n " ,
541+ " return utils::helper();\n " ,
542+ " }\n " ,
543+ "}\n " ,
544+ )
545+ . into ( ) ,
546+ ) ;
547+ source. set ( PathBuf :: from ( "/project/src/utils.leo" ) , "fn helper() -> u32 {\n return 42u32;\n }\n " . into ( ) ) ;
548+
549+ let handler = Handler :: default ( ) ;
550+ let node_builder = Rc :: new ( NodeBuilder :: default ( ) ) ;
551+ let mut compiler = Compiler :: new (
552+ Some ( "test" . into ( ) ) ,
553+ false ,
554+ handler,
555+ node_builder,
556+ PathBuf :: from ( "/unused" ) ,
557+ None ,
558+ IndexMap :: new ( ) ,
559+ NetworkName :: TestnetV0 ,
560+ ) ;
561+
562+ let ast = compiler
563+ . parse_from_directory_with_file_source ( "/project/src/main.leo" , "/project/src" , & source)
564+ . unwrap_or_else ( |err| panic ! ( "parsing from in-memory file source failed: {err}" ) ) ;
565+ let utils_key = vec ! [ Symbol :: intern( "utils" ) ] ;
566+
567+ assert ! (
568+ ast. modules. contains_key( & utils_key) ,
569+ "module `utils` should be loaded from the in-memory file source; found keys: {:?}" ,
570+ ast. modules. keys( ) . collect:: <Vec <_>>( )
571+ ) ;
572+ } ) ;
573+ }
574+ }
0 commit comments