implicit arrays and multiple definitions

This commit is contained in:
collin 2020-05-18 15:17:17 -07:00
parent d0c88a08be
commit aa63cf1dbb
8 changed files with 102 additions and 17 deletions

View File

@ -1,3 +1,10 @@
function main() {
let a: u32 = if true ? 1 : 5;
function test(mut a: u32) {
a = 0;
}
function main() -> u32 {
let a = 1;
test(a);
return a // <- returns 1
}

View File

@ -142,6 +142,9 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
(ConstrainedValue::FieldElement(fe_1), ConstrainedValue::FieldElement(fe_2)) => {
Ok(self.enforce_field_mul(cs, fe_1, fe_2)?)
}
// (ConstrainedValue::GroupElement(group), ConstrainedValue::FieldElement(scalar)) => {
// Ok(Self::evaluate_group_mul(group, scalar))
// }
(ConstrainedValue::Mutable(val_1), val_2) => {
self.enforce_mul_expression(cs, *val_1, val_2)
}
@ -439,9 +442,20 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
cs: &mut CS,
file_scope: String,
function_scope: String,
expected_types: Vec<Type<F, G>>,
mut expected_types: Vec<Type<F, G>>,
array: Vec<Box<SpreadOrExpression<F, G>>>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
// Check explicit array type dimension if given
let expected_dimensions = vec![];
if !expected_types.is_empty() {
match expected_types[0] {
Type::Array(ref _type, ref dimensions) => {
expected_types = vec![expected_types[0].inner_dimension(dimensions)];
}
ref _type => return Err(ExpressionError::IncompatibleTypes(_type.to_string())),
}
}
let mut result = vec![];
for element in array.into_iter() {
match *element {
@ -471,6 +485,17 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
}
}
}
// Check expected_dimensions if given
if !expected_dimensions.is_empty() {
if expected_dimensions[expected_dimensions.len() - 1] != result.len() {
return Err(ExpressionError::InvalidLength(
expected_dimensions[expected_dimensions.len() - 1],
result.len(),
));
}
}
Ok(ConstrainedValue::Array(result))
}
@ -484,6 +509,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
) -> Result<usize, ExpressionError> {
match self.enforce_expression(cs, file_scope, function_scope, expected_types, index)? {
ConstrainedValue::Integer(number) => Ok(number.to_usize()),
ConstrainedValue::Unresolved(string) => Ok(string.parse::<usize>()?),
value => Err(ExpressionError::InvalidIndex(value.to_string())),
}
}

View File

