1
0
Fork 0
mirror of synced 2025-09-23 12:18:44 +00:00

add debug flag to enable logs, add expression logging without abi and interpolation

This commit is contained in:
schaeff 2022-06-22 11:09:53 +02:00
parent 5ea93bb677
commit 57f42b5d5f
26 changed files with 284 additions and 34 deletions

View file

@ -58,6 +58,10 @@ pub fn subcommand() -> App<'static, 'static> {
.long("isolate-branches")
.help("Isolate the execution of branches: a panic in a branch only makes the program panic if this branch is being logically executed")
.required(false)
).arg(Arg::with_name("debug")
.long("debug")
.help("Include logs")
.required(false)
)
}
@ -106,8 +110,9 @@ fn cli_compile<T: Field>(sub_matches: &ArgMatches) -> Result<(), String> {
)),
}?;
let config =
CompileConfig::default().isolate_branches(sub_matches.is_present("isolate-branches"));
let config = CompileConfig::default()
.isolate_branches(sub_matches.is_present("isolate-branches"))
.debug(sub_matches.is_present("debug"));
let resolver = FileSystemResolver::with_stdlib_root(stdlib_path);

View file

@ -356,7 +356,13 @@ impl<'ast> From<pest::LogStatement<'ast>> for absy::StatementNode<'ast> {
fn from(statement: pest::LogStatement<'ast>) -> absy::StatementNode<'ast> {
use crate::absy::NodeValue;
absy::Statement::Log(statement.content.inner).span(statement.span)
let expressions = statement
.expressions
.into_iter()
.map(|e| absy::ExpressionNode::from(e))
.collect();
absy::Statement::Log(statement.content.inner, expressions).span(statement.span)
}
}

View file

@ -395,7 +395,7 @@ pub enum Statement<'ast> {
Vec<StatementNode<'ast>>,
),
MultipleDefinition(Vec<AssigneeNode<'ast>>, ExpressionNode<'ast>),
Log(String),
Log(String, Vec<ExpressionNode<'ast>>),
}
pub type StatementNode<'ast> = Node<Statement<'ast>>;
@ -429,7 +429,16 @@ impl<'ast> fmt::Display for Statement<'ast> {
}
write!(f, " = {}", rhs)
}
Statement::Log(ref l) => write!(f, "log!({})", l),
Statement::Log(ref l, ref expressions) => write!(
f,
"log!({}, {})",
l,
expressions
.iter()
.map(|x| x.to_string())
.collect::<Vec<_>>()
.join(", ")
),
}
}
}

View file

@ -176,6 +176,8 @@ impl fmt::Display for CompileErrorInner {
pub struct CompileConfig {
#[serde(default)]
pub isolate_branches: bool,
#[serde(default)]
pub debug: bool,
}
impl CompileConfig {
@ -183,6 +185,11 @@ impl CompileConfig {
self.isolate_branches = flag;
self
}
pub fn debug(mut self, debug: bool) -> Self {
self.debug = debug;
self
}
}
type FilePath = PathBuf;
@ -198,6 +205,8 @@ pub fn compile<'ast, T: Field, E: Into<imports::Error>>(
let (typed_ast, abi): (crate::zir::ZirProgram<'_, T>, _) =
check_with_arena(source, location, resolver, &config, arena)?;
println!("{}", typed_ast);
// flatten input program
log::debug!("Flatten");
let program_flattened = FlattenerIterator::from_function_and_config(typed_ast.main, config);

View file

@ -14,6 +14,7 @@ pub use self::flat_variable::FlatVariable;
use serde::{Deserialize, Serialize};
use crate::solvers::Solver;
use crate::typed_absy::ConcreteType;
use std::collections::HashMap;
use std::fmt;
use zokrates_field::Field;
@ -159,7 +160,7 @@ pub enum FlatStatement<T> {
Condition(FlatExpression<T>, FlatExpression<T>, RuntimeError),
Definition(FlatVariable, FlatExpression<T>),
Directive(FlatDirective<T>),
Log(String),
Log(String, Vec<(ConcreteType, Vec<FlatExpression<T>>)>),
}
impl<T: Field> fmt::Display for FlatStatement<T> {
@ -170,7 +171,22 @@ impl<T: Field> fmt::Display for FlatStatement<T> {
write!(f, "{} == {} // {}", lhs, rhs, message)
}
FlatStatement::Directive(ref d) => write!(f, "{}", d),
FlatStatement::Log(ref l) => write!(f, "log!({})", l),
FlatStatement::Log(ref l, ref expressions) => write!(
f,
"log!(\"{}\"), {})",
l,
expressions
.iter()
.map(|(_, e)| format!(
"[{}]",
e.iter()
.map(|e| e.to_string())
.collect::<Vec<_>>()
.join(", ")
))
.collect::<Vec<_>>()
.join(", ")
),
}
}
}
@ -208,7 +224,19 @@ impl<T: Field> FlatStatement<T> {
..d
})
}
FlatStatement::Log(l) => FlatStatement::Log(l),
FlatStatement::Log(l, e) => FlatStatement::Log(
l,
e.into_iter()
.map(|(t, e)| {
(
t,
e.into_iter()
.map(|e| e.apply_substitution(substitution))
.collect(),
)
})
.collect(),
),
}
}
}

