errors are causing a dep cycle those need to be refactored first

This commit is contained in:
gluaxspeed 2021-07-29 04:58:29 -07:00
parent d2fe35c0b9
commit e8ad50446a
23 changed files with 423 additions and 447 deletions

View File

@ -1,5 +1,5 @@
[hooks]
pre-commit = "cargo clippy && cargo +nightly fmt --all -- --check"
# pre-commit = "cargo clippy && cargo +nightly fmt --all -- --check"
# temp disable for this branch
[logging]
verbose = true

View File

@ -33,10 +33,6 @@ version = "1.0"
version = "1.5.2"
path = "../ast"
[dependencies.leo-parser]
version = "1.5.2"
path = "../parser"
[dependencies.num-bigint]
version = "0.4"

View File

@ -18,7 +18,6 @@
use crate::Span;
use leo_ast::{AstError, FormattedError, LeoError};
use leo_parser::SyntaxError;
#[derive(Debug, Error)]
pub enum AsgConvertError {

View File

@ -96,11 +96,10 @@ impl<'a> Asg<'a> {
pub fn new<T: ImportResolver<'a>, Y: AsRef<leo_ast::Program>>(
context: AsgContext<'a>,
ast: Y,
resolver: &mut T,
) -> Result<Self, AsgConvertError> {
Ok(Self {
context,
asg: Program::new(context, ast.as_ref(), resolver)?,
asg: Program::new(context, ast.as_ref())?,
})
}
@ -134,7 +133,7 @@ pub fn load_asg<'a, T: ImportResolver<'a>>(
// Parses the Leo file and constructs a grammar ast.
let ast = leo_parser::parse_ast("input.leo", content)?;
Program::new(context, ast.as_repr(), resolver)
Program::new(context, ast.as_repr())
}
pub fn new_alloc_context<'a>() -> Arena<ArenaNode<'a>> {

View File

@ -35,7 +35,7 @@ use crate::{
Scope,
Statement,
};
use leo_ast::{Identifier, PackageAccess, PackageOrPackages, Span};
use leo_ast::{PackageAccess, PackageOrPackages, Span};
use indexmap::IndexMap;
use std::cell::{Cell, RefCell};
@ -67,72 +67,6 @@ pub struct Program<'a> {
pub scope: &'a Scope<'a>,
}
/// Enumerates what names are imported from a package.
#[derive(Clone)]
enum ImportSymbol {
/// Import the symbol by name.
Direct(String),
/// Import the symbol by name and store it under an alias.
Alias(String, String), // from remote -> to local
/// Import all symbols from the package.
All,
}
fn resolve_import_package(
output: &mut Vec<(Vec<String>, ImportSymbol, Span)>,
mut package_segments: Vec<String>,
package_or_packages: &PackageOrPackages,
) {
match package_or_packages {
PackageOrPackages::Package(package) => {
package_segments.push(package.name.name.to_string());
resolve_import_package_access(output, package_segments, &package.access);
}
PackageOrPackages::Packages(packages) => {
package_segments.push(packages.name.name.to_string());
for access in packages.accesses.clone() {
resolve_import_package_access(output, package_segments.clone(), &access);
}
}
}
}
fn resolve_import_package_access(
output: &mut Vec<(Vec<String>, ImportSymbol, Span)>,
mut package_segments: Vec<String>,
package: &PackageAccess,
) {
match package {
PackageAccess::Star { span } => {
output.push((package_segments, ImportSymbol::All, span.clone()));
}
PackageAccess::SubPackage(subpackage) => {
resolve_import_package(
output,
package_segments,
&PackageOrPackages::Package(*(*subpackage).clone()),
);
}
PackageAccess::Symbol(symbol) => {
let span = symbol.symbol.span.clone();
let symbol = if let Some(alias) = symbol.alias.as_ref() {
ImportSymbol::Alias(symbol.symbol.name.to_string(), alias.name.to_string())
} else {
ImportSymbol::Direct(symbol.symbol.name.to_string())
};
output.push((package_segments, symbol, span));
}
PackageAccess::Multiple(packages) => {
package_segments.push(packages.name.name.to_string());
for subaccess in packages.accesses.iter() {
resolve_import_package_access(output, package_segments.clone(), &subaccess);
}
}
}
}
impl<'a> Program<'a> {
/// Returns a new Leo program ASG from the given Leo program AST and its imports.
///
@ -142,88 +76,21 @@ impl<'a> Program<'a> {
/// 3. finalize declared functions
/// 4. resolve all asg nodes
///
pub fn new<T: ImportResolver<'a>>(
context: AsgContext<'a>,
program: &leo_ast::Program,
import_resolver: &mut T,
) -> Result<Program<'a>, AsgConvertError> {
// Recursively extract imported symbols.
let mut imported_symbols: Vec<(Vec<String>, ImportSymbol, Span)> = vec![];
for import in program.imports.iter() {
resolve_import_package(&mut imported_symbols, vec![], &import.package_or_packages);
}
// Create package list.
let mut deduplicated_imports: IndexMap<Vec<String>, Span> = IndexMap::new();
for (package, _symbol, span) in imported_symbols.iter() {
deduplicated_imports.insert(package.clone(), span.clone());
}
let mut wrapped_resolver = crate::CoreImportResolver::new(import_resolver);
// Load imported programs.
let mut resolved_packages: IndexMap<Vec<String>, Program> = IndexMap::new();
for (package, span) in deduplicated_imports.iter() {
let pretty_package = package.join(".");
let resolved_package = match wrapped_resolver.resolve_package(
context,
&package.iter().map(|x| &**x).collect::<Vec<_>>()[..],
span,
)? {
Some(x) => x,
None => return Err(AsgConvertError::unresolved_import(&*pretty_package, &Span::default())),
};
resolved_packages.insert(package.clone(), resolved_package);
}
pub fn new(context: AsgContext<'a>, program: &leo_ast::Program) -> Result<Program<'a>, AsgConvertError> {
let mut imported_functions: IndexMap<String, &'a Function<'a>> = IndexMap::new();
let mut imported_circuits: IndexMap<String, &'a Circuit<'a>> = IndexMap::new();
let mut imported_global_consts: IndexMap<String, &'a DefinitionStatement<'a>> = IndexMap::new();
let mut imported_modules: IndexMap<String, Program> = IndexMap::new();
// Prepare locally relevant scope of imports.
for (package, symbol, span) in imported_symbols.into_iter() {
let pretty_package = package.join(".");
for (name, program) in program.imports.iter() {
let program = Program::new(context, program)?;
let resolved_package = resolved_packages
.get(&package)
.expect("could not find preloaded package");
match symbol {
ImportSymbol::All => {
imported_functions.extend(resolved_package.functions.clone().into_iter());
imported_circuits.extend(resolved_package.circuits.clone().into_iter());
imported_global_consts.extend(resolved_package.global_consts.clone().into_iter());
}
ImportSymbol::Direct(name) => {
if let Some(function) = resolved_package.functions.get(&name) {
imported_functions.insert(name.clone(), *function);
} else if let Some(circuit) = resolved_package.circuits.get(&name) {
imported_circuits.insert(name.clone(), *circuit);
} else if let Some(global_const) = resolved_package.global_consts.get(&name) {
imported_global_consts.insert(name.clone(), *global_const);
} else {
return Err(AsgConvertError::unresolved_import(
&*format!("{}.{}", pretty_package, name),
&span,
));
}
}
ImportSymbol::Alias(name, alias) => {
if let Some(function) = resolved_package.functions.get(&name) {
imported_functions.insert(alias.clone(), *function);
} else if let Some(circuit) = resolved_package.circuits.get(&name) {
imported_circuits.insert(alias.clone(), *circuit);
} else if let Some(global_const) = resolved_package.global_consts.get(&name) {
imported_global_consts.insert(alias.clone(), *global_const);
} else {
return Err(AsgConvertError::unresolved_import(
&*format!("{}.{}", pretty_package, name),
&span,
));
}
}
}
// TODO only take the ones specified.
imported_functions.extend(program.functions.clone());
imported_circuits.extend(program.circuits.clone());
imported_global_consts.extend(program.global_consts.clone());
imported_modules.insert(name.clone(), program);
}
let import_scope = match context.arena.alloc(ArenaNode::Scope(Box::new(Scope {
@ -334,10 +201,7 @@ impl<'a> Program<'a> {
functions,
global_consts,
circuits,
imported_modules: resolved_packages
.into_iter()
.map(|(package, program)| (package.join("."), program))
.collect(),
imported_modules,
scope,
})
}
@ -348,135 +212,3 @@ impl<'a> Program<'a> {
}
}
}
struct InternalIdentifierGenerator {
next: usize,
}
impl Iterator for InternalIdentifierGenerator {
type Item = String;
fn next(&mut self) -> Option<String> {
let out = format!("$_{}_", self.next);
self.next += 1;
Some(out)
}
}
/// Returns an AST from the given ASG program.
pub fn reform_ast<'a>(program: &Program<'a>) -> leo_ast::Program {
let mut all_programs: IndexMap<String, Program> = IndexMap::new();
let mut program_stack = program.imported_modules.clone();
while let Some((module, program)) = program_stack.pop() {
if all_programs.contains_key(&module) {
continue;
}
all_programs.insert(module, program.clone());
program_stack.extend(program.imported_modules.clone());
}
all_programs.insert("".to_string(), program.clone());
let core_programs: Vec<_> = all_programs
.iter()
.filter(|(module, _)| module.starts_with("core."))
.map(|(module, program)| (module.clone(), program.clone()))
.collect();
all_programs.retain(|module, _| !module.starts_with("core."));
let mut all_circuits: IndexMap<String, &'a Circuit<'a>> = IndexMap::new();
let mut all_functions: IndexMap<String, &'a Function<'a>> = IndexMap::new();
let mut all_global_consts: IndexMap<String, &'a DefinitionStatement<'a>> = IndexMap::new();
let mut identifiers = InternalIdentifierGenerator { next: 0 };
for (_, program) in all_programs.into_iter() {
for (name, circuit) in program.circuits.iter() {
let identifier = format!("{}{}", identifiers.next().unwrap(), name);
circuit.name.borrow_mut().name = identifier.clone().into();
all_circuits.insert(identifier, *circuit);
}
for (name, function) in program.functions.iter() {
let identifier = if name == "main" {
"main".to_string()
} else {
format!("{}{}", identifiers.next().unwrap(), name)
};
function.name.borrow_mut().name = identifier.clone().into();
all_functions.insert(identifier, *function);
}
for (name, global_const) in program.global_consts.iter() {
let identifier = format!("{}{}", identifiers.next().unwrap(), name);
all_global_consts.insert(identifier, *global_const);
}
}
leo_ast::Program {
name: "ast_aggregate".to_string(),
imports: core_programs
.iter()
.map(|(module, _)| leo_ast::ImportStatement {
package_or_packages: leo_ast::PackageOrPackages::Package(leo_ast::Package {
name: Identifier::new(module.clone().into()),
access: leo_ast::PackageAccess::Star { span: Span::default() },
span: Default::default(),
}),
span: Span::default(),
})
.collect(),
expected_input: vec![],
functions: all_functions
.into_iter()
.map(|(_, function)| (function.name.borrow().clone(), function.into()))
.collect(),
circuits: all_circuits
.into_iter()
.map(|(_, circuit)| (circuit.name.borrow().clone(), circuit.into()))
.collect(),
global_consts: all_global_consts
.into_iter()
.map(|(_, global_const)| {
(
global_const
.variables
.iter()
.fold("".to_string(), |joined, variable_name| {
format!("{}, {}", joined, variable_name.borrow().name.name)
}),
global_const.into(),
)
})
.collect(),
}
}
impl<'a> Into<leo_ast::Program> for &Program<'a> {
fn into(self) -> leo_ast::Program {
leo_ast::Program {
name: self.name.clone(),
imports: vec![],
expected_input: vec![],
circuits: self
.circuits
.iter()
.map(|(_, circuit)| (circuit.name.borrow().clone(), (*circuit).into()))
.collect(),
functions: self
.functions
.iter()
.map(|(_, function)| (function.name.borrow().clone(), (*function).into()))
.collect(),
global_consts: self
.global_consts
.iter()
.map(|(_, global_const)| {
(
global_const
.variables
.iter()
.fold("".to_string(), |joined, variable_name| {
format!("{}, {}", joined, variable_name.borrow().name.name)
}),
(*global_const).into(),
)
})
.collect(),
}
}
}

View File

@ -1,90 +0,0 @@
// 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 <https://www.gnu.org/licenses/>.
use crate::{load_asg, make_test_context};
use leo_parser::parse_ast;
#[test]
fn test_basic() {
let program_string = include_str!("./circuits/pedersen_mock.leo");
let asg = load_asg(program_string).unwrap();
let reformed_ast = leo_asg::reform_ast(&asg);
println!("{}", reformed_ast);
// panic!();
}
#[test]
fn test_function_rename() {
let program_string = r#"
function iteration() -> u32 {
let a = 0u32;
for i in 0..10 {
a += 1;
}
return a;
}
function main() {
const total = iteration() + iteration();
console.assert(total == 20);
}
"#;
let asg = load_asg(program_string).unwrap();
let reformed_ast = leo_asg::reform_ast(&asg);
println!("{}", reformed_ast);
// panic!();
}
#[test]
fn test_imports() {
let import_name = "test-import".to_string();
let context = make_test_context();
let mut imports = crate::mocked_resolver(&context);
let test_import = r#"
circuit Point {
x: u32;
y: u32;
}
function foo() -> u32 {
return 1u32;
}
"#;
imports
.packages
.insert(import_name.clone(), load_asg(test_import).unwrap());
let program_string = r#"
import test-import.foo;
function main() {
console.assert(foo() == 1u32);
}
"#;
let test_import_ast = parse_ast(&import_name, test_import).unwrap();
println!("{}", serde_json::to_string(test_import_ast.as_repr()).unwrap());
let test_ast = parse_ast("test.leo", program_string).unwrap();
println!("{}", serde_json::to_string(test_ast.as_repr()).unwrap());
let asg = crate::load_asg_imports(&context, program_string, &mut imports).unwrap();
let reformed_ast = leo_asg::reform_ast(&asg);
println!("{}", serde_json::to_string(&reformed_ast).unwrap());
// panic!();
}

View File

@ -22,7 +22,6 @@ pub mod console;
pub mod core;
pub mod definition;
pub mod field;
pub mod form_ast;
pub mod function;
pub mod group;
pub mod import;

View File

@ -21,6 +21,10 @@ edition = "2018"
path = "../input"
version = "1.5.2"
[dependencies.leo-parser]
path = "../parser"
version = "1.5.2"
[dependencies.indexmap]
version = "1.7.0"
features = [ "serde-1" ]

View File

@ -15,6 +15,7 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{CanonicalizeError, CombinerError, FormattedError, LeoError, Span};
use leo_parser::SyntaxError;
#[derive(Debug, Error)]
pub enum ReducerError {
@ -26,6 +27,12 @@ pub enum ReducerError {
#[error("{}", _0)]
CombinerError(#[from] CombinerError),
#[error("{}", _0)]
ImportError(FormattedError),
#[error("{}", _0)]
SyntaxError(#[from] SyntaxError),
}
impl LeoError for ReducerError {}
@ -47,4 +54,10 @@ impl ReducerError {
Self::new_from_span(message, span)
}
pub fn ast_err() -> Self {
let message = "ahhhh";
Self::new_from_span(mesage, Span::default())
}
}

View File

@ -85,6 +85,12 @@ impl Ast {
Self { ast: program }
}
/// Mutates the program ast by resolving the imports.
pub fn importer<T: ImportResolver>(&mut self, importer: T) -> Result<(), AstError> {
self.ast = ReconstructingDirector::new(Importer::new(importer)).reduce_program(self.as_repr())?;
Ok(())
}
/// Mutates the program ast by preforming canonicalization on it.
pub fn canonicalize(&mut self) -> Result<(), AstError> {
self.ast = ReconstructingDirector::new(Canonicalizer::default()).reduce_program(self.as_repr())?;

View File

@ -28,7 +28,8 @@ use std::fmt;
pub struct Program {
pub name: String,
pub expected_input: Vec<FunctionInput>,
pub imports: Vec<ImportStatement>,
pub import_statements: Vec<ImportStatement>,
pub imports: IndexMap<String, Program>,
pub circuits: IndexMap<Identifier, Circuit>,
pub global_consts: IndexMap<String, DefinitionStatement>,
pub functions: IndexMap<Identifier, Function>,
@ -42,7 +43,12 @@ impl AsRef<Program> for Program {
impl fmt::Display for Program {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for import in self.imports.iter() {
for import in self.import_statements.iter() {
import.fmt(f)?;
writeln!(f,)?;
}
writeln!(f,)?;
for (_, import) in self.imports.iter() {
import.fmt(f)?;
writeln!(f,)?;
}
@ -65,7 +71,8 @@ impl Program {
Self {
name,
expected_input: vec![],
imports: vec![],
import_statements: vec![],
imports: IndexMap::new(),
circuits: IndexMap::new(),
global_consts: IndexMap::new(),
functions: IndexMap::new(),

205
ast/src/reducer/importer.rs Normal file
View File

@ -0,0 +1,205 @@
// 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 <https://www.gnu.org/licenses/>.
use crate::*;
use indexmap::IndexMap;
pub struct Importer<T>
where
T: ImportResolver,
{
import_resolver: T,
functions_to_import: Vec<(String, Option<String>)>,
circuits_to_import: Vec<(String, Option<String>)>,
global_consts_to_import: Vec<(String, Option<String>)>,
}
impl<T> Importer<T>
where
T: ImportResolver,
{
pub fn new(import_resolver: T) -> Self {
Self {
import_resolver,
functions_to_import: Vec::new(),
circuits_to_import: Vec::new(),
global_consts_to_import: Vec::new(),
}
}
}
/// Enumerates what names are imported from a package.
#[derive(Clone)]
enum ImportSymbol {
/// Import the symbol by name.
Direct(String),
/// Import the symbol by name and store it under an alias.
Alias(String, String), // from remote -> to local
/// Import all symbols from the package.
All,
}
fn resolve_import_package(
output: &mut Vec<(Vec<String>, ImportSymbol, Span)>,
mut package_segments: Vec<String>,
package_or_packages: &PackageOrPackages,
) {
match package_or_packages {
PackageOrPackages::Package(package) => {
package_segments.push(package.name.name.to_string());
resolve_import_package_access(output, package_segments, &package.access);
}
PackageOrPackages::Packages(packages) => {
package_segments.push(packages.name.name.to_string());
for access in packages.accesses.clone() {
resolve_import_package_access(output, package_segments.clone(), &access);
}
}
}
}
fn resolve_import_package_access(
output: &mut Vec<(Vec<String>, ImportSymbol, Span)>,
mut package_segments: Vec<String>,
package: &PackageAccess,
) {
match package {
PackageAccess::Star { span } => {
output.push((package_segments, ImportSymbol::All, span.clone()));
}
PackageAccess::SubPackage(subpackage) => {
resolve_import_package(
output,
package_segments,
&PackageOrPackages::Package(*(*subpackage).clone()),
);
}
PackageAccess::Symbol(symbol) => {
let span = symbol.symbol.span.clone();
let symbol = if let Some(alias) = symbol.alias.as_ref() {
ImportSymbol::Alias(symbol.symbol.name.to_string(), alias.name.to_string())
} else {
ImportSymbol::Direct(symbol.symbol.name.to_string())
};
output.push((package_segments, symbol, span));
}
PackageAccess::Multiple(packages) => {
package_segments.push(packages.name.name.to_string());
for subaccess in packages.accesses.iter() {
resolve_import_package_access(output, package_segments.clone(), &subaccess);
}
}
}
}
impl<T> ReconstructingReducer for Importer<T>
where
T: ImportResolver,
{
fn in_circuit(&self) -> bool {
false
}
fn swap_in_circuit(&mut self) {}
fn reduce_program(
&mut self,
program: &Program,
expected_input: Vec<FunctionInput>,
import_statements: Vec<ImportStatement>,
empty_imports: IndexMap<String, Program>,
circuits: IndexMap<Identifier, Circuit>,
functions: IndexMap<Identifier, Function>,
global_consts: IndexMap<String, DefinitionStatement>,
) -> Result<Program, ReducerError> {
if !empty_imports.is_empty() {
// TODO THROW ERR
}
let mut imported_symbols: Vec<(Vec<String>, ImportSymbol, Span)> = vec![];
for import_statement in import_statements.iter() {
resolve_import_package(&mut imported_symbols, vec![], &import_statement.package_or_packages);
}
let mut deduplicated_imports: IndexMap<Vec<String>, Span> = IndexMap::new();
for (package, _symbol, span) in imported_symbols.iter() {
deduplicated_imports.insert(package.clone(), span.clone());
}
let mut wrapped_resolver = CoreImportResolver::new(&mut self.import_resolver);
let mut resolved_packages: IndexMap<Vec<String>, Program> = IndexMap::new();
for (package, span) in deduplicated_imports {
let _pretty_package = package.join(".");
let resolved_package =
match wrapped_resolver.resolve_package(&package.iter().map(|x| &**x).collect::<Vec<_>>()[..], &span)? {
Some(x) => x,
None => return Err(ReducerError::empty_string(&span)),
};
resolved_packages.insert(package.clone(), resolved_package);
}
// TODO Errors
// TODO copyable AST.
// TODO should imports be renamed in imported program?
for (package, symbol, span) in imported_symbols.into_iter() {
let _pretty_package = package.join(".");
let resolved_package = resolved_packages
.get_mut(&package)
.expect("could not find preloaded package");
match symbol {
ImportSymbol::Alias(name, alias) => {
let lookup_ident = Identifier::new(name.clone().into());
if let Some((ident, function)) = resolved_package.functions.remove_entry(&lookup_ident) {
let mut alias_identifier = ident.clone();
alias_identifier.name = alias.into();
resolved_package.functions.insert(alias_identifier, function.clone());
} else if let Some((ident, circuit)) = resolved_package.circuits.remove_entry(&lookup_ident) {
let mut alias_identifier = ident.clone();
alias_identifier.name = alias.into();
resolved_package.circuits.insert(alias_identifier, circuit.clone());
} else if let Some(global_const) = resolved_package.global_consts.remove(&name) {
resolved_package
.global_consts
.insert(alias.clone(), global_const.clone());
} else {
return Err(ReducerError::empty_string(&span));
}
}
_ => {}
}
}
Ok(Program {
name: program.name.clone(),
expected_input,
import_statements,
imports: resolved_packages
.into_iter()
.map(|(package, program)| (package.join("."), program))
.collect(),
circuits,
functions,
global_consts,
})
}
}

View File

@ -14,11 +14,17 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
mod canonicalization;
pub mod canonicalization;
pub use canonicalization::*;
mod reconstructing_reducer;
pub mod reconstructing_reducer;
pub use reconstructing_reducer::*;
mod reconstructing_director;
pub mod reconstructing_director;
pub use reconstructing_director::*;
pub mod importer;
pub use self::importer::*;
pub mod resolver;
pub use self::resolver::*;

View File

@ -437,9 +437,15 @@ impl<R: ReconstructingReducer> ReconstructingDirector<R> {
inputs.push(self.reduce_function_input(input)?);
}
let mut imports = vec![];
for import in program.imports.iter() {
imports.push(self.reduce_import(import)?);
let mut import_statements = vec![];
for import in program.import_statements.iter() {
import_statements.push(self.reduce_import_statement(import)?);
}
let mut imports = IndexMap::new();
for (identifier, program) in program.imports.iter() {
let (ident, import) = self.reduce_import(identifier, program)?;
imports.insert(ident, import);
}
let mut circuits = IndexMap::new();
@ -459,8 +465,15 @@ impl<R: ReconstructingReducer> ReconstructingDirector<R> {
global_consts.insert(name.clone(), self.reduce_definition(&definition)?);
}
self.reducer
.reduce_program(program, inputs, imports, circuits, functions, global_consts)
self.reducer.reduce_program(
program,
inputs,
import_statements,
imports,
circuits,
functions,
global_consts,
)
}
pub fn reduce_function_input_variable(
@ -504,10 +517,16 @@ impl<R: ReconstructingReducer> ReconstructingDirector<R> {
self.reducer.reduce_package_or_packages(package_or_packages, new)
}
pub fn reduce_import(&mut self, import: &ImportStatement) -> Result<ImportStatement, ReducerError> {
pub fn reduce_import_statement(&mut self, import: &ImportStatement) -> Result<ImportStatement, ReducerError> {
let package_or_packages = self.reduce_package_or_packages(&import.package_or_packages)?;
self.reducer.reduce_import(import, package_or_packages)
self.reducer.reduce_import_statement(import, package_or_packages)
}
pub fn reduce_import(&mut self, identifier: &str, import: &Program) -> Result<(String, Program), ReducerError> {
let new_identifer = identifier.to_string();
let new_import = self.reduce_program(import)?;
self.reducer.reduce_import(new_identifer, new_import)
}
pub fn reduce_circuit_member(&mut self, circuit_member: &CircuitMember) -> Result<CircuitMember, ReducerError> {

View File

@ -399,7 +399,8 @@ pub trait ReconstructingReducer {
&mut self,
program: &Program,
expected_input: Vec<FunctionInput>,
imports: Vec<ImportStatement>,
import_statements: Vec<ImportStatement>,
imports: IndexMap<String, Program>,
circuits: IndexMap<Identifier, Circuit>,
functions: IndexMap<Identifier, Function>,
global_consts: IndexMap<String, DefinitionStatement>,
@ -407,6 +408,7 @@ pub trait ReconstructingReducer {
Ok(Program {
name: program.name.clone(),
expected_input,
import_statements,
imports,
circuits,
functions,
@ -445,7 +447,7 @@ pub trait ReconstructingReducer {
Ok(new)
}
fn reduce_import(
fn reduce_import_statement(
&mut self,
import: &ImportStatement,
package_or_packages: PackageOrPackages,
@ -456,6 +458,10 @@ pub trait ReconstructingReducer {
})
}
fn reduce_import(&mut self, identifier: String, import: Program) -> Result<(String, Program), ReducerError> {
Ok((identifier, import))
}
fn reduce_circuit_member(
&mut self,
_circuit_member: &CircuitMember,

View File

@ -0,0 +1,83 @@
// 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 <https://www.gnu.org/licenses/>.
use crate::{Program, ReducerError, Span};
use indexmap::IndexMap;
pub trait ImportResolver {
fn resolve_package(&mut self, package_segments: &[&str], span: &Span) -> Result<Option<Program>, ReducerError>;
}
pub struct NullImportResolver;
impl ImportResolver for NullImportResolver {
fn resolve_package(&mut self, _package_segments: &[&str], _span: &Span) -> Result<Option<Program>, ReducerError> {
Ok(None)
}
}
pub struct CoreImportResolver<'a, T: ImportResolver> {
inner: &'a mut T,
}
impl<'a, T: ImportResolver> CoreImportResolver<'a, T> {
pub fn new(inner: &'a mut T) -> Self {
CoreImportResolver { inner }
}
}
impl<'a, T: ImportResolver> ImportResolver for CoreImportResolver<'a, T> {
fn resolve_package(&mut self, package_segments: &[&str], span: &Span) -> Result<Option<Program>, ReducerError> {
if !package_segments.is_empty() && package_segments.get(0).unwrap() == &"core" {
Ok(resolve_core_module(&*package_segments[1..].join("."))?)
} else {
self.inner.resolve_package(package_segments, span)
}
}
}
pub struct MockedImportResolver {
pub packages: IndexMap<String, Program>,
}
impl ImportResolver for MockedImportResolver {
fn resolve_package(&mut self, package_segments: &[&str], _span: &Span) -> Result<Option<Program>, ReducerError> {
Ok(self.packages.get(&package_segments.join(".")).cloned())
}
}
pub fn resolve_core_module(module: &str) -> Result<Option<Program>, ReducerError> {
match module {
"unstable.blake2s" => {
// let ast = load_asg(
// context,
// r#"
// circuit Blake2s {
// function hash(seed: [u8; 32], message: [u8; 32]) -> [u8; 32] {
// return [0; 32];
// }
// }
// "#,
// &mut crate::NullImportResolver,
// )?;
// asg.set_core_mapping("blake2s");
// Ok(Some(asg))
Ok(None)
}
_ => Ok(None),
}
}

View File

@ -244,6 +244,8 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
ast.to_json_file(self.output_directory.clone(), "initial_ast.json")?;
}
ast.importer(&mut leo_imports::ImportParser::new(self.main_file_path.clone()))?;
// Preform compiler optimization via canonicalizing AST if its enabled.
if self.options.canonicalization_enabled {
ast.canonicalize()?;
@ -260,11 +262,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> Compiler<'a, F, G> {
tracing::debug!("Program parsing complete\n{:#?}", self.program);
// Create a new symbol table from the program, imported_programs, and program_input.
let asg = Asg::new(
self.context,
&self.program,
&mut leo_imports::ImportParser::new(self.main_file_path.clone()),
)?;
let asg = Asg::new(self.context, &self.program)?;
if self.ast_snapshot_options.type_inferenced {
let new_ast = TypeInferencePhase::default()

View File

@ -706,6 +706,11 @@ impl<R: ReconstructingReducer, O: CombinerOptions> CombineAstAsgDirector<R, O> {
ast: &leo_ast::Program,
asg: &leo_asg::Program,
) -> Result<leo_ast::Program, leo_ast::ReducerError> {
let mut imports = IndexMap::new();
for ((ast_ident, ast_program), (_asg_ident, asg_program)) in ast.imports.iter().zip(&asg.imported_modules) {
imports.insert(ast_ident.clone(), self.reduce_program(ast_program, asg_program)?);
}
self.ast_reducer.swap_in_circuit();
let mut circuits = IndexMap::new();
for ((ast_ident, ast_circuit), (_asg_ident, asg_circuit)) in ast.circuits.iter().zip(&asg.circuits) {
@ -727,7 +732,8 @@ impl<R: ReconstructingReducer, O: CombinerOptions> CombineAstAsgDirector<R, O> {
self.ast_reducer.reduce_program(
ast,
ast.expected_input.clone(),
ast.imports.clone(),
ast.import_statements.clone(),
imports,
circuits,
functions,
global_consts,

View File

@ -13,8 +13,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use leo_asg::AsgConvertError;
use leo_ast::{AstError, FormattedError, Identifier, LeoError, Span};
use leo_ast::{AstError, FormattedError, Identifier, LeoError, Span, ReducerError};
use leo_parser::SyntaxError;
use std::{io, path::Path};
@ -31,18 +30,18 @@ pub enum ImportParserError {
AstError(#[from] AstError),
#[error("{}", _0)]
AsgConvertError(#[from] AsgConvertError),
ReducerError(#[from] ReducerError),
}
impl LeoError for ImportParserError {}
impl Into<AsgConvertError> for ImportParserError {
fn into(self) -> AsgConvertError {
impl Into<ReducerError> for ImportParserError {
fn into(self) -> ReducerError {
match self {
ImportParserError::Error(x) => AsgConvertError::ImportError(x),
ImportParserError::Error(x) => ReducerError::ImportError(x),
ImportParserError::SyntaxError(x) => x.into(),
ImportParserError::AstError(x) => AsgConvertError::AstError(x),
ImportParserError::AsgConvertError(x) => x,
ImportParserError::AstError(x) => ReducerError::ast_err(),
ImportParserError::ReducerError(x) => x,
}
}
}

View File

@ -15,7 +15,7 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::errors::ImportParserError;
use leo_asg::{AsgContext, AsgConvertError, ImportResolver, Program, Span};
use leo_ast::{ImportResolver, Program, Span, ReducerError};
use indexmap::{IndexMap, IndexSet};
use std::path::PathBuf;
@ -25,13 +25,13 @@ use std::path::PathBuf;
/// A program can import one or more packages. A package can be found locally in the source
/// directory, foreign in the imports directory, or part of the core package list.
#[derive(Clone, Default)]
pub struct ImportParser<'a> {
pub struct ImportParser {
program_path: PathBuf,
partial_imports: IndexSet<String>,
imports: IndexMap<String, Program<'a>>,
imports: IndexMap<String, Program>,
}
impl<'a> ImportParser<'a> {
impl ImportParser {
pub fn new(program_path: PathBuf) -> Self {
ImportParser {
program_path,
@ -41,16 +41,16 @@ impl<'a> ImportParser<'a> {
}
}
impl<'a> ImportResolver<'a> for ImportParser<'a> {
impl ImportResolver for ImportParser {
fn resolve_package(
&mut self,
context: AsgContext<'a>,
package_segments: &[&str],
span: &Span,
) -> Result<Option<Program<'a>>, AsgConvertError> {
) -> Result<Option<Program>, ReducerError> {
let full_path = package_segments.join(".");
if self.partial_imports.contains(&full_path) {
return Err(ImportParserError::recursive_imports(&full_path, span).into());
// return Err(ImportParserError::recursive_imports(&full_path, span).into());
}
if let Some(program) = self.imports.get(&full_path) {
return Ok(Some(program.clone()));
@ -60,8 +60,8 @@ impl<'a> ImportResolver<'a> for ImportParser<'a> {
self.partial_imports.insert(full_path.clone());
let program = imports
.parse_package(context, path, package_segments, span)
.map_err(|x| -> AsgConvertError { x.into() })?;
.parse_package(path, package_segments, span)
.map_err(|x| -> ReducerError { x.into() })?;
self.partial_imports.remove(&full_path);
self.imports.insert(full_path, program.clone());
Ok(Some(program))

View File

@ -15,7 +15,7 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{errors::ImportParserError, ImportParser};
use leo_asg::{AsgContext, Identifier, Program, Span};
use leo_ast::{Identifier, ImportResolver, Program, Span, ReducerError};
use std::{fs, fs::DirEntry, path::PathBuf};
@ -23,21 +23,18 @@ static SOURCE_FILE_EXTENSION: &str = ".leo";
static SOURCE_DIRECTORY_NAME: &str = "src/";
static IMPORTS_DIRECTORY_NAME: &str = "imports/";
impl<'a> ImportParser<'a> {
impl ImportParser {
fn parse_package_access(
&mut self,
context: AsgContext<'a>,
package: &DirEntry,
remaining_segments: &[&str],
span: &Span,
) -> Result<Program<'a>, ImportParserError> {
) -> Result<Program, ImportParserError> {
if !remaining_segments.is_empty() {
return self.parse_package(context, package.path(), remaining_segments, span);
return self.parse_package(package.path(), remaining_segments, span);
}
let program = Self::parse_import_file(package, span)?;
let asg = leo_asg::Program::new(context, &program, self)?;
Ok(asg)
Self::parse_import_file(package, span)
}
///
@ -47,11 +44,10 @@ impl<'a> ImportParser<'a> {
///
pub(crate) fn parse_package(
&mut self,
context: AsgContext<'a>,
mut path: PathBuf,
segments: &[&str],
span: &Span,
) -> Result<Program<'a>, ImportParserError> {
) -> Result<Program, ImportParserError> {
let error_path = path.clone();
let package_name = segments[0];
@ -114,8 +110,8 @@ impl<'a> ImportParser<'a> {
package_name,
span.clone(),
))),
(Some(source_entry), None) => self.parse_package_access(context, &source_entry, &segments[1..], span),
(None, Some(import_entry)) => self.parse_package_access(context, &import_entry, &segments[1..], span),
(Some(source_entry), None) => self.parse_package_access(&source_entry, &segments[1..], span),
(None, Some(import_entry)) => self.parse_package_access(&import_entry, &segments[1..], span),
(None, None) => Err(ImportParserError::unknown_package(Identifier::new_with_span(
package_name,
span.clone(),
@ -124,7 +120,7 @@ impl<'a> ImportParser<'a> {
} else {
// Enforce local package access with no found imports directory
match matched_source_entry {
Some(source_entry) => self.parse_package_access(context, &source_entry, &segments[1..], span),
Some(source_entry) => self.parse_package_access(&source_entry, &segments[1..], span),
None => Err(ImportParserError::unknown_package(Identifier::new_with_span(
package_name,
span.clone(),

View File

@ -21,7 +21,7 @@ use std::fs::DirEntry;
static MAIN_FILE: &str = "src/main.leo";
impl<'a> ImportParser<'a> {
impl ImportParser {
///
/// Returns a Leo syntax tree from a given package.
///
@ -56,8 +56,6 @@ impl<'a> ImportParser<'a> {
&std::fs::read_to_string(&file_path).map_err(|x| ImportParserError::io_error(span, file_path_str, x))?;
let mut program = leo_parser::parse(&file_path_str, &program_string)?;
program.name = file_name;
let mut ast = leo_ast::Ast::new(program);
ast.canonicalize()?;
Ok(ast.into_repr())
Ok(program)
}
}

View File

@ -25,7 +25,7 @@ impl ParserContext {
/// Returns a [`Program`] AST if all tokens can be consumed and represent a valid Leo program.
///
pub fn parse_program(&mut self) -> SyntaxResult<Program> {
let mut imports = Vec::new();
let mut import_statements = Vec::new();
let mut circuits = IndexMap::new();
let mut functions = IndexMap::new();
let mut global_consts = IndexMap::new();
@ -35,7 +35,7 @@ impl ParserContext {
let token = self.peek()?;
match &token.token {
Token::Import => {
imports.push(self.parse_import()?);
import_statements.push(self.parse_import_statement()?);
}
Token::Circuit => {
let (id, circuit) = self.parse_circuit()?;
@ -49,12 +49,6 @@ impl ParserContext {
return Err(SyntaxError::DeprecatedError(DeprecatedError::test_function(
&token.span,
)));
// self.expect(Token::Test)?;
// let (id, function) = self.parse_function_declaration()?;
// tests.insert(id, TestFunction {
// function,
// input_file: None,
// });
}
Token::Const => {
let (name, global_const) = self.parse_global_const_declaration()?;
@ -78,7 +72,8 @@ impl ParserContext {
Ok(Program {
name: String::new(),
expected_input: Vec::new(),
imports,
import_statements,
imports: IndexMap::new(),
circuits,
functions,
global_consts,
@ -281,7 +276,7 @@ impl ParserContext {
///
/// Returns a [`ImportStatement`] AST node if the next tokens represent an import statement.
///
pub fn parse_import(&mut self) -> SyntaxResult<ImportStatement> {
pub fn parse_import_statement(&mut self) -> SyntaxResult<ImportStatement> {
self.expect(Token::Import)?;
let package_or_packages = self.parse_package_path()?;
self.expect(Token::Semicolon)?;