mirror of
https://github.com/AleoHQ/leo.git
synced 2024-12-01 18:56:38 +03:00
impl constraints and tests for multiple imports
This commit is contained in:
parent
5900923d9d
commit
a4a9ed05ea
@ -8,8 +8,8 @@ use pest_ast::FromPest;
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::package_access))]
|
||||
pub enum PackageAccess<'ast> {
|
||||
Star(Star),
|
||||
Star(Star<'ast>),
|
||||
SubPackage(Box<Package<'ast>>),
|
||||
Multiple(Vec<Package<'ast>>),
|
||||
Symbol(ImportSymbol<'ast>),
|
||||
Multiple(Vec<PackageAccess<'ast>>),
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
use crate::ast::Rule;
|
||||
|
||||
use pest::Span;
|
||||
use pest_ast::FromPest;
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::star))]
|
||||
pub struct Star {}
|
||||
pub struct Star<'ast> {
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
@ -290,22 +290,22 @@ import = { "import" ~ package ~ LINE_END}
|
||||
|
||||
// Declared in imports/package.rs
|
||||
package = { identifier ~ "." ~ package_access }
|
||||
package_tuple = _{ "(" ~ package ~ ("," ~ NEWLINE* ~ package)* ~ ")" }
|
||||
|
||||
// Declared in imports/package_access
|
||||
package_access = {
|
||||
star
|
||||
| package // subpackage
|
||||
| package_tuple
|
||||
| multiple_package_access
|
||||
| import_symbol
|
||||
}
|
||||
|
||||
multiple_package_access = _{ "(" ~ NEWLINE* ~ package_access ~ ("," ~ NEWLINE* ~ package_access)* ~ NEWLINE* ~ ")"}
|
||||
|
||||
// Declared in imports/star.rs
|
||||
star = {"*"}
|
||||
|
||||
// Declared in imports/import_symbol.rs
|
||||
import_symbol = { identifier ~ ("as" ~ identifier)? }
|
||||
// import_tuple = _{}
|
||||
|
||||
/// Utilities
|
||||
|
||||
|
@ -5,49 +5,61 @@ use crate::{
|
||||
GroupType,
|
||||
};
|
||||
use leo_ast::LeoParser;
|
||||
use leo_types::{Import, ImportSymbol, Package, PackageAccess, Program};
|
||||
use leo_types::{Import, ImportSymbol, Package, PackageAccess, Program, Span};
|
||||
|
||||
use snarkos_models::curves::{Field, PrimeField};
|
||||
use std::{env::current_dir, fs, fs::DirEntry, path::PathBuf};
|
||||
|
||||
pub(crate) static SOURCE_DIRECTORY_NAME: &str = "src/";
|
||||
static SOURCE_FILE_EXTENSION: &str = ".leo";
|
||||
static SOURCE_DIRECTORY_NAME: &str = "src/";
|
||||
// pub(crate) static IMPORTS_DIRECTORY_NAME: &str = "imports/";
|
||||
|
||||
fn parse_import_file(entry: &DirEntry, span: &Span) -> Result<Program, ImportError> {
|
||||
// make sure the given entry is file
|
||||
let file_type = entry
|
||||
.file_type()
|
||||
.map_err(|error| ImportError::directory_error(error, span.clone()))?;
|
||||
let file_name = entry
|
||||
.file_name()
|
||||
.into_string()
|
||||
.map_err(|_| ImportError::convert_os_string(span.clone()))?;
|
||||
|
||||
if file_type.is_dir() {
|
||||
return Err(ImportError::expected_file(file_name, span.clone()));
|
||||
}
|
||||
|
||||
// Build the abstract syntax tree
|
||||
let file_path = &entry.path();
|
||||
let input_file = &LeoParser::load_file(file_path)?;
|
||||
let syntax_tree = LeoParser::parse_file(file_path, input_file)?;
|
||||
|
||||
// Generate aleo program from file
|
||||
Ok(Program::from(syntax_tree, file_name.clone()))
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn enforce_import_symbol(
|
||||
&mut self,
|
||||
scope: String,
|
||||
entry: DirEntry,
|
||||
symbol: ImportSymbol,
|
||||
) -> Result<(), ImportError> {
|
||||
// make sure the given entry is file
|
||||
let file_type = entry
|
||||
.file_type()
|
||||
.map_err(|error| ImportError::directory_error(error, symbol.span.clone()))?;
|
||||
let file_name = entry
|
||||
.file_name()
|
||||
.into_string()
|
||||
.map_err(|_| ImportError::convert_os_string(symbol.span.clone()))?;
|
||||
if file_type.is_dir() {
|
||||
return Err(ImportError::expected_file(file_name, symbol));
|
||||
}
|
||||
|
||||
// Build the abstract syntax tree
|
||||
let file_path = &entry.path();
|
||||
let input_file = &LeoParser::load_file(file_path)?;
|
||||
let syntax_tree = LeoParser::parse_file(file_path, input_file)?;
|
||||
|
||||
// Generate aleo program from file
|
||||
let mut program = Program::from(syntax_tree, file_name.clone());
|
||||
pub fn enforce_import_star(&mut self, scope: String, entry: &DirEntry, span: Span) -> Result<(), ImportError> {
|
||||
let mut program = parse_import_file(entry, &span)?;
|
||||
|
||||
// Use same namespace as calling function for imported symbols
|
||||
program = program.name(scope);
|
||||
|
||||
// * -> import all imports, circuits, functions in the current scope
|
||||
// if import.is_star() {
|
||||
// // recursively evaluate program statements
|
||||
// self.resolve_definitions(program)
|
||||
// } else {
|
||||
self.resolve_definitions(program)
|
||||
}
|
||||
|
||||
pub fn enforce_import_symbol(
|
||||
&mut self,
|
||||
scope: String,
|
||||
entry: &DirEntry,
|
||||
symbol: ImportSymbol,
|
||||
) -> Result<(), ImportError> {
|
||||
// Generate aleo program from file
|
||||
let mut program = parse_import_file(entry, &symbol.span)?;
|
||||
|
||||
// Use same namespace as calling function for imported symbols
|
||||
program = program.name(scope);
|
||||
|
||||
let program_name = program.name.clone();
|
||||
|
||||
// match each import symbol to a symbol in the imported file
|
||||
@ -71,7 +83,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
|
||||
match matched_function {
|
||||
Some((_function_name, function)) => ConstrainedValue::Function(None, function),
|
||||
None => return Err(ImportError::unknown_symbol(symbol, program_name, file_path)),
|
||||
None => return Err(ImportError::unknown_symbol(symbol, program_name, &entry.path())),
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -98,18 +110,18 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn enforce_package_access(
|
||||
&mut self,
|
||||
scope: String,
|
||||
entry: DirEntry,
|
||||
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
|
||||
match access {
|
||||
PackageAccess::Star => unimplemented!("star not impl"),
|
||||
PackageAccess::Star(span) => self.enforce_import_star(scope, entry, span),
|
||||
PackageAccess::Symbol(symbol) => self.enforce_import_symbol(scope, entry, symbol),
|
||||
PackageAccess::SubPackage(package) => self.enforce_package(scope, entry.path(), *package),
|
||||
PackageAccess::Multiple(packages) => {
|
||||
for package in packages {
|
||||
self.enforce_package(scope.clone(), entry.path(), package)?;
|
||||
PackageAccess::Multiple(accesses) => {
|
||||
for access in accesses {
|
||||
self.enforce_package_access(scope.clone(), entry, access)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -130,9 +142,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
.collect::<Result<Vec<_>, std::io::Error>>()
|
||||
.map_err(|error| ImportError::directory_error(error, package_name.span.clone()))?;
|
||||
|
||||
let matched_source_entry = entries
|
||||
.into_iter()
|
||||
.find(|entry| entry.file_name().into_string().unwrap().eq(&package_name.name));
|
||||
let matched_source_entry = entries.into_iter().find(|entry| {
|
||||
entry
|
||||
.file_name()
|
||||
.into_string()
|
||||
.unwrap()
|
||||
.trim_end_matches(SOURCE_FILE_EXTENSION)
|
||||
.eq(&package_name.name)
|
||||
});
|
||||
|
||||
// search for package name in imports directory
|
||||
// let mut source_directory = path.clone();
|
||||
@ -152,90 +169,15 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
|
||||
// Enforce package access
|
||||
if let Some(entry) = matched_source_entry {
|
||||
self.enforce_package_access(scope, entry, package.access)?;
|
||||
self.enforce_package_access(scope, &entry, package.access)
|
||||
} else {
|
||||
Err(ImportError::unknown_package(package_name))
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn enforce_import(&mut self, scope: String, import: Import) -> Result<(), ImportError> {
|
||||
let path = current_dir().map_err(|error| ImportError::directory_error(error, import.span.clone()))?;
|
||||
|
||||
self.enforce_package(scope, path, import.package)
|
||||
//
|
||||
// // Sanitize the package path to the imports directory
|
||||
// let mut package_path = path.clone();
|
||||
// if package_path.is_file() {
|
||||
// package_path.pop();
|
||||
// }
|
||||
//
|
||||
// // Construct the path to the import file in the import directory
|
||||
// let mut main_file_path = package_path.clone();
|
||||
// main_file_path.push(import.path_string_full());
|
||||
//
|
||||
// println!("Compiling import - {:?}", main_file_path);
|
||||
//
|
||||
// // Build the abstract syntax tree
|
||||
// let file_path = &main_file_path;
|
||||
// let input_file = &LeoParser::load_file(file_path)?;
|
||||
// let syntax_tree = LeoParser::parse_file(file_path, input_file)?;
|
||||
//
|
||||
// // Generate aleo program from file
|
||||
// let mut program = Program::from(syntax_tree, import.path_string.clone());
|
||||
//
|
||||
// // Use same namespace as calling function for imported symbols
|
||||
// program = program.name(scope);
|
||||
//
|
||||
// // * -> import all imports, circuits, functions in the current scope
|
||||
// if import.is_star() {
|
||||
// // recursively evaluate program statements
|
||||
// self.resolve_definitions(program)
|
||||
// } else {
|
||||
// let program_name = program.name.clone();
|
||||
//
|
||||
// // match each import symbol to a symbol in the imported file
|
||||
// for symbol in import.symbols.into_iter() {
|
||||
// // see if the imported symbol is a circuit
|
||||
// let matched_circuit = program
|
||||
// .circuits
|
||||
// .clone()
|
||||
// .into_iter()
|
||||
// .find(|(circuit_name, _circuit_def)| symbol.symbol == *circuit_name);
|
||||
//
|
||||
// let value = match matched_circuit {
|
||||
// Some((_circuit_name, circuit_def)) => ConstrainedValue::CircuitDefinition(circuit_def),
|
||||
// None => {
|
||||
// // see if the imported symbol is a function
|
||||
// let matched_function = program
|
||||
// .functions
|
||||
// .clone()
|
||||
// .into_iter()
|
||||
// .find(|(function_name, _function)| symbol.symbol.name == *function_name.name);
|
||||
//
|
||||
// match matched_function {
|
||||
// Some((_function_name, function)) => ConstrainedValue::Function(None, function),
|
||||
// None => return Err(ImportError::unknown_symbol(symbol, program_name, file_path)),
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// // take the alias if it is present
|
||||
// let resolved_name = symbol.alias.unwrap_or(symbol.symbol);
|
||||
// let resolved_circuit_name = new_scope(program_name.clone(), resolved_name.to_string());
|
||||
//
|
||||
// // store imported circuit under resolved name
|
||||
// self.store(resolved_circuit_name, value);
|
||||
// }
|
||||
//
|
||||
// // evaluate all import statements in imported file
|
||||
// // todo: add logic to detect import loops
|
||||
// program
|
||||
// .imports
|
||||
// .into_iter()
|
||||
// .map(|nested_import| self.enforce_import(program_name.clone(), nested_import))
|
||||
// .collect::<Result<Vec<_>, ImportError>>()?;
|
||||
//
|
||||
// Ok(())
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use leo_ast::ParserError;
|
||||
use leo_types::{Error as FormattedError, ImportSymbol, Span};
|
||||
use leo_types::{Error as FormattedError, Identifier, ImportSymbol, Span};
|
||||
|
||||
use std::{io, path::PathBuf};
|
||||
|
||||
@ -29,10 +29,19 @@ impl ImportError {
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn expected_file(entry: String, symbol: ImportSymbol) -> Self {
|
||||
let message = format!("cannot import symbol `{}` from directory `{}`", symbol, entry);
|
||||
pub fn expected_file(entry: String, span: Span) -> Self {
|
||||
let message = format!("cannot import symbol `{}` from directory `{}`", span.text, entry);
|
||||
|
||||
Self::new_from_span(message, symbol.span)
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn unknown_package(identifier: Identifier) -> Self {
|
||||
let message = format!(
|
||||
"cannot find imported package `{}` in source files or import directory",
|
||||
identifier.name
|
||||
);
|
||||
|
||||
Self::new_from_span(message, identifier.span)
|
||||
}
|
||||
|
||||
pub fn unknown_symbol(symbol: ImportSymbol, file: String, file_path: &PathBuf) -> Self {
|
||||
|
@ -1,4 +1,4 @@
|
||||
from "tests/import/test_import" import foo as bar;
|
||||
import test_import.foo as bar;
|
||||
|
||||
function main() -> u32 {
|
||||
return bar()
|
||||
|
@ -1,4 +1,4 @@
|
||||
from "tests/import/test_import" import foo;
|
||||
import test_import.foo;
|
||||
|
||||
function main() -> u32 {
|
||||
return foo()
|
||||
|
@ -1,13 +1,26 @@
|
||||
use crate::{integers::u32::output_one, parse_program};
|
||||
|
||||
use std::env::{current_dir, set_current_dir};
|
||||
|
||||
static TEST_SOURCE_DIRECTORY: &str = "tests/import";
|
||||
|
||||
// Import tests rely on knowledge of local directories. They should be run locally only.
|
||||
|
||||
fn set_local_dir() {
|
||||
let mut local = current_dir().unwrap();
|
||||
local.push(TEST_SOURCE_DIRECTORY);
|
||||
|
||||
set_current_dir(local).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_basic() {
|
||||
let bytes = include_bytes!("basic.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
set_local_dir();
|
||||
|
||||
output_one(program);
|
||||
}
|
||||
|
||||
@ -17,6 +30,8 @@ fn test_multiple() {
|
||||
let bytes = include_bytes!("multiple.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
set_local_dir();
|
||||
|
||||
output_one(program);
|
||||
}
|
||||
|
||||
@ -26,6 +41,8 @@ fn test_star() {
|
||||
let bytes = include_bytes!("star.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
set_local_dir();
|
||||
|
||||
output_one(program);
|
||||
}
|
||||
|
||||
@ -35,5 +52,7 @@ fn test_alias() {
|
||||
let bytes = include_bytes!("alias.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
set_local_dir();
|
||||
|
||||
output_one(program);
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
from "tests/import/test_import" import {
|
||||
import test_import.(
|
||||
Point,
|
||||
foo
|
||||
};
|
||||
);
|
||||
|
||||
function main() -> u32 {
|
||||
let p = Point { x: 1u32, y: 0u32 };
|
||||
return foo()
|
||||
return p.x
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
from "tests/import/test_import" import *;
|
||||
import test_import.*;
|
||||
|
||||
function main() -> u32 {
|
||||
let p = Point { x: 1u32, y: 0u32 };
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! The import type for a Leo program.
|
||||
|
||||
use crate::{ImportSymbol, Package, Span};
|
||||
use crate::{Package, Span};
|
||||
use leo_ast::imports::Import as AstImport;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{ImportSymbol, Package};
|
||||
use crate::{ImportSymbol, Package, Span};
|
||||
use leo_ast::imports::PackageAccess as AstPackageAccess;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -6,21 +6,21 @@ use std::fmt;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub enum PackageAccess {
|
||||
Star,
|
||||
Star(Span),
|
||||
SubPackage(Box<Package>),
|
||||
Multiple(Vec<Package>),
|
||||
Symbol(ImportSymbol),
|
||||
Multiple(Vec<PackageAccess>),
|
||||
}
|
||||
|
||||
impl<'ast> From<AstPackageAccess<'ast>> for PackageAccess {
|
||||
fn from(access: AstPackageAccess<'ast>) -> Self {
|
||||
match access {
|
||||
AstPackageAccess::Star(_) => PackageAccess::Star,
|
||||
AstPackageAccess::Star(star) => PackageAccess::Star(Span::from(star.span)),
|
||||
AstPackageAccess::SubPackage(package) => PackageAccess::SubPackage(Box::new(Package::from(*package))),
|
||||
AstPackageAccess::Multiple(packages) => {
|
||||
PackageAccess::Multiple(packages.into_iter().map(|package| Package::from(package)).collect())
|
||||
}
|
||||
AstPackageAccess::Symbol(symbol) => PackageAccess::Symbol(ImportSymbol::from(symbol)),
|
||||
AstPackageAccess::Multiple(accesses) => {
|
||||
PackageAccess::Multiple(accesses.into_iter().map(|access| PackageAccess::from(access)).collect())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -28,19 +28,19 @@ impl<'ast> From<AstPackageAccess<'ast>> for PackageAccess {
|
||||
impl PackageAccess {
|
||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
PackageAccess::Star => write!(f, ".*"),
|
||||
PackageAccess::Star(ref _span) => write!(f, ".*"),
|
||||
PackageAccess::SubPackage(ref package) => write!(f, ".{}", package),
|
||||
PackageAccess::Multiple(ref packages) => {
|
||||
PackageAccess::Symbol(ref symbol) => write!(f, ".{}", symbol),
|
||||
PackageAccess::Multiple(ref accesses) => {
|
||||
write!(f, ".(")?;
|
||||
for (i, package) in packages.iter().enumerate() {
|
||||
write!(f, "{}", package)?;
|
||||
if i < packages.len() - 1 {
|
||||
for (i, access) in accesses.iter().enumerate() {
|
||||
write!(f, "{}", access)?;
|
||||
if i < accesses.len() - 1 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
}
|
||||
write!(f, ")")
|
||||
}
|
||||
PackageAccess::Symbol(ref symbol) => write!(f, ".{}", symbol),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user