View file

@ -1234,7 +1234,20 @@ impl<'ast, T: Field> Flattener<'ast, T> {
inputs: new_inputs,
})
}
FlatStatement::Log(l) => FlatStatement::Log(l),
FlatStatement::Log(l, expressions) => FlatStatement::Log(
l,
expressions
.into_iter()
.map(|(t, e)| {
(
t,
e.into_iter()
.map(|e| e.apply_substitution(&replacement_map))
.collect(),
)
})
.collect(),
),
});
statements_flattened.extend(statements);
@ -2573,8 +2586,23 @@ impl<'ast, T: Field> Flattener<'ast, T> {
}
}
}
ZirStatement::Log(l) => {
statements_flattened.push_back(FlatStatement::Log(l));
ZirStatement::Log(l, expressions) => {
let expressions = expressions
.into_iter()
.map(|(t, e)| {
(
t,
e.into_iter()
.map(|e| {
self.flatten_expression(statements_flattened, e)
.get_field_unchecked()
})
.collect(),
)
})
.collect();
statements_flattened.push_back(FlatStatement::Log(l, expressions));
}
}
}

View file

@ -58,7 +58,19 @@ pub fn fold_statement<T: Field, F: Folder<T>>(f: &mut F, s: Statement<T>) -> Vec
message,
)],
Statement::Directive(dir) => vec![Statement::Directive(f.fold_directive(dir))],
Statement::Log(l) => vec![Statement::Log(l)],
Statement::Log(l, e) => vec![Statement::Log(
l,
e.into_iter()
.map(|(t, e)| {
(
t,
e.into_iter()
.map(|e| f.fold_linear_combination(e))
.collect(),
)
})
.collect(),
)],
}
}

View file

@ -74,7 +74,13 @@ impl<T: Field> From<FlatStatement<T>> for Statement<T> {
e => Statement::Constraint(LinComb::from(e).into(), var.into(), None),
},
FlatStatement::Directive(ds) => Statement::Directive(ds.into()),
FlatStatement::Log(l) => Statement::Log(l),
FlatStatement::Log(l, expressions) => Statement::Log(
l,
expressions
.into_iter()
.map(|(t, e)| (t, e.into_iter().map(|e| LinComb::from(e)).collect()))
.collect(),
),
}
}
}

View file

@ -76,8 +76,24 @@ impl Interpreter {
witness.insert(*o, res[i].clone());
}
}
Statement::Log(l) => {
writeln!(log_stream, "{}", l).map_err(|_| Error::LogStream)?;
Statement::Log(l, expressions) => {
write!(log_stream, "{}", l).map_err(|_| Error::LogStream)?;
write!(log_stream, " - ").map_err(|_| Error::LogStream)?;
let len = expressions.len();
for (index, (t, e)) in expressions.into_iter().enumerate() {
let values: Vec<_> =
e.iter().map(|e| e.evaluate(&witness).unwrap()).collect();
write!(log_stream, "{:?}", values).map_err(|_| Error::LogStream)?;
if index < len - 1 {
write!(log_stream, ", ").map_err(|_| Error::LogStream)?;
}
}
writeln!(log_stream).map_err(|_| Error::LogStream)?;
}
}
}

