From a422027e12f6775d8849a2a7f5c5c0c9f6853e50 Mon Sep 17 00:00:00 2001 From: collin Date: Wed, 1 Jul 2020 21:43:06 -0700 Subject: [PATCH] fix nested import parsing bug --- compiler/src/compiler.rs | 31 ++++++++++++------- compiler/src/constraints/function.rs | 9 ++++-- compiler/src/constraints/mod.rs | 8 +++-- compiler/src/errors/constraints/import.rs | 8 +++-- compiler/src/imports/import_symbol.rs | 20 ++++++++++-- ...rogram_imports.rs => imported_programs.rs} | 8 +++-- compiler/src/imports/mod.rs | 4 +-- compiler/src/imports/package.rs | 18 +++++++---- types/src/errors/error.rs | 11 +++++++ 9 files changed, 85 insertions(+), 32 deletions(-) rename compiler/src/imports/{program_imports.rs => imported_programs.rs} (87%) diff --git a/compiler/src/compiler.rs b/compiler/src/compiler.rs index 7abab1a683..fb589eed7b 100644 --- a/compiler/src/compiler.rs +++ b/compiler/src/compiler.rs @@ -4,7 +4,7 @@ use crate::{ constraints::{generate_constraints, generate_test_constraints, ConstrainedValue}, errors::CompilerError, GroupType, - ProgramImports, + ImportedPrograms, }; use leo_ast::LeoParser; use leo_inputs::LeoInputsParser; @@ -25,7 +25,7 @@ pub struct Compiler> { main_file_path: PathBuf, program: Program, program_inputs: Inputs, - program_imports: ProgramImports, + imported_programs: ImportedPrograms, output: Option>, _engine: PhantomData, } @@ -37,7 +37,7 @@ impl> Compiler { main_file_path: PathBuf::new(), program: Program::new(package_name), program_inputs: Inputs::new(), - program_imports: ProgramImports::new(), + imported_programs: ImportedPrograms::new(), output: None, _engine: PhantomData, } @@ -80,7 +80,9 @@ impl> Compiler { cs: &mut CS, ) -> Result, CompilerError> { let path = self.main_file_path; - generate_constraints(cs, self.program, self.program_inputs.get_inputs()).map_err(|mut error| { + let inputs = self.program_inputs.get_inputs(); + + generate_constraints(cs, self.program, inputs, self.imported_programs).map_err(|mut error| { error.set_path(path); error @@ -88,7 +90,7 @@ impl> Compiler { } pub fn compile_test_constraints(self, cs: &mut TestConstraintSystem) -> Result<(), CompilerError> { - generate_test_constraints::(cs, self.program) + generate_test_constraints::(cs, self.program, self.imported_programs) } fn load_program(&mut self) -> Result { @@ -105,7 +107,7 @@ impl> Compiler { self.program = Program::from(syntax_tree, package_name); self.program_inputs.set_inputs_size(self.program.expected_inputs.len()); - self.program_imports = ProgramImports::from_program(&self.program)?; + self.imported_programs = ImportedPrograms::from_program(&self.program)?; log::debug!("Program parsing complete\n{:#?}", self.program); @@ -136,7 +138,7 @@ impl> Compiler { main_file_path: PathBuf::new(), program, program_inputs, - program_imports: ProgramImports::new(), + imported_programs: ImportedPrograms::new(), output: None, _engine: PhantomData, }) @@ -145,11 +147,16 @@ impl> Compiler { impl> ConstraintSynthesizer for Compiler { fn generate_constraints>(self, cs: &mut CS) -> Result<(), SynthesisError> { - let result = - generate_constraints::<_, G, _>(cs, self.program, self.program_inputs.get_inputs()).map_err(|e| { - log::error!("{}", e); - SynthesisError::Unsatisfiable - })?; + let result = generate_constraints::<_, G, _>( + cs, + self.program, + self.program_inputs.get_inputs(), + self.imported_programs, + ) + .map_err(|e| { + log::error!("{}", e); + SynthesisError::Unsatisfiable + })?; // Write results to file or something log::info!("{}", result); diff --git a/compiler/src/constraints/function.rs b/compiler/src/constraints/function.rs index 9ddad53f1c..8c669eb8b5 100644 --- a/compiler/src/constraints/function.rs +++ b/compiler/src/constraints/function.rs @@ -8,6 +8,7 @@ use crate::{ field_from_input, group_from_input, GroupType, + ImportedPrograms, }; use leo_types::{Expression, Function, InputValue, Integer, Program, Span, Type}; @@ -272,10 +273,14 @@ impl> ConstrainedProgram { self.enforce_function(cs, scope, function_name, function, input_variables) } - pub(crate) fn resolve_definitions(&mut self, program: Program) -> Result<(), ImportError> { + pub(crate) fn resolve_definitions( + &mut self, + program: Program, + _imported_programs: ImportedPrograms, + ) -> Result<(), ImportError> { let program_name = program.name.clone(); - // evaluate and store all imports + // evaluate all import statements and store imported definitions // program // .imports // .into_iter() diff --git a/compiler/src/constraints/mod.rs b/compiler/src/constraints/mod.rs index 714e0ac42d..c9900ebf37 100644 --- a/compiler/src/constraints/mod.rs +++ b/compiler/src/constraints/mod.rs @@ -24,7 +24,7 @@ pub use value::*; pub mod statement; pub use statement::*; -use crate::{errors::CompilerError, GroupType}; +use crate::{errors::CompilerError, GroupType, ImportedPrograms}; use leo_types::{InputValue, Program}; use snarkos_models::{ @@ -36,12 +36,13 @@ pub fn generate_constraints, CS: Constrai cs: &mut CS, program: Program, parameters: Vec>, + imported_programs: ImportedPrograms, ) -> Result, CompilerError> { let mut resolved_program = ConstrainedProgram::new(); let program_name = program.get_name(); let main_function_name = new_scope(program_name.clone(), "main".into()); - resolved_program.resolve_definitions(program)?; + resolved_program.resolve_definitions(program, imported_programs)?; let main = resolved_program .get(&main_function_name) @@ -59,13 +60,14 @@ pub fn generate_constraints, CS: Constrai pub fn generate_test_constraints>( cs: &mut TestConstraintSystem, program: Program, + imported_programs: ImportedPrograms, ) -> Result<(), CompilerError> { let mut resolved_program = ConstrainedProgram::::new(); let program_name = program.get_name(); let tests = program.tests.clone(); - resolved_program.resolve_definitions(program)?; + resolved_program.resolve_definitions(program, imported_programs)?; log::info!("Running {} tests", tests.len()); diff --git a/compiler/src/errors/constraints/import.rs b/compiler/src/errors/constraints/import.rs index 6e445a8622..aabe8b2018 100644 --- a/compiler/src/errors/constraints/import.rs +++ b/compiler/src/errors/constraints/import.rs @@ -17,6 +17,10 @@ impl ImportError { ImportError::Error(FormattedError::new_from_span(message, span)) } + fn new_from_span_with_path(message: String, span: Span, path: PathBuf) -> Self { + ImportError::Error(FormattedError::new_from_span_with_path(message, span, path)) + } + pub fn conflicting_imports(identifier: Identifier) -> Self { let message = format!("conflicting imports found for `{}`", identifier.name); @@ -41,10 +45,10 @@ impl ImportError { Self::new_from_span(message, span) } - pub fn directory_error(error: io::Error, span: Span) -> Self { + pub fn directory_error(error: io::Error, span: Span, path: PathBuf) -> Self { let message = format!("compilation failed due to directory error - {:?}", error); - Self::new_from_span(message, span) + Self::new_from_span_with_path(message, span, path) } pub fn star(path: PathBuf, span: Span) -> Self { diff --git a/compiler/src/imports/import_symbol.rs b/compiler/src/imports/import_symbol.rs index 59acfe8f00..435d9a5750 100644 --- a/compiler/src/imports/import_symbol.rs +++ b/compiler/src/imports/import_symbol.rs @@ -1,4 +1,4 @@ -use crate::{errors::constraints::ImportError, ProgramImports}; +use crate::{errors::constraints::ImportError, ImportedPrograms}; use leo_ast::LeoParser; use leo_types::{ImportSymbol, Program, Span}; @@ -11,7 +11,7 @@ fn parse_import_file(entry: &DirEntry, span: &Span) -> Result Result Result<(), ImportError> { let path = entry.path(); let is_dir = path.is_dir(); @@ -57,6 +57,13 @@ impl ProgramImports { let name = format!("{:?}", entry.path()); let program = parse_import_file(entry, &span)?; + // Store program's imports in imports hashmap + program + .imports + .iter() + .map(|import| self.parse_package(entry.path(), &import.package)) + .collect::, ImportError>>()?; + // Store program in imports hashmap self.store(name, program); @@ -72,6 +79,13 @@ impl ProgramImports { let name = format!("{:?}", entry.path()); let program = parse_import_file(entry, &symbol.span)?; + // Store program's imports in imports hashmap + program + .imports + .iter() + .map(|import| self.parse_package(entry.path(), &import.package)) + .collect::, ImportError>>()?; + // Store program in imports hashmap self.store(name, program); diff --git a/compiler/src/imports/program_imports.rs b/compiler/src/imports/imported_programs.rs similarity index 87% rename from compiler/src/imports/program_imports.rs rename to compiler/src/imports/imported_programs.rs index e3bf89c7f9..bbfc068cf0 100644 --- a/compiler/src/imports/program_imports.rs +++ b/compiler/src/imports/imported_programs.rs @@ -4,11 +4,11 @@ use leo_types::Program; use std::{collections::HashMap, env::current_dir}; #[derive(Clone)] -pub struct ProgramImports { +pub struct ImportedPrograms { imports: HashMap, } -impl ProgramImports { +impl ImportedPrograms { pub fn new() -> Self { Self { imports: HashMap::new(), @@ -21,6 +21,10 @@ impl ProgramImports { let _res = self.imports.insert(name, program); } + pub fn get(&self, name: &String) -> Option<&Program> { + self.imports.get(name) + } + pub fn from_program(program: &Program) -> Result { let mut imports = Self::new(); diff --git a/compiler/src/imports/mod.rs b/compiler/src/imports/mod.rs index 0f303b4c62..1cb5fc35b4 100644 --- a/compiler/src/imports/mod.rs +++ b/compiler/src/imports/mod.rs @@ -1,5 +1,5 @@ -pub mod program_imports; -pub use self::program_imports::*; +pub mod imported_programs; +pub use self::imported_programs::*; pub mod import_symbol; pub use self::import_symbol::*; diff --git a/compiler/src/imports/package.rs b/compiler/src/imports/package.rs index c1f19d7ef2..9eba3d4cad 100644 --- a/compiler/src/imports/package.rs +++ b/compiler/src/imports/package.rs @@ -1,4 +1,4 @@ -use crate::{errors::constraints::ImportError, ProgramImports}; +use crate::{errors::constraints::ImportError, ImportedPrograms}; use leo_types::{Package, PackageAccess}; use std::{fs, fs::DirEntry, path::PathBuf}; @@ -7,7 +7,7 @@ static SOURCE_FILE_EXTENSION: &str = ".leo"; static SOURCE_DIRECTORY_NAME: &str = "src/"; static IMPORTS_DIRECTORY_NAME: &str = "imports/"; -impl ProgramImports { +impl ImportedPrograms { pub fn parse_package_access(&mut self, entry: &DirEntry, access: &PackageAccess) -> Result<(), ImportError> { // bring one or more import symbols into scope for the current constrained program // we will recursively traverse sub packages here until we find the desired symbol @@ -26,8 +26,14 @@ impl ProgramImports { } pub fn parse_package(&mut self, mut path: PathBuf, package: &Package) -> Result<(), ImportError> { + let error_path = path.clone(); let package_name = package.name.clone(); + // trim path if importing from another file + if path.is_file() { + path.pop(); + } + // search for package name in local directory let mut source_directory = path.clone(); source_directory.push(SOURCE_DIRECTORY_NAME); @@ -42,10 +48,10 @@ impl ProgramImports { } let entries = fs::read_dir(path) - .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))? + .map_err(|error| ImportError::directory_error(error, package_name.span.clone(), error_path.clone()))? .into_iter() .collect::, std::io::Error>>() - .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))?; + .map_err(|error| ImportError::directory_error(error, package_name.span.clone(), error_path.clone()))?; let matched_source_entry = entries.into_iter().find(|entry| { entry @@ -59,10 +65,10 @@ impl ProgramImports { if imports_directory.exists() { let entries = fs::read_dir(imports_directory) - .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))? + .map_err(|error| ImportError::directory_error(error, package_name.span.clone(), error_path.clone()))? .into_iter() .collect::, std::io::Error>>() - .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))?; + .map_err(|error| ImportError::directory_error(error, package_name.span.clone(), error_path.clone()))?; let matched_import_entry = entries .into_iter() diff --git a/types/src/errors/error.rs b/types/src/errors/error.rs index 4d2a7fdefa..6cc33969b4 100644 --- a/types/src/errors/error.rs +++ b/types/src/errors/error.rs @@ -39,6 +39,17 @@ impl Error { } } + pub fn new_from_span_with_path(message: String, span: Span, path: PathBuf) -> Self { + Self { + path: Some(format!("{:?}", path)), + line: span.line, + start: span.start, + end: span.end, + text: span.text, + message, + } + } + pub fn set_path(&mut self, path: PathBuf) { self.path = Some(format!("{:?}", path)); }