early function termination

This commit is contained in:
collin 2020-04-27 16:59:44 -07:00
parent c5fc02b51d
commit 1dcaa06ef0
4 changed files with 94 additions and 81 deletions

View File

@ -1,10 +1,11 @@
function main(a: private bool, b: private bool) -> (u32) {
if (a) {
res = 1;
} else if (b) {
res = 2;
} else {
res = 3;
function main(a: private bool) -> (u32) {
b = 0;
for i in 0..4 {
if (a) {
return 9
} else {
b = b + i;
}
}
return res
return b
}

View File

@ -105,21 +105,18 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
let mut return_values = ResolvedValue::Return(vec![]);
function
.statements
.clone()
.into_iter()
.for_each(|statement| {
if let Some(returned) = self.enforce_statement(
cs,
scope.clone(),
function_name.clone(),
statement,
function.returns.clone(),
) {
return_values = returned;
}
});
for statement in function.statements.iter() {
if let Some(returned) = self.enforce_statement(
cs,
scope.clone(),
function_name.clone(),
statement.clone(),
function.returns.clone(),
) {
return_values = returned;
break;
}
}
return_values
}

View File

@ -27,7 +27,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
// Check global scope (function and struct names)
self.get_mut_variable(&unresolved_variable).unwrap().clone()
} else {
unimplemented!("variable declaration {} not found", variable_name)
unimplemented!("variable declaration \"{}\" not found", unresolved_variable)
}
}

View File

@ -232,15 +232,40 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
)
}
fn iterate_or_early_return(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
statements: Vec<Statement<F>>,
return_types: Vec<Type<F>>,
) -> Option<ResolvedValue<F>> {
let mut res = None;
// Evaluate statements and possibly return early
for statement in statements.iter() {
if let Some(early_return) = self.enforce_statement(
cs,
file_scope.clone(),
function_scope.clone(),
statement.clone(),
return_types.clone(),
) {
res = Some(early_return);
break;
}
}
res
}
fn enforce_conditional_statement(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
statement: ConditionalStatement<F>,
return_types: Vec<Type<F>>,
) -> Option<ResolvedValue<F>> {
let mut res = None;
let condition = match self.enforce_expression(
cs,
file_scope.clone(),
@ -252,50 +277,34 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
};
if condition.eq(&Boolean::Constant(true)) {
statement
.statements
.clone()
.into_iter()
.for_each(|statement| {
if let Some(early_return) = self.enforce_statement(
cs,
file_scope.clone(),
function_scope.clone(),
statement,
vec![],
) {
res = Some(early_return)
}
});
self.iterate_or_early_return(
cs,
file_scope,
function_scope,
statement.statements,
return_types,
)
} else {
if let Some(next) = statement.next {
match next {
ConditionalNestedOrEnd::Nested(nested) => {
res = self.enforce_conditional_statement(
cs,
file_scope,
function_scope,
*nested,
)
}
ConditionalNestedOrEnd::End(statements) => {
statements.into_iter().for_each(|statement| {
if let Some(early_return) = self.enforce_statement(
cs,
file_scope.clone(),
function_scope.clone(),
statement,
vec![],
) {
res = Some(early_return)
}
})
}
}
match statement.next {
Some(next) => match next {
ConditionalNestedOrEnd::Nested(nested) => self.enforce_conditional_statement(
cs,
file_scope,
function_scope,
*nested,
return_types,
),
ConditionalNestedOrEnd::End(statements) => self.iterate_or_early_return(
cs,
file_scope,
function_scope,
statements,
return_types,
),
},
None => None,
}
}
res
}
fn enforce_for_statement(
@ -307,6 +316,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
start: Integer,
stop: Integer,
statements: Vec<Statement<F>>,
return_types: Vec<Type<F>>,
) -> Option<ResolvedValue<F>> {
let mut res = None;
@ -316,17 +326,17 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
let index_name = new_scope_from_variable(function_scope.clone(), &index);
self.store(index_name, ResolvedValue::U32(UInt32::constant(i as u32)));
// Evaluate statements (for loop statements should not have a return type)
statements.clone().into_iter().for_each(|statement| {
// TODO: handle for loop early termination here
res = self.enforce_statement(
cs,
file_scope.clone(),
function_scope.clone(),
statement,
vec![],
);
});
// Evaluate statements and possibly return early
if let Some(early_return) = self.iterate_or_early_return(
cs,
file_scope.clone(),
function_scope.clone(),
statements.clone(),
return_types.clone(),
) {
res = Some(early_return);
break;
}
}
res
@ -375,9 +385,13 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
);
}
Statement::Conditional(statement) => {
if let Some(early_return) =
self.enforce_conditional_statement(cs, file_scope, function_scope, statement)
{
if let Some(early_return) = self.enforce_conditional_statement(
cs,
file_scope,
function_scope,
statement,
return_types,
) {
res = Some(early_return)
}
}
@ -390,6 +404,7 @@ impl<F: Field + PrimeField, CS: ConstraintSystem<F>> ResolvedProgram<F, CS> {
start,
stop,
statements,
return_types,
) {
res = Some(early_return)
}