constraints basic imports

This commit is contained in:
collin 2020-04-17 16:05:20 -07:00
parent 1e9e49db57
commit dbbf816645
7 changed files with 112 additions and 37 deletions

View File

@ -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()

3
simple_import.program Normal file
View File

@ -0,0 +1,3 @@
def foo() -> (field):
// return myGlobal <- not allowed
return 42

View File

@ -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(), &parameter.variable);
let variable_name = new_scope_from_variable(
function.get_name(),
&parameter.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(), &parameter.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(),
&parameter.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<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&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<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&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<F: Field + PrimeField, CS: ConstraintSystem<F>>(
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())

View File

@ -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()),
}
}
}

View File

@ -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<Import<'ast>>,
pub structs: HashMap<Variable, Struct>,
pub functions: HashMap<FunctionName, Function>,
}
impl<'ast> Program<'ast> {
pub fn name(mut self, name: String) -> Self {
self.name = Variable(name);
self
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -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 <collin@aleo.org>
@ -793,6 +792,7 @@ impl<'ast> From<ast::File<'ast>> for types::Program<'ast> {
});
types::Program {
name: types::Variable("".into()),
imports,
structs,
functions,

View File

@ -50,6 +50,7 @@ impl<F: Field + PrimeField> ConstraintSynthesizer<F> for Benchmark<F> {
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(())