From dbbf816645989f1c3fdeed9455864bd951e112d5 Mon Sep 17 00:00:00 2001 From: collin Date: Fri, 17 Apr 2020 16:05:20 -0700 Subject: [PATCH] constraints basic imports --- simple.program | 7 +- simple_import.program | 3 + src/aleo_program/constraints.rs | 119 ++++++++++++++++++++++++-------- src/aleo_program/imports.rs | 7 +- src/aleo_program/types.rs | 10 ++- src/aleo_program/types_from.rs | 2 +- src/main.rs | 1 + 7 files changed, 112 insertions(+), 37 deletions(-) create mode 100644 simple_import.program diff --git a/simple.program b/simple.program index e8659e1ec8..01982b85de 100644 --- a/simple.program +++ b/simple.program @@ -1,9 +1,4 @@ -from "./path/to/my/module" import MySymbol - -def foo() -> (field): - // return myGlobal <- not allowed - return 42 +from "./simple_import" import foo def main() -> (field): - myGlobal = 42 return foo() \ No newline at end of file diff --git a/simple_import.program b/simple_import.program new file mode 100644 index 0000000000..57f9d307c9 --- /dev/null +++ b/simple_import.program @@ -0,0 +1,3 @@ +def foo() -> (field): + // return myGlobal <- not allowed + return 42 \ No newline at end of file diff --git a/src/aleo_program/constraints.rs b/src/aleo_program/constraints.rs index 07828d00a9..5b5e1fbb17 100644 --- a/src/aleo_program/constraints.rs +++ b/src/aleo_program/constraints.rs @@ -1,9 +1,11 @@ use crate::aleo_program::{ Assignee, BooleanExpression, BooleanSpreadOrExpression, Expression, FieldExpression, - FieldRangeOrExpression, FieldSpreadOrExpression, Function, Program, Statement, Struct, + FieldRangeOrExpression, FieldSpreadOrExpression, Function, Import, Program, Statement, Struct, StructMember, Type, Variable, }; +use crate::ast; +use from_pest::FromPest; use snarkos_models::curves::{Field, PrimeField}; use snarkos_models::gadgets::utilities::eq::EqGadget; use snarkos_models::gadgets::{ @@ -12,6 +14,7 @@ use snarkos_models::gadgets::{ }; use std::collections::HashMap; use std::fmt; +use std::fs; #[derive(Clone)] pub enum ResolvedValue { @@ -756,6 +759,8 @@ impl ResolvedProgram { Assignee::Variable(name) => { // Store the variable in the current scope let definition_name = new_scope_from_variable(scope.clone(), &name); + + // Evaluate the rhs expression in the current function scope let result = self.enforce_expression(cs, scope, expression); self.store(definition_name, result); @@ -958,25 +963,33 @@ impl ResolvedProgram { // Check that argument is correct type match parameter.ty.clone() { Type::FieldElement => { - match self.enforce_expression(cs, function.name(), argument) { + match self.enforce_expression(cs, function.get_name(), argument) { ResolvedValue::FieldElement(field) => { // Store argument as variable with {function_name}_{parameter name} - let variable_name = - new_scope_from_variable(function.name(), ¶meter.variable); + let variable_name = new_scope_from_variable( + function.get_name(), + ¶meter.variable, + ); self.store(variable_name, ResolvedValue::FieldElement(field)); } argument => unimplemented!("expected field argument got {}", argument), } } - Type::Boolean => match self.enforce_expression(cs, function.name(), argument) { - ResolvedValue::Boolean(bool) => { - // Store argument as variable with {function_name}_{parameter name} - let variable_name = - new_scope_from_variable(function.name(), ¶meter.variable); - self.store(variable_name, ResolvedValue::Boolean(bool)); + Type::Boolean => { + match self.enforce_expression(cs, function.get_name(), argument) { + ResolvedValue::Boolean(bool) => { + // Store argument as variable with {function_name}_{parameter name} + let variable_name = new_scope_from_variable( + function.get_name(), + ¶meter.variable, + ); + self.store(variable_name, ResolvedValue::Boolean(bool)); + } + argument => { + unimplemented!("expected boolean argument got {}", argument) + } } - argument => unimplemented!("expected boolean argument got {}", argument), - }, + } ty => unimplemented!("parameter type {} not matched yet", ty), } }); @@ -991,38 +1004,88 @@ impl ResolvedProgram { .into_iter() .for_each(|statement| match statement { Statement::Definition(variable, expression) => { - self.enforce_definition_statement(cs, function.name(), variable, expression); + self.enforce_definition_statement( + cs, + function.get_name(), + variable, + expression, + ); } Statement::For(index, start, stop, statements) => { - self.enforce_for_statement(cs, function.name(), index, start, stop, statements); + self.enforce_for_statement( + cs, + function.get_name(), + index, + start, + stop, + statements, + ); } Statement::Return(expressions) => { - return_values = self.enforce_return_statement(cs, function.name(), expressions) + return_values = + self.enforce_return_statement(cs, function.get_name(), expressions) } }); return_values } + fn enforce_import>( + &mut self, + cs: &mut CS, + import: Import, + ) { + // println!("import: {}", import); + + // Resolve program file path + let unparsed_file = fs::read_to_string(import.get_file()).expect("cannot read file"); + let mut file = ast::parse(&unparsed_file).expect("unsuccessful parse"); + // println!("successful import parse!"); + + // generate ast from file + let syntax_tree = ast::File::from_pest(&mut file).expect("infallible"); + + // generate aleo program from file + let program = Program::from(syntax_tree); + // println!(" compiled: {:#?}", program); + + // recursively evaluate program statements TODO: in file scope + self.resolve_definitions(cs, program); + + // store import under designated name + // self.store(name, value) + } + + pub fn resolve_definitions>( + &mut self, + cs: &mut CS, + program: Program, + ) { + program + .imports + .into_iter() + .for_each(|import| self.enforce_import(cs, import)); + program + .structs + .into_iter() + .for_each(|(variable, struct_def)| { + self.store_variable(variable, ResolvedValue::StructDefinition(struct_def)); + }); + program + .functions + .into_iter() + .for_each(|(function_name, function)| { + self.store(function_name.0, ResolvedValue::Function(function)); + }); + } + pub fn generate_constraints>( cs: &mut CS, program: Program, ) { let mut resolved_program = ResolvedProgram::new(); - program - .structs - .into_iter() - .for_each(|(variable, struct_def)| { - resolved_program - .store_variable(variable, ResolvedValue::StructDefinition(struct_def)); - }); - program - .functions - .into_iter() - .for_each(|(function_name, function)| { - resolved_program.store(function_name.0, ResolvedValue::Function(function)); - }); + resolved_program.resolve_definitions(cs, program); let main = resolved_program .get(&"main".into()) diff --git a/src/aleo_program/imports.rs b/src/aleo_program/imports.rs index 289b0a8919..4688a0815c 100644 --- a/src/aleo_program/imports.rs +++ b/src/aleo_program/imports.rs @@ -44,6 +44,11 @@ impl<'ast> Import<'ast> { pub fn get_source(&self) -> &Path { &self.source } + + pub fn get_file(&self) -> String { + let path = self.get_source().to_str().unwrap(); + format!("{}.program", path) + } } impl<'ast> fmt::Display for Import<'ast> { @@ -64,7 +69,7 @@ impl<'ast> fmt::Debug for Import<'ast> { self.source.display(), alias ), - None => write!(f, "import source: {})", self.source.display()), + None => write!(f, "import( source: {})", self.source.display()), } } } diff --git a/src/aleo_program/types.rs b/src/aleo_program/types.rs index ed05731341..ebf0c09f88 100644 --- a/src/aleo_program/types.rs +++ b/src/aleo_program/types.rs @@ -167,7 +167,7 @@ pub struct Function { } impl Function { - pub fn name(&self) -> String { + pub fn get_name(&self) -> String { self.function_name.0.clone() } } @@ -175,11 +175,19 @@ impl Function { /// A simple program with statement expressions, program arguments and program returns. #[derive(Debug, Clone)] pub struct Program<'ast> { + pub name: Variable, pub imports: Vec>, pub structs: HashMap, pub functions: HashMap, } +impl<'ast> Program<'ast> { + pub fn name(mut self, name: String) -> Self { + self.name = Variable(name); + self + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/aleo_program/types_from.rs b/src/aleo_program/types_from.rs index 66e08685e7..39120fac42 100644 --- a/src/aleo_program/types_from.rs +++ b/src/aleo_program/types_from.rs @@ -1,5 +1,4 @@ //! Logic to convert from an abstract syntax tree (ast) representation to a typed zokrates_program. -//! We implement "unwrap" functions instead of the From trait to handle nested statements (flattening). //! //! @file zokrates_program.rs //! @author Collin Chin @@ -793,6 +792,7 @@ impl<'ast> From> for types::Program<'ast> { }); types::Program { + name: types::Variable("".into()), imports, structs, functions, diff --git a/src/main.rs b/src/main.rs index b22959e23c..531879e162 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,6 +50,7 @@ impl ConstraintSynthesizer for Benchmark { let program = aleo_program::Program::from(syntax_tree); println!(" compiled: {:#?}", program); + let program = program.name("simple".into()); aleo_program::ResolvedProgram::generate_constraints(cs, program); Ok(())