impl console functions in compiler

This commit is contained in:
collin 2020-08-16 15:18:30 -07:00
parent f3ee68be2b
commit b2866951f6
13 changed files with 122 additions and 97 deletions

View File

@ -0,0 +1,43 @@
//! Enforces an assert equals statement in a compiled Leo program.
use crate::{errors::ConsoleError, evaluate_eq, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
use leo_typed::{Expression, Span, Type};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean},
};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn evaluate_console_assert<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
expression: Expression,
span: Span,
) -> Result<(), ConsoleError> {
let expected_type = Some(Type::Boolean);
let expression_string = expression.to_string();
// Evaluate assert expression
let assert_expression = self.enforce_expression(cs, file_scope, function_scope, expected_type, expression)?;
// Expect assert expression to evaluate to true
let expect_true = ConstrainedValue::Boolean(Boolean::Constant(true));
let result = evaluate_eq(cs, expect_true, assert_expression, span.clone())?;
// Unwrap assertion value and handle errors
let result_option = match result {
ConstrainedValue::Boolean(boolean) => boolean.get_value(),
_ => unreachable!("evaluate_eq must return boolean"),
};
let result_bool = result_option.ok_or(ConsoleError::assertion_depends_on_input(span.clone()))?;
if !result_bool {
Err(ConsoleError::assertion_failed(expression_string, span))
} else {
Ok(())
}
}
}

View File

@ -0,0 +1,42 @@
//! Evaluates a macro in a compiled Leo program.
use crate::{errors::ConsoleError, program::ConstrainedProgram, GroupType};
use leo_typed::{ConsoleFunction, ConsoleFunctionCall};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn evaluate_console_function_call<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
console: ConsoleFunctionCall,
) -> Result<(), ConsoleError> {
match console.function {
ConsoleFunction::Assert(expression) => {
self.evaluate_console_assert(cs, file_scope, function_scope, expression, console.span)?;
}
ConsoleFunction::Debug(string) => {
let string = self.format(cs, file_scope, function_scope, string)?;
log::debug!("{}", string);
}
ConsoleFunction::Error(string) => {
let string = self.format(cs, file_scope, function_scope, string)?;
log::error!("{}", string);
}
ConsoleFunction::Log(string) => {
let string = self.format(cs, file_scope, function_scope, string)?;
println!("{}", string);
}
}
Ok(())
}
}

View File

