retrieve import definitions at program execution

This commit is contained in:
collin 2020-07-02 05:21:06 -07:00
parent 14f5f448be
commit c30a50c5dc
6 changed files with 120 additions and 83 deletions

View File

@ -23,28 +23,18 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
.map(|import| self.store_import(program_name.clone(), import, imported_programs))
.collect::<Result<Vec<_>, ImportError>>()?;
self.store_all(program_name.clone(), &program);
Ok(())
}
pub(crate) fn store_all(&mut self, scope: String, program: &Program) {
// evaluate and store all circuit definitions
program.circuits.iter().for_each(|(identifier, circuit)| {
let resolved_circuit_name = new_scope(scope.clone(), identifier.to_string());
self.store(
resolved_circuit_name,
ConstrainedValue::CircuitDefinition(circuit.clone()),
);
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.iter().for_each(|(function_name, function)| {
let resolved_function_name = new_scope(scope.clone(), function_name.to_string());
self.store(
resolved_function_name,
ConstrainedValue::Function(None, function.clone()),
);
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(())
}
}

View File

@ -10,14 +10,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
import: &Import,
imported_programs: &ImportedPrograms,
) -> Result<(), ImportError> {
println!("program name {}", scope);
println!("import {}", import);
// get imported program name from import
// get imported symbols from from import
let imported_symbols = ImportedSymbols::from(import);
let program_name = imported_symbols.name.clone();
println!("symbols {:?}", imported_symbols);
// get imported program from hashmap
let program = imported_programs
@ -35,7 +31,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
imported_symbols
.symbols
.iter()
.map(|symbol| self.store_symbol(scope.clone(), symbol, program))
.map(|symbol| self.store_symbol(scope.clone(), program_name.clone(), symbol, program))
.collect::<Result<Vec<()>, ImportError>>()?;
Ok(())

View File

@ -7,19 +7,44 @@ 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() {
self.store_all(scope, program);
// 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_def)) => ConstrainedValue::CircuitDefinition(circuit_def.clone()),
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
@ -28,18 +53,21 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
.find(|(function_name, _function)| symbol.symbol == **function_name);
match matched_function {
Some((_function_name, function)) => ConstrainedValue::Function(None, function.clone()),
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(), scope)),
}
}
};
// take the alias if it is present
let name = symbol.alias.clone().unwrap_or(symbol.symbol.clone());
let resolved_name = new_scope(scope, name.to_string());
let id = symbol.alias.clone().unwrap_or(symbol.symbol.clone());
let name = new_scope(scope, id.to_string());
// store imported circuit under resolved name
self.store(resolved_name, value);
// store imported circuit under imported name
self.store(name, value);
}
Ok(())

View File

@ -51,6 +51,9 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
} else if let Some(value) = self.get(&identifier_name) {
// Check global scope (function and circuit names)
value.clone()
} else if let Some(value) = self.get(&unresolved_identifier.name) {
// Check imported file scope
value.clone()
} else {
return Err(ExpressionError::undefined_identifier(unresolved_identifier));
};
@ -609,53 +612,55 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
program_identifier = file_scope.clone();
}
if let Some(ConstrainedValue::CircuitDefinition(circuit_definition)) = self.get_mut(&program_identifier) {
let circuit_identifier = circuit_definition.circuit_name.clone();
let mut resolved_members = vec![];
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,
)?;
let circuit = match self.get(&program_identifier) {
Some(value) => value.clone().extract_circuit(span.clone())?,
None => return Err(ExpressionError::undefined_circuit(identifier.to_string(), span)),
};
resolved_members.push(ConstrainedCircuitMember(identifier, field_value))
}
None => return Err(ExpressionError::expected_circuit_member(identifier.to_string(), span)),
let circuit_identifier = circuit.circuit_name.clone();
let mut resolved_members = vec![];
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();
let mut constrained_function_value =
ConstrainedValue::Function(Some(circuit_identifier.clone()), function);
}
CircuitMember::CircuitFunction(_static, function) => {
let identifier = function.function_name.clone();
let mut constrained_function_value =
ConstrainedValue::Function(Some(circuit_identifier.clone()), function);
if _static {
constrained_function_value = ConstrainedValue::Static(Box::new(constrained_function_value));
}
resolved_members.push(ConstrainedCircuitMember(identifier, constrained_function_value));
if _static {
constrained_function_value = ConstrainedValue::Static(Box::new(constrained_function_value));
}
};
}
Ok(ConstrainedValue::CircuitExpression(
circuit_identifier.clone(),
resolved_members,
))
} else {
Err(ExpressionError::undefined_circuit(identifier.to_string(), span))
resolved_members.push(ConstrainedCircuitMember(identifier, constrained_function_value));
}
};
}
Ok(ConstrainedValue::CircuitExpression(
circuit_identifier.clone(),
resolved_members,
))
}
fn enforce_circuit_access_expression<CS: ConstraintSystem<F>>(
@ -786,18 +791,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
*function.clone(),
)?;
let (outer_scope, function_call) = match function_value {
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 (outer_scope, function_call) = function_value.extract_function(file_scope, span.clone())?;
let name_unique = format!(
"function call {} {}:{}",

View File

@ -6,11 +6,13 @@ use crate::{
allocate_group,
errors::ValueError,
new_bool_constant,
new_scope,
FieldType,
GroupType,
};
use leo_types::{Circuit, Function, Identifier, Integer, Span, Type};
use crate::errors::ExpressionError;
use snarkos_errors::gadgets::SynthesisError;
use snarkos_models::{
curves::{Field, PrimeField},
@ -41,6 +43,7 @@ pub enum ConstrainedValue<F: Field + PrimeField, G: GroupType<F>> {
Mutable(Box<ConstrainedValue<F, G>>),
Static(Box<ConstrainedValue<F, G>>),
Import(String, Box<ConstrainedValue<F, G>>),
Unresolved(String),
}
@ -115,6 +118,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) {
if let ConstrainedValue::Mutable(inner) = self {
*self = *inner.clone()
@ -192,6 +219,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
// empty wrappers
ConstrainedValue::CircuitDefinition(_) => {}
ConstrainedValue::Function(_, _) => {}
ConstrainedValue::Import(_, _) => {}
ConstrainedValue::Unresolved(value) => {
return Err(ValueError::implicit(value.to_string(), span));
}
@ -249,6 +278,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> fmt::Display for ConstrainedValue<F
ConstrainedValue::Function(ref _circuit_option, ref function) => {
write!(f, "function {{ {}() }}", function.function_name)
}
ConstrainedValue::Import(_, ref value) => write!(f, "{}", value),
ConstrainedValue::Mutable(ref value) => write!(f, "mut {}", value),
ConstrainedValue::Static(ref value) => write!(f, "static {}", value),
ConstrainedValue::Unresolved(ref value) => write!(f, "unresolved {}", value),

View File

@ -17,7 +17,6 @@ impl ImportedPrograms {
pub(crate) fn store(&mut self, file_name: String, program: Program) {
// todo: handle conflicting versions for duplicate imports here
println!("storing: {},\n {:?}", file_name, program);
let _res = self.imports.insert(file_name, program);
}