array dimensions check added, const tuples added

This commit is contained in:
damirka 2021-03-15 22:58:34 +03:00
parent 258255102a
commit 2508ec7ef1
7 changed files with 99 additions and 17 deletions

View File

@ -118,6 +118,15 @@ impl FunctionError {
Self::new_from_span(message, span) Self::new_from_span(message, span)
} }
pub fn tuple_size_mismatch(expected: usize, actual: usize, span: &Span) -> Self {
let message = format!(
"Input tuple size mismatch expected {}, found tuple with length {}",
expected, actual
);
Self::new_from_span(message, span)
}
pub fn invalid_tuple(actual: String, span: &Span) -> Self { pub fn invalid_tuple(actual: String, span: &Span) -> Self {
let message = format!("Expected function input tuple, found `{}`", actual); let message = format!("Expected function input tuple, found `{}`", actual);
@ -141,4 +150,10 @@ impl FunctionError {
Self::new_from_span(message, span) Self::new_from_span(message, span)
} }
pub fn double_input_declaration(input_name: String, span: &Span) -> Self {
let message = format!("Input variable {} declared twice", input_name);
Self::new_from_span(message, span)
}
} }

View File

@ -60,18 +60,18 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
)?)), )?)),
Type::Array(type_, len) => self.allocate_array(cs, name, &*type_, *len, input_option, span), Type::Array(type_, len) => self.allocate_array(cs, name, &*type_, *len, input_option, span),
Type::Tuple(types) => self.allocate_tuple(cs, &name, types, input_option, span), Type::Tuple(types) => self.allocate_tuple(cs, &name, types, input_option, span),
_ => unimplemented!("main function input not implemented for type"), _ => unimplemented!("main function input not implemented for type {}", type_),
} }
} }
} }
/// Process constant inputs and return ConstrainedValue with constant value in it. /// Process constant inputs and return ConstrainedValue with constant value in it.
impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> { impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
pub fn parse_constant_main_function_input<CS: ConstraintSystem<F>>( pub fn constant_main_function_input<CS: ConstraintSystem<F>>(
&mut self, &mut self,
// TODO: remove unnecessary arguments // TODO: remove unnecessary arguments
_cs: &mut CS, _cs: &mut CS,
_type_: &Type, type_: &Type,
name: &str, name: &str,
input_option: Option<InputValue>, input_option: Option<InputValue>,
span: &Span, span: &Span,
@ -101,18 +101,48 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
ConstrainedValue::Integer(Integer::new(&const_int)) ConstrainedValue::Integer(Integer::new(&const_int))
} }
InputValue::Array(values) => ConstrainedValue::Array( InputValue::Array(values) => {
values // Get ASG type and array length to compare with provided inputs.
.iter() let (type_, arr_len) = if let Type::Array(type_, len) = type_ {
.map(|x| self.parse_constant_main_function_input(_cs, _type_, name, Some(x.clone()), span)) (type_, *len)
.collect::<Result<Vec<_>, _>>()?, } else {
), return Err(FunctionError::input_not_found("expected".to_string(), &span));
InputValue::Tuple(values) => ConstrainedValue::Tuple( };
values
.iter() if arr_len != values.len() {
.map(|x| self.parse_constant_main_function_input(_cs, _type_, name, Some(x.clone()), span)) return Err(FunctionError::invalid_input_array_dimensions(
.collect::<Result<Vec<_>, _>>()?, arr_len,
), values.len(),
span,
));
}
ConstrainedValue::Array(
values
.iter()
.map(|x| self.constant_main_function_input(_cs, type_, name, Some(x.clone()), span))
.collect::<Result<Vec<_>, _>>()?,
)
}
InputValue::Tuple(values) => {
// Get ASG tuple size and compare it to input tuple size.
let tuple_len = if let Type::Tuple(types) = type_ {
types.len()
} else {
return Err(FunctionError::tuple_size_mismatch(0, values.len(), span));
};
if values.len() != tuple_len {
return Err(FunctionError::tuple_size_mismatch(tuple_len, values.len(), span));
}
ConstrainedValue::Tuple(
values
.iter()
.map(|x| self.constant_main_function_input(_cs, type_, name, Some(x.clone()), span))
.collect::<Result<Vec<_>, _>>()?,
)
}
}) })
} }
} }

View File

@ -63,8 +63,15 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
let name = input_variable.name.name.clone(); let name = input_variable.name.name.clone();
let input_value = match (input.get(&name), input.get_constant(&name)) { let input_value = match (input.get(&name), input.get_constant(&name)) {
// If variable is in both [main] and [constants] sections - error.
(Some(_), Some(_)) => {
return Err(FunctionError::double_input_declaration(
name.clone(),
&function.span.clone().unwrap_or_default(),
));
}
// If input option is found in [main] section. // If input option is found in [main] section.
(Some(input_option), _) => self.parse_constant_main_function_input( (Some(input_option), _) => self.allocate_main_function_input(
cs, cs,
&input_variable.type_.clone(), &input_variable.type_.clone(),
&name, &name,
@ -72,7 +79,7 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
&function.span.clone().unwrap_or_default(), &function.span.clone().unwrap_or_default(),
)?, )?,
// If input option is found in [constants] section. // If input option is found in [constants] section.
(_, Some(input_option)) => self.allocate_main_function_input( (_, Some(input_option)) => self.constant_main_function_input(
cs, cs,
&input_variable.type_.clone(), &input_variable.type_.clone(),
&name, &name,

View File

@ -0,0 +1,5 @@
[main]
a: bool = true;
[constants]
a: bool = false;

View File

@ -0,0 +1,2 @@
[constants]
x: (u8, bool) = (10, true); // wrong size here; main expects (u8, bool, u8)

View File

@ -0,0 +1,3 @@
function main(x: (u8, bool, u8)) {
console.log("x: {}", x);
}

View File

@ -94,6 +94,26 @@ fn test_input_array_dimensions_mismatch() {
expect_fail(program); expect_fail(program);
} }
#[test]
fn test_input_double_declaration() {
let program_string = include_str!("main.leo");
let input_string = include_str!("input/main_double_declaration_fail.in");
let program = parse_program_with_input(program_string, input_string).unwrap();
expect_fail(program);
}
#[test]
fn test_tuple_size_mismatch() {
let program_string = include_str!("main_tuple_fail.leo");
let input_string = include_str!("input/main_tuple_fail.in");
let program = parse_program_with_input(program_string, input_string).unwrap();
expect_fail(program);
}
#[test] #[test]
fn test_field_input() { fn test_field_input() {
let program_string = include_str!("main_field.leo"); let program_string = include_str!("main_field.leo");