impl function scope

This commit is contained in:
collin 2020-04-16 15:15:13 -07:00
parent 455c0b631a
commit 6b6bce38cb
6 changed files with 218 additions and 152 deletions

View File

@ -1,6 +1,6 @@
def main() -> (field): struct Foo {
a = 1 bool x
for i in 0..4 do }
a = a + 1 def main() -> (bool):
endfor Foo f = Foo {x: true}
return a return f.x

View File

@ -70,34 +70,76 @@ impl fmt::Display for ResolvedValue {
} }
write!(f, "]") write!(f, "]")
} }
_ => unimplemented!("display not impl for value"), ResolvedValue::StructDefinition(ref _definition) => {
unimplemented!("cannot return struct definition in program")
}
ResolvedValue::Function(ref _function) => {
unimplemented!("cannot return function definition in program")
}
// _ => unimplemented!("display not impl for value"),
} }
} }
} }
pub struct ResolvedProgram { pub struct ResolvedProgram {
pub resolved_variables: HashMap<Variable, ResolvedValue>, pub resolved_names: HashMap<String, ResolvedValue>,
}
pub fn new_scope(outer: String, inner: String) -> String {
format!("{}_{}", outer, inner)
}
pub fn new_scope_from_variable(outer: String, inner: &Variable) -> String {
new_scope(outer, inner.0.clone())
} }
impl ResolvedProgram { impl ResolvedProgram {
fn new() -> Self { fn new() -> Self {
Self { Self {
resolved_variables: HashMap::new(), resolved_names: HashMap::new(),
} }
} }
fn insert(&mut self, variable: Variable, value: ResolvedValue) { fn store(&mut self, name: String, value: ResolvedValue) {
self.resolved_variables.insert(variable, value); self.resolved_names.insert(name, value);
}
fn store_variable(&mut self, variable: Variable, value: ResolvedValue) {
self.store(variable.0, value);
}
fn contains_name(&self, name: &String) -> bool {
self.resolved_names.contains_key(name)
}
fn contains_variable(&self, variable: &Variable) -> bool {
self.contains_name(&variable.0)
}
fn get(&self, name: &String) -> Option<&ResolvedValue> {
self.resolved_names.get(name)
}
fn get_mut(&mut self, name: &String) -> Option<&mut ResolvedValue> {
self.resolved_names.get_mut(name)
}
fn get_mut_variable(&mut self, variable: &Variable) -> Option<&mut ResolvedValue> {
self.get_mut(&variable.0)
} }
fn bool_from_variable<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn bool_from_variable<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
variable: Variable, variable: Variable,
) -> Boolean { ) -> Boolean {
if self.resolved_variables.contains_key(&variable) { // Evaluate variable name in current function scope
let variable_name = new_scope_from_variable(scope, &variable);
if self.contains_name(&variable_name) {
// TODO: return synthesis error: "assignment missing" here // TODO: return synthesis error: "assignment missing" here
match self.resolved_variables.get(&variable).unwrap() { match self.get(&variable_name).unwrap() {
ResolvedValue::Boolean(boolean) => boolean.clone(), ResolvedValue::Boolean(boolean) => boolean.clone(),
_ => panic!("expected a boolean, got field"), _ => panic!("expected a boolean, got field"),
} }
@ -116,11 +158,15 @@ impl ResolvedProgram {
fn u32_from_variable<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn u32_from_variable<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
variable: Variable, variable: Variable,
) -> UInt32 { ) -> UInt32 {
if self.resolved_variables.contains_key(&variable) { // Evaluate variable name in current function scope
let variable_name = new_scope_from_variable(scope, &variable);
if self.contains_name(&variable_name) {
// TODO: return synthesis error: "assignment missing" here // TODO: return synthesis error: "assignment missing" here
match self.resolved_variables.get(&variable).unwrap() { match self.get(&variable_name).unwrap() {
ResolvedValue::FieldElement(field) => field.clone(), ResolvedValue::FieldElement(field) => field.clone(),
_ => panic!("expected a field, got boolean"), _ => panic!("expected a field, got boolean"),
} }
@ -141,12 +187,13 @@ impl ResolvedProgram {
fn get_bool_value<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn get_bool_value<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
expression: BooleanExpression, expression: BooleanExpression,
) -> Boolean { ) -> Boolean {
match expression { match expression {
BooleanExpression::Variable(variable) => self.bool_from_variable(cs, variable), BooleanExpression::Variable(variable) => self.bool_from_variable(cs, scope, variable),
BooleanExpression::Value(value) => Boolean::Constant(value), BooleanExpression::Value(value) => Boolean::Constant(value),
expression => match self.enforce_boolean_expression(cs, expression) { expression => match self.enforce_boolean_expression(cs, scope, expression) {
ResolvedValue::Boolean(value) => value, ResolvedValue::Boolean(value) => value,
_ => unimplemented!("boolean expression did not resolve to boolean"), _ => unimplemented!("boolean expression did not resolve to boolean"),
}, },
@ -156,12 +203,13 @@ impl ResolvedProgram {
fn get_u32_value<F: Field + PrimeField + PrimeField, CS: ConstraintSystem<F>>( fn get_u32_value<F: Field + PrimeField + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
expression: FieldExpression, expression: FieldExpression,
) -> UInt32 { ) -> UInt32 {
match expression { match expression {
FieldExpression::Variable(variable) => self.u32_from_variable(cs, variable), FieldExpression::Variable(variable) => self.u32_from_variable(cs, scope, variable),
FieldExpression::Number(number) => UInt32::constant(number), FieldExpression::Number(number) => UInt32::constant(number),
field => match self.enforce_field_expression(cs, field) { field => match self.enforce_field_expression(cs, scope, field) {
ResolvedValue::FieldElement(value) => value, ResolvedValue::FieldElement(value) => value,
_ => unimplemented!("field expression did not resolve to field"), _ => unimplemented!("field expression did not resolve to field"),
}, },
@ -171,9 +219,10 @@ impl ResolvedProgram {
fn enforce_not<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_not<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
expression: BooleanExpression, expression: BooleanExpression,
) -> Boolean { ) -> Boolean {
let expression = self.get_bool_value(cs, expression); let expression = self.get_bool_value(cs, scope, expression);
expression.not() expression.not()
} }
@ -181,11 +230,12 @@ impl ResolvedProgram {
fn enforce_or<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_or<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
left: BooleanExpression, left: BooleanExpression,
right: BooleanExpression, right: BooleanExpression,
) -> Boolean { ) -> Boolean {
let left = self.get_bool_value(cs, left); let left = self.get_bool_value(cs, scope.clone(), left);
let right = self.get_bool_value(cs, right); let right = self.get_bool_value(cs, scope.clone(), right);
Boolean::or(cs, &left, &right).unwrap() Boolean::or(cs, &left, &right).unwrap()
} }
@ -193,11 +243,12 @@ impl ResolvedProgram {
fn enforce_and<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_and<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
left: BooleanExpression, left: BooleanExpression,
right: BooleanExpression, right: BooleanExpression,
) -> Boolean { ) -> Boolean {
let left = self.get_bool_value(cs, left); let left = self.get_bool_value(cs, scope.clone(), left);
let right = self.get_bool_value(cs, right); let right = self.get_bool_value(cs, scope.clone(), right);
Boolean::and(cs, &left, &right).unwrap() Boolean::and(cs, &left, &right).unwrap()
} }
@ -205,11 +256,12 @@ impl ResolvedProgram {
fn enforce_bool_equality<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_bool_equality<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
left: BooleanExpression, left: BooleanExpression,
right: BooleanExpression, right: BooleanExpression,
) -> Boolean { ) -> Boolean {
let left = self.get_bool_value(cs, left); let left = self.get_bool_value(cs, scope.clone(), left);
let right = self.get_bool_value(cs, right); let right = self.get_bool_value(cs, scope.clone(), right);
left.enforce_equal(cs.ns(|| format!("enforce bool equal")), &right) left.enforce_equal(cs.ns(|| format!("enforce bool equal")), &right)
.unwrap(); .unwrap();
@ -220,11 +272,12 @@ impl ResolvedProgram {
fn enforce_field_equality<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_field_equality<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
left: FieldExpression, left: FieldExpression,
right: FieldExpression, right: FieldExpression,
) -> Boolean { ) -> Boolean {
let left = self.get_u32_value(cs, left); let left = self.get_u32_value(cs, scope.clone(), left);
let right = self.get_u32_value(cs, right); let right = self.get_u32_value(cs, scope.clone(), right);
left.conditional_enforce_equal( left.conditional_enforce_equal(
cs.ns(|| format!("enforce field equal")), cs.ns(|| format!("enforce field equal")),
@ -239,37 +292,39 @@ impl ResolvedProgram {
fn enforce_boolean_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_boolean_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
expression: BooleanExpression, expression: BooleanExpression,
) -> ResolvedValue { ) -> ResolvedValue {
match expression { match expression {
BooleanExpression::Variable(variable) => { BooleanExpression::Variable(variable) => {
ResolvedValue::Boolean(self.bool_from_variable(cs, variable)) ResolvedValue::Boolean(self.bool_from_variable(cs, scope, variable))
} }
BooleanExpression::Value(value) => ResolvedValue::Boolean(Boolean::Constant(value)), BooleanExpression::Value(value) => ResolvedValue::Boolean(Boolean::Constant(value)),
BooleanExpression::Not(expression) => { BooleanExpression::Not(expression) => {
ResolvedValue::Boolean(self.enforce_not(cs, *expression)) ResolvedValue::Boolean(self.enforce_not(cs, scope, *expression))
} }
BooleanExpression::Or(left, right) => { BooleanExpression::Or(left, right) => {
ResolvedValue::Boolean(self.enforce_or(cs, *left, *right)) ResolvedValue::Boolean(self.enforce_or(cs, scope, *left, *right))
} }
BooleanExpression::And(left, right) => { BooleanExpression::And(left, right) => {
ResolvedValue::Boolean(self.enforce_and(cs, *left, *right)) ResolvedValue::Boolean(self.enforce_and(cs, scope, *left, *right))
} }
BooleanExpression::BoolEq(left, right) => { BooleanExpression::BoolEq(left, right) => {
ResolvedValue::Boolean(self.enforce_bool_equality(cs, *left, *right)) ResolvedValue::Boolean(self.enforce_bool_equality(cs, scope, *left, *right))
} }
BooleanExpression::FieldEq(left, right) => { BooleanExpression::FieldEq(left, right) => {
ResolvedValue::Boolean(self.enforce_field_equality(cs, *left, *right)) ResolvedValue::Boolean(self.enforce_field_equality(cs, scope, *left, *right))
} }
BooleanExpression::IfElse(first, second, third) => { BooleanExpression::IfElse(first, second, third) => {
let resolved_first = match self.enforce_boolean_expression(cs, *first) { let resolved_first =
ResolvedValue::Boolean(resolved) => resolved, match self.enforce_boolean_expression(cs, scope.clone(), *first) {
_ => unimplemented!("if else conditional must resolve to boolean"), ResolvedValue::Boolean(resolved) => resolved,
}; _ => unimplemented!("if else conditional must resolve to boolean"),
};
if resolved_first.eq(&Boolean::Constant(true)) { if resolved_first.eq(&Boolean::Constant(true)) {
self.enforce_boolean_expression(cs, *second) self.enforce_boolean_expression(cs, scope, *second)
} else { } else {
self.enforce_boolean_expression(cs, *third) self.enforce_boolean_expression(cs, scope, *third)
} }
} }
BooleanExpression::Array(array) => ResolvedValue::BooleanArray( BooleanExpression::Array(array) => ResolvedValue::BooleanArray(
@ -280,7 +335,7 @@ impl ResolvedProgram {
unimplemented!("spreads not enforced yet") unimplemented!("spreads not enforced yet")
} }
BooleanSpreadOrExpression::BooleanExpression(expression) => { BooleanSpreadOrExpression::BooleanExpression(expression) => {
match self.enforce_boolean_expression(cs, expression) { match self.enforce_boolean_expression(cs, scope.clone(), expression) {
ResolvedValue::Boolean(value) => value, ResolvedValue::Boolean(value) => value,
_ => unimplemented!("cannot resolve boolean"), _ => unimplemented!("cannot resolve boolean"),
} }
@ -295,11 +350,12 @@ impl ResolvedProgram {
fn enforce_add<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_add<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
left: FieldExpression, left: FieldExpression,
right: FieldExpression, right: FieldExpression,
) -> UInt32 { ) -> UInt32 {
let left = self.get_u32_value(cs, left); let left = self.get_u32_value(cs, scope.clone(), left);
let right = self.get_u32_value(cs, right); let right = self.get_u32_value(cs, scope.clone(), right);
UInt32::addmany( UInt32::addmany(
cs.ns(|| format!("enforce {} + {}", left.value.unwrap(), right.value.unwrap())), cs.ns(|| format!("enforce {} + {}", left.value.unwrap(), right.value.unwrap())),
@ -311,11 +367,12 @@ impl ResolvedProgram {
fn enforce_sub<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_sub<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
left: FieldExpression, left: FieldExpression,
right: FieldExpression, right: FieldExpression,
) -> UInt32 { ) -> UInt32 {
let left = self.get_u32_value(cs, left); let left = self.get_u32_value(cs, scope.clone(), left);
let right = self.get_u32_value(cs, right); let right = self.get_u32_value(cs, scope.clone(), right);
left.sub( left.sub(
cs.ns(|| format!("enforce {} - {}", left.value.unwrap(), right.value.unwrap())), cs.ns(|| format!("enforce {} - {}", left.value.unwrap(), right.value.unwrap())),
@ -327,11 +384,12 @@ impl ResolvedProgram {
fn enforce_mul<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_mul<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
left: FieldExpression, left: FieldExpression,
right: FieldExpression, right: FieldExpression,
) -> UInt32 { ) -> UInt32 {
let left = self.get_u32_value(cs, left); let left = self.get_u32_value(cs, scope.clone(), left);
let right = self.get_u32_value(cs, right); let right = self.get_u32_value(cs, scope.clone(), right);
let res = left let res = left
.mul( .mul(
@ -346,11 +404,12 @@ impl ResolvedProgram {
fn enforce_div<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_div<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
left: FieldExpression, left: FieldExpression,
right: FieldExpression, right: FieldExpression,
) -> UInt32 { ) -> UInt32 {
let left = self.get_u32_value(cs, left); let left = self.get_u32_value(cs, scope.clone(), left);
let right = self.get_u32_value(cs, right); let right = self.get_u32_value(cs, scope.clone(), right);
left.div( left.div(
cs.ns(|| format!("enforce {} / {}", left.value.unwrap(), right.value.unwrap())), cs.ns(|| format!("enforce {} / {}", left.value.unwrap(), right.value.unwrap())),
@ -362,11 +421,12 @@ impl ResolvedProgram {
fn enforce_pow<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_pow<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
left: FieldExpression, left: FieldExpression,
right: FieldExpression, right: FieldExpression,
) -> UInt32 { ) -> UInt32 {
let left = self.get_u32_value(cs, left); let left = self.get_u32_value(cs, scope.clone(), left);
let right = self.get_u32_value(cs, right); let right = self.get_u32_value(cs, scope.clone(), right);
left.pow( left.pow(
cs.ns(|| { cs.ns(|| {
@ -384,40 +444,42 @@ impl ResolvedProgram {
fn enforce_field_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_field_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
expression: FieldExpression, expression: FieldExpression,
) -> ResolvedValue { ) -> ResolvedValue {
match expression { match expression {
FieldExpression::Variable(variable) => { FieldExpression::Variable(variable) => {
ResolvedValue::FieldElement(self.u32_from_variable(cs, variable)) ResolvedValue::FieldElement(self.u32_from_variable(cs, scope, variable))
} }
FieldExpression::Number(number) => { FieldExpression::Number(number) => {
ResolvedValue::FieldElement(UInt32::constant(number)) ResolvedValue::FieldElement(UInt32::constant(number))
} }
FieldExpression::Add(left, right) => { FieldExpression::Add(left, right) => {
ResolvedValue::FieldElement(self.enforce_add(cs, *left, *right)) ResolvedValue::FieldElement(self.enforce_add(cs, scope, *left, *right))
} }
FieldExpression::Sub(left, right) => { FieldExpression::Sub(left, right) => {
ResolvedValue::FieldElement(self.enforce_sub(cs, *left, *right)) ResolvedValue::FieldElement(self.enforce_sub(cs, scope, *left, *right))
} }
FieldExpression::Mul(left, right) => { FieldExpression::Mul(left, right) => {
ResolvedValue::FieldElement(self.enforce_mul(cs, *left, *right)) ResolvedValue::FieldElement(self.enforce_mul(cs, scope, *left, *right))
} }
FieldExpression::Div(left, right) => { FieldExpression::Div(left, right) => {
ResolvedValue::FieldElement(self.enforce_div(cs, *left, *right)) ResolvedValue::FieldElement(self.enforce_div(cs, scope, *left, *right))
} }
FieldExpression::Pow(left, right) => { FieldExpression::Pow(left, right) => {
ResolvedValue::FieldElement(self.enforce_pow(cs, *left, *right)) ResolvedValue::FieldElement(self.enforce_pow(cs, scope, *left, *right))
} }
FieldExpression::IfElse(first, second, third) => { FieldExpression::IfElse(first, second, third) => {
let resolved_first = match self.enforce_boolean_expression(cs, *first) { let resolved_first =
ResolvedValue::Boolean(resolved) => resolved, match self.enforce_boolean_expression(cs, scope.clone(), *first) {
_ => unimplemented!("if else conditional must resolve to boolean"), ResolvedValue::Boolean(resolved) => resolved,
}; _ => unimplemented!("if else conditional must resolve to boolean"),
};
if resolved_first.eq(&Boolean::Constant(true)) { if resolved_first.eq(&Boolean::Constant(true)) {
self.enforce_field_expression(cs, *second) self.enforce_field_expression(cs, scope, *second)
} else { } else {
self.enforce_field_expression(cs, *third) self.enforce_field_expression(cs, scope, *third)
} }
} }
FieldExpression::Array(array) => ResolvedValue::FieldElementArray( FieldExpression::Array(array) => ResolvedValue::FieldElementArray(
@ -428,7 +490,7 @@ impl ResolvedProgram {
unimplemented!("spreads not enforced yet") unimplemented!("spreads not enforced yet")
} }
FieldSpreadOrExpression::FieldExpression(expression) => { FieldSpreadOrExpression::FieldExpression(expression) => {
match self.enforce_field_expression(cs, expression) { match self.enforce_field_expression(cs, scope.clone(), expression) {
ResolvedValue::FieldElement(value) => value, ResolvedValue::FieldElement(value) => value,
_ => unimplemented!("cannot resolve field"), _ => unimplemented!("cannot resolve field"),
} }
@ -442,10 +504,11 @@ impl ResolvedProgram {
fn enforce_struct_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_struct_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
variable: Variable, variable: Variable,
members: Vec<StructMember>, members: Vec<StructMember>,
) -> ResolvedValue { ) -> ResolvedValue {
if let Some(resolved_value) = self.resolved_variables.get_mut(&variable) { if let Some(resolved_value) = self.get_mut_variable(&variable) {
match resolved_value { match resolved_value {
ResolvedValue::StructDefinition(struct_definition) => { ResolvedValue::StructDefinition(struct_definition) => {
struct_definition struct_definition
@ -459,7 +522,8 @@ impl ResolvedProgram {
} }
// Resolve and possibly enforce struct fields // Resolve and possibly enforce struct fields
// do we need to store the results here? // do we need to store the results here?
let _result = self.enforce_expression(cs, member.expression); let _result =
self.enforce_expression(cs, scope.clone(), member.expression);
}); });
ResolvedValue::StructExpression(variable, members) ResolvedValue::StructExpression(variable, members)
@ -474,9 +538,10 @@ impl ResolvedProgram {
fn enforce_index<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_index<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
index: FieldExpression, index: FieldExpression,
) -> usize { ) -> usize {
match self.enforce_field_expression(cs, index) { match self.enforce_field_expression(cs, scope.clone(), index) {
ResolvedValue::FieldElement(number) => number.value.unwrap() as usize, ResolvedValue::FieldElement(number) => number.value.unwrap() as usize,
value => unimplemented!("From index must resolve to a uint32, got {}", value), value => unimplemented!("From index must resolve to a uint32, got {}", value),
} }
@ -485,19 +550,20 @@ impl ResolvedProgram {
fn enforce_array_access_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_array_access_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
array: Box<Expression>, array: Box<Expression>,
index: FieldRangeOrExpression, index: FieldRangeOrExpression,
) -> ResolvedValue { ) -> ResolvedValue {
match self.enforce_expression(cs, *array) { match self.enforce_expression(cs, scope.clone(), *array) {
ResolvedValue::FieldElementArray(field_array) => { ResolvedValue::FieldElementArray(field_array) => {
match index { match index {
FieldRangeOrExpression::Range(from, to) => { FieldRangeOrExpression::Range(from, to) => {
let from_resolved = match from { let from_resolved = match from {
Some(from_index) => self.enforce_index(cs, from_index), Some(from_index) => self.enforce_index(cs, scope.clone(), from_index),
None => 0usize, // Array slice starts at index 0 None => 0usize, // Array slice starts at index 0
}; };
let to_resolved = match to { let to_resolved = match to {
Some(to_index) => self.enforce_index(cs, to_index), Some(to_index) => self.enforce_index(cs, scope.clone(), to_index),
None => field_array.len(), // Array slice ends at array length None => field_array.len(), // Array slice ends at array length
}; };
ResolvedValue::FieldElementArray( ResolvedValue::FieldElementArray(
@ -505,7 +571,7 @@ impl ResolvedProgram {
) )
} }
FieldRangeOrExpression::FieldExpression(index) => { FieldRangeOrExpression::FieldExpression(index) => {
let index_resolved = self.enforce_index(cs, index); let index_resolved = self.enforce_index(cs, scope.clone(), index);
ResolvedValue::FieldElement(field_array[index_resolved].to_owned()) ResolvedValue::FieldElement(field_array[index_resolved].to_owned())
} }
} }
@ -514,11 +580,11 @@ impl ResolvedProgram {
match index { match index {
FieldRangeOrExpression::Range(from, to) => { FieldRangeOrExpression::Range(from, to) => {
let from_resolved = match from { let from_resolved = match from {
Some(from_index) => self.enforce_index(cs, from_index), Some(from_index) => self.enforce_index(cs, scope.clone(), from_index),
None => 0usize, // Array slice starts at index 0 None => 0usize, // Array slice starts at index 0
}; };
let to_resolved = match to { let to_resolved = match to {
Some(to_index) => self.enforce_index(cs, to_index), Some(to_index) => self.enforce_index(cs, scope.clone(), to_index),
None => bool_array.len(), // Array slice ends at array length None => bool_array.len(), // Array slice ends at array length
}; };
ResolvedValue::BooleanArray( ResolvedValue::BooleanArray(
@ -526,7 +592,7 @@ impl ResolvedProgram {
) )
} }
FieldRangeOrExpression::FieldExpression(index) => { FieldRangeOrExpression::FieldExpression(index) => {
let index_resolved = self.enforce_index(cs, index); let index_resolved = self.enforce_index(cs, scope.clone(), index);
ResolvedValue::Boolean(bool_array[index_resolved].to_owned()) ResolvedValue::Boolean(bool_array[index_resolved].to_owned())
} }
} }
@ -538,16 +604,17 @@ impl ResolvedProgram {
fn enforce_struct_access_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_struct_access_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
struct_variable: Box<Expression>, struct_variable: Box<Expression>,
struct_member: Variable, struct_member: Variable,
) -> ResolvedValue { ) -> ResolvedValue {
match self.enforce_expression(cs, *struct_variable) { match self.enforce_expression(cs, scope.clone(), *struct_variable) {
ResolvedValue::StructExpression(_name, members) => { ResolvedValue::StructExpression(_name, members) => {
let matched_member = members let matched_member = members
.into_iter() .into_iter()
.find(|member| member.variable == struct_member); .find(|member| member.variable == struct_member);
match matched_member { match matched_member {
Some(member) => self.enforce_expression(cs, member.expression), Some(member) => self.enforce_expression(cs, scope.clone(), member.expression),
None => unimplemented!("Cannot access struct member {}", struct_member.0), None => unimplemented!("Cannot access struct member {}", struct_member.0),
} }
} }
@ -558,10 +625,11 @@ impl ResolvedProgram {
fn enforce_function_access_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_function_access_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
function: Box<Expression>, function: Box<Expression>,
arguments: Vec<Expression>, arguments: Vec<Expression>,
) -> ResolvedValue { ) -> ResolvedValue {
match self.enforce_expression(cs, *function) { match self.enforce_expression(cs, scope, *function) {
ResolvedValue::Function(function) => self.enforce_function(cs, function, arguments), ResolvedValue::Function(function) => self.enforce_function(cs, function, arguments),
value => unimplemented!("Cannot call unknown function {}", value), value => unimplemented!("Cannot call unknown function {}", value),
} }
@ -570,22 +638,26 @@ impl ResolvedProgram {
fn enforce_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_expression<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
expression: Expression, expression: Expression,
) -> ResolvedValue { ) -> ResolvedValue {
match expression { match expression {
Expression::Boolean(boolean_expression) => { Expression::Boolean(boolean_expression) => {
self.enforce_boolean_expression(cs, boolean_expression) self.enforce_boolean_expression(cs, scope, boolean_expression)
} }
Expression::FieldElement(field_expression) => { Expression::FieldElement(field_expression) => {
self.enforce_field_expression(cs, field_expression) self.enforce_field_expression(cs, scope, field_expression)
} }
Expression::Variable(unresolved_variable) => { Expression::Variable(unresolved_variable) => {
if self.resolved_variables.contains_key(&unresolved_variable) { let variable_name = new_scope_from_variable(scope, &unresolved_variable);
// Evaluate the variable name in the current function scope
if self.contains_name(&variable_name) {
// Reassigning variable to another variable // Reassigning variable to another variable
self.resolved_variables self.get_mut(&variable_name).unwrap().clone()
.get_mut(&unresolved_variable) } else if self.contains_variable(&unresolved_variable) {
.unwrap() // Check global scope (function and struct names)
.clone() self.get_mut_variable(&unresolved_variable).unwrap().clone()
} else { } else {
// The type of the unassigned variable depends on what is passed in // The type of the unassigned variable depends on what is passed in
if std::env::args() if std::env::args()
@ -594,23 +666,31 @@ impl ResolvedProgram {
.parse::<bool>() .parse::<bool>()
.is_ok() .is_ok()
{ {
ResolvedValue::Boolean(self.bool_from_variable(cs, unresolved_variable)) ResolvedValue::Boolean(self.bool_from_variable(
cs,
variable_name,
unresolved_variable,
))
} else { } else {
ResolvedValue::FieldElement(self.u32_from_variable(cs, unresolved_variable)) ResolvedValue::FieldElement(self.u32_from_variable(
cs,
variable_name,
unresolved_variable,
))
} }
} }
} }
Expression::Struct(struct_name, members) => { Expression::Struct(struct_name, members) => {
self.enforce_struct_expression(cs, struct_name, members) self.enforce_struct_expression(cs, scope, struct_name, members)
} }
Expression::ArrayAccess(array, index) => { Expression::ArrayAccess(array, index) => {
self.enforce_array_access_expression(cs, array, index) self.enforce_array_access_expression(cs, scope, array, index)
} }
Expression::StructMemberAccess(struct_variable, struct_member) => { Expression::StructMemberAccess(struct_variable, struct_member) => {
self.enforce_struct_access_expression(cs, struct_variable, struct_member) self.enforce_struct_access_expression(cs, scope, struct_variable, struct_member)
} }
Expression::FunctionCall(function, arguments) => { Expression::FunctionCall(function, arguments) => {
self.enforce_function_access_expression(cs, function, arguments) self.enforce_function_access_expression(cs, scope, function, arguments)
} }
} }
} }
@ -618,23 +698,29 @@ impl ResolvedProgram {
fn enforce_definition_statement<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_definition_statement<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
variable: Variable, scope: String,
name: Variable,
expression: Expression, expression: Expression,
) { ) {
let result = self.enforce_expression(cs, expression); // Evaluate the expression in the current function scope
// println!(" statement result: {} = {}", variable.0, result); let result = self.enforce_expression(cs, scope.clone(), expression);
self.insert(variable, result);
// Store the definition in the current scope
let definition_name = new_scope_from_variable(scope, &name);
self.store(definition_name, result);
} }
fn enforce_return_statement<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_return_statement<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
statements: Vec<Expression>, statements: Vec<Expression>,
) -> ResolvedValue { ) -> ResolvedValue {
ResolvedValue::Return( ResolvedValue::Return(
statements statements
.into_iter() .into_iter()
.map(|expression| self.enforce_expression(cs, expression)) .map(|expression| self.enforce_expression(cs, scope.clone(), expression))
.collect::<Vec<ResolvedValue>>(), .collect::<Vec<ResolvedValue>>(),
) )
} }
@ -642,18 +728,19 @@ impl ResolvedProgram {
fn enforce_statement<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_statement<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
statement: Statement, statement: Statement,
) { ) {
match statement { match statement {
Statement::Definition(variable, expression) => { Statement::Definition(variable, expression) => {
self.enforce_definition_statement(cs, variable, expression); self.enforce_definition_statement(cs, scope, variable, expression);
} }
Statement::For(index, start, stop, statements) => { Statement::For(index, start, stop, statements) => {
self.enforce_for_statement(cs, index, start, stop, statements); self.enforce_for_statement(cs, scope, index, start, stop, statements);
} }
Statement::Return(statements) => { Statement::Return(statements) => {
// TODO: add support for early termination // TODO: add support for early termination
let _res = self.enforce_return_statement(cs, statements); let _res = self.enforce_return_statement(cs, scope, statements);
} }
}; };
} }
@ -661,18 +748,21 @@ impl ResolvedProgram {
fn enforce_for_statement<F: Field + PrimeField, CS: ConstraintSystem<F>>( fn enforce_for_statement<F: Field + PrimeField, CS: ConstraintSystem<F>>(
&mut self, &mut self,
cs: &mut CS, cs: &mut CS,
scope: String,
index: Variable, index: Variable,
start: FieldExpression, start: FieldExpression,
stop: FieldExpression, stop: FieldExpression,
statements: Vec<Statement>, statements: Vec<Statement>,
) { ) {
let start_index = self.enforce_index(cs, start); let start_index = self.enforce_index(cs, scope.clone(), start);
let stop_index = self.enforce_index(cs, stop); let stop_index = self.enforce_index(cs, scope.clone(), stop);
for i in start_index..stop_index { for i in start_index..stop_index {
// Store index // Store index in current function scope.
self.resolved_variables.insert( // For loop scope is not implemented.
index.clone(), let index_name = new_scope_from_variable(scope.clone(), &index);
self.store(
index_name,
ResolvedValue::FieldElement(UInt32::constant(i as u32)), ResolvedValue::FieldElement(UInt32::constant(i as u32)),
); );
@ -680,7 +770,7 @@ impl ResolvedProgram {
statements statements
.clone() .clone()
.into_iter() .into_iter()
.for_each(|statement| self.enforce_statement(cs, statement)); .for_each(|statement| self.enforce_statement(cs, scope.clone(), statement));
} }
} }
@ -711,22 +801,22 @@ impl ResolvedProgram {
// Check that argument is correct type // Check that argument is correct type
match parameter.ty.clone() { match parameter.ty.clone() {
Type::FieldElement => { Type::FieldElement => {
match self.enforce_expression(cs, argument) { match self.enforce_expression(cs, function.name(), argument) {
ResolvedValue::FieldElement(field) => { ResolvedValue::FieldElement(field) => {
// Store argument as variable with parameter name // Store argument as variable with {function_name}_{parameter name}
// TODO: this will not support multiple function calls or variables with same name as parameter let variable_name =
self.resolved_variables.insert( new_scope_from_variable(function.name(), &parameter.variable);
parameter.variable.clone(), self.store(variable_name, ResolvedValue::FieldElement(field));
ResolvedValue::FieldElement(field),
);
} }
argument => unimplemented!("expected field argument got {}", argument), argument => unimplemented!("expected field argument got {}", argument),
} }
} }
Type::Boolean => match self.enforce_expression(cs, argument) { Type::Boolean => match self.enforce_expression(cs, function.name(), argument) {
ResolvedValue::Boolean(bool) => { ResolvedValue::Boolean(bool) => {
self.resolved_variables // Store argument as variable with {function_name}_{parameter name}
.insert(parameter.variable.clone(), ResolvedValue::Boolean(bool)); let variable_name =
new_scope_from_variable(function.name(), &parameter.variable);
self.store(variable_name, ResolvedValue::Boolean(bool));
} }
argument => unimplemented!("expected boolean argument got {}", argument), argument => unimplemented!("expected boolean argument got {}", argument),
}, },
@ -744,13 +834,13 @@ impl ResolvedProgram {
.into_iter() .into_iter()
.for_each(|statement| match statement { .for_each(|statement| match statement {
Statement::Definition(variable, expression) => { Statement::Definition(variable, expression) => {
self.enforce_definition_statement(cs, variable, expression); self.enforce_definition_statement(cs, function.name(), variable, expression);
} }
Statement::For(index, start, stop, statements) => { Statement::For(index, start, stop, statements) => {
self.enforce_for_statement(cs, index, start, stop, statements); self.enforce_for_statement(cs, function.name(), index, start, stop, statements);
} }
Statement::Return(expressions) => { Statement::Return(expressions) => {
return_values = self.enforce_return_statement(cs, expressions) return_values = self.enforce_return_statement(cs, function.name(), expressions)
} }
}); });
@ -768,21 +858,17 @@ impl ResolvedProgram {
.into_iter() .into_iter()
.for_each(|(variable, struct_def)| { .for_each(|(variable, struct_def)| {
resolved_program resolved_program
.resolved_variables .store_variable(variable, ResolvedValue::StructDefinition(struct_def));
.insert(variable, ResolvedValue::StructDefinition(struct_def));
}); });
program program
.functions .functions
.into_iter() .into_iter()
.for_each(|(function_name, function)| { .for_each(|(function_name, function)| {
resolved_program resolved_program.store(function_name.0, ResolvedValue::Function(function));
.resolved_variables
.insert(Variable(function_name.0), ResolvedValue::Function(function));
}); });
let main = resolved_program let main = resolved_program
.resolved_variables .get(&"main".into())
.get(&Variable("main".into()))
.expect("main function not defined"); .expect("main function not defined");
let result = match main.clone() { let result = match main.clone() {
@ -792,20 +878,5 @@ impl ResolvedProgram {
_ => unimplemented!("main must be a function"), _ => unimplemented!("main must be a function"),
}; };
println!("\n {}", result); println!("\n {}", result);
// program
// .statements
// .into_iter()
// .for_each(|statement| resolved_program.enforce_statement(cs, statement));
} }
} }
// impl Program {
// pub fn setup(&self) {
// self.statements
// .iter()
// .for_each(|statement| {
//
// })
// }
// }

View File

@ -158,15 +158,17 @@ pub struct Function {
pub statements: Vec<Statement>, pub statements: Vec<Statement>,
} }
impl Function {
pub fn name(&self) -> String {
self.function_name.0.clone()
}
}
/// A simple program with statement expressions, program arguments and program returns. /// A simple program with statement expressions, program arguments and program returns.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Program { pub struct Program {
pub id: String,
pub structs: HashMap<Variable, Struct>, pub structs: HashMap<Variable, Struct>,
pub functions: HashMap<FunctionName, Function>, pub functions: HashMap<FunctionName, Function>,
// pub statements: Vec<Statement>,
pub arguments: Vec<Variable>,
pub returns: Vec<Variable>,
} }
#[cfg(test)] #[cfg(test)]

View File

@ -730,12 +730,6 @@ impl<'ast> From<ast::File<'ast>> for types::Program {
); );
}); });
types::Program { types::Program { structs, functions }
id: "main".into(),
structs,
functions,
arguments: vec![],
returns: vec![],
}
} }
} }

View File

@ -812,7 +812,6 @@ pub struct Function<'ast> {
pub struct File<'ast> { pub struct File<'ast> {
pub structs: Vec<Struct<'ast>>, pub structs: Vec<Struct<'ast>>,
pub functions: Vec<Function<'ast>>, pub functions: Vec<Function<'ast>>,
pub statements: Vec<Statement<'ast>>,
pub eoi: EOI, pub eoi: EOI,
#[pest_ast(outer())] #[pest_ast(outer())]
pub span: Span<'ast>, pub span: Span<'ast>,

View File

@ -161,4 +161,4 @@ WHITESPACE = _{ " " | "\t" ~ (NEWLINE)* }
/// Abstract Syntax Tree File /// Abstract Syntax Tree File
file = { SOI ~ NEWLINE* ~ struct_definition* ~ NEWLINE* ~ function_definition* ~ NEWLINE* ~ statement* ~ NEWLINE* ~ EOI } file = { SOI ~ NEWLINE* ~ struct_definition* ~ NEWLINE* ~ function_definition* ~ NEWLINE* ~ EOI }