diff --git a/compiler/src/constraints/statement.rs b/compiler/src/constraints/statement.rs index add36fa538..ab2ca91b1b 100644 --- a/compiler/src/constraints/statement.rs +++ b/compiler/src/constraints/statement.rs @@ -15,6 +15,7 @@ use leo_types::{ Identifier, Integer, RangeOrExpression, + Span, Statement, Type, Variable, @@ -37,14 +38,18 @@ impl> ConstrainedProgram { } } - fn get_mutable_assignee(&mut self, name: String) -> Result<&mut ConstrainedValue, StatementError> { + fn get_mutable_assignee( + &mut self, + name: String, + span: Span, + ) -> Result<&mut ConstrainedValue, 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> ConstrainedProgram { name: String, range_or_expression: RangeOrExpression, mut new_value: ConstrainedValue, + span: Span, ) -> Result<(), StatementError> { let condition = indicator.unwrap_or(Boolean::Constant(true)); @@ -66,18 +72,18 @@ impl> ConstrainedProgram { 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> ConstrainedProgram { }; // 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> ConstrainedProgram { 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> ConstrainedProgram { circuit_name: String, object_name: Identifier, mut new_value: ConstrainedValue, + 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> ConstrainedProgram { 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> ConstrainedProgram { indicator: Option, 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> ConstrainedProgram { 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> ConstrainedProgram { 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> ConstrainedProgram { 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> ConstrainedProgram { function_scope: String, variables: Vec, function: Expression, + span: Span, ) -> Result<(), StatementError> { let mut expected_types = vec![]; for variable in variables.iter() { @@ -273,9 +285,10 @@ impl> ConstrainedProgram { }; 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> ConstrainedProgram { function_scope: String, expressions: Vec, return_types: Vec, + span: Span, ) -> Result, 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> ConstrainedProgram { indicator: Option, statement: ConditionalStatement, return_types: Vec, + span: Span, ) -> Result>, StatementError> { let statement_string = statement.to_string(); let outer_indicator = indicator.unwrap_or(Boolean::Constant(true)); @@ -371,7 +387,7 @@ impl> ConstrainedProgram { 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> ConstrainedProgram { Some(branch_2_indicator), *nested, return_types, + span, ), ConditionalNestedOrEndStatement::End(statements) => self.evaluate_branch( cs, @@ -432,6 +449,7 @@ impl> ConstrainedProgram { stop: Integer, statements: Vec, return_types: Vec, + _span: Span, ) -> Result>, StatementError> { let mut res = None; @@ -469,11 +487,12 @@ impl> ConstrainedProgram { indicator: Option, left: &ConstrainedValue, right: &ConstrainedValue, + 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>( @@ -487,19 +506,26 @@ impl> ConstrainedProgram { ) -> Result>, 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> ConstrainedProgram { 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> ConstrainedProgram { 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)), } } }; diff --git a/compiler/src/errors/constraints/expression.rs b/compiler/src/errors/constraints/expression.rs index b9a3ccbab0..7e3b3aeac9 100644 --- a/compiler/src/errors/constraints/expression.rs +++ b/compiler/src/errors/constraints/expression.rs @@ -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 { diff --git a/compiler/src/errors/constraints/statement.rs b/compiler/src/errors/constraints/statement.rs index 180d5acbb6..f293b16e5f 100644 --- a/compiler/src/errors/constraints/statement.rs +++ b/compiler/src/errors/constraints/statement.rs @@ -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) + } +} diff --git a/compiler/src/errors/error.rs b/compiler/src/errors/error.rs index 5d246501be..60cc40ff64 100644 --- a/compiler/src/errors/error.rs +++ b/compiler/src/errors/error.rs @@ -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(); diff --git a/compiler/tests/boolean/mod.rs b/compiler/tests/boolean/mod.rs index 651d1692a1..b42f9e3d4b 100644 --- a/compiler/tests/boolean/mod.rs +++ b/compiler/tests/boolean/mod.rs @@ -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); diff --git a/compiler/tests/mod.rs b/compiler/tests/mod.rs index 7ac270acfd..6877b7f736 100644 --- a/compiler/tests/mod.rs +++ b/compiler/tests/mod.rs @@ -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), } } diff --git a/compiler/tests/statements/mod.rs b/compiler/tests/statements/mod.rs index 950f2896f5..e58103fc9b 100644 --- a/compiler/tests/statements/mod.rs +++ b/compiler/tests/statements/mod.rs @@ -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::::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::::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::::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::::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); } diff --git a/compiler/tests/statements/num_returns_fail.leo b/compiler/tests/statements/num_returns_fail.leo new file mode 100644 index 0000000000..64cfa7b3e2 --- /dev/null +++ b/compiler/tests/statements/num_returns_fail.leo @@ -0,0 +1,3 @@ +function main() -> (bool, bool) { + return true +} \ No newline at end of file diff --git a/leo/commands/build.rs b/leo/commands/build.rs index 255fc91847..ee0269805d 100644 --- a/leo/commands/build.rs +++ b/leo/commands/build.rs @@ -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); } diff --git a/leo/errors/cli.rs b/leo/errors/cli.rs index 53599b83cc..c0921be3f7 100644 --- a/leo/errors/cli.rs +++ b/leo/errors/cli.rs @@ -53,7 +53,8 @@ pub enum CLIError { impl From 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()) } } diff --git a/types/src/statements/statement.rs b/types/src/statements/statement.rs index 1ce46adf14..d7cc1e0300 100644 --- a/types/src/statements/statement.rs +++ b/types/src/statements/statement.rs @@ -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), - Definition(Declare, Variable, Expression), - Assign(Assignee, Expression), - MultipleAssign(Vec, Expression), - Conditional(ConditionalStatement), - For(Identifier, Integer, Integer, Vec), - AssertEq(Expression, Expression), - Expression(Expression), + Return(Vec, Span), + Definition(Declare, Variable, Expression, Span), + Assign(Assignee, Expression, Span), + MultipleAssign(Vec, Expression, Span), + Conditional(ConditionalStatement, Span), + For(Identifier, Integer, Integer, Vec, Span), + AssertEq(Expression, Expression, Span), + Expression(Expression, Span), } impl<'ast> From> for Statement { @@ -36,6 +36,7 @@ impl<'ast> From> for Statement { .into_iter() .map(|expression| Expression::from(expression)) .collect(), + Span::from(statement.span), ) } } @@ -46,6 +47,7 @@ impl<'ast> From> 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> 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> 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> 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> for Statement { .into_iter() .map(|statement| Statement::from(statement)) .collect(), + Span::from(statement.span), ) } } @@ -136,16 +146,18 @@ impl<'ast> From> for Statement { impl<'ast> From> 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> 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> 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> 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), } } }