@ -127,7 +127,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
// Allocate each value in the current row
for (i, value) in arr.into_iter().enumerate() {
let value_name = new_scope(name.clone(), i.to_string());
let value_type = array_type.next_dimension(&array_dimensions);
let value_type = array_type.outer_dimension(&array_dimensions);
array_value.push(self.allocate_main_function_input(
cs,
@ -142,7 +142,7 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
// Allocate all row values as none
for i in 0..expected_length {
let value_name = new_scope(name.clone(), i.to_string());
let value_type = array_type.next_dimension(&array_dimensions);
let value_type = array_type.outer_dimension(&array_dimensions);
array_value.push(
self.allocate_main_function_input(

View File

@ -17,4 +17,8 @@ impl<F: Field + PrimeField, G: Group, CS: ConstraintSystem<F>> ConstrainedProgra
pub fn evaluate_group_sub(group_element_1: G, group_element_2: G) -> ConstrainedValue<F, G> {
ConstrainedValue::GroupElement(group_element_1.sub(&group_element_2))
}
//
// pub fn evaluate_group_mul(group_element: G, scalar_field: G::ScalarField) -> ConstrainedValue<F, G> {
// ConstrainedValue::GroupElement(group_element.mul(&scalar_field))
// }
}

View File

@ -51,27 +51,30 @@ impl<F: Field + PrimeField, G: Group> ConstrainedValue<F, G> {
}
pub(crate) fn from_type(value: String, _type: &Type<F, G>) -> Result<Self, ValueError> {
Ok(match _type {
Type::IntegerType(integer_type) => ConstrainedValue::Integer(match integer_type {
match _type {
Type::IntegerType(integer_type) => Ok(ConstrainedValue::Integer(match integer_type {
IntegerType::U8 => Integer::U8(UInt8::constant(value.parse::<u8>()?)),
IntegerType::U16 => Integer::U16(UInt16::constant(value.parse::<u16>()?)),
IntegerType::U32 => Integer::U32(UInt32::constant(value.parse::<u32>()?)),
IntegerType::U64 => Integer::U64(UInt64::constant(value.parse::<u64>()?)),
IntegerType::U128 => Integer::U128(UInt128::constant(value.parse::<u128>()?)),
}),
Type::FieldElement => ConstrainedValue::FieldElement(FieldElement::Constant(
})),
Type::FieldElement => Ok(ConstrainedValue::FieldElement(FieldElement::Constant(
F::from_str(&value).unwrap_or_default(),
)),
Type::GroupElement => ConstrainedValue::GroupElement({
))),
Type::GroupElement => Ok(ConstrainedValue::GroupElement({
use std::str::FromStr;
let scalar = G::ScalarField::from_str(&value).unwrap_or_default();
let point = G::default().mul(&scalar);
point
}),
Type::Boolean => ConstrainedValue::Boolean(Boolean::Constant(value.parse::<bool>()?)),
_ => ConstrainedValue::Unresolved(value),
})
})),
Type::Boolean => Ok(ConstrainedValue::Boolean(Boolean::Constant(
value.parse::<bool>()?,
))),
Type::Array(ref _type, _dimensions) => ConstrainedValue::from_type(value, _type),
_ => Ok(ConstrainedValue::Unresolved(value)),
}
}
pub(crate) fn to_type(&self) -> Type<F, G> {

View File

@ -1,6 +1,7 @@
use crate::errors::{BooleanError, FieldElementError, FunctionError, IntegerError, ValueError};
use snarkos_errors::gadgets::SynthesisError;
use std::num::ParseIntError;
#[derive(Debug, Error)]
pub enum ExpressionError {
@ -21,6 +22,9 @@ pub enum ExpressionError {
#[error("{}", _0)]
IntegerError(IntegerError),
#[error("{}", _0)]
ParseIntError(ParseIntError),
#[error("{}", _0)]
FieldElementError(FieldElementError),
@ -46,6 +50,9 @@ pub enum ExpressionError {
#[error("Index must resolve to an integer, got {}", _0)]
InvalidIndex(String),
#[error("Expected array length {}, got {}", _0, _1)]
InvalidLength(usize, usize),
// Circuits
#[error(
"Circuit {} must be declared before it is used in an inline expression",
@ -110,6 +117,12 @@ impl From<IntegerError> for ExpressionError {
}
}
impl From<ParseIntError> for ExpressionError {
fn from(error: ParseIntError) -> Self {
ExpressionError::ParseIntError(error)
}
}
impl From<FieldElementError> for ExpressionError {
fn from(error: FieldElementError) -> Self {
ExpressionError::FieldElementError(error)

View File

@ -156,7 +156,7 @@ pub enum Type<F: Field + PrimeField, G: Group> {
}
impl<F: Field + PrimeField, G: Group> Type<F, G> {
pub fn next_dimension(&self, dimensions: &Vec<usize>) -> Self {
pub fn outer_dimension(&self, dimensions: &Vec<usize>) -> Self {
let _type = self.clone();
if dimensions.len() > 1 {
@ -168,6 +168,19 @@ impl<F: Field + PrimeField, G: Group> Type<F, G> {
_type
}
pub fn inner_dimension(&self, dimensions: &Vec<usize>) -> Self {
let _type = self.clone();
if dimensions.len() > 1 {
let mut next = vec![];
next.extend_from_slice(&dimensions[..dimensions.len() - 1]);
return Type::Array(Box::new(_type), next);
}
_type
}
}
#[derive(Clone, PartialEq, Eq)]

View File

@ -61,6 +61,12 @@ impl<'ast> types::Integer {
)),
}
}
pub(crate) fn from_implicit(number: String) -> Self {
types::Integer::U128(UInt128::constant(
number.parse::<u128>().expect("unable to parse u128"),
))
}
}
impl<'ast, F: Field + PrimeField, G: Group> From<ast::Integer<'ast>> for types::Expression<F, G> {
@ -79,6 +85,9 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::RangeOrExpression<'ast>>
.from
.map(|from| match types::Expression::<F, G>::from(from.0) {
types::Expression::Integer(number) => number,
types::Expression::Implicit(string) => {
types::Integer::from_implicit(string)
}
expression => {
unimplemented!("Range bounds should be integers, found {}", expression)
}
@ -87,6 +96,9 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::RangeOrExpression<'ast>>
.to
.map(|to| match types::Expression::<F, G>::from(to.0) {
types::Expression::Integer(number) => number,
types::Expression::Implicit(string) => {
types::Integer::from_implicit(string)
}
expression => {
unimplemented!("Range bounds should be integers, found {}", expression)
}
@ -375,7 +387,12 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::Expression<'ast>>
impl<'ast, F: Field + PrimeField, G: Group> types::Expression<F, G> {
fn get_count(count: ast::Value<'ast>) -> usize {
match count {
ast::Value::Integer(f) => f
ast::Value::Integer(integer) => integer
.number
.value
.parse::<usize>()
.expect("Unable to read array size"),
ast::Value::Implicit(number) => number
.number
.value
.parse::<usize>()
@ -590,10 +607,12 @@ impl<'ast, F: Field + PrimeField, G: Group> From<ast::ForStatement<'ast>>
fn from(statement: ast::ForStatement<'ast>) -> Self {
let from = match types::Expression::<F, G>::from(statement.start) {
types::Expression::Integer(number) => number,
types::Expression::Implicit(string) => types::Integer::from_implicit(string),
expression => unimplemented!("Range bounds should be integers, found {}", expression),
};
let to = match types::Expression::<F, G>::from(statement.stop) {
types::Expression::Integer(number) => number,
types::Expression::Implicit(string) => types::Integer::from_implicit(string),
expression => unimplemented!("Range bounds should be integers, found {}", expression),
};