mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-25 11:12:48 +03:00
merge refactor/const
This commit is contained in:
commit
a78d077d40
38
Cargo.lock
generated
38
Cargo.lock
generated
@ -101,7 +101,7 @@ dependencies = [
|
|||||||
"byte-tools",
|
"byte-tools",
|
||||||
"crypto-mac",
|
"crypto-mac",
|
||||||
"digest 0.8.1",
|
"digest 0.8.1",
|
||||||
"opaque-debug",
|
"opaque-debug 0.2.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -118,13 +118,10 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-buffer"
|
name = "block-buffer"
|
||||||
version = "0.8.0"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dbcf92448676f82bb7a334c58bbce8b0d43580fb5362a9d608b18879d12a3d31"
|
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block-padding",
|
|
||||||
"byte-tools",
|
|
||||||
"byteorder",
|
|
||||||
"generic-array 0.14.2",
|
"generic-array 0.14.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -217,6 +214,12 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpuid-bool"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d375c433320f6c5057ae04a04376eef4d04ce2801448cf8863a78da99107be4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@ -685,6 +688,12 @@ version = "0.2.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opaque-debug"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pest"
|
name = "pest"
|
||||||
version = "2.1.3"
|
version = "2.1.3"
|
||||||
@ -955,9 +964,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.55"
|
version = "1.0.56"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226"
|
checksum = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
@ -973,19 +982,20 @@ dependencies = [
|
|||||||
"block-buffer 0.7.3",
|
"block-buffer 0.7.3",
|
||||||
"digest 0.8.1",
|
"digest 0.8.1",
|
||||||
"fake-simd",
|
"fake-simd",
|
||||||
"opaque-debug",
|
"opaque-debug 0.2.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.9.0"
|
version = "0.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72377440080fd008550fe9b441e854e43318db116f90181eef92e9ae9aedab48"
|
checksum = "2933378ddfeda7ea26f48c555bdad8bb446bf8a3d17832dc83e380d444cfb8c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block-buffer 0.8.0",
|
"block-buffer 0.9.0",
|
||||||
|
"cfg-if",
|
||||||
|
"cpuid-bool",
|
||||||
"digest 0.9.0",
|
"digest 0.9.0",
|
||||||
"fake-simd",
|
"opaque-debug 0.3.0",
|
||||||
"opaque-debug",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4,6 +4,7 @@ use crate::{
|
|||||||
constraints::{generate_constraints, generate_test_constraints, ConstrainedValue},
|
constraints::{generate_constraints, generate_test_constraints, ConstrainedValue},
|
||||||
errors::CompilerError,
|
errors::CompilerError,
|
||||||
GroupType,
|
GroupType,
|
||||||
|
ImportedPrograms,
|
||||||
};
|
};
|
||||||
use leo_ast::LeoParser;
|
use leo_ast::LeoParser;
|
||||||
use leo_inputs::LeoInputsParser;
|
use leo_inputs::LeoInputsParser;
|
||||||
@ -24,6 +25,7 @@ pub struct Compiler<F: Field + PrimeField, G: GroupType<F>> {
|
|||||||
main_file_path: PathBuf,
|
main_file_path: PathBuf,
|
||||||
program: Program,
|
program: Program,
|
||||||
program_inputs: Inputs,
|
program_inputs: Inputs,
|
||||||
|
imported_programs: ImportedPrograms,
|
||||||
output: Option<ConstrainedValue<F, G>>,
|
output: Option<ConstrainedValue<F, G>>,
|
||||||
_engine: PhantomData<F>,
|
_engine: PhantomData<F>,
|
||||||
}
|
}
|
||||||
@ -35,6 +37,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
|||||||
main_file_path: PathBuf::new(),
|
main_file_path: PathBuf::new(),
|
||||||
program: Program::new(package_name),
|
program: Program::new(package_name),
|
||||||
program_inputs: Inputs::new(),
|
program_inputs: Inputs::new(),
|
||||||
|
imported_programs: ImportedPrograms::new(),
|
||||||
output: None,
|
output: None,
|
||||||
_engine: PhantomData,
|
_engine: PhantomData,
|
||||||
}
|
}
|
||||||
@ -77,7 +80,9 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
|||||||
cs: &mut CS,
|
cs: &mut CS,
|
||||||
) -> Result<ConstrainedValue<F, G>, CompilerError> {
|
) -> Result<ConstrainedValue<F, G>, CompilerError> {
|
||||||
let path = self.main_file_path;
|
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.set_path(path);
|
||||||
|
|
||||||
error
|
error
|
||||||
@ -85,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> {
|
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> {
|
fn load_program(&mut self) -> Result<String, CompilerError> {
|
||||||
@ -102,6 +107,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
|||||||
|
|
||||||
self.program = Program::from(syntax_tree, package_name);
|
self.program = Program::from(syntax_tree, package_name);
|
||||||
self.program_inputs.set_inputs_size(self.program.expected_inputs.len());
|
self.program_inputs.set_inputs_size(self.program.expected_inputs.len());
|
||||||
|
self.imported_programs = ImportedPrograms::from_program(&self.program)?;
|
||||||
|
|
||||||
log::debug!("Program parsing complete\n{:#?}", self.program);
|
log::debug!("Program parsing complete\n{:#?}", self.program);
|
||||||
|
|
||||||
@ -132,6 +138,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
|||||||
main_file_path: PathBuf::new(),
|
main_file_path: PathBuf::new(),
|
||||||
program,
|
program,
|
||||||
program_inputs,
|
program_inputs,
|
||||||
|
imported_programs: ImportedPrograms::new(),
|
||||||
output: None,
|
output: None,
|
||||||
_engine: PhantomData,
|
_engine: PhantomData,
|
||||||
})
|
})
|
||||||
@ -140,11 +147,16 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
|||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstraintSynthesizer<F> for 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> {
|
fn generate_constraints<CS: ConstraintSystem<F>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
|
||||||
let result =
|
let result = generate_constraints::<_, G, _>(
|
||||||
generate_constraints::<_, G, _>(cs, self.program, self.program_inputs.get_inputs()).map_err(|e| {
|
cs,
|
||||||
log::error!("{}", e);
|
self.program,
|
||||||
SynthesisError::Unsatisfiable
|
self.program_inputs.get_inputs(),
|
||||||
})?;
|
&self.imported_programs,
|
||||||
|
)
|
||||||
|
.map_err(|e| {
|
||||||
|
log::error!("{}", e);
|
||||||
|
SynthesisError::Unsatisfiable
|
||||||
|
})?;
|
||||||
|
|
||||||
// Write results to file or something
|
// Write results to file or something
|
||||||
log::info!("{}", result);
|
log::info!("{}", result);
|
||||||
|
40
compiler/src/constraints/definitions/definitions.rs
Normal file
40
compiler/src/constraints/definitions/definitions.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
use crate::{
|
||||||
|
constraints::{new_scope, ConstrainedProgram, ConstrainedValue},
|
||||||
|
errors::ImportError,
|
||||||
|
GroupType,
|
||||||
|
ImportedPrograms,
|
||||||
|
};
|
||||||
|
use leo_types::Program;
|
||||||
|
|
||||||
|
use snarkos_models::curves::{Field, PrimeField};
|
||||||
|
|
||||||
|
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||||
|
pub(crate) fn store_definitions(
|
||||||
|
&mut self,
|
||||||
|
program: Program,
|
||||||
|
imported_programs: &ImportedPrograms,
|
||||||
|
) -> Result<(), ImportError> {
|
||||||
|
let program_name = program.name.clone();
|
||||||
|
|
||||||
|
// evaluate all import statements and store imported definitions
|
||||||
|
program
|
||||||
|
.imports
|
||||||
|
.iter()
|
||||||
|
.map(|import| self.store_import(program_name.clone(), import, imported_programs))
|
||||||
|
.collect::<Result<Vec<_>, ImportError>>()?;
|
||||||
|
|
||||||
|
// evaluate and store all circuit definitions
|
||||||
|
program.circuits.into_iter().for_each(|(identifier, circuit)| {
|
||||||
|
let resolved_circuit_name = new_scope(program_name.clone(), identifier.to_string());
|
||||||
|
self.store(resolved_circuit_name, ConstrainedValue::CircuitDefinition(circuit));
|
||||||
|
});
|
||||||
|
|
||||||
|
// evaluate and store all function definitions
|
||||||
|
program.functions.into_iter().for_each(|(function_name, function)| {
|
||||||
|
let resolved_function_name = new_scope(program_name.clone(), function_name.to_string());
|
||||||
|
self.store(resolved_function_name, ConstrainedValue::Function(None, function));
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
35
compiler/src/constraints/definitions/import.rs
Normal file
35
compiler/src/constraints/definitions/import.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use crate::{errors::ImportError, imported_symbols::ImportedSymbols, ConstrainedProgram, GroupType, ImportedPrograms};
|
||||||
|
use leo_types::Import;
|
||||||
|
|
||||||
|
use snarkos_models::curves::{Field, PrimeField};
|
||||||
|
|
||||||
|
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||||
|
pub(crate) fn store_import(
|
||||||
|
&mut self,
|
||||||
|
scope: String,
|
||||||
|
import: &Import,
|
||||||
|
imported_programs: &ImportedPrograms,
|
||||||
|
) -> Result<(), ImportError> {
|
||||||
|
// get imported program name from import
|
||||||
|
// get imported symbols from from import
|
||||||
|
let imported_symbols = ImportedSymbols::from(import);
|
||||||
|
|
||||||
|
for (package, symbol) in imported_symbols.symbols {
|
||||||
|
// get imported program from hashmap
|
||||||
|
let program = imported_programs
|
||||||
|
.get(&package)
|
||||||
|
.ok_or(ImportError::unknown_package(import.package.name.clone()))?;
|
||||||
|
|
||||||
|
// resolve imported program's import statements
|
||||||
|
program
|
||||||
|
.imports
|
||||||
|
.iter()
|
||||||
|
.map(|import| self.store_import(package.clone(), import, imported_programs))
|
||||||
|
.collect::<Result<Vec<()>, ImportError>>()?;
|
||||||
|
|
||||||
|
self.store_symbol(scope.clone(), package, &symbol, program)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
38
compiler/src/constraints/definitions/imported_symbols.rs
Normal file
38
compiler/src/constraints/definitions/imported_symbols.rs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
use leo_types::{Import, ImportSymbol, Package, PackageAccess};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct ImportedSymbols {
|
||||||
|
pub symbols: Vec<(String, ImportSymbol)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImportedSymbols {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self { symbols: vec![] }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from(import: &Import) -> Self {
|
||||||
|
let mut symbols = Self::new();
|
||||||
|
|
||||||
|
symbols.from_package(&import.package);
|
||||||
|
|
||||||
|
symbols
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_package(&mut self, package: &Package) {
|
||||||
|
self.from_package_access(package.name.name.clone(), &package.access);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_package_access(&mut self, package: String, access: &PackageAccess) {
|
||||||
|
match access {
|
||||||
|
PackageAccess::SubPackage(package) => self.from_package(package),
|
||||||
|
PackageAccess::Star(span) => {
|
||||||
|
let star = ImportSymbol::star(span);
|
||||||
|
self.symbols.push((package, star));
|
||||||
|
}
|
||||||
|
PackageAccess::Symbol(symbol) => self.symbols.push((package, symbol.clone())),
|
||||||
|
PackageAccess::Multiple(packages) => packages
|
||||||
|
.iter()
|
||||||
|
.for_each(|access| self.from_package_access(package.clone(), access)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
compiler/src/constraints/definitions/mod.rs
Normal file
8
compiler/src/constraints/definitions/mod.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
pub mod import;
|
||||||
|
pub use self::import::*;
|
||||||
|
|
||||||
|
pub mod imported_symbols;
|
||||||
|
|
||||||
|
pub mod definitions;
|
||||||
|
|
||||||
|
pub mod symbol;
|
75
compiler/src/constraints/definitions/symbol.rs
Normal file
75
compiler/src/constraints/definitions/symbol.rs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
use crate::{errors::ImportError, new_scope, ConstrainedProgram, ConstrainedValue, GroupType};
|
||||||
|
use leo_types::{ImportSymbol, Program};
|
||||||
|
|
||||||
|
use snarkos_models::curves::{Field, PrimeField};
|
||||||
|
|
||||||
|
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||||
|
pub(crate) fn store_symbol(
|
||||||
|
&mut self,
|
||||||
|
scope: String,
|
||||||
|
program_name: String,
|
||||||
|
symbol: &ImportSymbol,
|
||||||
|
program: &Program,
|
||||||
|
) -> Result<(), ImportError> {
|
||||||
|
if symbol.is_star() {
|
||||||
|
// evaluate and store all circuit definitions
|
||||||
|
program.circuits.iter().for_each(|(identifier, circuit)| {
|
||||||
|
let name = new_scope(scope.clone(), identifier.to_string());
|
||||||
|
let value = ConstrainedValue::Import(
|
||||||
|
program_name.clone(),
|
||||||
|
Box::new(ConstrainedValue::CircuitDefinition(circuit.clone())),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.store(name, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
// evaluate and store all function definitions
|
||||||
|
program.functions.iter().for_each(|(identifier, function)| {
|
||||||
|
let name = new_scope(scope.clone(), identifier.to_string());
|
||||||
|
let value = ConstrainedValue::Import(
|
||||||
|
program_name.clone(),
|
||||||
|
Box::new(ConstrainedValue::Function(None, function.clone())),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.store(name, value);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// see if the imported symbol is a circuit
|
||||||
|
let matched_circuit = program
|
||||||
|
.circuits
|
||||||
|
.iter()
|
||||||
|
.find(|(circuit_name, _circuit_def)| symbol.symbol == **circuit_name);
|
||||||
|
|
||||||
|
let value = match matched_circuit {
|
||||||
|
Some((_circuit_name, circuit)) => ConstrainedValue::Import(
|
||||||
|
program_name.clone(),
|
||||||
|
Box::new(ConstrainedValue::CircuitDefinition(circuit.clone())),
|
||||||
|
),
|
||||||
|
None => {
|
||||||
|
// see if the imported symbol is a function
|
||||||
|
let matched_function = program
|
||||||
|
.functions
|
||||||
|
.iter()
|
||||||
|
.find(|(function_name, _function)| symbol.symbol == **function_name);
|
||||||
|
|
||||||
|
match matched_function {
|
||||||
|
Some((_function_name, function)) => ConstrainedValue::Import(
|
||||||
|
program_name.clone(),
|
||||||
|
Box::new(ConstrainedValue::Function(None, function.clone())),
|
||||||
|
),
|
||||||
|
None => return Err(ImportError::unknown_symbol(symbol.to_owned(), program_name)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// take the alias if it is present
|
||||||
|
let id = symbol.alias.clone().unwrap_or(symbol.symbol.clone());
|
||||||
|
let name = new_scope(scope, id.to_string());
|
||||||
|
|
||||||
|
// store imported circuit under imported name
|
||||||
|
self.store(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -2,13 +2,14 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
comparator::{ComparatorGadget, EvaluateLtGadget},
|
comparator::{ComparatorGadget, EvaluateLtGadget},
|
||||||
constraints::{ConstrainedCircuitMember, ConstrainedProgram, ConstrainedValue},
|
constraints::{
|
||||||
enforce_and,
|
boolean::{enforce_and, enforce_or, evaluate_not, new_bool_constant},
|
||||||
enforce_or,
|
new_scope,
|
||||||
|
ConstrainedCircuitMember,
|
||||||
|
ConstrainedProgram,
|
||||||
|
ConstrainedValue,
|
||||||
|
},
|
||||||
errors::ExpressionError,
|
errors::ExpressionError,
|
||||||
evaluate_not,
|
|
||||||
new_bool_constant,
|
|
||||||
new_scope,
|
|
||||||
FieldType,
|
FieldType,
|
||||||
GroupType,
|
GroupType,
|
||||||
Integer,
|
Integer,
|
||||||
@ -52,6 +53,9 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
} else if let Some(value) = self.get(&identifier_name) {
|
} else if let Some(value) = self.get(&identifier_name) {
|
||||||
// Check global scope (function and circuit names)
|
// Check global scope (function and circuit names)
|
||||||
value.clone()
|
value.clone()
|
||||||
|
} else if let Some(value) = self.get(&unresolved_identifier.name) {
|
||||||
|
// Check imported file scope
|
||||||
|
value.clone()
|
||||||
} else {
|
} else {
|
||||||
return Err(ExpressionError::undefined_identifier(unresolved_identifier));
|
return Err(ExpressionError::undefined_identifier(unresolved_identifier));
|
||||||
};
|
};
|
||||||
@ -634,53 +638,55 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
program_identifier = file_scope.clone();
|
program_identifier = file_scope.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ConstrainedValue::CircuitDefinition(circuit_definition)) = self.get_mut(&program_identifier) {
|
let circuit = match self.get(&program_identifier) {
|
||||||
let circuit_identifier = circuit_definition.circuit_name.clone();
|
Some(value) => value.clone().extract_circuit(span.clone())?,
|
||||||
let mut resolved_members = vec![];
|
None => return Err(ExpressionError::undefined_circuit(identifier.to_string(), span)),
|
||||||
for member in circuit_definition.members.clone().into_iter() {
|
};
|
||||||
match member {
|
|
||||||
CircuitMember::CircuitField(identifier, _type) => {
|
|
||||||
let matched_field = members
|
|
||||||
.clone()
|
|
||||||
.into_iter()
|
|
||||||
.find(|field| field.identifier.eq(&identifier));
|
|
||||||
match matched_field {
|
|
||||||
Some(field) => {
|
|
||||||
// Resolve and enforce circuit object
|
|
||||||
let field_value = self.enforce_expression(
|
|
||||||
cs,
|
|
||||||
file_scope.clone(),
|
|
||||||
function_scope.clone(),
|
|
||||||
&vec![_type.clone()],
|
|
||||||
field.expression,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
resolved_members.push(ConstrainedCircuitMember(identifier, field_value))
|
let circuit_identifier = circuit.circuit_name.clone();
|
||||||
}
|
let mut resolved_members = vec![];
|
||||||
None => return Err(ExpressionError::expected_circuit_member(identifier.to_string(), span)),
|
|
||||||
|
for member in circuit.members.clone().into_iter() {
|
||||||
|
match member {
|
||||||
|
CircuitMember::CircuitField(identifier, _type) => {
|
||||||
|
let matched_field = members
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.find(|field| field.identifier.eq(&identifier));
|
||||||
|
match matched_field {
|
||||||
|
Some(field) => {
|
||||||
|
// Resolve and enforce circuit object
|
||||||
|
let field_value = self.enforce_expression(
|
||||||
|
cs,
|
||||||
|
file_scope.clone(),
|
||||||
|
function_scope.clone(),
|
||||||
|
&vec![_type.clone()],
|
||||||
|
field.expression,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
resolved_members.push(ConstrainedCircuitMember(identifier, field_value))
|
||||||
}
|
}
|
||||||
|
None => return Err(ExpressionError::expected_circuit_member(identifier.to_string(), span)),
|
||||||
}
|
}
|
||||||
CircuitMember::CircuitFunction(_static, function) => {
|
}
|
||||||
let identifier = function.function_name.clone();
|
CircuitMember::CircuitFunction(_static, function) => {
|
||||||
let mut constrained_function_value =
|
let identifier = function.function_name.clone();
|
||||||
ConstrainedValue::Function(Some(circuit_identifier.clone()), function);
|
let mut constrained_function_value =
|
||||||
|
ConstrainedValue::Function(Some(circuit_identifier.clone()), function);
|
||||||
|
|
||||||
if _static {
|
if _static {
|
||||||
constrained_function_value = ConstrainedValue::Static(Box::new(constrained_function_value));
|
constrained_function_value = ConstrainedValue::Static(Box::new(constrained_function_value));
|
||||||
}
|
|
||||||
|
|
||||||
resolved_members.push(ConstrainedCircuitMember(identifier, constrained_function_value));
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(ConstrainedValue::CircuitExpression(
|
resolved_members.push(ConstrainedCircuitMember(identifier, constrained_function_value));
|
||||||
circuit_identifier.clone(),
|
}
|
||||||
resolved_members,
|
};
|
||||||
))
|
|
||||||
} else {
|
|
||||||
Err(ExpressionError::undefined_circuit(identifier.to_string(), span))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(ConstrainedValue::CircuitExpression(
|
||||||
|
circuit_identifier.clone(),
|
||||||
|
resolved_members,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enforce_circuit_access_expression<CS: ConstraintSystem<F>>(
|
fn enforce_circuit_access_expression<CS: ConstraintSystem<F>>(
|
||||||
@ -811,18 +817,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
*function.clone(),
|
*function.clone(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let (outer_scope, function_call) = match function_value {
|
let (outer_scope, function_call) = function_value.extract_function(file_scope, span.clone())?;
|
||||||
ConstrainedValue::Function(circuit_identifier, function) => {
|
|
||||||
let mut outer_scope = file_scope.clone();
|
|
||||||
// If this is a circuit function, evaluate inside the circuit scope
|
|
||||||
if circuit_identifier.is_some() {
|
|
||||||
outer_scope = new_scope(file_scope, circuit_identifier.unwrap().to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
(outer_scope, function.clone())
|
|
||||||
}
|
|
||||||
value => return Err(ExpressionError::undefined_function(value.to_string(), span)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let name_unique = format!(
|
let name_unique = format!(
|
||||||
"function call {} {}:{}",
|
"function call {} {}:{}",
|
||||||
|
@ -2,17 +2,21 @@
|
|||||||
//! a resolved Leo program.
|
//! a resolved Leo program.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bool_from_input,
|
constraints::{
|
||||||
constraints::{new_scope, ConstrainedProgram, ConstrainedValue},
|
boolean::bool_from_input,
|
||||||
errors::{FunctionError, ImportError},
|
field::field_from_input,
|
||||||
field_from_input,
|
group::group_from_input,
|
||||||
group_from_input,
|
new_scope,
|
||||||
|
ConstrainedProgram,
|
||||||
|
ConstrainedValue,
|
||||||
|
},
|
||||||
|
errors::{FunctionError, StatementError},
|
||||||
GroupType,
|
GroupType,
|
||||||
Integer,
|
Integer,
|
||||||
};
|
};
|
||||||
use leo_types::{Expression, Function, InputValue, Program, Span, Type};
|
|
||||||
|
|
||||||
use crate::errors::StatementError;
|
use leo_types::{Expression, Function, InputValue, Span, Type};
|
||||||
|
|
||||||
use snarkos_models::{
|
use snarkos_models::{
|
||||||
curves::{Field, PrimeField},
|
curves::{Field, PrimeField},
|
||||||
gadgets::{
|
gadgets::{
|
||||||
@ -272,29 +276,4 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
|
|
||||||
self.enforce_function(cs, scope, function_name, function, input_variables)
|
self.enforce_function(cs, scope, function_name, function, input_variables)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resolve_definitions(&mut self, program: Program) -> Result<(), ImportError> {
|
|
||||||
let program_name = program.name.clone();
|
|
||||||
|
|
||||||
// evaluate and store all imports
|
|
||||||
program
|
|
||||||
.imports
|
|
||||||
.into_iter()
|
|
||||||
.map(|import| self.enforce_import(program_name.clone(), import))
|
|
||||||
.collect::<Result<Vec<_>, ImportError>>()?;
|
|
||||||
|
|
||||||
// evaluate and store all circuit definitions
|
|
||||||
program.circuits.into_iter().for_each(|(identifier, circuit)| {
|
|
||||||
let resolved_circuit_name = new_scope(program_name.clone(), identifier.to_string());
|
|
||||||
self.store(resolved_circuit_name, ConstrainedValue::CircuitDefinition(circuit));
|
|
||||||
});
|
|
||||||
|
|
||||||
// evaluate and store all function definitions
|
|
||||||
program.functions.into_iter().for_each(|(function_name, function)| {
|
|
||||||
let resolved_function_name = new_scope(program_name.clone(), function_name.to_string());
|
|
||||||
self.store(resolved_function_name, ConstrainedValue::Function(None, function));
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
70
compiler/src/constraints/generate_constraints.rs
Normal file
70
compiler/src/constraints/generate_constraints.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
use crate::{errors::CompilerError, new_scope, ConstrainedProgram, ConstrainedValue, GroupType, ImportedPrograms};
|
||||||
|
use leo_types::{InputValue, Program};
|
||||||
|
|
||||||
|
use snarkos_models::{
|
||||||
|
curves::{Field, PrimeField},
|
||||||
|
gadgets::r1cs::{ConstraintSystem, TestConstraintSystem},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
|
||||||
|
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.store_definitions(program, imported_programs)?;
|
||||||
|
|
||||||
|
let main = resolved_program
|
||||||
|
.get(&main_function_name)
|
||||||
|
.ok_or_else(|| CompilerError::NoMain)?;
|
||||||
|
|
||||||
|
match main.clone() {
|
||||||
|
ConstrainedValue::Function(_circuit_identifier, function) => {
|
||||||
|
let result = resolved_program.enforce_main_function(cs, program_name, function, parameters)?;
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
_ => Err(CompilerError::NoMainFunction),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.store_definitions(program, imported_programs)?;
|
||||||
|
|
||||||
|
log::info!("Running {} tests", tests.len());
|
||||||
|
|
||||||
|
for (test_name, test_function) in tests.into_iter() {
|
||||||
|
let full_test_name = format!("{}::{}", program_name.clone(), test_name.to_string());
|
||||||
|
|
||||||
|
let result = resolved_program.enforce_main_function(
|
||||||
|
cs,
|
||||||
|
program_name.clone(),
|
||||||
|
test_function.0,
|
||||||
|
vec![], // test functions should not take any inputs
|
||||||
|
);
|
||||||
|
|
||||||
|
if result.is_ok() {
|
||||||
|
log::info!(
|
||||||
|
"test {} passed. Constraint system satisfied: {}",
|
||||||
|
full_test_name,
|
||||||
|
cs.is_satisfied()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
log::error!("test {} errored: {}", full_test_name, result.unwrap_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -1,13 +0,0 @@
|
|||||||
use crate::{constraints::ConstrainedProgram, errors::constraints::ImportError, GroupType};
|
|
||||||
use leo_types::Import;
|
|
||||||
|
|
||||||
use snarkos_models::curves::{Field, PrimeField};
|
|
||||||
use std::env::current_dir;
|
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,136 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
constraints::{ConstrainedProgram, ConstrainedValue},
|
|
||||||
errors::constraints::ImportError,
|
|
||||||
new_scope,
|
|
||||||
GroupType,
|
|
||||||
};
|
|
||||||
use leo_ast::LeoParser;
|
|
||||||
use leo_types::{ImportSymbol, Program, Span};
|
|
||||||
|
|
||||||
use snarkos_models::curves::{Field, PrimeField};
|
|
||||||
use std::{
|
|
||||||
ffi::OsString,
|
|
||||||
fs::{read_dir, DirEntry},
|
|
||||||
};
|
|
||||||
|
|
||||||
static LIBRARY_FILE: &str = "src/lib.leo";
|
|
||||||
|
|
||||||
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()))?;
|
|
||||||
|
|
||||||
let mut file_path = entry.path();
|
|
||||||
if file_type.is_dir() {
|
|
||||||
file_path.push(LIBRARY_FILE);
|
|
||||||
|
|
||||||
if !file_path.exists() {
|
|
||||||
return Err(ImportError::expected_lib_file(
|
|
||||||
format!("{:?}", file_path.as_path()),
|
|
||||||
span.clone(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the abstract syntax tree
|
|
||||||
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_star(&mut self, scope: String, entry: &DirEntry, span: Span) -> Result<(), ImportError> {
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// * -> 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(
|
|
||||||
&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();
|
|
||||||
|
|
||||||
// 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 == *function_name);
|
|
||||||
|
|
||||||
match matched_function {
|
|
||||||
Some((_function_name, function)) => ConstrainedValue::Function(None, function),
|
|
||||||
None => return Err(ImportError::unknown_symbol(symbol, program_name, &entry.path())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// take the alias if it is present
|
|
||||||
let name = symbol.alias.unwrap_or(symbol.symbol);
|
|
||||||
let resolved_name = new_scope(program_name.clone(), name.to_string());
|
|
||||||
|
|
||||||
// store imported circuit under resolved name
|
|
||||||
self.store(resolved_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,8 +0,0 @@
|
|||||||
pub mod import;
|
|
||||||
pub use import::*;
|
|
||||||
|
|
||||||
pub mod import_symbol;
|
|
||||||
pub use import_symbol::*;
|
|
||||||
|
|
||||||
pub mod package;
|
|
||||||
pub use package::*;
|
|
@ -1,103 +1,34 @@
|
|||||||
//! Module containing methods to enforce constraints in an Leo program
|
//! Module containing methods to enforce constraints in an Leo program
|
||||||
|
|
||||||
pub(crate) mod boolean;
|
pub mod boolean;
|
||||||
pub(crate) use boolean::*;
|
|
||||||
|
|
||||||
pub(crate) mod comparator;
|
pub(crate) mod comparator;
|
||||||
pub(crate) use comparator::*;
|
pub(crate) use comparator::*;
|
||||||
|
|
||||||
pub mod function;
|
pub mod function;
|
||||||
pub use function::*;
|
pub use self::function::*;
|
||||||
|
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
pub use expression::*;
|
pub use self::expression::*;
|
||||||
|
|
||||||
pub mod import;
|
pub mod field;
|
||||||
pub use import::*;
|
|
||||||
|
|
||||||
pub mod integer;
|
pub mod integer;
|
||||||
pub use integer::*;
|
pub use integer::*;
|
||||||
|
|
||||||
pub(crate) mod field;
|
pub mod generate_constraints;
|
||||||
pub(crate) use field::*;
|
pub use self::generate_constraints::*;
|
||||||
|
|
||||||
pub(crate) mod group;
|
pub mod group;
|
||||||
pub(crate) use group::*;
|
|
||||||
|
pub mod definitions;
|
||||||
|
pub use self::definitions::*;
|
||||||
|
|
||||||
pub mod program;
|
pub mod program;
|
||||||
pub use program::*;
|
pub use self::program::*;
|
||||||
|
|
||||||
pub mod value;
|
pub mod value;
|
||||||
pub use value::*;
|
pub use self::value::*;
|
||||||
|
|
||||||
pub mod statement;
|
pub mod statement;
|
||||||
pub use statement::*;
|
pub use self::statement::*;
|
||||||
|
|
||||||
use crate::{errors::CompilerError, GroupType};
|
|
||||||
use leo_types::{InputValue, Program};
|
|
||||||
|
|
||||||
use snarkos_models::{
|
|
||||||
curves::{Field, PrimeField},
|
|
||||||
gadgets::r1cs::{ConstraintSystem, TestConstraintSystem},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>>(
|
|
||||||
cs: &mut CS,
|
|
||||||
program: Program,
|
|
||||||
parameters: Vec<Option<InputValue>>,
|
|
||||||
) -> 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)?;
|
|
||||||
|
|
||||||
let main = resolved_program
|
|
||||||
.get(&main_function_name)
|
|
||||||
.ok_or_else(|| CompilerError::NoMain)?;
|
|
||||||
|
|
||||||
match main.clone() {
|
|
||||||
ConstrainedValue::Function(_circuit_identifier, function) => {
|
|
||||||
let result = resolved_program.enforce_main_function(cs, program_name, function, parameters)?;
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
_ => Err(CompilerError::NoMainFunction),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate_test_constraints<F: Field + PrimeField, G: GroupType<F>>(
|
|
||||||
cs: &mut TestConstraintSystem<F>,
|
|
||||||
program: Program,
|
|
||||||
) -> 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)?;
|
|
||||||
|
|
||||||
log::info!("Running {} tests", tests.len());
|
|
||||||
|
|
||||||
for (test_name, test_function) in tests.into_iter() {
|
|
||||||
let full_test_name = format!("{}::{}", program_name.clone(), test_name.to_string());
|
|
||||||
|
|
||||||
let result = resolved_program.enforce_main_function(
|
|
||||||
cs,
|
|
||||||
program_name.clone(),
|
|
||||||
test_function.0,
|
|
||||||
vec![], // test functions should not take any inputs
|
|
||||||
);
|
|
||||||
|
|
||||||
if result.is_ok() {
|
|
||||||
log::info!(
|
|
||||||
"test {} passed. Constraint system satisfied: {}",
|
|
||||||
full_test_name,
|
|
||||||
cs.is_satisfied()
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
log::error!("test {} errored: {}", full_test_name, result.unwrap_err());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
//! The in memory stored value for a defined name in a resolved Leo program.
|
//! The in memory stored value for a defined name in a resolved Leo program.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
allocate_bool,
|
constraints::boolean::{allocate_bool, new_bool_constant},
|
||||||
errors::{FieldError, ValueError},
|
errors::{ExpressionError, FieldError, ValueError},
|
||||||
new_bool_constant,
|
new_scope,
|
||||||
FieldType,
|
FieldType,
|
||||||
GroupType,
|
GroupType,
|
||||||
Integer,
|
Integer,
|
||||||
@ -40,6 +40,7 @@ pub enum ConstrainedValue<F: Field + PrimeField, G: GroupType<F>> {
|
|||||||
|
|
||||||
Mutable(Box<ConstrainedValue<F, G>>),
|
Mutable(Box<ConstrainedValue<F, G>>),
|
||||||
Static(Box<ConstrainedValue<F, G>>),
|
Static(Box<ConstrainedValue<F, G>>),
|
||||||
|
Import(String, Box<ConstrainedValue<F, G>>),
|
||||||
Unresolved(String),
|
Unresolved(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,6 +115,30 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn extract_function(self, scope: String, span: Span) -> Result<(String, Function), ExpressionError> {
|
||||||
|
match self {
|
||||||
|
ConstrainedValue::Function(circuit_identifier, function) => {
|
||||||
|
let mut outer_scope = scope.clone();
|
||||||
|
// If this is a circuit function, evaluate inside the circuit scope
|
||||||
|
if circuit_identifier.is_some() {
|
||||||
|
outer_scope = new_scope(scope, circuit_identifier.unwrap().to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((outer_scope, function.clone()))
|
||||||
|
}
|
||||||
|
ConstrainedValue::Import(import_scope, function) => function.extract_function(import_scope, span),
|
||||||
|
value => return Err(ExpressionError::undefined_function(value.to_string(), span)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn extract_circuit(self, span: Span) -> Result<Circuit, ExpressionError> {
|
||||||
|
match self {
|
||||||
|
ConstrainedValue::CircuitDefinition(circuit) => Ok(circuit),
|
||||||
|
ConstrainedValue::Import(_import_scope, circuit) => circuit.extract_circuit(span),
|
||||||
|
value => return Err(ExpressionError::undefined_circuit(value.to_string(), span)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn get_inner_mut(&mut self) {
|
pub(crate) fn get_inner_mut(&mut self) {
|
||||||
if let ConstrainedValue::Mutable(inner) = self {
|
if let ConstrainedValue::Mutable(inner) = self {
|
||||||
*self = *inner.clone()
|
*self = *inner.clone()
|
||||||
@ -189,6 +214,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
|
|||||||
// empty wrappers
|
// empty wrappers
|
||||||
ConstrainedValue::CircuitDefinition(_) => {}
|
ConstrainedValue::CircuitDefinition(_) => {}
|
||||||
ConstrainedValue::Function(_, _) => {}
|
ConstrainedValue::Function(_, _) => {}
|
||||||
|
ConstrainedValue::Import(_, _) => {}
|
||||||
|
|
||||||
ConstrainedValue::Unresolved(value) => {
|
ConstrainedValue::Unresolved(value) => {
|
||||||
return Err(ValueError::implicit(value.to_string(), span));
|
return Err(ValueError::implicit(value.to_string(), span));
|
||||||
}
|
}
|
||||||
@ -246,6 +273,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> fmt::Display for ConstrainedValue<F
|
|||||||
ConstrainedValue::Function(ref _circuit_option, ref function) => {
|
ConstrainedValue::Function(ref _circuit_option, ref function) => {
|
||||||
write!(f, "function {{ {}() }}", function.function_name)
|
write!(f, "function {{ {}() }}", function.function_name)
|
||||||
}
|
}
|
||||||
|
ConstrainedValue::Import(_, ref value) => write!(f, "{}", value),
|
||||||
ConstrainedValue::Mutable(ref value) => write!(f, "mut {}", value),
|
ConstrainedValue::Mutable(ref value) => write!(f, "mut {}", value),
|
||||||
ConstrainedValue::Static(ref value) => write!(f, "static {}", value),
|
ConstrainedValue::Static(ref value) => write!(f, "static {}", value),
|
||||||
ConstrainedValue::Unresolved(ref value) => write!(f, "unresolved {}", value),
|
ConstrainedValue::Unresolved(ref value) => write!(f, "unresolved {}", value),
|
||||||
|
@ -17,6 +17,10 @@ impl ImportError {
|
|||||||
ImportError::Error(FormattedError::new_from_span(message, span))
|
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 {
|
pub fn conflicting_imports(identifier: Identifier) -> Self {
|
||||||
let message = format!("conflicting imports found for `{}`", identifier.name);
|
let message = format!("conflicting imports found for `{}`", identifier.name);
|
||||||
|
|
||||||
@ -29,9 +33,27 @@ impl ImportError {
|
|||||||
Self::new_from_span(message, span)
|
Self::new_from_span(message, span)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn directory_error(error: io::Error, span: Span) -> Self {
|
pub fn current_directory_error(error: io::Error) -> Self {
|
||||||
|
let span = Span {
|
||||||
|
text: "".to_string(),
|
||||||
|
line: 0,
|
||||||
|
start: 0,
|
||||||
|
end: 0,
|
||||||
|
};
|
||||||
|
let message = format!("compilation failed trying to find current directory - {:?}", error);
|
||||||
|
|
||||||
|
Self::new_from_span(message, span)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn directory_error(error: io::Error, span: Span, path: PathBuf) -> Self {
|
||||||
let message = format!("compilation failed due to directory error - {:?}", error);
|
let message = format!("compilation failed due to directory error - {:?}", error);
|
||||||
|
|
||||||
|
Self::new_from_span_with_path(message, span, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn star(path: PathBuf, span: Span) -> Self {
|
||||||
|
let message = format!("cannot import `*` from path `{:?}`", path);
|
||||||
|
|
||||||
Self::new_from_span(message, span)
|
Self::new_from_span(message, span)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,11 +75,9 @@ impl ImportError {
|
|||||||
Self::new_from_span(message, identifier.span)
|
Self::new_from_span(message, identifier.span)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unknown_symbol(symbol: ImportSymbol, file: String, file_path: &PathBuf) -> Self {
|
pub fn unknown_symbol(symbol: ImportSymbol, file: String) -> Self {
|
||||||
let message = format!("cannot find imported symbol `{}` in imported file `{}`", symbol, file);
|
let message = format!("cannot find imported symbol `{}` in imported file `{}`", symbol, file);
|
||||||
let mut error = FormattedError::new_from_span(message, symbol.span);
|
let error = FormattedError::new_from_span(message, symbol.span);
|
||||||
|
|
||||||
error.path = Some(format!("{:?}", file_path));
|
|
||||||
|
|
||||||
ImportError::Error(error)
|
ImportError::Error(error)
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,28 @@
|
|||||||
//! Module containing errors returned when enforcing constraints in an Leo program
|
//! Module containing errors returned when enforcing constraints in an Leo program
|
||||||
|
|
||||||
pub mod boolean;
|
pub mod boolean;
|
||||||
pub use boolean::*;
|
pub use self::boolean::*;
|
||||||
|
|
||||||
pub mod function;
|
pub mod function;
|
||||||
pub use function::*;
|
pub use self::function::*;
|
||||||
|
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
pub use expression::*;
|
pub use self::expression::*;
|
||||||
|
|
||||||
pub mod import;
|
pub mod import;
|
||||||
pub use import::*;
|
pub use self::import::*;
|
||||||
|
|
||||||
pub mod integer;
|
pub mod integer;
|
||||||
pub use integer::*;
|
pub use integer::*;
|
||||||
|
|
||||||
pub mod field;
|
pub mod field;
|
||||||
pub use field::*;
|
pub use self::field::*;
|
||||||
|
|
||||||
pub mod group;
|
pub mod group;
|
||||||
pub use group::*;
|
pub use self::group::*;
|
||||||
|
|
||||||
pub mod value;
|
pub mod value;
|
||||||
pub use value::*;
|
pub use self::value::*;
|
||||||
|
|
||||||
pub mod statement;
|
pub mod statement;
|
||||||
pub use statement::*;
|
pub use self::statement::*;
|
||||||
|
108
compiler/src/imports/import_symbol.rs
Normal file
108
compiler/src/imports/import_symbol.rs
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
use crate::{errors::constraints::ImportError, ImportedPrograms};
|
||||||
|
use leo_ast::LeoParser;
|
||||||
|
use leo_types::{ImportSymbol, Program, Span};
|
||||||
|
|
||||||
|
use std::{ffi::OsString, fs::DirEntry, path::PathBuf};
|
||||||
|
|
||||||
|
static LIBRARY_FILE: &str = "src/lib.leo";
|
||||||
|
static FILE_EXTENSION: &str = "leo";
|
||||||
|
|
||||||
|
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(), entry.path()))?;
|
||||||
|
let file_name = entry
|
||||||
|
.file_name()
|
||||||
|
.to_os_string()
|
||||||
|
.into_string()
|
||||||
|
.map_err(|_| ImportError::convert_os_string(span.clone()))?;
|
||||||
|
|
||||||
|
let mut file_path = entry.path().to_path_buf();
|
||||||
|
if file_type.is_dir() {
|
||||||
|
file_path.push(LIBRARY_FILE);
|
||||||
|
|
||||||
|
if !file_path.exists() {
|
||||||
|
return Err(ImportError::expected_lib_file(
|
||||||
|
format!("{:?}", file_path.as_path()),
|
||||||
|
span.clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the abstract syntax tree
|
||||||
|
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 ImportedPrograms {
|
||||||
|
pub fn parse_import_star(&mut self, entry: &DirEntry, span: &Span) -> Result<(), ImportError> {
|
||||||
|
let path = entry.path();
|
||||||
|
let is_dir = path.is_dir();
|
||||||
|
let is_leo_file = path
|
||||||
|
.extension()
|
||||||
|
.map_or(false, |ext| ext.eq(&OsString::from(FILE_EXTENSION)));
|
||||||
|
|
||||||
|
let mut package_path = path.to_path_buf();
|
||||||
|
package_path.push(LIBRARY_FILE);
|
||||||
|
|
||||||
|
let is_package = is_dir && package_path.exists();
|
||||||
|
|
||||||
|
// import * can only be invoked on a package with a library file or a leo file
|
||||||
|
if is_package || is_leo_file {
|
||||||
|
// Generate aleo program from file
|
||||||
|
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
|
||||||
|
let file_name_path = PathBuf::from(entry.file_name());
|
||||||
|
let file_name = file_name_path
|
||||||
|
.file_stem()
|
||||||
|
.unwrap()
|
||||||
|
.to_os_string()
|
||||||
|
.into_string()
|
||||||
|
.unwrap(); // the file exists so these will not fail
|
||||||
|
|
||||||
|
self.store(file_name, program);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
// importing * from a directory or non-leo file in `package/src/` is illegal
|
||||||
|
Err(ImportError::star(entry.path().to_path_buf(), span.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_import_symbol(&mut self, entry: &DirEntry, symbol: &ImportSymbol) -> Result<(), ImportError> {
|
||||||
|
// Generate aleo program from file
|
||||||
|
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
|
||||||
|
let file_name_path = PathBuf::from(entry.file_name());
|
||||||
|
let file_name = file_name_path
|
||||||
|
.file_stem()
|
||||||
|
.unwrap()
|
||||||
|
.to_os_string()
|
||||||
|
.into_string()
|
||||||
|
.unwrap(); // the file exists so these will not fail
|
||||||
|
|
||||||
|
self.store(file_name, program);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
42
compiler/src/imports/imported_programs.rs
Normal file
42
compiler/src/imports/imported_programs.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
use crate::errors::ImportError;
|
||||||
|
use leo_types::Program;
|
||||||
|
|
||||||
|
use std::{collections::HashMap, env::current_dir};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ImportedPrograms {
|
||||||
|
imports: HashMap<String, Program>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImportedPrograms {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
imports: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn store(&mut self, file_name: String, program: Program) {
|
||||||
|
// todo: handle conflicting versions for duplicate imports here
|
||||||
|
let _res = self.imports.insert(file_name, program);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, file_name: &String) -> Option<&Program> {
|
||||||
|
self.imports.get(file_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_program(program: &Program) -> Result<Self, ImportError> {
|
||||||
|
let mut imports = Self::new();
|
||||||
|
|
||||||
|
// Find all imports relative to current directory
|
||||||
|
let path = current_dir().map_err(|error| ImportError::current_directory_error(error))?;
|
||||||
|
|
||||||
|
// Parse each imported file
|
||||||
|
program
|
||||||
|
.imports
|
||||||
|
.iter()
|
||||||
|
.map(|import| imports.parse_package(path.clone(), &import.package))
|
||||||
|
.collect::<Result<Vec<()>, ImportError>>()?;
|
||||||
|
|
||||||
|
Ok(imports)
|
||||||
|
}
|
||||||
|
}
|
8
compiler/src/imports/mod.rs
Normal file
8
compiler/src/imports/mod.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
pub mod imported_programs;
|
||||||
|
pub use self::imported_programs::*;
|
||||||
|
|
||||||
|
pub mod import_symbol;
|
||||||
|
pub use self::import_symbol::*;
|
||||||
|
|
||||||
|
pub mod package;
|
||||||
|
pub use self::package::*;
|
@ -1,29 +1,23 @@
|
|||||||
use crate::{constraints::ConstrainedProgram, errors::constraints::ImportError, GroupType};
|
use crate::{errors::constraints::ImportError, ImportedPrograms};
|
||||||
use leo_types::{Package, PackageAccess};
|
use leo_types::{Package, PackageAccess};
|
||||||
|
|
||||||
use snarkos_models::curves::{Field, PrimeField};
|
|
||||||
use std::{fs, fs::DirEntry, path::PathBuf};
|
use std::{fs, fs::DirEntry, path::PathBuf};
|
||||||
|
|
||||||
static SOURCE_FILE_EXTENSION: &str = ".leo";
|
static SOURCE_FILE_EXTENSION: &str = ".leo";
|
||||||
static SOURCE_DIRECTORY_NAME: &str = "src/";
|
static SOURCE_DIRECTORY_NAME: &str = "src/";
|
||||||
static IMPORTS_DIRECTORY_NAME: &str = "imports/";
|
static IMPORTS_DIRECTORY_NAME: &str = "imports/";
|
||||||
|
|
||||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
impl ImportedPrograms {
|
||||||
pub fn enforce_package_access(
|
pub fn parse_package_access(&mut self, entry: &DirEntry, access: &PackageAccess) -> Result<(), ImportError> {
|
||||||
&mut self,
|
|
||||||
scope: String,
|
|
||||||
entry: &DirEntry,
|
|
||||||
access: PackageAccess,
|
|
||||||
) -> Result<(), ImportError> {
|
|
||||||
// bring one or more import symbols into scope for the current constrained program
|
// 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
|
// we will recursively traverse sub packages here until we find the desired symbol
|
||||||
match access {
|
match access {
|
||||||
PackageAccess::Star(span) => self.enforce_import_star(scope, entry, span),
|
PackageAccess::Star(span) => self.parse_import_star(entry, span),
|
||||||
PackageAccess::Symbol(symbol) => self.enforce_import_symbol(scope, entry, symbol),
|
PackageAccess::Symbol(symbol) => self.parse_import_symbol(entry, symbol),
|
||||||
PackageAccess::SubPackage(package) => self.enforce_package(scope, entry.path(), *package),
|
PackageAccess::SubPackage(package) => self.parse_package(entry.path(), package),
|
||||||
PackageAccess::Multiple(accesses) => {
|
PackageAccess::Multiple(accesses) => {
|
||||||
for access in accesses {
|
for access in accesses {
|
||||||
self.enforce_package_access(scope.clone(), entry, access)?;
|
self.parse_package_access(entry, access)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -31,8 +25,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enforce_package(&mut self, scope: String, mut path: PathBuf, package: Package) -> Result<(), ImportError> {
|
pub fn parse_package(&mut self, mut path: PathBuf, package: &Package) -> Result<(), ImportError> {
|
||||||
let package_name = package.name;
|
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
|
// search for package name in local directory
|
||||||
let mut source_directory = path.clone();
|
let mut source_directory = path.clone();
|
||||||
@ -48,14 +48,15 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let entries = fs::read_dir(path)
|
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()
|
.into_iter()
|
||||||
.collect::<Result<Vec<_>, std::io::Error>>()
|
.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| {
|
let matched_source_entry = entries.into_iter().find(|entry| {
|
||||||
entry
|
entry
|
||||||
.file_name()
|
.file_name()
|
||||||
|
.to_os_string()
|
||||||
.into_string()
|
.into_string()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.trim_end_matches(SOURCE_FILE_EXTENSION)
|
.trim_end_matches(SOURCE_FILE_EXTENSION)
|
||||||
@ -64,26 +65,25 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
|||||||
|
|
||||||
if imports_directory.exists() {
|
if imports_directory.exists() {
|
||||||
let entries = fs::read_dir(imports_directory)
|
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()
|
.into_iter()
|
||||||
.collect::<Result<Vec<_>, std::io::Error>>()
|
.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
|
let matched_import_entry = entries
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.find(|entry| entry.file_name().into_string().unwrap().eq(&package_name.name));
|
.find(|entry| entry.file_name().into_string().unwrap().eq(&package_name.name));
|
||||||
|
|
||||||
// Enforce package access and potential collisions
|
|
||||||
match (matched_source_entry, matched_import_entry) {
|
match (matched_source_entry, matched_import_entry) {
|
||||||
(Some(_), Some(_)) => Err(ImportError::conflicting_imports(package_name)),
|
(Some(_), Some(_)) => Err(ImportError::conflicting_imports(package_name)),
|
||||||
(Some(source_entry), None) => self.enforce_package_access(scope, &source_entry, package.access),
|
(Some(source_entry), None) => self.parse_package_access(&source_entry, &package.access),
|
||||||
(None, Some(import_entry)) => self.enforce_package_access(scope, &import_entry, package.access),
|
(None, Some(import_entry)) => self.parse_package_access(&import_entry, &package.access),
|
||||||
(None, None) => Err(ImportError::unknown_package(package_name)),
|
(None, None) => Err(ImportError::unknown_package(package_name)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Enforce local package access with no found imports directory
|
// Enforce local package access with no found imports directory
|
||||||
match matched_source_entry {
|
match matched_source_entry {
|
||||||
Some(source_entry) => self.enforce_package_access(scope, &source_entry, package.access),
|
Some(source_entry) => self.parse_package_access(&source_entry, &package.access),
|
||||||
None => Err(ImportError::unknown_package(package_name)),
|
None => Err(ImportError::unknown_package(package_name)),
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -15,3 +15,6 @@ pub use self::field::*;
|
|||||||
|
|
||||||
pub mod group;
|
pub mod group;
|
||||||
pub use self::group::*;
|
pub use self::group::*;
|
||||||
|
|
||||||
|
pub mod imports;
|
||||||
|
pub use self::imports::*;
|
||||||
|
@ -12,12 +12,12 @@ import bar.( // imports directory import
|
|||||||
import car.Car; // imports directory import
|
import car.Car; // imports directory import
|
||||||
|
|
||||||
function main() -> u32 {
|
function main() -> u32 {
|
||||||
// const point = Point { x: 1u32, y: 1u32 };
|
const point = Point { x: 1u32, y: 1u32 };
|
||||||
// const foo = foo();
|
const foo = foo();
|
||||||
|
|
||||||
const bar = Bar { r: 1u32 };
|
const bar = Bar { r: 1u32 };
|
||||||
const bat = Bat { t: 1u32 };
|
|
||||||
const baz = Baz { z: 1u32 };
|
const baz = Baz { z: 1u32 };
|
||||||
|
const bat = Bat { t: 1u32 };
|
||||||
|
|
||||||
const car = Car { c: 1u32 };
|
const car = Car { c: 1u32 };
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import test_import.*; // local import
|
import test_import.*; // local import
|
||||||
import bar.*; // imports directory import
|
|
||||||
import car.*; // imports directory import
|
import bar.*; // imports directory import
|
||||||
|
import bar.baz.*; // imports directory import
|
||||||
|
import bar.bat.bat.*; // imports directory import
|
||||||
|
import car.*; // imports directory import
|
||||||
|
|
||||||
function main() -> u32 {
|
function main() -> u32 {
|
||||||
const point = Point { x: 1u32, y: 1u32 };
|
const point = Point { x: 1u32, y: 1u32 };
|
||||||
|
@ -16,44 +16,53 @@ fn set_local_dir() {
|
|||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn test_basic() {
|
fn test_basic() {
|
||||||
|
set_local_dir();
|
||||||
|
|
||||||
let bytes = include_bytes!("basic.leo");
|
let bytes = include_bytes!("basic.leo");
|
||||||
let program = parse_program(bytes).unwrap();
|
let program = parse_program(bytes).unwrap();
|
||||||
|
|
||||||
set_local_dir();
|
|
||||||
|
|
||||||
output_one(program);
|
output_one(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn test_multiple() {
|
fn test_multiple() {
|
||||||
|
set_local_dir();
|
||||||
|
|
||||||
let bytes = include_bytes!("multiple.leo");
|
let bytes = include_bytes!("multiple.leo");
|
||||||
let program = parse_program(bytes).unwrap();
|
let program = parse_program(bytes).unwrap();
|
||||||
|
|
||||||
set_local_dir();
|
|
||||||
|
|
||||||
output_one(program);
|
output_one(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn test_star() {
|
fn test_star() {
|
||||||
|
set_local_dir();
|
||||||
|
|
||||||
let bytes = include_bytes!("star.leo");
|
let bytes = include_bytes!("star.leo");
|
||||||
let program = parse_program(bytes).unwrap();
|
let program = parse_program(bytes).unwrap();
|
||||||
|
|
||||||
set_local_dir();
|
|
||||||
|
|
||||||
output_one(program);
|
output_one(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn test_star_fail() {
|
||||||
|
set_local_dir();
|
||||||
|
|
||||||
|
let bytes = include_bytes!("star_fail.leo");
|
||||||
|
assert!(parse_program(bytes).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn test_alias() {
|
fn test_alias() {
|
||||||
|
set_local_dir();
|
||||||
|
|
||||||
let bytes = include_bytes!("alias.leo");
|
let bytes = include_bytes!("alias.leo");
|
||||||
let program = parse_program(bytes).unwrap();
|
let program = parse_program(bytes).unwrap();
|
||||||
|
|
||||||
set_local_dir();
|
|
||||||
|
|
||||||
output_one(program);
|
output_one(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,21 +70,21 @@ fn test_alias() {
|
|||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn test_many_import() {
|
fn test_many_import() {
|
||||||
|
set_local_dir();
|
||||||
|
|
||||||
let bytes = include_bytes!("many_import.leo");
|
let bytes = include_bytes!("many_import.leo");
|
||||||
let program = parse_program(bytes).unwrap();
|
let program = parse_program(bytes).unwrap();
|
||||||
|
|
||||||
set_local_dir();
|
|
||||||
|
|
||||||
output_one(program);
|
output_one(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn test_many_import_star() {
|
fn test_many_import_star() {
|
||||||
|
set_local_dir();
|
||||||
|
|
||||||
let bytes = include_bytes!("many_import_star.leo");
|
let bytes = include_bytes!("many_import_star.leo");
|
||||||
let program = parse_program(bytes).unwrap();
|
let program = parse_program(bytes).unwrap();
|
||||||
|
|
||||||
set_local_dir();
|
|
||||||
|
|
||||||
output_one(program);
|
output_one(program);
|
||||||
}
|
}
|
||||||
|
4
compiler/tests/import/star_fail.leo
Normal file
4
compiler/tests/import/star_fail.leo
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// importing `*` from a directory is illegal
|
||||||
|
import bar.bat.*;
|
||||||
|
|
||||||
|
function main() {}
|
@ -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) {
|
pub fn set_path(&mut self, path: PathBuf) {
|
||||||
self.path = Some(format!("{:?}", path));
|
self.path = Some(format!("{:?}", path));
|
||||||
}
|
}
|
||||||
|
@ -22,16 +22,6 @@ impl<'ast> From<AstImport<'ast>> for Import {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Import {
|
impl Import {
|
||||||
pub fn path_string_full(&self) -> String {
|
|
||||||
format!("{}.leo", self.package.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// from "./import" import *;
|
|
||||||
pub fn is_star(&self) -> bool {
|
|
||||||
// self.symbols.is_empty()
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "import {};", self.package)
|
write!(f, "import {};", self.package)
|
||||||
}
|
}
|
||||||
|
@ -30,3 +30,31 @@ impl fmt::Display for ImportSymbol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: remove this
|
||||||
|
impl fmt::Debug for ImportSymbol {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
if self.alias.is_some() {
|
||||||
|
write!(f, "{} as {}", self.symbol, self.alias.as_ref().unwrap())
|
||||||
|
} else {
|
||||||
|
write!(f, "{}", self.symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImportSymbol {
|
||||||
|
pub fn star(span: &Span) -> Self {
|
||||||
|
Self {
|
||||||
|
symbol: Identifier {
|
||||||
|
name: "*".to_string(),
|
||||||
|
span: span.clone(),
|
||||||
|
},
|
||||||
|
alias: None,
|
||||||
|
span: span.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_star(&self) -> bool {
|
||||||
|
self.symbol.name.eq("*")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -28,11 +28,11 @@ impl<'ast> From<AstPackageAccess<'ast>> for PackageAccess {
|
|||||||
impl PackageAccess {
|
impl PackageAccess {
|
||||||
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn format(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
PackageAccess::Star(ref _span) => write!(f, ".*"),
|
PackageAccess::Star(ref _span) => write!(f, "*"),
|
||||||
PackageAccess::SubPackage(ref package) => write!(f, ".{}", package),
|
PackageAccess::SubPackage(ref package) => write!(f, "{}", package),
|
||||||
PackageAccess::Symbol(ref symbol) => write!(f, ".{}", symbol),
|
PackageAccess::Symbol(ref symbol) => write!(f, "{}", symbol),
|
||||||
PackageAccess::Multiple(ref accesses) => {
|
PackageAccess::Multiple(ref accesses) => {
|
||||||
write!(f, ".(")?;
|
write!(f, "(")?;
|
||||||
for (i, access) in accesses.iter().enumerate() {
|
for (i, access) in accesses.iter().enumerate() {
|
||||||
write!(f, "{}", access)?;
|
write!(f, "{}", access)?;
|
||||||
if i < accesses.len() - 1 {
|
if i < accesses.len() - 1 {
|
||||||
|
@ -1,29 +1,29 @@
|
|||||||
pub mod circuits;
|
pub mod circuits;
|
||||||
pub use circuits::*;
|
pub use self::circuits::*;
|
||||||
|
|
||||||
pub mod common;
|
pub mod common;
|
||||||
pub use common::*;
|
pub use self::common::*;
|
||||||
|
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
pub use errors::*;
|
pub use self::errors::*;
|
||||||
|
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
pub use expression::*;
|
pub use self::expression::*;
|
||||||
|
|
||||||
pub mod functions;
|
pub mod functions;
|
||||||
pub use functions::*;
|
pub use self::functions::*;
|
||||||
|
|
||||||
pub mod imports;
|
pub mod imports;
|
||||||
pub use imports::*;
|
pub use self::imports::*;
|
||||||
|
|
||||||
pub mod inputs;
|
pub mod inputs;
|
||||||
pub use inputs::*;
|
pub use self::inputs::*;
|
||||||
|
|
||||||
pub mod program;
|
pub mod program;
|
||||||
pub use program::*;
|
pub use self::program::*;
|
||||||
|
|
||||||
pub mod statements;
|
pub mod statements;
|
||||||
pub use statements::*;
|
pub use self::statements::*;
|
||||||
|
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub use types::*;
|
pub use self::types::*;
|
||||||
|
Loading…
Reference in New Issue
Block a user