convert statements to span with error

This commit is contained in:
collin 2020-06-19 19:04:13 -07:00
parent 6922d5dd73
commit 3d1fe9cc4b
11 changed files with 290 additions and 164 deletions

View File

@ -15,6 +15,7 @@ use leo_types::{
Identifier, Identifier,
Integer, Integer,
RangeOrExpression, RangeOrExpression,
Span,
Statement, Statement,
Type, Type,
Variable, 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 // Check that assignee exists and is mutable
Ok(match self.get_mut(&name) { Ok(match self.get_mut(&name) {
Some(value) => match value { Some(value) => match value {
ConstrainedValue::Mutable(mutable_value) => mutable_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, name: String,
range_or_expression: RangeOrExpression, range_or_expression: RangeOrExpression,
mut new_value: ConstrainedValue<F, G>, mut new_value: ConstrainedValue<F, G>,
span: Span,
) -> Result<(), StatementError> { ) -> Result<(), StatementError> {
let condition = indicator.unwrap_or(Boolean::Constant(true)); 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)?; let index = self.enforce_index(cs, file_scope.clone(), function_scope.clone(), index)?;
// Modify the single value of the array in place // 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) => { ConstrainedValue::Array(old) => {
new_value.resolve_type(&vec![old[index].to_type()])?; new_value.resolve_type(&vec![old[index].to_type()])?;
let selected_value = let selected_value =
ConstrainedValue::conditionally_select(cs, &condition, &new_value, &old[index]).map_err( 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; old[index] = selected_value;
} }
_ => return Err(StatementError::ArrayAssignIndex), _ => return Err(StatementError::array_assign_index(span)),
} }
} }
RangeOrExpression::Range(from, to) => { 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 // 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) { let new_array = match (old_array.clone(), new_value) {
(ConstrainedValue::Array(mut mutable), ConstrainedValue::Array(new)) => { (ConstrainedValue::Array(mut mutable), ConstrainedValue::Array(new)) => {
let to_index = to_index_option.unwrap_or(mutable.len()); 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()); mutable.splice(from_index..to_index, new.iter().cloned());
ConstrainedValue::Array(mutable) 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) 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; *old_array = selected_array;
} }
} }
@ -117,10 +123,11 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
circuit_name: String, circuit_name: String,
object_name: Identifier, object_name: Identifier,
mut new_value: ConstrainedValue<F, G>, mut new_value: ConstrainedValue<F, G>,
span: Span,
) -> Result<(), StatementError> { ) -> Result<(), StatementError> {
let condition = indicator.unwrap_or(Boolean::Constant(true)); 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) => { ConstrainedValue::CircuitExpression(_variable, members) => {
// Modify the circuit field in place // Modify the circuit field in place
let matched_field = members.into_iter().find(|object| object.0 == object_name); 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 { match matched_field {
Some(object) => match &object.1 { Some(object) => match &object.1 {
ConstrainedValue::Function(_circuit_identifier, function) => { ConstrainedValue::Function(_circuit_identifier, function) => {
return Err(StatementError::ImmutableCircuitFunction( return Err(StatementError::immutable_circuit_function(
function.function_name.to_string(), function.function_name.to_string(),
span,
)); ));
} }
ConstrainedValue::Static(_value) => { 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()])?; new_value.resolve_type(&vec![object.1.to_type()])?;
let selected_value = ConstrainedValue::conditionally_select( let selected_value =
cs, &condition, &new_value, &object.1, ConstrainedValue::conditionally_select(cs, &condition, &new_value, &object.1).map_err(
) |_| StatementError::select_fail(new_value.to_string(), object.1.to_string(), span),
.map_err(|_| StatementError::SelectFail(new_value.to_string(), object.1.to_string()))?; )?;
object.1 = selected_value.to_owned(); 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(()) Ok(())
@ -163,6 +171,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
indicator: Option<Boolean>, indicator: Option<Boolean>,
assignee: Assignee, assignee: Assignee,
expression: Expression, expression: Expression,
span: Span,
) -> Result<(), StatementError> { ) -> Result<(), StatementError> {
// Get the name of the variable we are assigning to // Get the name of the variable we are assigning to
let variable_name = self.resolve_assignee(function_scope.clone(), assignee.clone()); 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 { match assignee {
Assignee::Identifier(_identifier) => { Assignee::Identifier(_identifier) => {
let condition = indicator.unwrap_or(Boolean::Constant(true)); 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()])?; new_value.resolve_type(&vec![old_value.to_type()])?;
let selected_value = ConstrainedValue::conditionally_select(cs, &condition, &new_value, old_value) 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; *old_value = selected_value;
@ -192,9 +201,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
variable_name, variable_name,
range_or_expression, range_or_expression,
new_value, new_value,
span,
), ),
Assignee::CircuitField(_assignee, object_name) => { 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, declare: Declare,
variable: Variable, variable: Variable,
expression: Expression, expression: Expression,
_span: Span,
) -> Result<(), StatementError> { ) -> Result<(), StatementError> {
let mut expected_types = vec![]; let mut expected_types = vec![];
if let Some(ref _type) = variable._type { if let Some(ref _type) = variable._type {
@ -252,6 +263,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope: String, function_scope: String,
variables: Vec<Variable>, variables: Vec<Variable>,
function: Expression, function: Expression,
span: Span,
) -> Result<(), StatementError> { ) -> Result<(), StatementError> {
let mut expected_types = vec![]; let mut expected_types = vec![];
for variable in variables.iter() { 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() { if variables.len() != return_values.len() {
return Err(StatementError::InvalidNumberOfDefinitions( return Err(StatementError::invalid_number_of_definitions(
variables.len(), variables.len(),
return_values.len(), return_values.len(),
span,
)); ));
} }
@ -292,12 +305,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
function_scope: String, function_scope: String,
expressions: Vec<Expression>, expressions: Vec<Expression>,
return_types: Vec<Type>, return_types: Vec<Type>,
span: Span,
) -> Result<ConstrainedValue<F, G>, StatementError> { ) -> Result<ConstrainedValue<F, G>, StatementError> {
// Make sure we return the correct number of values // Make sure we return the correct number of values
if return_types.len() != expressions.len() { if return_types.len() != expressions.len() {
return Err(StatementError::InvalidNumberOfReturns( return Err(StatementError::invalid_number_of_returns(
return_types.len(), return_types.len(),
expressions.len(), expressions.len(),
span,
)); ));
} }
@ -358,6 +373,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
indicator: Option<Boolean>, indicator: Option<Boolean>,
statement: ConditionalStatement, statement: ConditionalStatement,
return_types: Vec<Type>, return_types: Vec<Type>,
span: Span,
) -> Result<Option<ConstrainedValue<F, G>>, StatementError> { ) -> Result<Option<ConstrainedValue<F, G>>, StatementError> {
let statement_string = statement.to_string(); let statement_string = statement.to_string();
let outer_indicator = indicator.unwrap_or(Boolean::Constant(true)); 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(), statement.condition.clone(),
)? { )? {
ConstrainedValue::Boolean(resolved) => resolved, 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 // Determine nested branch selection
@ -407,6 +423,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
Some(branch_2_indicator), Some(branch_2_indicator),
*nested, *nested,
return_types, return_types,
span,
), ),
ConditionalNestedOrEndStatement::End(statements) => self.evaluate_branch( ConditionalNestedOrEndStatement::End(statements) => self.evaluate_branch(
cs, cs,
@ -432,6 +449,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
stop: Integer, stop: Integer,
statements: Vec<Statement>, statements: Vec<Statement>,
return_types: Vec<Type>, return_types: Vec<Type>,
_span: Span,
) -> Result<Option<ConstrainedValue<F, G>>, StatementError> { ) -> Result<Option<ConstrainedValue<F, G>>, StatementError> {
let mut res = None; let mut res = None;
@ -469,11 +487,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
indicator: Option<Boolean>, indicator: Option<Boolean>,
left: &ConstrainedValue<F, G>, left: &ConstrainedValue<F, G>,
right: &ConstrainedValue<F, G>, right: &ConstrainedValue<F, G>,
span: Span,
) -> Result<(), StatementError> { ) -> Result<(), StatementError> {
let condition = indicator.unwrap_or(Boolean::Constant(true)); let condition = indicator.unwrap_or(Boolean::Constant(true));
let result = left.conditional_enforce_equal(cs, right, &condition); 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>>( 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> { ) -> Result<Option<ConstrainedValue<F, G>>, StatementError> {
let mut res = None; let mut res = None;
match statement { match statement {
Statement::Return(expressions) => { Statement::Return(expressions, span) => {
res = Some(self.enforce_return_statement(cs, file_scope, function_scope, expressions, return_types)?); res = Some(self.enforce_return_statement(
cs,
file_scope,
function_scope,
expressions,
return_types,
span,
)?);
} }
Statement::Definition(declare, variable, expression) => { Statement::Definition(declare, variable, expression, span) => {
self.enforce_definition_statement(cs, file_scope, function_scope, declare, variable, expression)?; self.enforce_definition_statement(cs, file_scope, function_scope, declare, variable, expression, span)?;
} }
Statement::Assign(variable, expression) => { Statement::Assign(variable, expression, span) => {
self.enforce_assign_statement(cs, file_scope, function_scope, indicator, variable, expression)?; self.enforce_assign_statement(cs, file_scope, function_scope, indicator, variable, expression, span)?;
} }
Statement::MultipleAssign(variables, function) => { Statement::MultipleAssign(variables, function, span) => {
self.enforce_multiple_definition_statement(cs, file_scope, function_scope, variables, function)?; 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( if let Some(early_return) = self.enforce_conditional_statement(
cs, cs,
file_scope, file_scope,
@ -507,11 +533,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
indicator, indicator,
statement, statement,
return_types, return_types,
span,
)? { )? {
res = Some(early_return) 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( if let Some(early_return) = self.enforce_for_statement(
cs, cs,
file_scope, file_scope,
@ -522,24 +549,25 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
stop, stop,
statements, statements,
return_types, return_types,
span,
)? { )? {
res = Some(early_return) res = Some(early_return)
} }
} }
Statement::AssertEq(left, right) => { Statement::AssertEq(left, right, span) => {
let (resolved_left, resolved_right) = let (resolved_left, resolved_right) =
self.enforce_binary_expression(cs, file_scope, function_scope, &vec![], left, 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())? { match self.enforce_expression(cs, file_scope, function_scope, &vec![], expression.clone())? {
ConstrainedValue::Return(values) => { ConstrainedValue::Return(values) => {
if !values.is_empty() { 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)),
} }
} }
}; };

View File

@ -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 leo_types::{Identifier, IntegerError, Span};
use snarkos_errors::gadgets::SynthesisError; use snarkos_errors::gadgets::SynthesisError;
@ -6,8 +6,12 @@ use std::num::ParseIntError;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum ExpressionError { pub enum ExpressionError {
// Identifiers
#[error("Identifier \"{}\" not found", _0)]
UndefinedIdentifier(String),
#[error("{}", _0)] #[error("{}", _0)]
Error(#[from] Error), Error(#[from] FormattedError),
// Types // Types
#[error("{}", _0)] #[error("{}", _0)]
@ -89,7 +93,7 @@ pub enum ExpressionError {
impl ExpressionError { impl ExpressionError {
fn new_from_span(message: String, span: Span) -> Self { 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 { pub fn undefined_identifier(identifier: Identifier) -> Self {

View File

@ -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; use snarkos_errors::gadgets::SynthesisError;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum StatementError { pub enum StatementError {
#[error("{}", _0)]
Error(#[from] FormattedError),
#[error("{}", _0)] #[error("{}", _0)]
BooleanError(#[from] BooleanError), BooleanError(#[from] BooleanError),
#[error("{}", _0)] #[error("{}", _0)]
ExpressionError(#[from] ExpressionError), 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)] #[error("{}", _0)]
SynthesisError(#[from] SynthesisError), SynthesisError(#[from] SynthesisError),
#[error("Expected assignment of return values for expression {}", _0)]
Unassigned(String),
#[error("{}", _0)] #[error("{}", _0)]
ValueError(#[from] ValueError), 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)
}
}

View File

@ -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 { if start > end {
panic!("underline start column is greater than end column") let tmp = start;
start = end;
end = tmp;
} }
let mut underline = String::new(); let mut underline = String::new();

View File

@ -7,6 +7,20 @@ use leo_inputs::syntax::SyntaxError;
use crate::input_value_u32_one; use crate::input_value_u32_one;
use snarkos_models::gadgets::utilities::boolean::Boolean; 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) { pub fn output_expected_boolean(program: EdwardsTestCompiler, boolean: bool) {
let output = get_output(program); let output = get_output(program);

View File

@ -8,7 +8,7 @@ pub mod boolean;
pub mod inputs; pub mod inputs;
// pub mod integers; // pub mod integers;
// pub mod mutability; // pub mod mutability;
// pub mod statements; pub mod statements;
pub mod syntax; pub mod syntax;
use leo_compiler::{ use leo_compiler::{
@ -45,7 +45,7 @@ pub(crate) fn get_error(program: EdwardsTestCompiler) -> CompilerError {
pub(crate) fn fail_enforce(program: EdwardsTestCompiler) { pub(crate) fn fail_enforce(program: EdwardsTestCompiler) {
match get_error(program) { match get_error(program) {
CompilerError::FunctionError(FunctionError::StatementError(StatementError::AssertionFailed(_, _))) => {} CompilerError::FunctionError(FunctionError::StatementError(StatementError::Error(_))) => {}
error => panic!("Expected evaluate error, got {}", error), error => panic!("Expected evaluate error, got {}", error),
} }
} }

View File

@ -1,60 +1,67 @@
use crate::{ use crate::{get_error, parse_program};
integers::u32::{output_one, output_zero},
parse_program,
};
use leo_types::InputValue; use leo_types::InputValue;
use snarkos_curves::edwards_bls12::Fq; use snarkos_curves::edwards_bls12::Fq;
use snarkos_models::gadgets::r1cs::TestConstraintSystem; use snarkos_models::gadgets::r1cs::TestConstraintSystem;
pub mod conditional; // pub mod conditional;
// Ternary if {bool}? {expression} : {expression}; // Ternary if {bool}? {expression} : {expression};
#[test] // #[test]
fn test_ternary_basic() { // fn test_ternary_basic() {
let bytes = include_bytes!("ternary_basic.leo"); // let bytes = include_bytes!("ternary_basic.leo");
let mut program_input_true = parse_program(bytes).unwrap(); // let mut program_input_true = parse_program(bytes).unwrap();
//
let mut program_input_false = program_input_true.clone(); // let mut program_input_false = program_input_true.clone();
//
program_input_true.set_inputs(vec![Some(InputValue::Boolean(true))]); // program_input_true.set_inputs(vec![Some(input_value_bool(true))]);
output_one(program_input_true); // output_one(program_input_true);
//
program_input_false.set_inputs(vec![Some(InputValue::Boolean(false))]); // program_input_false.set_inputs(vec![Some(input_value_bool(false))]);
output_zero(program_input_false); // output_zero(program_input_false);
} // }
//
// Iteration for i {start}..{stop} { statements } // // 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] #[test]
fn test_iteration_basic() { fn test_num_returns_fail() {
let bytes = include_bytes!("iteration_basic.leo"); let bytes = include_bytes!("num_returns_fail.leo");
let program = parse_program(bytes).unwrap(); let program = parse_program(bytes).unwrap();
output_one(program); let error = get_error(program);
}
println!("{}", error);
// 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());
} }

View File

@ -0,0 +1,3 @@
function main() -> (bool, bool) {
return true
}

View File

@ -74,7 +74,7 @@ impl CLI for BuildCommand {
ct: vec![], ct: vec![],
}; };
let temporary_program = program.clone(); 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); log::debug!("Compiled constraints - {:#?}", output);
} }

View File

@ -53,7 +53,8 @@ pub enum CLIError {
impl From<leo_compiler::errors::CompilerError> for CLIError { impl From<leo_compiler::errors::CompilerError> for CLIError {
fn from(error: leo_compiler::errors::CompilerError) -> Self { 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())
} }
} }

View File

@ -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::{ use leo_ast::{
operations::AssignOperation, operations::AssignOperation,
statements::{ statements::{
@ -18,14 +18,14 @@ use std::fmt;
/// Program statement that defines some action (or expression) to be carried out. /// Program statement that defines some action (or expression) to be carried out.
#[derive(Clone, PartialEq, Eq)] #[derive(Clone, PartialEq, Eq)]
pub enum Statement { pub enum Statement {
Return(Vec<Expression>), Return(Vec<Expression>, Span),
Definition(Declare, Variable, Expression), Definition(Declare, Variable, Expression, Span),
Assign(Assignee, Expression), Assign(Assignee, Expression, Span),
MultipleAssign(Vec<Variable>, Expression), MultipleAssign(Vec<Variable>, Expression, Span),
Conditional(ConditionalStatement), Conditional(ConditionalStatement, Span),
For(Identifier, Integer, Integer, Vec<Statement>), For(Identifier, Integer, Integer, Vec<Statement>, Span),
AssertEq(Expression, Expression), AssertEq(Expression, Expression, Span),
Expression(Expression), Expression(Expression, Span),
} }
impl<'ast> From<ReturnStatement<'ast>> for Statement { impl<'ast> From<ReturnStatement<'ast>> for Statement {
@ -36,6 +36,7 @@ impl<'ast> From<ReturnStatement<'ast>> for Statement {
.into_iter() .into_iter()
.map(|expression| Expression::from(expression)) .map(|expression| Expression::from(expression))
.collect(), .collect(),
Span::from(statement.span),
) )
} }
} }
@ -46,6 +47,7 @@ impl<'ast> From<DefinitionStatement<'ast>> for Statement {
Declare::from(statement.declare), Declare::from(statement.declare),
Variable::from(statement.variable), Variable::from(statement.variable),
Expression::from(statement.expression), 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( AssignOperation::Assign(ref _assign) => Statement::Assign(
Assignee::from(statement.assignee), Assignee::from(statement.assignee),
Expression::from(statement.expression), Expression::from(statement.expression),
Span::from(statement.span),
), ),
operation_assign => { operation_assign => {
// convert assignee into postfix expression // convert assignee into postfix expression
@ -65,22 +68,27 @@ impl<'ast> From<AssignStatement<'ast>> for Statement {
AssignOperation::AddAssign(ref _assign) => Statement::Assign( AssignOperation::AddAssign(ref _assign) => Statement::Assign(
Assignee::from(statement.assignee), Assignee::from(statement.assignee),
Expression::Add(Box::new(converted), Box::new(Expression::from(statement.expression))), Expression::Add(Box::new(converted), Box::new(Expression::from(statement.expression))),
Span::from(statement.span),
), ),
AssignOperation::SubAssign(ref _assign) => Statement::Assign( AssignOperation::SubAssign(ref _assign) => Statement::Assign(
Assignee::from(statement.assignee), Assignee::from(statement.assignee),
Expression::Sub(Box::new(converted), Box::new(Expression::from(statement.expression))), Expression::Sub(Box::new(converted), Box::new(Expression::from(statement.expression))),
Span::from(statement.span),
), ),
AssignOperation::MulAssign(ref _assign) => Statement::Assign( AssignOperation::MulAssign(ref _assign) => Statement::Assign(
Assignee::from(statement.assignee), Assignee::from(statement.assignee),
Expression::Mul(Box::new(converted), Box::new(Expression::from(statement.expression))), Expression::Mul(Box::new(converted), Box::new(Expression::from(statement.expression))),
Span::from(statement.span),
), ),
AssignOperation::DivAssign(ref _assign) => Statement::Assign( AssignOperation::DivAssign(ref _assign) => Statement::Assign(
Assignee::from(statement.assignee), Assignee::from(statement.assignee),
Expression::Div(Box::new(converted), Box::new(Expression::from(statement.expression))), Expression::Div(Box::new(converted), Box::new(Expression::from(statement.expression))),
Span::from(statement.span),
), ),
AssignOperation::PowAssign(ref _assign) => Statement::Assign( AssignOperation::PowAssign(ref _assign) => Statement::Assign(
Assignee::from(statement.assignee), Assignee::from(statement.assignee),
Expression::Pow(Box::new(converted), Box::new(Expression::from(statement.expression))), 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"), 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)), Box::new(Expression::from(statement.function_name)),
statement.arguments.into_iter().map(|e| Expression::from(e)).collect(), 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() .into_iter()
.map(|statement| Statement::from(statement)) .map(|statement| Statement::from(statement))
.collect(), .collect(),
Span::from(statement.span),
) )
} }
} }
@ -136,16 +146,18 @@ impl<'ast> From<ForStatement<'ast>> for Statement {
impl<'ast> From<AssertStatement<'ast>> for Statement { impl<'ast> From<AssertStatement<'ast>> for Statement {
fn from(statement: AssertStatement<'ast>) -> Self { fn from(statement: AssertStatement<'ast>) -> Self {
match statement { match statement {
AssertStatement::AssertEq(assert_eq) => { AssertStatement::AssertEq(assert_eq) => Statement::AssertEq(
Statement::AssertEq(Expression::from(assert_eq.left), Expression::from(assert_eq.right)) Expression::from(assert_eq.left),
} Expression::from(assert_eq.right),
Span::from(assert_eq.span),
),
} }
} }
} }
impl<'ast> From<ExpressionStatement<'ast>> for Statement { impl<'ast> From<ExpressionStatement<'ast>> for Statement {
fn from(statement: ExpressionStatement<'ast>) -> Self { 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::Definition(statement) => Statement::from(statement),
AstStatement::Assign(statement) => Statement::from(statement), AstStatement::Assign(statement) => Statement::from(statement),
AstStatement::MultipleAssignment(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::Iteration(statement) => Statement::from(statement),
AstStatement::Assert(statement) => Statement::from(statement), AstStatement::Assert(statement) => Statement::from(statement),
AstStatement::Expression(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 { impl fmt::Display for Statement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self { match *self {
Statement::Return(ref statements) => { Statement::Return(ref statements, ref _span) => {
write!(f, "return (")?; write!(f, "return (")?;
for (i, value) in statements.iter().enumerate() { for (i, value) in statements.iter().enumerate() {
write!(f, "{}", value)?; write!(f, "{}", value)?;
@ -177,11 +192,11 @@ impl fmt::Display for Statement {
} }
write!(f, ")\n") 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) write!(f, "{} {} = {};", declare, variable, expression)
} }
Statement::Assign(ref variable, ref statement) => write!(f, "{} = {};", variable, statement), Statement::Assign(ref variable, ref statement, ref _span) => write!(f, "{} = {};", variable, statement),
Statement::MultipleAssign(ref assignees, ref function) => { Statement::MultipleAssign(ref assignees, ref function, ref _span) => {
write!(f, "let (")?; write!(f, "let (")?;
for (i, id) in assignees.iter().enumerate() { for (i, id) in assignees.iter().enumerate() {
write!(f, "{}", id)?; write!(f, "{}", id)?;
@ -191,16 +206,16 @@ impl fmt::Display for Statement {
} }
write!(f, ") = {};", function) write!(f, ") = {};", function)
} }
Statement::Conditional(ref statement) => write!(f, "{}", statement), Statement::Conditional(ref statement, ref _span) => write!(f, "{}", statement),
Statement::For(ref var, ref start, ref stop, ref list) => { Statement::For(ref var, ref start, ref stop, ref list, ref _span) => {
write!(f, "for {} in {}..{} {{\n", var, start, stop)?; write!(f, "for {} in {}..{} {{\n", var, start, stop)?;
for l in list { for l in list {
write!(f, "\t\t{}\n", l)?; write!(f, "\t\t{}\n", l)?;
} }
write!(f, "\t}}") write!(f, "\t}}")
} }
Statement::AssertEq(ref left, ref right) => write!(f, "assert_eq({}, {});", left, right), Statement::AssertEq(ref left, ref right, ref _span) => write!(f, "assert_eq({}, {});", left, right),
Statement::Expression(ref expression) => write!(f, "{};", expression), Statement::Expression(ref expression, ref _span) => write!(f, "{};", expression),
} }
} }
} }