View file

@ -1,6 +1,7 @@
use crate::flat_absy::flat_parameter::FlatParameter;
use crate::flat_absy::{FlatVariable, RuntimeError};
use crate::solvers::Solver;
use crate::typed_absy::ConcreteType;
use serde::{Deserialize, Serialize};
use std::fmt;
use std::hash::Hash;
@ -26,7 +27,7 @@ pub use self::witness::Witness;
pub enum Statement<T> {
Constraint(QuadComb<T>, LinComb<T>, Option<RuntimeError>),
Directive(Directive<T>),
Log(String),
Log(String, Vec<(ConcreteType, Vec<LinComb<T>>)>),
}
impl<T: Field> Statement<T> {
@ -71,7 +72,22 @@ impl<T: Field> fmt::Display for Statement<T> {
match *self {
Statement::Constraint(ref quad, ref lin, _) => write!(f, "{} == {}", quad, lin),
Statement::Directive(ref s) => write!(f, "{}", s),
Statement::Log(ref s) => write!(f, "{}", s),
Statement::Log(ref s, ref expressions) => write!(
f,
"log!(\"{}\", {})",
s,
expressions
.iter()
.map(|(_, l)| format!(
"[{}]",
l.iter()
.map(|l| l.to_string())
.collect::<Vec<_>>()
.join(", ")
))
.collect::<Vec<_>>()
.join(", ")
),
}
}
}

View file

@ -86,7 +86,7 @@ impl<T: Field> SMTLib2 for Statement<T> {
write!(f, " |~prime|))")
}
Statement::Directive(ref s) => s.to_smtlib2(f),
Statement::Log(_) => write!(f, ""),
Statement::Log(..) => write!(f, ""),
}
}
}

View file

@ -61,7 +61,13 @@ pub fn visit_statement<T: Field, F: Visitor<T>>(f: &mut F, s: &Statement<T>) {
}
}
Statement::Directive(dir) => f.visit_directive(dir),
Statement::Log(_) => {}
Statement::Log(_, expressions) => {
for (_, e) in expressions {
for e in e {
f.visit_linear_combination(e);
}
}
}
}
}

View file

@ -36,10 +36,10 @@
// - `q == k * v if v isn't in i`: insert `v` into `i` and return `c_0`
// - otherwise return `c_0`
use crate::flat_absy::flat_variable::FlatVariable;
use crate::ir::folder::Folder;
use crate::ir::LinComb;
use crate::ir::*;
use crate::{flat_absy::flat_variable::FlatVariable, ir::folder::fold_statement};
use std::collections::{HashMap, HashSet};
use zokrates_field::Field;
@ -168,7 +168,7 @@ impl<T: Field> Folder<T> for RedefinitionOptimizer<T> {
}
}
}
Statement::Log(l) => vec![Statement::Log(l)],
s => fold_statement(self, s),
}
}

View file

@ -2024,7 +2024,15 @@ impl<'ast, T: Field> Checker<'ast, T> {
}),
}.map_err(|e| vec![e])
}
Statement::Log(l) => Ok(TypedStatement::Log(l)),
Statement::Log(l, expressions) => {
let expressions = expressions
.into_iter()
.map(|e| self.check_expression(e, module_id, types))
.collect::<Result<Vec<_>, _>>()
.map_err(|e| vec![e])?;
Ok(TypedStatement::Log(l, expressions))
}
}
}

View file

@ -75,7 +75,13 @@ impl<T: Field> FlatStatement<T> {
.collect(),
..d
})),
FlatStatement::Log(l) => Some(FlatStatement::Log(l)),
FlatStatement::Log(l, expressions) => Some(FlatStatement::Log(
l,
expressions
.into_iter()
.map(|(t, e)| (t, e.into_iter().map(|e| e.propagate(constants)).collect()))
.collect(),
)),
}
}
}

View file

