diff --git a/asg/src/program/mod.rs b/asg/src/program/mod.rs index a01ed8c6c6..4de5e81f54 100644 --- a/asg/src/program/mod.rs +++ b/asg/src/program/mod.rs @@ -25,7 +25,7 @@ mod function; pub use function::*; use crate::{AsgConvertError, ImportResolver, InnerScope, Input, Scope}; -use leo_ast::{Identifier, Package, PackageAccess, Span}; +use leo_ast::{Identifier, PackageAccess, PackageOrPackages, Span}; use indexmap::IndexMap; use std::{cell::RefCell, sync::Arc}; @@ -74,16 +74,25 @@ enum ImportSymbol { fn resolve_import_package( output: &mut Vec<(Vec, ImportSymbol, Span)>, mut package_segments: Vec, - package: &Package, + package_or_packages: &PackageOrPackages, ) { - package_segments.push(package.name.name.clone()); - - resolve_import_package_access(output, package_segments, &package.access); + match package_or_packages { + PackageOrPackages::Package(package) => { + package_segments.push(package.name.name.clone()); + resolve_import_package_access(output, package_segments, &package.access); + } + PackageOrPackages::Packages(packages) => { + package_segments.push(packages.name.name.clone()); + for access in packages.accesses.clone() { + resolve_import_package_access(output, package_segments.clone(), &access); + } + } + } } fn resolve_import_package_access( output: &mut Vec<(Vec, ImportSymbol, Span)>, - package_segments: Vec, + mut package_segments: Vec, package: &PackageAccess, ) { match package { @@ -91,7 +100,11 @@ fn resolve_import_package_access( output.push((package_segments, ImportSymbol::All, span.clone())); } PackageAccess::SubPackage(subpackage) => { - resolve_import_package(output, package_segments, &*subpackage); + resolve_import_package( + output, + package_segments, + &PackageOrPackages::Package(*(*subpackage).clone()), + ); } PackageAccess::Symbol(symbol) => { let span = symbol.symbol.span.clone(); @@ -102,8 +115,9 @@ fn resolve_import_package_access( }; output.push((package_segments, symbol, span)); } - PackageAccess::Multiple(subaccesses) => { - for subaccess in subaccesses.iter() { + PackageAccess::Multiple(packages) => { + package_segments.push(packages.name.name.clone()); + for subaccess in packages.accesses.iter() { resolve_import_package_access(output, package_segments.clone(), &subaccess); } } @@ -126,7 +140,7 @@ impl InternalProgram { // Recursively extract imported symbols. let mut imported_symbols: Vec<(Vec, ImportSymbol, Span)> = vec![]; for import in program.imports.iter() { - resolve_import_package(&mut imported_symbols, vec![], &import.package); + resolve_import_package(&mut imported_symbols, vec![], &import.package_or_packages); } // Create package list. @@ -383,11 +397,11 @@ pub fn reform_ast(program: &Program) -> leo_ast::Program { imports: core_programs .iter() .map(|(module, _)| leo_ast::ImportStatement { - package: leo_ast::Package { + package_or_packages: leo_ast::PackageOrPackages::Package(leo_ast::Package { name: Identifier::new(module.clone()), access: leo_ast::PackageAccess::Star(Span::default()), span: Default::default(), - }, + }), span: Span::default(), }) .collect(), diff --git a/asg/tests/pass/import/imports/bar/src/baz.leo b/asg/tests/pass/import/imports/bar/src/baz.leo index 6c1df2d4b9..1bb268a84c 100755 --- a/asg/tests/pass/import/imports/bar/src/baz.leo +++ b/asg/tests/pass/import/imports/bar/src/baz.leo @@ -1,3 +1,7 @@ circuit Baz { z: u32 +} + +circuit Bazzar { + a: u32 } \ No newline at end of file diff --git a/asg/tests/pass/import/many_import.leo b/asg/tests/pass/import/many_import.leo index 339700fd68..08ae494c4f 100644 --- a/asg/tests/pass/import/many_import.leo +++ b/asg/tests/pass/import/many_import.leo @@ -5,7 +5,7 @@ import test-import.( // local import import bar.( // imports directory import Bar, - baz.Baz, + baz.(Baz, Bazzar), bat.bat.Bat, ); @@ -17,6 +17,7 @@ function main() { const bar = Bar { r: 1u32 }; const baz = Baz { z: 1u32 }; + const bazzar = Bazzar { a: 1u32 }; const bat = Bat { t: 1u32 }; const car = Car { c: 1u32 }; diff --git a/ast/src/imports/import.rs b/ast/src/imports/import.rs index 614fa5b36d..246f61c3b1 100644 --- a/ast/src/imports/import.rs +++ b/ast/src/imports/import.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{Package, Span}; +use crate::{PackageOrPackages, Span}; use leo_grammar::imports::Import as GrammarImport; use serde::{Deserialize, Serialize}; @@ -23,7 +23,7 @@ use std::fmt; /// Represents an import statement in a Leo program. #[derive(Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct ImportStatement { - pub package: Package, + pub package_or_packages: PackageOrPackages, pub span: Span, } @@ -32,14 +32,17 @@ impl ImportStatement { /// Returns the the package file name of the self import statement. /// pub fn get_file_name(&self) -> &str { - &self.package.name.name + match self.package_or_packages { + PackageOrPackages::Package(ref package) => &package.name.name, + PackageOrPackages::Packages(ref packages) => &packages.name.name, + } } } impl<'ast> From> for ImportStatement { fn from(import: GrammarImport<'ast>) -> Self { ImportStatement { - package: Package::from(import.package), + package_or_packages: PackageOrPackages::from(import.package_or_packages), span: Span::from(import.span), } } @@ -47,7 +50,7 @@ impl<'ast> From> for ImportStatement { impl ImportStatement { fn format(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "import {};", self.package) + write!(f, "import {};", self.package_or_packages) } } diff --git a/ast/src/imports/mod.rs b/ast/src/imports/mod.rs index ba6e6d8eb9..a1b223c861 100644 --- a/ast/src/imports/mod.rs +++ b/ast/src/imports/mod.rs @@ -23,5 +23,11 @@ pub use import_symbol::*; pub mod package; pub use package::*; +pub mod packages; +pub use packages::*; + +pub mod package_or_packages; +pub use package_or_packages::*; + pub mod package_access; pub use package_access::*; diff --git a/ast/src/imports/package_access.rs b/ast/src/imports/package_access.rs index a94b77452e..b329cc6b82 100644 --- a/ast/src/imports/package_access.rs +++ b/ast/src/imports/package_access.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{ImportSymbol, Package, Span}; +use crate::{ImportSymbol, Package, Packages, Span}; use leo_grammar::imports::PackageAccess as GrammarPackageAccess; use serde::{Deserialize, Serialize}; @@ -25,7 +25,7 @@ pub enum PackageAccess { Star(Span), SubPackage(Box), Symbol(ImportSymbol), - Multiple(Vec), + Multiple(Packages), } impl<'ast> From> for PackageAccess { @@ -34,9 +34,7 @@ impl<'ast> From> for PackageAccess { GrammarPackageAccess::Star(star) => PackageAccess::Star(Span::from(star.span)), GrammarPackageAccess::SubPackage(package) => PackageAccess::SubPackage(Box::new(Package::from(*package))), GrammarPackageAccess::Symbol(symbol) => PackageAccess::Symbol(ImportSymbol::from(symbol)), - GrammarPackageAccess::Multiple(accesses) => { - PackageAccess::Multiple(accesses.into_iter().map(PackageAccess::from).collect()) - } + GrammarPackageAccess::Multiple(packages) => PackageAccess::Multiple(Packages::from(packages)), } } } @@ -47,11 +45,11 @@ impl PackageAccess { PackageAccess::Star(ref _span) => write!(f, "*"), PackageAccess::SubPackage(ref package) => write!(f, "{}", package), PackageAccess::Symbol(ref symbol) => write!(f, "{}", symbol), - PackageAccess::Multiple(ref accesses) => { + PackageAccess::Multiple(ref packages) => { write!(f, "(")?; - for (i, access) in accesses.iter().enumerate() { + for (i, access) in packages.accesses.iter().enumerate() { write!(f, "{}", access)?; - if i < accesses.len() - 1 { + if i < packages.accesses.len() - 1 { write!(f, ", ")?; } } diff --git a/ast/src/imports/package_or_packages.rs b/ast/src/imports/package_or_packages.rs new file mode 100644 index 0000000000..2f1b9bc717 --- /dev/null +++ b/ast/src/imports/package_or_packages.rs @@ -0,0 +1,66 @@ +// Copyright (C) 2019-2021 Aleo Systems Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use crate::{Package, Packages}; +use leo_grammar::imports::PackageOrPackages as GrammarPackageOrPackages; + +use serde::{Deserialize, Serialize}; +use std::fmt; + +#[derive(Clone, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub enum PackageOrPackages { + Package(Package), + Packages(Packages), +} + +impl<'ast> From> for PackageOrPackages { + fn from(package_or_packages: GrammarPackageOrPackages<'ast>) -> Self { + match package_or_packages { + GrammarPackageOrPackages::Package(package) => PackageOrPackages::Package(Package::from(package)), + GrammarPackageOrPackages::Packages(packages) => PackageOrPackages::Packages(Packages::from(packages)), + } + } +} + +impl PackageOrPackages { + fn format(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + PackageOrPackages::Package(ref package) => write!(f, "{}", package), + PackageOrPackages::Packages(ref packages) => { + write!(f, "(")?; + for (i, access) in packages.accesses.iter().enumerate() { + write!(f, "{}", access)?; + if i < packages.accesses.len() - 1 { + write!(f, ", ")?; + } + } + write!(f, ")") + } + } + } +} + +impl fmt::Debug for PackageOrPackages { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.format(f) + } +} + +impl fmt::Display for PackageOrPackages { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.format(f) + } +} diff --git a/ast/src/imports/packages.rs b/ast/src/imports/packages.rs new file mode 100644 index 0000000000..fab9542716 --- /dev/null +++ b/ast/src/imports/packages.rs @@ -0,0 +1,63 @@ +// Copyright (C) 2019-2021 Aleo Systems Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use crate::{common::Identifier, PackageAccess, Span}; +use leo_grammar::imports::Packages as GrammarPackages; + +use serde::{Deserialize, Serialize}; +use std::fmt; + +#[derive(Clone, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct Packages { + pub name: Identifier, + pub accesses: Vec, + pub span: Span, +} + +impl<'ast> From> for Packages { + fn from(packages: GrammarPackages<'ast>) -> Self { + Packages { + name: Identifier::from(packages.name), + accesses: packages.accesses.into_iter().map(PackageAccess::from).collect(), + span: Span::from(packages.span), + } + } +} + +impl Packages { + fn format(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}.(", self.name)?; + for (i, access) in self.accesses.iter().enumerate() { + write!(f, "{}", access)?; + if i < self.accesses.len() - 1 { + write!(f, ", ")?; + } + } + write!(f, ")") + } +} + +impl fmt::Display for Packages { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.format(f) + } +} + +impl fmt::Debug for Packages { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.format(f) + } +} diff --git a/compiler/tests/import/imports/bar/src/baz.leo b/compiler/tests/import/imports/bar/src/baz.leo index 6c1df2d4b9..1bb268a84c 100755 --- a/compiler/tests/import/imports/bar/src/baz.leo +++ b/compiler/tests/import/imports/bar/src/baz.leo @@ -1,3 +1,7 @@ circuit Baz { z: u32 +} + +circuit Bazzar { + a: u32 } \ No newline at end of file diff --git a/compiler/tests/import/many_import.leo b/compiler/tests/import/many_import.leo index 339700fd68..08ae494c4f 100644 --- a/compiler/tests/import/many_import.leo +++ b/compiler/tests/import/many_import.leo @@ -5,7 +5,7 @@ import test-import.( // local import import bar.( // imports directory import Bar, - baz.Baz, + baz.(Baz, Bazzar), bat.bat.Bat, ); @@ -17,6 +17,7 @@ function main() { const bar = Bar { r: 1u32 }; const baz = Baz { z: 1u32 }; + const bazzar = Bazzar { a: 1u32 }; const bat = Bat { t: 1u32 }; const car = Car { c: 1u32 }; diff --git a/examples/pedersen-hash/src/main.leo b/examples/pedersen-hash/src/main.leo index c1d79bf74f..225a05ad19 100644 --- a/examples/pedersen-hash/src/main.leo +++ b/examples/pedersen-hash/src/main.leo @@ -7,7 +7,7 @@ circuit PedersenHash { } function hash(self, bits: [bool; 256]) -> group { - let mut digest: group = 0; + let mut digest: group = 0group; for i in 0..256 { if bits[i] { digest += self.parameters[i]; diff --git a/grammar/src/imports/import.rs b/grammar/src/imports/import.rs index 37a9fde2ec..1b62df80f3 100644 --- a/grammar/src/imports/import.rs +++ b/grammar/src/imports/import.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with the Leo library. If not, see . -use crate::{ast::Rule, common::LineEnd, imports::Package, SpanDef}; +use crate::{ast::Rule, common::LineEnd, imports::PackageOrPackages, SpanDef}; use pest::Span; use pest_ast::FromPest; @@ -23,7 +23,7 @@ use serde::Serialize; #[derive(Clone, Debug, FromPest, PartialEq, Serialize)] #[pest_ast(rule(Rule::import))] pub struct Import<'ast> { - pub package: Package<'ast>, + pub package_or_packages: PackageOrPackages<'ast>, pub line_end: LineEnd, #[pest_ast(outer())] #[serde(with = "SpanDef")] diff --git a/grammar/src/imports/mod.rs b/grammar/src/imports/mod.rs index d16b54c012..7665e520c5 100644 --- a/grammar/src/imports/mod.rs +++ b/grammar/src/imports/mod.rs @@ -23,6 +23,12 @@ pub use import_symbol::*; pub mod package; pub use package::*; +pub mod packages; +pub use packages::*; + +pub mod package_or_packages; +pub use package_or_packages::*; + pub mod package_access; pub use package_access::*; diff --git a/grammar/src/imports/package_access.rs b/grammar/src/imports/package_access.rs index e22194e231..7d172bd545 100644 --- a/grammar/src/imports/package_access.rs +++ b/grammar/src/imports/package_access.rs @@ -16,7 +16,7 @@ use crate::{ ast::Rule, - imports::{ImportSymbol, Package, Star}, + imports::{ImportSymbol, Package, Packages, Star}, }; use pest_ast::FromPest; @@ -28,5 +28,5 @@ pub enum PackageAccess<'ast> { Star(Star<'ast>), SubPackage(Box>), Symbol(ImportSymbol<'ast>), - Multiple(Vec>), + Multiple(Packages<'ast>), } diff --git a/grammar/src/imports/package_or_packages.rs b/grammar/src/imports/package_or_packages.rs new file mode 100644 index 0000000000..3cd0324480 --- /dev/null +++ b/grammar/src/imports/package_or_packages.rs @@ -0,0 +1,30 @@ +// Copyright (C) 2019-2021 Aleo Systems Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use crate::{ + ast::Rule, + imports::{Package, Packages}, +}; + +use pest_ast::FromPest; +use serde::Serialize; + +#[derive(Clone, Debug, FromPest, PartialEq, Serialize)] +#[pest_ast(rule(Rule::package_or_packages))] +pub enum PackageOrPackages<'ast> { + Package(Package<'ast>), + Packages(Packages<'ast>), +} diff --git a/grammar/src/imports/packages.rs b/grammar/src/imports/packages.rs new file mode 100644 index 0000000000..32003ffb16 --- /dev/null +++ b/grammar/src/imports/packages.rs @@ -0,0 +1,35 @@ +// Copyright (C) 2019-2021 Aleo Systems Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use crate::{ + ast::Rule, + imports::{PackageAccess, PackageName}, + SpanDef, +}; + +use pest::Span; +use pest_ast::FromPest; +use serde::Serialize; + +#[derive(Clone, Debug, FromPest, PartialEq, Serialize)] +#[pest_ast(rule(Rule::packages))] +pub struct Packages<'ast> { + pub name: PackageName<'ast>, + pub accesses: Vec>, + #[pest_ast(outer())] + #[serde(with = "SpanDef")] + pub span: Span<'ast>, +} diff --git a/grammar/src/leo.pest b/grammar/src/leo.pest index 1f236952d3..4a5fbdde2e 100644 --- a/grammar/src/leo.pest +++ b/grammar/src/leo.pest @@ -461,18 +461,25 @@ input_tuple = _{ "(" ~ (input ~ ("," ~ input)* ~ ","?)? ~ ")"} /// Imports // Declared in imports/import.rs -import = { "import " ~ package ~ LINE_END} +import = { "import " ~ package_or_packages ~ LINE_END} // Declared in imports/package_name.rs package_name = @{ (ASCII_ALPHA_LOWER | ASCII_DIGIT)+ ~ ( "-" ~ (ASCII_ALPHA_LOWER | ASCII_DIGIT)+)* } +// Declared in imports/package_or_packages.rs +package_or_packages = { + packages + | package +} // Declared in imports/package.rs package = { package_name ~ "." ~ package_access } +// Declared in imports/packages.rs +packages = { package_name ~ "." ~ multiple_package_access } // Declared in imports/package_access package_access = { - multiple_package_access - | star + star + | packages | package // subpackage | import_symbol } diff --git a/grammar/tests/imports.rs b/grammar/tests/imports.rs new file mode 100644 index 0000000000..8ddd874e3d --- /dev/null +++ b/grammar/tests/imports.rs @@ -0,0 +1,91 @@ +// Copyright (C) 2019-2021 Aleo Systems Inc. +// This file is part of the Leo library. + +// The Leo library is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// The Leo library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with the Leo library. If not, see . + +use leo_grammar::ast::{LanguageParser, Rule}; + +use pest::*; + +#[test] +fn test_import_package_rule() { + parses_to! { + parser: LanguageParser, + input: "import p.*;", + rule: Rule::import, + tokens: [ + import(0, 11, [ + package_or_packages(7, 10, [ + package(7, 10, [ + package_name(7, 8, []), + package_access(9, 10, [star(9, 10, [])]) + ]) + ]), + LINE_END(10, 11, []) + ]), + ] + } +} + +#[test] +fn test_import_packages_rule() { + parses_to! { + parser: LanguageParser, + input: "import p.(x, y);", + rule: Rule::import, + tokens: [ + import(0, 16, [ + package_or_packages(7, 15, [ + packages(7, 15, [ + package_name(7, 8, []), + package_access(10, 11, [ + import_symbol(10, 11, [identifier(10, 11, [])]), + ]), + package_access(13, 14, [ + import_symbol(13, 14, [identifier(13, 14, [])]), + ]), + ]) + ]), + LINE_END(15, 16, []) + ]) + ] + } +} + +#[test] +fn test_complex_import_rule() { + parses_to! { + parser: LanguageParser, + input: "import p.(q.(x, y), z);", + rule: Rule::import, + tokens: [ + import(0, 23, [ + package_or_packages(7, 22, [ + packages(7, 22, [ + package_name(7, 8, []), + package_access(10, 18, [ + packages(10, 18, [ + package_name(10, 11, []), + package_access(13, 14, [import_symbol(13, 14, [identifier(13, 14, [])])]), + package_access(16, 17, [import_symbol(16, 17, [identifier(16, 17, [])])]), + ]), + ]), + package_access(20, 21, [import_symbol(20, 21, [identifier(20, 21, [])])]), + ]) + ]), + LINE_END(22, 23, []) + ]) + ] + } +}