mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-24 07:48:04 +03:00
convert statements to span with error
This commit is contained in:
parent
6922d5dd73
commit
3d1fe9cc4b
@ -15,6 +15,7 @@ use leo_types::{
|
||||
Identifier,
|
||||
Integer,
|
||||
RangeOrExpression,
|
||||
Span,
|
||||
Statement,
|
||||
Type,
|
||||
Variable,
|
||||
@ -37,14 +38,18 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_mutable_assignee(&mut self, name: String) -> Result<&mut ConstrainedValue<F, G>, StatementError> {
|
||||
fn get_mutable_assignee(
|
||||
&mut self,
|
||||
name: String,
|
||||
span: Span,
|
||||
) -> Result<&mut ConstrainedValue<F, G>, StatementError> {
|
||||
// Check that assignee exists and is mutable
|
||||
Ok(match self.get_mut(&name) {
|
||||
Some(value) => match value {
|
||||
ConstrainedValue::Mutable(mutable_value) => mutable_value,
|
||||
_ => return Err(StatementError::ImmutableAssign(name)),
|
||||
_ => return Err(StatementError::immutable_assign(name, span)),
|
||||
},
|
||||
None => return Err(StatementError::UndefinedVariable(name)),
|
||||
None => return Err(StatementError::undefined_variable(name, span)),
|
||||
})
|
||||
}
|
||||
|
||||
@ -57,6 +62,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
name: String,
|
||||
range_or_expression: RangeOrExpression,
|
||||
mut new_value: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
) -> Result<(), StatementError> {
|
||||
let condition = indicator.unwrap_or(Boolean::Constant(true));
|
||||
|
||||
@ -66,18 +72,18 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
let index = self.enforce_index(cs, file_scope.clone(), function_scope.clone(), index)?;
|
||||
|
||||
// Modify the single value of the array in place
|
||||
match self.get_mutable_assignee(name)? {
|
||||
match self.get_mutable_assignee(name, span.clone())? {
|
||||
ConstrainedValue::Array(old) => {
|
||||
new_value.resolve_type(&vec![old[index].to_type()])?;
|
||||
|
||||
let selected_value =
|
||||
ConstrainedValue::conditionally_select(cs, &condition, &new_value, &old[index]).map_err(
|
||||
|_| StatementError::SelectFail(new_value.to_string(), old[index].to_string()),
|
||||
|_| StatementError::select_fail(new_value.to_string(), old[index].to_string(), span),
|
||||
)?;
|
||||
|
||||
old[index] = selected_value;
|
||||
}
|
||||
_ => return Err(StatementError::ArrayAssignIndex),
|
||||
_ => return Err(StatementError::array_assign_index(span)),
|
||||
}
|
||||
}
|
||||
RangeOrExpression::Range(from, to) => {
|
||||
@ -91,7 +97,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
};
|
||||
|
||||
// Modify the range of values of the array
|
||||
let old_array = self.get_mutable_assignee(name)?;
|
||||
let old_array = self.get_mutable_assignee(name, span.clone())?;
|
||||
let new_array = match (old_array.clone(), new_value) {
|
||||
(ConstrainedValue::Array(mut mutable), ConstrainedValue::Array(new)) => {
|
||||
let to_index = to_index_option.unwrap_or(mutable.len());
|
||||
@ -99,10 +105,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
mutable.splice(from_index..to_index, new.iter().cloned());
|
||||
ConstrainedValue::Array(mutable)
|
||||
}
|
||||
_ => return Err(StatementError::ArrayAssignRange),
|
||||
_ => return Err(StatementError::array_assign_range(span)),
|
||||
};
|
||||
let selected_array = ConstrainedValue::conditionally_select(cs, &condition, &new_array, old_array)
|
||||
.map_err(|_| StatementError::SelectFail(new_array.to_string(), old_array.to_string()))?;
|
||||
.map_err(|_| StatementError::select_fail(new_array.to_string(), old_array.to_string(), span))?;
|
||||
*old_array = selected_array;
|
||||
}
|
||||
}
|
||||
@ -117,10 +123,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
circuit_name: String,
|
||||
object_name: Identifier,
|
||||
mut new_value: ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
) -> Result<(), StatementError> {
|
||||
let condition = indicator.unwrap_or(Boolean::Constant(true));
|
||||
|
||||
match self.get_mutable_assignee(circuit_name)? {
|
||||
match self.get_mutable_assignee(circuit_name, span.clone())? {
|
||||
ConstrainedValue::CircuitExpression(_variable, members) => {
|
||||
// Modify the circuit field in place
|
||||
let matched_field = members.into_iter().find(|object| object.0 == object_name);
|
||||
@ -128,28 +135,29 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
match matched_field {
|
||||
Some(object) => match &object.1 {
|
||||
ConstrainedValue::Function(_circuit_identifier, function) => {
|
||||
return Err(StatementError::ImmutableCircuitFunction(
|
||||
return Err(StatementError::immutable_circuit_function(
|
||||
function.function_name.to_string(),
|
||||
span,
|
||||
));
|
||||
}
|
||||
ConstrainedValue::Static(_value) => {
|
||||
return Err(StatementError::ImmutableCircuitFunction("static".into()));
|
||||
return Err(StatementError::immutable_circuit_function("static".into(), span));
|
||||
}
|
||||
_ => {
|
||||
new_value.resolve_type(&vec![object.1.to_type()])?;
|
||||
|
||||
let selected_value = ConstrainedValue::conditionally_select(
|
||||
cs, &condition, &new_value, &object.1,
|
||||
)
|
||||
.map_err(|_| StatementError::SelectFail(new_value.to_string(), object.1.to_string()))?;
|
||||
let selected_value =
|
||||
ConstrainedValue::conditionally_select(cs, &condition, &new_value, &object.1).map_err(
|
||||
|_| StatementError::select_fail(new_value.to_string(), object.1.to_string(), span),
|
||||
)?;
|
||||
|
||||
object.1 = selected_value.to_owned();
|
||||
}
|
||||
},
|
||||
None => return Err(StatementError::UndefinedCircuitObject(object_name.to_string())),
|
||||
None => return Err(StatementError::undefined_circuit_object(object_name.to_string(), span)),
|
||||
}
|
||||
}
|
||||
_ => return Err(StatementError::UndefinedCircuit(object_name.to_string())),
|
||||
_ => return Err(StatementError::undefined_circuit(object_name.to_string(), span)),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -163,6 +171,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
indicator: Option<Boolean>,
|
||||
assignee: Assignee,
|
||||
expression: Expression,
|
||||
span: Span,
|
||||
) -> Result<(), StatementError> {
|
||||
// Get the name of the variable we are assigning to
|
||||
let variable_name = self.resolve_assignee(function_scope.clone(), assignee.clone());
|
||||
@ -175,10 +184,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
match assignee {
|
||||
Assignee::Identifier(_identifier) => {
|
||||
let condition = indicator.unwrap_or(Boolean::Constant(true));
|
||||
let old_value = self.get_mutable_assignee(variable_name.clone())?;
|
||||
let old_value = self.get_mutable_assignee(variable_name.clone(), span.clone())?;
|
||||
new_value.resolve_type(&vec![old_value.to_type()])?;
|
||||
let selected_value = ConstrainedValue::conditionally_select(cs, &condition, &new_value, old_value)
|
||||
.map_err(|_| StatementError::SelectFail(new_value.to_string(), old_value.to_string()))?;
|
||||
.map_err(|_| StatementError::select_fail(new_value.to_string(), old_value.to_string(), span))?;
|
||||
|
||||
*old_value = selected_value;
|
||||
|
||||
@ -192,9 +201,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
variable_name,
|
||||
range_or_expression,
|
||||
new_value,
|
||||
span,
|
||||
),
|
||||
Assignee::CircuitField(_assignee, object_name) => {
|
||||
self.mutute_circuit_field(cs, indicator, variable_name, object_name, new_value)
|
||||
self.mutute_circuit_field(cs, indicator, variable_name, object_name, new_value, span)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -225,6 +235,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
declare: Declare,
|
||||
variable: Variable,
|
||||
expression: Expression,
|
||||
_span: Span,
|
||||
) -> Result<(), StatementError> {
|
||||
let mut expected_types = vec![];
|
||||
if let Some(ref _type) = variable._type {
|
||||
@ -252,6 +263,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
function_scope: String,
|
||||
variables: Vec<Variable>,
|
||||
function: Expression,
|
||||
span: Span,
|
||||
) -> Result<(), StatementError> {
|
||||
let mut expected_types = vec![];
|
||||
for variable in variables.iter() {
|
||||
@ -273,9 +285,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
};
|
||||
|
||||
if variables.len() != return_values.len() {
|
||||
return Err(StatementError::InvalidNumberOfDefinitions(
|
||||
return Err(StatementError::invalid_number_of_definitions(
|
||||
variables.len(),
|
||||
return_values.len(),
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
@ -292,12 +305,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
function_scope: String,
|
||||
expressions: Vec<Expression>,
|
||||
return_types: Vec<Type>,
|
||||
span: Span,
|
||||
) -> Result<ConstrainedValue<F, G>, StatementError> {
|
||||
// Make sure we return the correct number of values
|
||||
if return_types.len() != expressions.len() {
|
||||
return Err(StatementError::InvalidNumberOfReturns(
|
||||
return Err(StatementError::invalid_number_of_returns(
|
||||
return_types.len(),
|
||||
expressions.len(),
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
@ -358,6 +373,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
indicator: Option<Boolean>,
|
||||
statement: ConditionalStatement,
|
||||
return_types: Vec<Type>,
|
||||
span: Span,
|
||||
) -> Result<Option<ConstrainedValue<F, G>>, StatementError> {
|
||||
let statement_string = statement.to_string();
|
||||
let outer_indicator = indicator.unwrap_or(Boolean::Constant(true));
|
||||
@ -371,7 +387,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
statement.condition.clone(),
|
||||
)? {
|
||||
ConstrainedValue::Boolean(resolved) => resolved,
|
||||
value => return Err(StatementError::IfElseConditional(value.to_string())),
|
||||
value => return Err(StatementError::conditional_boolean(value.to_string(), span)),
|
||||
};
|
||||
|
||||
// Determine nested branch selection
|
||||
@ -407,6 +423,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
Some(branch_2_indicator),
|
||||
*nested,
|
||||
return_types,
|
||||
span,
|
||||
),
|
||||
ConditionalNestedOrEndStatement::End(statements) => self.evaluate_branch(
|
||||
cs,
|
||||
@ -432,6 +449,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
stop: Integer,
|
||||
statements: Vec<Statement>,
|
||||
return_types: Vec<Type>,
|
||||
_span: Span,
|
||||
) -> Result<Option<ConstrainedValue<F, G>>, StatementError> {
|
||||
let mut res = None;
|
||||
|
||||
@ -469,11 +487,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
indicator: Option<Boolean>,
|
||||
left: &ConstrainedValue<F, G>,
|
||||
right: &ConstrainedValue<F, G>,
|
||||
span: Span,
|
||||
) -> Result<(), StatementError> {
|
||||
let condition = indicator.unwrap_or(Boolean::Constant(true));
|
||||
let result = left.conditional_enforce_equal(cs, right, &condition);
|
||||
|
||||
Ok(result.map_err(|_| StatementError::AssertionFailed(left.to_string(), right.to_string()))?)
|
||||
Ok(result.map_err(|_| StatementError::assertion_failed(left.to_string(), right.to_string(), span))?)
|
||||
}
|
||||
|
||||
pub(crate) fn enforce_statement<CS: ConstraintSystem<F>>(
|
||||
@ -487,19 +506,26 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
) -> Result<Option<ConstrainedValue<F, G>>, StatementError> {
|
||||
let mut res = None;
|
||||
match statement {
|
||||
Statement::Return(expressions) => {
|
||||
res = Some(self.enforce_return_statement(cs, file_scope, function_scope, expressions, return_types)?);
|
||||
Statement::Return(expressions, span) => {
|
||||
res = Some(self.enforce_return_statement(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope,
|
||||
expressions,
|
||||
return_types,
|
||||
span,
|
||||
)?);
|
||||
}
|
||||
Statement::Definition(declare, variable, expression) => {
|
||||
self.enforce_definition_statement(cs, file_scope, function_scope, declare, variable, expression)?;
|
||||
Statement::Definition(declare, variable, expression, span) => {
|
||||
self.enforce_definition_statement(cs, file_scope, function_scope, declare, variable, expression, span)?;
|
||||
}
|
||||
Statement::Assign(variable, expression) => {
|
||||
self.enforce_assign_statement(cs, file_scope, function_scope, indicator, variable, expression)?;
|
||||
Statement::Assign(variable, expression, span) => {
|
||||
self.enforce_assign_statement(cs, file_scope, function_scope, indicator, variable, expression, span)?;
|
||||
}
|
||||
Statement::MultipleAssign(variables, function) => {
|
||||
self.enforce_multiple_definition_statement(cs, file_scope, function_scope, variables, function)?;
|
||||
Statement::MultipleAssign(variables, function, span) => {
|
||||
self.enforce_multiple_definition_statement(cs, file_scope, function_scope, variables, function, span)?;
|
||||
}
|
||||
Statement::Conditional(statement) => {
|
||||
Statement::Conditional(statement, span) => {
|
||||
if let Some(early_return) = self.enforce_conditional_statement(
|
||||
cs,
|
||||
file_scope,
|
||||
@ -507,11 +533,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
indicator,
|
||||
statement,
|
||||
return_types,
|
||||
span,
|
||||
)? {
|
||||
res = Some(early_return)
|
||||
}
|
||||
}
|
||||
Statement::For(index, start, stop, statements) => {
|
||||
Statement::For(index, start, stop, statements, span) => {
|
||||
if let Some(early_return) = self.enforce_for_statement(
|
||||
cs,
|
||||
file_scope,
|
||||
@ -522,24 +549,25 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
stop,
|
||||
statements,
|
||||
return_types,
|
||||
span,
|
||||
)? {
|
||||
res = Some(early_return)
|
||||
}
|
||||
}
|
||||
Statement::AssertEq(left, right) => {
|
||||
Statement::AssertEq(left, right, span) => {
|
||||
let (resolved_left, resolved_right) =
|
||||
self.enforce_binary_expression(cs, file_scope, function_scope, &vec![], left, right)?;
|
||||
|
||||
self.enforce_assert_eq_statement(cs, indicator, &resolved_left, &resolved_right)?;
|
||||
self.enforce_assert_eq_statement(cs, indicator, &resolved_left, &resolved_right, span)?;
|
||||
}
|
||||
Statement::Expression(expression) => {
|
||||
Statement::Expression(expression, span) => {
|
||||
match self.enforce_expression(cs, file_scope, function_scope, &vec![], expression.clone())? {
|
||||
ConstrainedValue::Return(values) => {
|
||||
if !values.is_empty() {
|
||||
return Err(StatementError::Unassigned(expression.to_string()));
|
||||
return Err(StatementError::unassigned(expression.to_string(), span));
|
||||
}
|
||||
}
|
||||
_ => return Err(StatementError::Unassigned(expression.to_string())),
|
||||
_ => return Err(StatementError::unassigned(expression.to_string(), span)),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::errors::{BooleanError, Error, FieldError, FunctionError, GroupError, ValueError};
|
||||
use crate::errors::{BooleanError, Error as FormattedError, FieldError, FunctionError, GroupError, ValueError};
|
||||
use leo_types::{Identifier, IntegerError, Span};
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
@ -6,8 +6,12 @@ use std::num::ParseIntError;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ExpressionError {
|
||||
// Identifiers
|
||||
#[error("Identifier \"{}\" not found", _0)]
|
||||
UndefinedIdentifier(String),
|
||||
|
||||
#[error("{}", _0)]
|
||||
Error(#[from] Error),
|
||||
Error(#[from] FormattedError),
|
||||
|
||||
// Types
|
||||
#[error("{}", _0)]
|
||||
@ -89,7 +93,7 @@ pub enum ExpressionError {
|
||||
|
||||
impl ExpressionError {
|
||||
fn new_from_span(message: String, span: Span) -> Self {
|
||||
ExpressionError::Error(Error::new_from_span(message, span))
|
||||
ExpressionError::Error(FormattedError::new_from_span(message, span))
|
||||
}
|
||||
|
||||
pub fn undefined_identifier(identifier: Identifier) -> Self {
|
||||
|
@ -1,63 +1,115 @@
|
||||
use crate::errors::{BooleanError, ExpressionError, ValueError};
|
||||
use crate::errors::{BooleanError, Error as FormattedError, ExpressionError, ValueError};
|
||||
use leo_types::Span;
|
||||
|
||||
use snarkos_errors::gadgets::SynthesisError;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum StatementError {
|
||||
#[error("{}", _0)]
|
||||
Error(#[from] FormattedError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
BooleanError(#[from] BooleanError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
ExpressionError(#[from] ExpressionError),
|
||||
|
||||
#[error("Attempted to assign to unknown variable {}", _0)]
|
||||
UndefinedVariable(String),
|
||||
|
||||
// Arrays
|
||||
#[error("Cannot assign single index to array of values")]
|
||||
ArrayAssignIndex,
|
||||
|
||||
#[error("Cannot assign range of array values to single value")]
|
||||
ArrayAssignRange,
|
||||
|
||||
// Circuits
|
||||
#[error("Cannot mutate circuit function, {}", _0)]
|
||||
ImmutableCircuitFunction(String),
|
||||
|
||||
#[error("Attempted to assign to unknown circuit {}", _0)]
|
||||
UndefinedCircuit(String),
|
||||
|
||||
#[error("Attempted to assign to unknown circuit {}", _0)]
|
||||
UndefinedCircuitObject(String),
|
||||
|
||||
// Statements
|
||||
#[error("Cannot assert equality between {} == {}", _0, _1)]
|
||||
AssertEq(String, String),
|
||||
|
||||
#[error("Assertion {:?} == {:?} failed", _0, _1)]
|
||||
AssertionFailed(String, String),
|
||||
|
||||
#[error("If, else statements.conditional must resolve to a boolean, got {}", _0)]
|
||||
IfElseConditional(String),
|
||||
|
||||
#[error("Cannot assign to immutable variable {}", _0)]
|
||||
ImmutableAssign(String),
|
||||
|
||||
#[error("Multiple definition statement expected {} return values, got {}", _0, _1)]
|
||||
InvalidNumberOfDefinitions(usize, usize),
|
||||
|
||||
#[error("Function return statement expected {} return values, got {}", _0, _1)]
|
||||
InvalidNumberOfReturns(usize, usize),
|
||||
|
||||
#[error("Conditional select gadget failed to select between {} or {}", _0, _1)]
|
||||
SelectFail(String, String),
|
||||
|
||||
#[error("{}", _0)]
|
||||
SynthesisError(#[from] SynthesisError),
|
||||
|
||||
#[error("Expected assignment of return values for expression {}", _0)]
|
||||
Unassigned(String),
|
||||
|
||||
#[error("{}", _0)]
|
||||
ValueError(#[from] ValueError),
|
||||
}
|
||||
|
||||
impl StatementError {
|
||||
fn new_from_span(message: String, span: Span) -> Self {
|
||||
StatementError::Error(FormattedError::new_from_span(message, span))
|
||||
}
|
||||
|
||||
pub fn array_assign_index(span: Span) -> Self {
|
||||
let message = format!("Cannot assign single index to array of values");
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn array_assign_range(span: Span) -> Self {
|
||||
let message = format!("Cannot assign range of array values to single value");
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn assertion_failed(left: String, right: String, span: Span) -> Self {
|
||||
let message = format!("Assertion {} == {} failed", left, right);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn conditional_boolean(actual: String, span: Span) -> Self {
|
||||
let message = format!("If, else conditional must resolve to a boolean, got {}", actual);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn invalid_number_of_definitions(expected: usize, actual: usize, span: Span) -> Self {
|
||||
let message = format!(
|
||||
"Multiple definition statement expected {} return values, got {}",
|
||||
expected, actual
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn invalid_number_of_returns(expected: usize, actual: usize, span: Span) -> Self {
|
||||
let message = format!(
|
||||
"Function return statement expected {} return values, got {}",
|
||||
expected, actual
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn immutable_assign(name: String, span: Span) -> Self {
|
||||
let message = format!("Cannot assign to immutable variable {}", name);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn immutable_circuit_function(name: String, span: Span) -> Self {
|
||||
let message = format!("Cannot mutate circuit function, {}", name);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn select_fail(first: String, second: String, span: Span) -> Self {
|
||||
let message = format!(
|
||||
"Conditional select gadget failed to select between {} or {}",
|
||||
first, second
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn unassigned(name: String, span: Span) -> Self {
|
||||
let message = format!("Expected assignment of return values for expression {}", name);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn undefined_variable(name: String, span: Span) -> Self {
|
||||
let message = format!("Attempted to assign to unknown variable {}", name);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn undefined_circuit(name: String, span: Span) -> Self {
|
||||
let message = format!("Attempted to assign to unknown circuit {}", name);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn undefined_circuit_object(name: String, span: Span) -> Self {
|
||||
let message = format!("Attempted to assign to unknown circuit object {}", name);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
}
|
||||
|
@ -61,9 +61,11 @@ impl Error {
|
||||
}
|
||||
}
|
||||
|
||||
fn underline(start: usize, mut end: usize) -> String {
|
||||
fn underline(mut start: usize, mut end: usize) -> String {
|
||||
if start > end {
|
||||
panic!("underline start column is greater than end column")
|
||||
let tmp = start;
|
||||
start = end;
|
||||
end = tmp;
|
||||
}
|
||||
|
||||
let mut underline = String::new();
|
||||
|
@ -7,6 +7,20 @@ use leo_inputs::syntax::SyntaxError;
|
||||
|
||||
use crate::input_value_u32_one;
|
||||
use snarkos_models::gadgets::utilities::boolean::Boolean;
|
||||
// use leo_types::InputValue;
|
||||
// use pest::Span;
|
||||
// use leo_inputs::types::BooleanType;
|
||||
// use leo_inputs::values::BooleanValue;
|
||||
//
|
||||
// pub fn input_value_bool(bool: bool) -> InputValue<'static> {
|
||||
// let input = bool.to_string();
|
||||
// let span = Span::new(&input, 0, input.len()).unwrap();
|
||||
//
|
||||
// InputValue::Boolean(BooleanValue {
|
||||
// value: input,
|
||||
// span,
|
||||
// })
|
||||
// }
|
||||
|
||||
pub fn output_expected_boolean(program: EdwardsTestCompiler, boolean: bool) {
|
||||
let output = get_output(program);
|
||||
|
@ -8,7 +8,7 @@ pub mod boolean;
|
||||
pub mod inputs;
|
||||
// pub mod integers;
|
||||
// pub mod mutability;
|
||||
// pub mod statements;
|
||||
pub mod statements;
|
||||
pub mod syntax;
|
||||
|
||||
use leo_compiler::{
|
||||
@ -45,7 +45,7 @@ pub(crate) fn get_error(program: EdwardsTestCompiler) -> CompilerError {
|
||||
|
||||
pub(crate) fn fail_enforce(program: EdwardsTestCompiler) {
|
||||
match get_error(program) {
|
||||
CompilerError::FunctionError(FunctionError::StatementError(StatementError::AssertionFailed(_, _))) => {}
|
||||
CompilerError::FunctionError(FunctionError::StatementError(StatementError::Error(_))) => {}
|
||||
error => panic!("Expected evaluate error, got {}", error),
|
||||
}
|
||||
}
|
||||
|
@ -1,60 +1,67 @@
|
||||
use crate::{
|
||||
integers::u32::{output_one, output_zero},
|
||||
parse_program,
|
||||
};
|
||||
use crate::{get_error, parse_program};
|
||||
use leo_types::InputValue;
|
||||
|
||||
use snarkos_curves::edwards_bls12::Fq;
|
||||
use snarkos_models::gadgets::r1cs::TestConstraintSystem;
|
||||
|
||||
pub mod conditional;
|
||||
// pub mod conditional;
|
||||
|
||||
// Ternary if {bool}? {expression} : {expression};
|
||||
|
||||
#[test]
|
||||
fn test_ternary_basic() {
|
||||
let bytes = include_bytes!("ternary_basic.leo");
|
||||
let mut program_input_true = parse_program(bytes).unwrap();
|
||||
|
||||
let mut program_input_false = program_input_true.clone();
|
||||
|
||||
program_input_true.set_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
output_one(program_input_true);
|
||||
|
||||
program_input_false.set_inputs(vec![Some(InputValue::Boolean(false))]);
|
||||
output_zero(program_input_false);
|
||||
}
|
||||
|
||||
// Iteration for i {start}..{stop} { statements }
|
||||
// #[test]
|
||||
// fn test_ternary_basic() {
|
||||
// let bytes = include_bytes!("ternary_basic.leo");
|
||||
// let mut program_input_true = parse_program(bytes).unwrap();
|
||||
//
|
||||
// let mut program_input_false = program_input_true.clone();
|
||||
//
|
||||
// program_input_true.set_inputs(vec![Some(input_value_bool(true))]);
|
||||
// output_one(program_input_true);
|
||||
//
|
||||
// program_input_false.set_inputs(vec![Some(input_value_bool(false))]);
|
||||
// output_zero(program_input_false);
|
||||
// }
|
||||
//
|
||||
// // Iteration for i {start}..{stop} { statements }
|
||||
//
|
||||
// #[test]
|
||||
// fn test_iteration_basic() {
|
||||
// let bytes = include_bytes!("iteration_basic.leo");
|
||||
// let program = parse_program(bytes).unwrap();
|
||||
//
|
||||
// output_one(program);
|
||||
// }
|
||||
//
|
||||
// // Assertion
|
||||
//
|
||||
// #[test]
|
||||
// fn test_assertion_basic() {
|
||||
// let bytes = include_bytes!("assertion_basic.leo");
|
||||
// let program = parse_program(bytes).unwrap();
|
||||
//
|
||||
// let mut program_input_true = program.clone();
|
||||
// let mut cs_satisfied = TestConstraintSystem::<Fq>::new();
|
||||
//
|
||||
// program_input_true.set_inputs(vec![Some(input_value_bool(true))]);
|
||||
// let _output = program_input_true.compile_constraints(&mut cs_satisfied).unwrap();
|
||||
//
|
||||
// assert!(cs_satisfied.is_satisfied());
|
||||
//
|
||||
// let mut program_input_false = program.clone();
|
||||
// let mut cs_unsatisfied = TestConstraintSystem::<Fq>::new();
|
||||
//
|
||||
// program_input_false.set_inputs(vec![Some(input_value_bool(false))]);
|
||||
// let _output = program_input_false.compile_constraints(&mut cs_unsatisfied).unwrap();
|
||||
//
|
||||
// assert!(!cs_unsatisfied.is_satisfied());
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn test_iteration_basic() {
|
||||
let bytes = include_bytes!("iteration_basic.leo");
|
||||
fn test_num_returns_fail() {
|
||||
let bytes = include_bytes!("num_returns_fail.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
output_one(program);
|
||||
}
|
||||
|
||||
// Assertion
|
||||
|
||||
#[test]
|
||||
fn test_assertion_basic() {
|
||||
let bytes = include_bytes!("assertion_basic.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
let mut program_input_true = program.clone();
|
||||
let mut cs_satisfied = TestConstraintSystem::<Fq>::new();
|
||||
|
||||
program_input_true.set_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
let _output = program_input_true.compile_constraints(&mut cs_satisfied).unwrap();
|
||||
|
||||
assert!(cs_satisfied.is_satisfied());
|
||||
|
||||
let mut program_input_false = program.clone();
|
||||
let mut cs_unsatisfied = TestConstraintSystem::<Fq>::new();
|
||||
|
||||
program_input_false.set_inputs(vec![Some(InputValue::Boolean(false))]);
|
||||
let _output = program_input_false.compile_constraints(&mut cs_unsatisfied).unwrap();
|
||||
|
||||
assert!(!cs_unsatisfied.is_satisfied());
|
||||
let error = get_error(program);
|
||||
|
||||
println!("{}", error);
|
||||
}
|
||||
|
3
compiler/tests/statements/num_returns_fail.leo
Normal file
3
compiler/tests/statements/num_returns_fail.leo
Normal file
@ -0,0 +1,3 @@
|
||||
function main() -> (bool, bool) {
|
||||
return true
|
||||
}
|
@ -74,7 +74,7 @@ impl CLI for BuildCommand {
|
||||
ct: vec![],
|
||||
};
|
||||
let temporary_program = program.clone();
|
||||
let output = temporary_program.compile_constraints(&mut cs).unwrap();
|
||||
let output = temporary_program.compile_constraints(&mut cs)?;
|
||||
log::debug!("Compiled constraints - {:#?}", output);
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,8 @@ pub enum CLIError {
|
||||
|
||||
impl From<leo_compiler::errors::CompilerError> for CLIError {
|
||||
fn from(error: leo_compiler::errors::CompilerError) -> Self {
|
||||
CLIError::Crate("leo_compiler", format!("{}", error))
|
||||
log::error!("{}", error);
|
||||
CLIError::Crate("leo_compiler", "Program failed due to previous error".into())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{Assignee, ConditionalStatement, Declare, Expression, Identifier, Integer, Variable};
|
||||
use crate::{Assignee, ConditionalStatement, Declare, Expression, Identifier, Integer, Span, Variable};
|
||||
use leo_ast::{
|
||||
operations::AssignOperation,
|
||||
statements::{
|
||||
@ -18,14 +18,14 @@ use std::fmt;
|
||||
/// Program statement that defines some action (or expression) to be carried out.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub enum Statement {
|
||||
Return(Vec<Expression>),
|
||||
Definition(Declare, Variable, Expression),
|
||||
Assign(Assignee, Expression),
|
||||
MultipleAssign(Vec<Variable>, Expression),
|
||||
Conditional(ConditionalStatement),
|
||||
For(Identifier, Integer, Integer, Vec<Statement>),
|
||||
AssertEq(Expression, Expression),
|
||||
Expression(Expression),
|
||||
Return(Vec<Expression>, Span),
|
||||
Definition(Declare, Variable, Expression, Span),
|
||||
Assign(Assignee, Expression, Span),
|
||||
MultipleAssign(Vec<Variable>, Expression, Span),
|
||||
Conditional(ConditionalStatement, Span),
|
||||
For(Identifier, Integer, Integer, Vec<Statement>, Span),
|
||||
AssertEq(Expression, Expression, Span),
|
||||
Expression(Expression, Span),
|
||||
}
|
||||
|
||||
impl<'ast> From<ReturnStatement<'ast>> for Statement {
|
||||
@ -36,6 +36,7 @@ impl<'ast> From<ReturnStatement<'ast>> for Statement {
|
||||
.into_iter()
|
||||
.map(|expression| Expression::from(expression))
|
||||
.collect(),
|
||||
Span::from(statement.span),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -46,6 +47,7 @@ impl<'ast> From<DefinitionStatement<'ast>> for Statement {
|
||||
Declare::from(statement.declare),
|
||||
Variable::from(statement.variable),
|
||||
Expression::from(statement.expression),
|
||||
Span::from(statement.span),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -56,6 +58,7 @@ impl<'ast> From<AssignStatement<'ast>> for Statement {
|
||||
AssignOperation::Assign(ref _assign) => Statement::Assign(
|
||||
Assignee::from(statement.assignee),
|
||||
Expression::from(statement.expression),
|
||||
Span::from(statement.span),
|
||||
),
|
||||
operation_assign => {
|
||||
// convert assignee into postfix expression
|
||||
@ -65,22 +68,27 @@ impl<'ast> From<AssignStatement<'ast>> for Statement {
|
||||
AssignOperation::AddAssign(ref _assign) => Statement::Assign(
|
||||
Assignee::from(statement.assignee),
|
||||
Expression::Add(Box::new(converted), Box::new(Expression::from(statement.expression))),
|
||||
Span::from(statement.span),
|
||||
),
|
||||
AssignOperation::SubAssign(ref _assign) => Statement::Assign(
|
||||
Assignee::from(statement.assignee),
|
||||
Expression::Sub(Box::new(converted), Box::new(Expression::from(statement.expression))),
|
||||
Span::from(statement.span),
|
||||
),
|
||||
AssignOperation::MulAssign(ref _assign) => Statement::Assign(
|
||||
Assignee::from(statement.assignee),
|
||||
Expression::Mul(Box::new(converted), Box::new(Expression::from(statement.expression))),
|
||||
Span::from(statement.span),
|
||||
),
|
||||
AssignOperation::DivAssign(ref _assign) => Statement::Assign(
|
||||
Assignee::from(statement.assignee),
|
||||
Expression::Div(Box::new(converted), Box::new(Expression::from(statement.expression))),
|
||||
Span::from(statement.span),
|
||||
),
|
||||
AssignOperation::PowAssign(ref _assign) => Statement::Assign(
|
||||
Assignee::from(statement.assignee),
|
||||
Expression::Pow(Box::new(converted), Box::new(Expression::from(statement.expression))),
|
||||
Span::from(statement.span),
|
||||
),
|
||||
AssignOperation::Assign(ref _assign) => unimplemented!("cannot assign twice to assign statement"),
|
||||
}
|
||||
@ -103,6 +111,7 @@ impl<'ast> From<MultipleAssignmentStatement<'ast>> for Statement {
|
||||
Box::new(Expression::from(statement.function_name)),
|
||||
statement.arguments.into_iter().map(|e| Expression::from(e)).collect(),
|
||||
),
|
||||
Span::from(statement.span),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -129,6 +138,7 @@ impl<'ast> From<ForStatement<'ast>> for Statement {
|
||||
.into_iter()
|
||||
.map(|statement| Statement::from(statement))
|
||||
.collect(),
|
||||
Span::from(statement.span),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -136,16 +146,18 @@ impl<'ast> From<ForStatement<'ast>> for Statement {
|
||||
impl<'ast> From<AssertStatement<'ast>> for Statement {
|
||||
fn from(statement: AssertStatement<'ast>) -> Self {
|
||||
match statement {
|
||||
AssertStatement::AssertEq(assert_eq) => {
|
||||
Statement::AssertEq(Expression::from(assert_eq.left), Expression::from(assert_eq.right))
|
||||
}
|
||||
AssertStatement::AssertEq(assert_eq) => Statement::AssertEq(
|
||||
Expression::from(assert_eq.left),
|
||||
Expression::from(assert_eq.right),
|
||||
Span::from(assert_eq.span),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<ExpressionStatement<'ast>> for Statement {
|
||||
fn from(statement: ExpressionStatement<'ast>) -> Self {
|
||||
Statement::Expression(Expression::from(statement.expression))
|
||||
Statement::Expression(Expression::from(statement.expression), Span::from(statement.span))
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,7 +168,10 @@ impl<'ast> From<AstStatement<'ast>> for Statement {
|
||||
AstStatement::Definition(statement) => Statement::from(statement),
|
||||
AstStatement::Assign(statement) => Statement::from(statement),
|
||||
AstStatement::MultipleAssignment(statement) => Statement::from(statement),
|
||||
AstStatement::Conditional(statement) => Statement::Conditional(ConditionalStatement::from(statement)),
|
||||
AstStatement::Conditional(statement) => {
|
||||
let span = Span::from(statement.span.clone());
|
||||
Statement::Conditional(ConditionalStatement::from(statement), span)
|
||||
}
|
||||
AstStatement::Iteration(statement) => Statement::from(statement),
|
||||
AstStatement::Assert(statement) => Statement::from(statement),
|
||||
AstStatement::Expression(statement) => Statement::from(statement),
|
||||
@ -167,7 +182,7 @@ impl<'ast> From<AstStatement<'ast>> for Statement {
|
||||
impl fmt::Display for Statement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Statement::Return(ref statements) => {
|
||||
Statement::Return(ref statements, ref _span) => {
|
||||
write!(f, "return (")?;
|
||||
for (i, value) in statements.iter().enumerate() {
|
||||
write!(f, "{}", value)?;
|
||||
@ -177,11 +192,11 @@ impl fmt::Display for Statement {
|
||||
}
|
||||
write!(f, ")\n")
|
||||
}
|
||||
Statement::Definition(ref declare, ref variable, ref expression) => {
|
||||
Statement::Definition(ref declare, ref variable, ref expression, ref _span) => {
|
||||
write!(f, "{} {} = {};", declare, variable, expression)
|
||||
}
|
||||
Statement::Assign(ref variable, ref statement) => write!(f, "{} = {};", variable, statement),
|
||||
Statement::MultipleAssign(ref assignees, ref function) => {
|
||||
Statement::Assign(ref variable, ref statement, ref _span) => write!(f, "{} = {};", variable, statement),
|
||||
Statement::MultipleAssign(ref assignees, ref function, ref _span) => {
|
||||
write!(f, "let (")?;
|
||||
for (i, id) in assignees.iter().enumerate() {
|
||||
write!(f, "{}", id)?;
|
||||
@ -191,16 +206,16 @@ impl fmt::Display for Statement {
|
||||
}
|
||||
write!(f, ") = {};", function)
|
||||
}
|
||||
Statement::Conditional(ref statement) => write!(f, "{}", statement),
|
||||
Statement::For(ref var, ref start, ref stop, ref list) => {
|
||||
Statement::Conditional(ref statement, ref _span) => write!(f, "{}", statement),
|
||||
Statement::For(ref var, ref start, ref stop, ref list, ref _span) => {
|
||||
write!(f, "for {} in {}..{} {{\n", var, start, stop)?;
|
||||
for l in list {
|
||||
write!(f, "\t\t{}\n", l)?;
|
||||
}
|
||||
write!(f, "\t}}")
|
||||
}
|
||||
Statement::AssertEq(ref left, ref right) => write!(f, "assert_eq({}, {});", left, right),
|
||||
Statement::Expression(ref expression) => write!(f, "{};", expression),
|
||||
Statement::AssertEq(ref left, ref right, ref _span) => write!(f, "assert_eq({}, {});", left, right),
|
||||
Statement::Expression(ref expression, ref _span) => write!(f, "{};", expression),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user