fix nested import parsing bug

This commit is contained in:
collin 2020-07-01 21:43:06 -07:00
parent 6a04dd0f58
commit a422027e12
9 changed files with 85 additions and 32 deletions

View File

@ -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<F: Field + PrimeField, G: GroupType<F>> {
main_file_path: PathBuf,
program: Program,
program_inputs: Inputs,
program_imports: ProgramImports,
imported_programs: ImportedPrograms,
output: Option<ConstrainedValue<F, G>>,
_engine: PhantomData<F>,
}
@ -37,7 +37,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
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<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
cs: &mut CS,
) -> Result<ConstrainedValue<F, G>, 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<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
}
pub fn compile_test_constraints(self, cs: &mut TestConstraintSystem<F>) -> Result<(), CompilerError> {
generate_test_constraints::<F, G>(cs, self.program)
generate_test_constraints::<F, G>(cs, self.program, self.imported_programs)
}
fn load_program(&mut self) -> Result<String, CompilerError> {
@ -105,7 +107,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
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<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
main_file_path: PathBuf::new(),
program,
program_inputs,
program_imports: ProgramImports::new(),
imported_programs: ImportedPrograms::new(),
output: None,
_engine: PhantomData,
})
@ -145,8 +147,13 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
impl<F: Field + PrimeField, G: GroupType<F>> ConstraintSynthesizer<F> for Compiler<F, G> {
fn generate_constraints<CS: ConstraintSystem<F>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
let result =
generate_constraints::<_, G, _>(cs, self.program, self.program_inputs.get_inputs()).map_err(|e| {
let result = generate_constraints::<_, G, _>(
cs,
self.program,
self.program_inputs.get_inputs(),
self.imported_programs,
)
.map_err(|e| {
log::error!("{}", e);
SynthesisError::Unsatisfiable
})?;

View File

@ -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<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
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()

View File

@ -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<F: Field + PrimeField, G: GroupType<F>, CS: Constrai
cs: &mut CS,
program: Program,
parameters: Vec<Option<InputValue>>,
imported_programs: ImportedPrograms,
) -> Result<ConstrainedValue<F, G>, 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<F: Field + PrimeField, G: GroupType<F>, CS: Constrai
pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
cs: &mut TestConstraintSystem<F>,
program: Program,
imported_programs: ImportedPrograms,
) -> Result<(), CompilerError> {
let mut resolved_program = ConstrainedProgram::<F, G>::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());

View File

@ -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 {

View File

@ -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<Program, ImportErr
// make sure the given entry is file
let file_type = entry
.file_type()
.map_err(|error| ImportError::directory_error(error, span.clone()))?;
.map_err(|error| ImportError::directory_error(error, span.clone(), entry.path()))?;
let file_name = entry
.file_name()
.to_os_string()
@ -38,7 +38,7 @@ fn parse_import_file(entry: &DirEntry, span: &Span) -> Result<Program, ImportErr
Ok(Program::from(syntax_tree, file_name.clone()))
}
impl ProgramImports {
impl ImportedPrograms {
pub fn parse_import_star(&mut self, entry: &DirEntry, span: &Span) -> 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::<Result<Vec<()>, 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::<Result<Vec<()>, ImportError>>()?;
// Store program in imports hashmap
self.store(name, program);

View File

@ -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<String, Program>,
}
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<Self, ImportError> {
let mut imports = Self::new();

View File

@ -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::*;

View File

@ -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::<Result<Vec<_>, 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::<Result<Vec<_>, 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()

View File

@ -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));
}