mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-24 07:48:04 +03:00
impl console functions in compiler
This commit is contained in:
parent
f3ee68be2b
commit
b2866951f6
43
compiler/src/console/assert.rs
Normal file
43
compiler/src/console/assert.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
}
|
42
compiler/src/console/console.rs
Normal file
42
compiler/src/console/console.rs
Normal 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(())
|
||||
}
|
||||
}
|
@ -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(),
|
8
compiler/src/console/mod.rs
Normal file
8
compiler/src/console/mod.rs
Normal 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::*;
|
@ -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)
|
||||
}
|
||||
}
|
@ -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::*;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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::*;
|
||||
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
@ -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))?)
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
//! Methods to enforce constraints on assert statements in a Leo program.
|
||||
|
||||
pub mod assert_eq;
|
||||
pub use self::assert_eq::*;
|
@ -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::*;
|
||||
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user