@ -1,5 +1,5 @@
use crate::typed_absy::types::UBitwidth;
use crate::typed_absy::{self, Expr};
use crate::typed_absy::{self, Expr, Typed};
use crate::zir;
use std::marker::PhantomData;
use zokrates_field::Field;
@ -474,7 +474,17 @@ fn fold_statement<'ast, T: Field>(
f.fold_expression_list(statements_buffer, elist),
)]
}
typed_absy::TypedStatement::Log(l) => vec![zir::ZirStatement::Log(l)],
typed_absy::TypedStatement::Log(l, e) => vec![zir::ZirStatement::Log(
l,
e.into_iter()
.map(|e| {
(
e.get_type().try_into().unwrap(),
f.fold_expression(statements_buffer, e),
)
})
.collect(),
)],
typed_absy::TypedStatement::PushCallLog(..) => vec![],
typed_absy::TypedStatement::PopCallLog => vec![],
};

View file

@ -0,0 +1,20 @@
use crate::typed_absy::{folder::*, TypedProgram, TypedStatement};
use zokrates_field::Field;
#[derive(Default)]
pub struct LogIgnorer;
impl LogIgnorer {
pub fn ignore<'ast, T: Field>(p: TypedProgram<'ast, T>) -> TypedProgram<'ast, T> {
Self::default().fold_program(p)
}
}
impl<'ast, T: Field> Folder<'ast, T> for LogIgnorer {
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
match s {
TypedStatement::Log(..) => vec![],
s => fold_statement(self, s),
}
}
}

View file

@ -10,6 +10,7 @@ mod constant_argument_checker;
mod constant_resolver;
mod flat_propagation;
mod flatten_complex_types;
mod log_ignorer;
mod out_of_bounds;
mod propagation;
mod reducer;
@ -23,6 +24,7 @@ use self::branch_isolator::Isolator;
use self::condition_redefiner::ConditionRedefiner;
use self::constant_argument_checker::ConstantArgumentChecker;
use self::flatten_complex_types::Flattener;
use self::log_ignorer::LogIgnorer;
use self::out_of_bounds::OutOfBoundsChecker;
use self::propagation::Propagator;
use self::reducer::reduce_program;
@ -107,6 +109,17 @@ impl<'ast, T: Field> TypedProgram<'ast, T> {
r
};
// include logs
let r = if config.debug {
log::debug!("Static analyser: Include logs");
r
} else {
log::debug!("Static analyser: Ignore logs");
let r = LogIgnorer::ignore(r);
log::trace!("\n{}", r);
r
};
// reduce the program to a single function
log::debug!("Static analyser: Reduce program");
let r = reduce_program(r).map_err(Error::from)?;

View file

@ -540,6 +540,9 @@ pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>(
assignees.into_iter().map(|a| f.fold_assignee(a)).collect(),
f.fold_expression_list(elist),
),
TypedStatement::Log(s, e) => {
TypedStatement::Log(s, e.into_iter().map(|e| f.fold_expression(e)).collect())
}
s => s,
};
vec![res]

View file

@ -641,7 +641,7 @@ pub enum TypedStatement<'ast, T> {
Vec<TypedStatement<'ast, T>>,
),
MultipleDefinition(Vec<TypedAssignee<'ast, T>>, TypedExpressionList<'ast, T>),
Log(String),
Log(String, Vec<TypedExpression<'ast, T>>),
// Aux
PushCallLog(
DeclarationFunctionKey<'ast, T>,
@ -708,7 +708,16 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedStatement<'ast, T> {
}
write!(f, " = {}", rhs)
}
TypedStatement::Log(ref l) => write!(f, "log!({})", l),
TypedStatement::Log(ref l, ref expressions) => write!(
f,
"log!({}, {})",
l,
expressions
.iter()
.map(|e| e.to_string())
.collect::<Vec<_>>()
.join(", ")
),
TypedStatement::PushCallLog(ref key, ref generics) => write!(
f,
"// PUSH CALL TO {}/{}::<{}>",

View file

@ -555,6 +555,12 @@ pub fn fold_statement<'ast, T: Field, F: ResultFolder<'ast, T>>(
.collect::<Result<_, _>>()?,
f.fold_expression_list(elist)?,
),
TypedStatement::Log(s, e) => TypedStatement::Log(
s,
e.into_iter()
.map(|e| f.fold_expression(e))
.collect::<Result<Vec<_>, _>>()?,
),
s => s,
};
Ok(vec![res])

