add debug flag to enable logs, add expression logging without abi and interpolation
This commit is contained in:
parent
5ea93bb677
commit
57f42b5d5f
26 changed files with 284 additions and 34 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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(", ")
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
)],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(", ")
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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, ""),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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![],
|
||||
};
|
||||
|
|
20
zokrates_core/src/static_analysis/log_ignorer.rs
Normal file
20
zokrates_core/src/static_analysis/log_ignorer.rs
Normal 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),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)?;
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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 {}/{}::<{}>",
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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]
|
||||
}
|
||||
|
|
|
@ -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(", ")
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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])
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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>,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue