From c30a50c5dcc615a0dc857bf85fdc299c64f6c033 Mon Sep 17 00:00:00 2001 From: collin Date: Thu, 2 Jul 2020 05:21:06 -0700 Subject: [PATCH] retrieve import definitions at program execution --- .../constraints/definitions/definitions.rs | 26 ++--- .../src/constraints/definitions/import.rs | 6 +- .../src/constraints/definitions/symbol.rs | 42 ++++++-- compiler/src/constraints/expression.rs | 98 +++++++++---------- compiler/src/constraints/value.rs | 30 ++++++ compiler/src/imports/imported_programs.rs | 1 - 6 files changed, 120 insertions(+), 83 deletions(-) diff --git a/compiler/src/constraints/definitions/definitions.rs b/compiler/src/constraints/definitions/definitions.rs index 5e85392016..7d0712a7d2 100644 --- a/compiler/src/constraints/definitions/definitions.rs +++ b/compiler/src/constraints/definitions/definitions.rs @@ -23,28 +23,18 @@ impl> ConstrainedProgram { .map(|import| self.store_import(program_name.clone(), import, imported_programs)) .collect::, 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(()) } } diff --git a/compiler/src/constraints/definitions/import.rs b/compiler/src/constraints/definitions/import.rs index 701b02f0c5..cf917610f6 100644 --- a/compiler/src/constraints/definitions/import.rs +++ b/compiler/src/constraints/definitions/import.rs @@ -10,14 +10,10 @@ impl> ConstrainedProgram { 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> ConstrainedProgram { 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::, ImportError>>()?; Ok(()) diff --git a/compiler/src/constraints/definitions/symbol.rs b/compiler/src/constraints/definitions/symbol.rs index 55b98b0336..79db3c990b 100644 --- a/compiler/src/constraints/definitions/symbol.rs +++ b/compiler/src/constraints/definitions/symbol.rs @@ -7,19 +7,44 @@ impl> ConstrainedProgram { 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> ConstrainedProgram { .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(()) diff --git a/compiler/src/constraints/expression.rs b/compiler/src/constraints/expression.rs index c41656dbb5..887abb3f29 100644 --- a/compiler/src/constraints/expression.rs +++ b/compiler/src/constraints/expression.rs @@ -51,6 +51,9 @@ impl> ConstrainedProgram { } 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> ConstrainedProgram { 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>( @@ -786,18 +791,7 @@ impl> ConstrainedProgram { *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 {} {}:{}", diff --git a/compiler/src/constraints/value.rs b/compiler/src/constraints/value.rs index 81a0f3602a..090aacd9c0 100644 --- a/compiler/src/constraints/value.rs +++ b/compiler/src/constraints/value.rs @@ -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> { Mutable(Box>), Static(Box>), + Import(String, Box>), Unresolved(String), } @@ -115,6 +118,30 @@ impl> ConstrainedValue { } } + 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 { + 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> ConstrainedValue { // empty wrappers ConstrainedValue::CircuitDefinition(_) => {} ConstrainedValue::Function(_, _) => {} + ConstrainedValue::Import(_, _) => {} + ConstrainedValue::Unresolved(value) => { return Err(ValueError::implicit(value.to_string(), span)); } @@ -249,6 +278,7 @@ impl> fmt::Display for ConstrainedValue { 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), diff --git a/compiler/src/imports/imported_programs.rs b/compiler/src/imports/imported_programs.rs index d6c78b79ca..3b01f36ae5 100644 --- a/compiler/src/imports/imported_programs.rs +++ b/compiler/src/imports/imported_programs.rs @@ -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); }