View file

@ -122,7 +122,12 @@ pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>(
variables.into_iter().map(|v| f.fold_variable(v)).collect(),
f.fold_expression_list(elist),
),
ZirStatement::Log(l) => ZirStatement::Log(l),
ZirStatement::Log(l, e) => ZirStatement::Log(
l,
e.into_iter()
.map(|(t, e)| (t, e.into_iter().map(|e| f.fold_expression(e)).collect()))
.collect(),
),
};
vec![res]
}

View file

@ -10,6 +10,7 @@ mod variable;
pub use self::parameter::Parameter;
pub use self::types::Type;
pub use self::variable::Variable;
use crate::typed_absy::ConcreteType;
pub use crate::zir::uint::{ShouldReduce, UExpression, UExpressionInner, UMetadata};
use crate::embed::FlatEmbed;
@ -112,7 +113,7 @@ pub enum ZirStatement<'ast, T> {
),
Assertion(BooleanExpression<'ast, T>, RuntimeError),
MultipleDefinition(Vec<ZirAssignee<'ast>>, ZirExpressionList<'ast, T>),
Log(String),
Log(String, Vec<(ConcreteType, Vec<ZirExpression<'ast, T>>)>),
}
impl<'ast, T: fmt::Display> fmt::Display for ZirStatement<'ast, T> {
@ -162,7 +163,22 @@ impl<'ast, T: fmt::Display> fmt::Display for ZirStatement<'ast, T> {
}
write!(f, " = {}", rhs)
}
ZirStatement::Log(ref l) => write!(f, "log!({})", l),
ZirStatement::Log(ref l, ref expressions) => write!(
f,
"log!(\"{}\"), {})",
l,
expressions
.iter()
.map(|(_, e)| format!(
"[{}]",
e.iter()
.map(|e| e.to_string())
.collect::<Vec<_>>()
.join(", ")
))
.collect::<Vec<_>>()
.join(", ")
),
}
}
}

View file

@ -147,7 +147,19 @@ pub fn fold_statement<'ast, T: Field, F: ResultFolder<'ast, T>>(
.collect::<Result<_, _>>()?,
f.fold_expression_list(elist)?,
),
ZirStatement::Log(l) => ZirStatement::Log(l),
ZirStatement::Log(l, e) => {
let e = e
.into_iter()
.map(|(t, e)| {
e.into_iter()
.map(|e| f.fold_expression(e))
.collect::<Result<Vec<_>, _>>()
.map(|e| (t, e))
})
.collect::<Result<Vec<_>, _>>()?;
ZirStatement::Log(l, e)
}
};
Ok(vec![res])
}

View file

@ -60,8 +60,8 @@ statement = { (return_statement // does not require subsequent newline
) ~ NEWLINE
) ~ NEWLINE* }
log_statement = { "log!(\"" ~ log_statement_content ~ "\")"}
log_statement_content = { ASCII_ALPHANUMERIC* }
log_statement = { "log!(\"" ~ log_statement_content ~ "\"" ~ "," ~ expression_list ~ ")"}
log_statement_content = { (ASCII_ALPHANUMERIC | "{" | "}")* }
iteration_statement = { "for" ~ ty ~ identifier ~ "in" ~ expression ~ ".." ~ expression ~ "do" ~ NEWLINE* ~ statement* ~ "endfor"}
return_statement = { "return" ~ expression_list}
definition_statement = { typed_identifier_or_assignee_list ~ "=" ~ expression } // declare and assign, so only identifiers are allowed, unlike `assignment_statement`

View file

@ -373,6 +373,7 @@ mod ast {
#[pest_ast(rule(Rule::log_statement))]
pub struct LogStatement<'ast> {
pub content: LogStatementContent<'ast>,
pub expressions: Vec<Expression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}