@ -1,6 +1,6 @@
//! Evaluates a formatted string in a compiled Leo program.
use crate::{errors::MacroError, program::ConstrainedProgram, GroupType};
use crate::{errors::ConsoleError, program::ConstrainedProgram, GroupType};
use leo_typed::FormattedString;
use snarkos_models::{
@ -15,10 +15,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
file_scope: String,
function_scope: String,
formatted: FormattedString,
) -> Result<String, MacroError> {
) -> Result<String, ConsoleError> {
// Check that containers and parameters match
if formatted.containers.len() != formatted.parameters.len() {
return Err(MacroError::length(
return Err(ConsoleError::length(
formatted.containers.len(),
formatted.parameters.len(),
formatted.span.clone(),

View File

@ -0,0 +1,8 @@
pub mod assert;
pub use assert::*;
pub mod console;
pub use self::console::*;
pub mod format;
pub use self::format::*;

View File

@ -4,7 +4,7 @@ use leo_typed::{Error as FormattedError, Span};
use std::path::PathBuf;
#[derive(Debug, Error)]
pub enum MacroError {
pub enum ConsoleError {
#[error("{}", _0)]
Error(#[from] FormattedError),
@ -12,16 +12,16 @@ pub enum MacroError {
Expression(#[from] ExpressionError),
}
impl MacroError {
impl ConsoleError {
pub fn set_path(&mut self, path: PathBuf) {
match self {
MacroError::Expression(error) => error.set_path(path),
MacroError::Error(error) => error.set_path(path),
ConsoleError::Expression(error) => error.set_path(path),
ConsoleError::Error(error) => error.set_path(path),
}
}
fn new_from_span(message: String, span: Span) -> Self {
MacroError::Error(FormattedError::new_from_span(message, span))
ConsoleError::Error(FormattedError::new_from_span(message, span))
}
pub fn length(containers: usize, parameters: usize, span: Span) -> Self {
@ -32,4 +32,16 @@ impl MacroError {
Self::new_from_span(message, span)
}
pub fn assertion_depends_on_input(span: Span) -> Self {
let message = format!("console.assert() failed to evaluate. This error is caused by empty input file values");
Self::new_from_span(message, span)
}
pub fn assertion_failed(expression: String, span: Span) -> Self {
let message = format!("Assertion `true == {}` failed", expression);
Self::new_from_span(message, span)
}
}

View File

@ -10,8 +10,8 @@ pub use self::function::*;
pub mod import;
pub use self::import::*;
pub mod macro_;
pub use self::macro_::*;
pub mod console;
pub use self::console::*;
pub mod output_file;
pub use self::output_file::*;

View File

@ -1,4 +1,4 @@
use crate::errors::{AddressError, BooleanError, ExpressionError, IntegerError, MacroError, ValueError};
use crate::errors::{AddressError, BooleanError, ConsoleError, ExpressionError, IntegerError, ValueError};
use leo_typed::{Error as FormattedError, Span, Type};
use std::path::PathBuf;
@ -21,7 +21,7 @@ pub enum StatementError {
IntegerError(#[from] IntegerError),
#[error("{}", _0)]
MacroError(#[from] MacroError),
MacroError(#[from] ConsoleError),
#[error("{}", _0)]
ValueError(#[from] ValueError),
@ -62,12 +62,6 @@ impl StatementError {
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, found `{}`", actual);

View File

@ -5,6 +5,9 @@ extern crate thiserror;
pub mod compiler;
pub mod console;
pub use self::console::*;
pub mod constraints;
pub use self::constraints::*;
@ -21,9 +24,6 @@ pub use self::function::*;
pub mod import;
pub use self::import::*;
pub mod macro_;
pub use self::macro_::*;
pub mod output;
pub use self::output::*;

View File

@ -1,32 +0,0 @@
//! Evaluates a macro in a compiled Leo program.
use crate::{errors::MacroError, program::ConstrainedProgram, GroupType};
use leo_typed::{FormattedMacro, MacroName};
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::r1cs::ConstraintSystem,
};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn evaluate_macro<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
file_scope: String,
function_scope: String,
macro_: FormattedMacro,
) -> Result<(), MacroError> {
let string = macro_
.string
.map(|string| self.format(cs, file_scope, function_scope, string))
.unwrap_or(Ok("".to_string()))?;
match macro_.name {
MacroName::Debug(_) => log::debug!("{}", string),
MacroName::Error(_) => log::error!("{}", string),
MacroName::Print(_) => println!("{}", string),
}
Ok(())
}
}

View File

@ -1,29 +0,0 @@
//! Enforces an assert equals statement in a compiled Leo program.
use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
use leo_typed::Span;
use snarkos_models::{
curves::{Field, PrimeField},
gadgets::{
r1cs::ConstraintSystem,
utilities::{boolean::Boolean, eq::ConditionalEqGadget},
},
};
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
pub fn enforce_assert_eq_statement<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
indicator: Option<Boolean>,
left: &ConstrainedValue<F, G>,
right: &ConstrainedValue<F, G>,
span: Span,
) -> Result<(), StatementError> {
let condition = indicator.unwrap_or(Boolean::Constant(true));
let name_unique = format!("assert {} == {} {}:{}", left, right, span.line, span.start);
let result = left.conditional_enforce_equal(cs.ns(|| name_unique), right, &condition);
Ok(result.map_err(|_| StatementError::assertion_failed(left.to_string(), right.to_string(), span))?)
}
}

View File

@ -1,4 +0,0 @@
//! Methods to enforce constraints on assert statements in a Leo program.
pub mod assert_eq;
pub use self::assert_eq::*;

View File

@ -1,8 +1,5 @@
//! Methods to enforce constraints on statements in a Leo program.
pub mod assert;
pub use self::assert::*;
pub mod assign;
pub use self::assign::*;

View File

@ -77,14 +77,8 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
results.append(&mut result);
}
Statement::Assert(left, right, span) => {
let (resolved_left, resolved_right) =
self.enforce_binary_expression(cs, file_scope, function_scope, None, left, right, span.clone())?;
self.enforce_assert_eq_statement(cs, indicator, &resolved_left, &resolved_right, span)?;
}
Statement::Console(macro_) => {
self.evaluate_macro(cs, file_scope, function_scope, macro_)?;
Statement::Console(console) => {
self.evaluate_console_function_call(cs, file_scope, function_scope, console)?;
}
Statement::Expression(expression, span) => {
let expression_string = expression.to_string();