diff --git a/zokrates_cli/src/ops/compile.rs b/zokrates_cli/src/ops/compile.rs index a6730aaf..d9af2ce1 100644 --- a/zokrates_cli/src/ops/compile.rs +++ b/zokrates_cli/src/ops/compile.rs @@ -58,7 +58,11 @@ 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) +) } pub fn exec(sub_matches: &ArgMatches) -> Result<(), String> { @@ -106,8 +110,9 @@ fn cli_compile(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); diff --git a/zokrates_core/src/absy/from_ast.rs b/zokrates_core/src/absy/from_ast.rs index c9535236..bd4265e3 100644 --- a/zokrates_core/src/absy/from_ast.rs +++ b/zokrates_core/src/absy/from_ast.rs @@ -356,7 +356,13 @@ impl<'ast> From> 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) } } diff --git a/zokrates_core/src/absy/mod.rs b/zokrates_core/src/absy/mod.rs index 7c729566..f7b0caf7 100644 --- a/zokrates_core/src/absy/mod.rs +++ b/zokrates_core/src/absy/mod.rs @@ -395,7 +395,7 @@ pub enum Statement<'ast> { Vec>, ), MultipleDefinition(Vec>, ExpressionNode<'ast>), - Log(String), + Log(String, Vec>), } pub type StatementNode<'ast> = Node>; @@ -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::>() + .join(", ") + ), } } } diff --git a/zokrates_core/src/compile.rs b/zokrates_core/src/compile.rs index f8804bbf..d2472fa4 100644 --- a/zokrates_core/src/compile.rs +++ b/zokrates_core/src/compile.rs @@ -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>( 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); diff --git a/zokrates_core/src/flat_absy/mod.rs b/zokrates_core/src/flat_absy/mod.rs index 8890c825..1869489e 100644 --- a/zokrates_core/src/flat_absy/mod.rs +++ b/zokrates_core/src/flat_absy/mod.rs @@ -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 { Condition(FlatExpression, FlatExpression, RuntimeError), Definition(FlatVariable, FlatExpression), Directive(FlatDirective), - Log(String), + Log(String, Vec<(ConcreteType, Vec>)>), } impl fmt::Display for FlatStatement { @@ -170,7 +171,22 @@ impl fmt::Display for FlatStatement { 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::>() + .join(", ") + )) + .collect::>() + .join(", ") + ), } } } @@ -208,7 +224,19 @@ impl FlatStatement { ..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(), + ), } } } diff --git a/zokrates_core/src/flatten/mod.rs b/zokrates_core/src/flatten/mod.rs index 5cd2bf97..c33856d1 100644 --- a/zokrates_core/src/flatten/mod.rs +++ b/zokrates_core/src/flatten/mod.rs @@ -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)); } } } diff --git a/zokrates_core/src/ir/folder.rs b/zokrates_core/src/ir/folder.rs index d4f86ade..a1f14a16 100644 --- a/zokrates_core/src/ir/folder.rs +++ b/zokrates_core/src/ir/folder.rs @@ -58,7 +58,19 @@ pub fn fold_statement>(f: &mut F, s: Statement) -> 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(), + )], } } diff --git a/zokrates_core/src/ir/from_flat.rs b/zokrates_core/src/ir/from_flat.rs index 7dc7f49d..f5f68395 100644 --- a/zokrates_core/src/ir/from_flat.rs +++ b/zokrates_core/src/ir/from_flat.rs @@ -74,7 +74,13 @@ impl From> for Statement { 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(), + ), } } } diff --git a/zokrates_core/src/ir/interpreter.rs b/zokrates_core/src/ir/interpreter.rs index 0253f6e3..c9ed1d41 100644 --- a/zokrates_core/src/ir/interpreter.rs +++ b/zokrates_core/src/ir/interpreter.rs @@ -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)?; } } } diff --git a/zokrates_core/src/ir/mod.rs b/zokrates_core/src/ir/mod.rs index ec395f2b..24a498cb 100644 --- a/zokrates_core/src/ir/mod.rs +++ b/zokrates_core/src/ir/mod.rs @@ -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 { Constraint(QuadComb, LinComb, Option), Directive(Directive), - Log(String), + Log(String, Vec<(ConcreteType, Vec>)>), } impl Statement { @@ -71,7 +72,22 @@ impl fmt::Display for Statement { 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::>() + .join(", ") + )) + .collect::>() + .join(", ") + ), } } } diff --git a/zokrates_core/src/ir/smtlib2.rs b/zokrates_core/src/ir/smtlib2.rs index f25603b5..6caab316 100644 --- a/zokrates_core/src/ir/smtlib2.rs +++ b/zokrates_core/src/ir/smtlib2.rs @@ -86,7 +86,7 @@ impl SMTLib2 for Statement { write!(f, " |~prime|))") } Statement::Directive(ref s) => s.to_smtlib2(f), - Statement::Log(_) => write!(f, ""), + Statement::Log(..) => write!(f, ""), } } } diff --git a/zokrates_core/src/ir/visitor.rs b/zokrates_core/src/ir/visitor.rs index bcf74f15..4d5c2164 100644 --- a/zokrates_core/src/ir/visitor.rs +++ b/zokrates_core/src/ir/visitor.rs @@ -61,7 +61,13 @@ pub fn visit_statement>(f: &mut F, s: &Statement) { } } 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); + } + } + } } } diff --git a/zokrates_core/src/optimizer/redefinition.rs b/zokrates_core/src/optimizer/redefinition.rs index 2bacad2f..078bb931 100644 --- a/zokrates_core/src/optimizer/redefinition.rs +++ b/zokrates_core/src/optimizer/redefinition.rs @@ -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 Folder for RedefinitionOptimizer { } } } - Statement::Log(l) => vec![Statement::Log(l)], + s => fold_statement(self, s), } } diff --git a/zokrates_core/src/semantics.rs b/zokrates_core/src/semantics.rs index ea721924..6a147275 100644 --- a/zokrates_core/src/semantics.rs +++ b/zokrates_core/src/semantics.rs @@ -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::, _>>() + .map_err(|e| vec![e])?; + + Ok(TypedStatement::Log(l, expressions)) + } } } diff --git a/zokrates_core/src/static_analysis/flat_propagation.rs b/zokrates_core/src/static_analysis/flat_propagation.rs index 9026b9cb..5428a919 100644 --- a/zokrates_core/src/static_analysis/flat_propagation.rs +++ b/zokrates_core/src/static_analysis/flat_propagation.rs @@ -75,7 +75,13 @@ impl FlatStatement { .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(), + )), } } } diff --git a/zokrates_core/src/static_analysis/flatten_complex_types.rs b/zokrates_core/src/static_analysis/flatten_complex_types.rs index ed1a3771..caba98c7 100644 --- a/zokrates_core/src/static_analysis/flatten_complex_types.rs +++ b/zokrates_core/src/static_analysis/flatten_complex_types.rs @@ -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![], }; diff --git a/zokrates_core/src/static_analysis/log_ignorer.rs b/zokrates_core/src/static_analysis/log_ignorer.rs new file mode 100644 index 00000000..ef48dce1 --- /dev/null +++ b/zokrates_core/src/static_analysis/log_ignorer.rs @@ -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> { + match s { + TypedStatement::Log(..) => vec![], + s => fold_statement(self, s), + } + } +} diff --git a/zokrates_core/src/static_analysis/mod.rs b/zokrates_core/src/static_analysis/mod.rs index ed362863..9d870e3e 100644 --- a/zokrates_core/src/static_analysis/mod.rs +++ b/zokrates_core/src/static_analysis/mod.rs @@ -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)?; diff --git a/zokrates_core/src/typed_absy/folder.rs b/zokrates_core/src/typed_absy/folder.rs index 1f0aba6d..cf128d25 100644 --- a/zokrates_core/src/typed_absy/folder.rs +++ b/zokrates_core/src/typed_absy/folder.rs @@ -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] diff --git a/zokrates_core/src/typed_absy/mod.rs b/zokrates_core/src/typed_absy/mod.rs index 4d46d9e3..0d84585e 100644 --- a/zokrates_core/src/typed_absy/mod.rs +++ b/zokrates_core/src/typed_absy/mod.rs @@ -641,7 +641,7 @@ pub enum TypedStatement<'ast, T> { Vec>, ), MultipleDefinition(Vec>, TypedExpressionList<'ast, T>), - Log(String), + Log(String, Vec>), // 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::>() + .join(", ") + ), TypedStatement::PushCallLog(ref key, ref generics) => write!( f, "// PUSH CALL TO {}/{}::<{}>", diff --git a/zokrates_core/src/typed_absy/result_folder.rs b/zokrates_core/src/typed_absy/result_folder.rs index 842e9852..da71befc 100644 --- a/zokrates_core/src/typed_absy/result_folder.rs +++ b/zokrates_core/src/typed_absy/result_folder.rs @@ -555,6 +555,12 @@ pub fn fold_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( .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, }; Ok(vec![res]) diff --git a/zokrates_core/src/zir/folder.rs b/zokrates_core/src/zir/folder.rs index 2c1ac297..74863e6e 100644 --- a/zokrates_core/src/zir/folder.rs +++ b/zokrates_core/src/zir/folder.rs @@ -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] } diff --git a/zokrates_core/src/zir/mod.rs b/zokrates_core/src/zir/mod.rs index fe6f9039..c45c9028 100644 --- a/zokrates_core/src/zir/mod.rs +++ b/zokrates_core/src/zir/mod.rs @@ -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>, ZirExpressionList<'ast, T>), - Log(String), + Log(String, Vec<(ConcreteType, Vec>)>), } 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::>() + .join(", ") + )) + .collect::>() + .join(", ") + ), } } } diff --git a/zokrates_core/src/zir/result_folder.rs b/zokrates_core/src/zir/result_folder.rs index 458cf3c0..e6ea2062 100644 --- a/zokrates_core/src/zir/result_folder.rs +++ b/zokrates_core/src/zir/result_folder.rs @@ -147,7 +147,19 @@ pub fn fold_statement<'ast, T: Field, F: ResultFolder<'ast, T>>( .collect::>()?, 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::, _>>() + .map(|e| (t, e)) + }) + .collect::, _>>()?; + + ZirStatement::Log(l, e) + } }; Ok(vec![res]) } diff --git a/zokrates_parser/src/zokrates.pest b/zokrates_parser/src/zokrates.pest index 61c7393d..57e93bf8 100644 --- a/zokrates_parser/src/zokrates.pest +++ b/zokrates_parser/src/zokrates.pest @@ -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` diff --git a/zokrates_pest_ast/src/lib.rs b/zokrates_pest_ast/src/lib.rs index 778d895c..b7968a1e 100644 --- a/zokrates_pest_ast/src/lib.rs +++ b/zokrates_pest_ast/src/lib.rs @@ -373,6 +373,7 @@ mod ast { #[pest_ast(rule(Rule::log_statement))] pub struct LogStatement<'ast> { pub content: LogStatementContent<'ast>, + pub expressions: Vec>, #[pest_ast(outer())] pub span: Span<'ast>, }