From d905ffd569d8f32f8e0d634c4292d50b0e3f01a3 Mon Sep 17 00:00:00 2001 From: collin Date: Mon, 29 Jun 2020 17:47:23 -0700 Subject: [PATCH] impl importing from package lib, file, directory, and star --- ast/src/leo.pest | 2 +- .../src/constraints/import/import_symbol.rs | 42 +++++++++++++++---- compiler/src/constraints/import/package.rs | 19 +++++---- compiler/src/errors/constraints/import.rs | 7 +++- compiler/tests/import/imports/bar/.gitignore | 1 + compiler/tests/import/imports/bar/Leo.toml | 3 ++ .../tests/import/imports/bar/src/bat/bat.leo | 3 ++ compiler/tests/import/imports/bar/src/baz.leo | 3 ++ compiler/tests/import/imports/bar/src/lib.leo | 3 ++ compiler/tests/import/imports/car/.gitignore | 1 + compiler/tests/import/imports/car/Leo.toml | 3 ++ compiler/tests/import/imports/car/src/lib.leo | 3 ++ compiler/tests/import/many_import.leo | 25 +++++++++++ compiler/tests/import/many_import_star.leo | 16 +++++++ compiler/tests/import/mod.rs | 23 ++++++++++ leo/files/lib.rs | 4 +- 16 files changed, 139 insertions(+), 19 deletions(-) create mode 100755 compiler/tests/import/imports/bar/.gitignore create mode 100755 compiler/tests/import/imports/bar/Leo.toml create mode 100755 compiler/tests/import/imports/bar/src/bat/bat.leo create mode 100755 compiler/tests/import/imports/bar/src/baz.leo create mode 100755 compiler/tests/import/imports/bar/src/lib.leo create mode 100755 compiler/tests/import/imports/car/.gitignore create mode 100755 compiler/tests/import/imports/car/Leo.toml create mode 100755 compiler/tests/import/imports/car/src/lib.leo create mode 100644 compiler/tests/import/many_import.leo create mode 100644 compiler/tests/import/many_import_star.leo diff --git a/ast/src/leo.pest b/ast/src/leo.pest index 18f5ce31ca..78652c5fd8 100644 --- a/ast/src/leo.pest +++ b/ast/src/leo.pest @@ -299,7 +299,7 @@ package_access = { | import_symbol } -multiple_package_access = _{ "(" ~ NEWLINE* ~ package_access ~ ("," ~ NEWLINE* ~ package_access)* ~ NEWLINE* ~ ")"} +multiple_package_access = _{ "(" ~ NEWLINE* ~ package_access ~ ("," ~ NEWLINE* ~ package_access)* ~ ","? ~ NEWLINE* ~ ")"} // Declared in imports/star.rs star = {"*"} diff --git a/compiler/src/constraints/import/import_symbol.rs b/compiler/src/constraints/import/import_symbol.rs index da457f59c0..b7a61c11a4 100644 --- a/compiler/src/constraints/import/import_symbol.rs +++ b/compiler/src/constraints/import/import_symbol.rs @@ -8,7 +8,10 @@ use leo_ast::LeoParser; use leo_types::{ImportSymbol, Program, Span}; use snarkos_models::curves::{Field, PrimeField}; -use std::fs::DirEntry; +use std::{ + ffi::OsString, + fs::{read_dir, DirEntry}, +}; static LIBRARY_FILE: &str = "src/lib.leo"; @@ -27,7 +30,10 @@ fn parse_import_file(entry: &DirEntry, span: &Span) -> Result Result> ConstrainedProgram { pub fn enforce_import_star(&mut self, scope: String, entry: &DirEntry, span: Span) -> Result<(), ImportError> { - let mut program = parse_import_file(entry, &span)?; + // import star from a file + if entry.path().is_file() { + // only parse `.leo` files + if let Some(extension) = entry.path().extension() { + if extension.eq(&OsString::from("leo")) { + let mut program = parse_import_file(entry, &span)?; - // Use same namespace as calling function for imported symbols - program = program.name(scope); + // Use same namespace as calling function for imported symbols + program = program.name(scope); - // * -> import all imports, circuits, functions in the current scope - self.resolve_definitions(program) + // * -> import all imports, circuits, functions in the current scope + self.resolve_definitions(program) + } else { + Ok(()) + } + } else { + Ok(()) + } + } else { + // import star for every file in the directory + for entry in read_dir(entry.path()).map_err(|error| ImportError::directory_error(error, span.clone()))? { + match entry { + Ok(entry) => self.enforce_import_star(scope.clone(), &entry, span.clone())?, + Err(error) => return Err(ImportError::directory_error(error, span.clone())), + } + } + + Ok(()) + } } pub fn enforce_import_symbol( diff --git a/compiler/src/constraints/import/package.rs b/compiler/src/constraints/import/package.rs index 868b5048f2..5497bb9f0a 100644 --- a/compiler/src/constraints/import/package.rs +++ b/compiler/src/constraints/import/package.rs @@ -31,14 +31,23 @@ impl> ConstrainedProgram { } } - pub fn enforce_package(&mut self, scope: String, path: PathBuf, package: Package) -> Result<(), ImportError> { + pub fn enforce_package(&mut self, scope: String, mut path: PathBuf, package: Package) -> Result<(), ImportError> { let package_name = package.name; - // search for package name in local src directory + // search for package name in local directory let mut source_directory = path.clone(); source_directory.push(SOURCE_DIRECTORY_NAME); - let entries = fs::read_dir(source_directory) + // search for package name in `imports` directory + let mut imports_directory = path.clone(); + imports_directory.push(IMPORTS_DIRECTORY_NAME); + + // read from local `src` directory or the current path + if source_directory.exists() { + path = source_directory + } + + let entries = fs::read_dir(path) .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))? .into_iter() .collect::, std::io::Error>>() @@ -53,10 +62,6 @@ impl> ConstrainedProgram { .eq(&package_name.name) }); - // search for package name in imports directory - let mut imports_directory = path.clone(); - imports_directory.push(IMPORTS_DIRECTORY_NAME); - if imports_directory.exists() { let entries = fs::read_dir(imports_directory) .map_err(|error| ImportError::directory_error(error, package_name.span.clone()))? diff --git a/compiler/src/errors/constraints/import.rs b/compiler/src/errors/constraints/import.rs index d9f7ed2406..2152bee06c 100644 --- a/compiler/src/errors/constraints/import.rs +++ b/compiler/src/errors/constraints/import.rs @@ -35,8 +35,11 @@ impl ImportError { Self::new_from_span(message, span) } - pub fn expected_file(entry: String, span: Span) -> Self { - let message = format!("cannot import symbol `{}` from directory `{}`", span.text, entry); + pub fn expected_lib_file(entry: String, span: Span) -> Self { + let message = format!( + "expected library file`{}` when looking for symbol `{}`", + entry, span.text + ); Self::new_from_span(message, span) } diff --git a/compiler/tests/import/imports/bar/.gitignore b/compiler/tests/import/imports/bar/.gitignore new file mode 100755 index 0000000000..17aa483ab4 --- /dev/null +++ b/compiler/tests/import/imports/bar/.gitignore @@ -0,0 +1 @@ +outputs/ diff --git a/compiler/tests/import/imports/bar/Leo.toml b/compiler/tests/import/imports/bar/Leo.toml new file mode 100755 index 0000000000..8e22d51a95 --- /dev/null +++ b/compiler/tests/import/imports/bar/Leo.toml @@ -0,0 +1,3 @@ +[package] +name = "bar" +version = "0.1.0" diff --git a/compiler/tests/import/imports/bar/src/bat/bat.leo b/compiler/tests/import/imports/bar/src/bat/bat.leo new file mode 100755 index 0000000000..a7d2fc83d4 --- /dev/null +++ b/compiler/tests/import/imports/bar/src/bat/bat.leo @@ -0,0 +1,3 @@ +circuit Bat { + t: u32 +} \ No newline at end of file diff --git a/compiler/tests/import/imports/bar/src/baz.leo b/compiler/tests/import/imports/bar/src/baz.leo new file mode 100755 index 0000000000..6c1df2d4b9 --- /dev/null +++ b/compiler/tests/import/imports/bar/src/baz.leo @@ -0,0 +1,3 @@ +circuit Baz { + z: u32 +} \ No newline at end of file diff --git a/compiler/tests/import/imports/bar/src/lib.leo b/compiler/tests/import/imports/bar/src/lib.leo new file mode 100755 index 0000000000..c169f5935e --- /dev/null +++ b/compiler/tests/import/imports/bar/src/lib.leo @@ -0,0 +1,3 @@ +circuit Bar { + r: u32 +} \ No newline at end of file diff --git a/compiler/tests/import/imports/car/.gitignore b/compiler/tests/import/imports/car/.gitignore new file mode 100755 index 0000000000..17aa483ab4 --- /dev/null +++ b/compiler/tests/import/imports/car/.gitignore @@ -0,0 +1 @@ +outputs/ diff --git a/compiler/tests/import/imports/car/Leo.toml b/compiler/tests/import/imports/car/Leo.toml new file mode 100755 index 0000000000..15b76f1d76 --- /dev/null +++ b/compiler/tests/import/imports/car/Leo.toml @@ -0,0 +1,3 @@ +[package] +name = "car" +version = "0.1.0" diff --git a/compiler/tests/import/imports/car/src/lib.leo b/compiler/tests/import/imports/car/src/lib.leo new file mode 100755 index 0000000000..b1e037fd38 --- /dev/null +++ b/compiler/tests/import/imports/car/src/lib.leo @@ -0,0 +1,3 @@ +circuit Car { + c: u32 +} \ No newline at end of file diff --git a/compiler/tests/import/many_import.leo b/compiler/tests/import/many_import.leo new file mode 100644 index 0000000000..d67b775cbe --- /dev/null +++ b/compiler/tests/import/many_import.leo @@ -0,0 +1,25 @@ +import test_import.( // local import + Point, + foo, +); + +import bar.( // imports directory import + Bar, + baz.Baz, + bat.bat.Bat, +); + +import car.Car; // imports directory import + +function main() -> u32 { + // const point = Point { x: 1u32, y: 1u32 }; + // const foo = foo(); + + const bar = Bar { r: 1u32 }; + const bat = Bat { t: 1u32 }; + const baz = Baz { z: 1u32 }; + + const car = Car { c: 1u32 }; + + return car.c +} \ No newline at end of file diff --git a/compiler/tests/import/many_import_star.leo b/compiler/tests/import/many_import_star.leo new file mode 100644 index 0000000000..b98e84a2f1 --- /dev/null +++ b/compiler/tests/import/many_import_star.leo @@ -0,0 +1,16 @@ +import test_import.*; // local import +import bar.*; // imports directory import +import car.*; // imports directory import + +function main() -> u32 { + const point = Point { x: 1u32, y: 1u32 }; + const foo = foo(); + + const bar = Bar { r: 1u32 }; + const bat = Bat { t: 1u32 }; + const baz = Baz { z: 1u32 }; + + const car = Car { c: 1u32 }; + + return car.c +} \ No newline at end of file diff --git a/compiler/tests/import/mod.rs b/compiler/tests/import/mod.rs index 5c7ba19c0a..30d210a055 100644 --- a/compiler/tests/import/mod.rs +++ b/compiler/tests/import/mod.rs @@ -56,3 +56,26 @@ fn test_alias() { output_one(program); } + +// more complex tests +#[test] +#[ignore] +fn test_many_import() { + let bytes = include_bytes!("many_import.leo"); + let program = parse_program(bytes).unwrap(); + + set_local_dir(); + + output_one(program); +} + +#[test] +#[ignore] +fn test_many_import_star() { + let bytes = include_bytes!("many_import_star.leo"); + let program = parse_program(bytes).unwrap(); + + set_local_dir(); + + output_one(program); +} diff --git a/leo/files/lib.rs b/leo/files/lib.rs index 2b514cc1cf..54fed26c83 100644 --- a/leo/files/lib.rs +++ b/leo/files/lib.rs @@ -46,8 +46,8 @@ impl LibFile { fn template(&self) -> String { format!( r#"// The '{}' lib function. -circuit Circ {{ - c: field +circuit Foo {{ + a: field }} "#, self.package_name