implement basic log statement
This commit is contained in:
parent
a08d49b7e5
commit
5ea93bb677
22 changed files with 70 additions and 8 deletions
|
@ -159,7 +159,7 @@ fn cli_compute<T: Field, I: Iterator<Item = ir::Statement<T>>>(
|
||||||
let interpreter = ir::Interpreter::default();
|
let interpreter = ir::Interpreter::default();
|
||||||
|
|
||||||
let witness = interpreter
|
let witness = interpreter
|
||||||
.execute(ir_prog, &arguments.encode())
|
.execute(ir_prog, &arguments.encode(), &mut std::io::stdout())
|
||||||
.map_err(|e| format!("Execution failed: {}", e))?;
|
.map_err(|e| format!("Execution failed: {}", e))?;
|
||||||
|
|
||||||
use zokrates_abi::Decode;
|
use zokrates_abi::Decode;
|
||||||
|
|
|
@ -256,6 +256,7 @@ fn statements_from_statement(statement: pest::Statement) -> Vec<absy::StatementN
|
||||||
pest::Statement::Iteration(s) => vec![absy::StatementNode::from(s)],
|
pest::Statement::Iteration(s) => vec![absy::StatementNode::from(s)],
|
||||||
pest::Statement::Assertion(s) => vec![absy::StatementNode::from(s)],
|
pest::Statement::Assertion(s) => vec![absy::StatementNode::from(s)],
|
||||||
pest::Statement::Return(s) => vec![absy::StatementNode::from(s)],
|
pest::Statement::Return(s) => vec![absy::StatementNode::from(s)],
|
||||||
|
pest::Statement::Log(l) => vec![absy::StatementNode::from(l)],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,6 +352,14 @@ fn statements_from_definition(definition: pest::DefinitionStatement) -> Vec<absy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'ast> From<pest::ReturnStatement<'ast>> for absy::StatementNode<'ast> {
|
impl<'ast> From<pest::ReturnStatement<'ast>> for absy::StatementNode<'ast> {
|
||||||
fn from(statement: pest::ReturnStatement<'ast>) -> absy::StatementNode<'ast> {
|
fn from(statement: pest::ReturnStatement<'ast>) -> absy::StatementNode<'ast> {
|
||||||
use crate::absy::NodeValue;
|
use crate::absy::NodeValue;
|
||||||
|
|
|
@ -395,6 +395,7 @@ pub enum Statement<'ast> {
|
||||||
Vec<StatementNode<'ast>>,
|
Vec<StatementNode<'ast>>,
|
||||||
),
|
),
|
||||||
MultipleDefinition(Vec<AssigneeNode<'ast>>, ExpressionNode<'ast>),
|
MultipleDefinition(Vec<AssigneeNode<'ast>>, ExpressionNode<'ast>),
|
||||||
|
Log(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type StatementNode<'ast> = Node<Statement<'ast>>;
|
pub type StatementNode<'ast> = Node<Statement<'ast>>;
|
||||||
|
@ -428,6 +429,7 @@ impl<'ast> fmt::Display for Statement<'ast> {
|
||||||
}
|
}
|
||||||
write!(f, " = {}", rhs)
|
write!(f, " = {}", rhs)
|
||||||
}
|
}
|
||||||
|
Statement::Log(ref l) => write!(f, "log!({})", l),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,6 +159,7 @@ pub enum FlatStatement<T> {
|
||||||
Condition(FlatExpression<T>, FlatExpression<T>, RuntimeError),
|
Condition(FlatExpression<T>, FlatExpression<T>, RuntimeError),
|
||||||
Definition(FlatVariable, FlatExpression<T>),
|
Definition(FlatVariable, FlatExpression<T>),
|
||||||
Directive(FlatDirective<T>),
|
Directive(FlatDirective<T>),
|
||||||
|
Log(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Field> fmt::Display for FlatStatement<T> {
|
impl<T: Field> fmt::Display for FlatStatement<T> {
|
||||||
|
@ -169,6 +170,7 @@ impl<T: Field> fmt::Display for FlatStatement<T> {
|
||||||
write!(f, "{} == {} // {}", lhs, rhs, message)
|
write!(f, "{} == {} // {}", lhs, rhs, message)
|
||||||
}
|
}
|
||||||
FlatStatement::Directive(ref d) => write!(f, "{}", d),
|
FlatStatement::Directive(ref d) => write!(f, "{}", d),
|
||||||
|
FlatStatement::Log(ref l) => write!(f, "log!({})", l),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,6 +208,7 @@ impl<T: Field> FlatStatement<T> {
|
||||||
..d
|
..d
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
FlatStatement::Log(l) => FlatStatement::Log(l),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1234,6 +1234,7 @@ impl<'ast, T: Field> Flattener<'ast, T> {
|
||||||
inputs: new_inputs,
|
inputs: new_inputs,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
FlatStatement::Log(l) => FlatStatement::Log(l),
|
||||||
});
|
});
|
||||||
|
|
||||||
statements_flattened.extend(statements);
|
statements_flattened.extend(statements);
|
||||||
|
@ -2572,6 +2573,9 @@ impl<'ast, T: Field> Flattener<'ast, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ZirStatement::Log(l) => {
|
||||||
|
statements_flattened.push_back(FlatStatement::Log(l));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ pub fn fold_statement<T: Field, F: Folder<T>>(f: &mut F, s: Statement<T>) -> Vec
|
||||||
message,
|
message,
|
||||||
)],
|
)],
|
||||||
Statement::Directive(dir) => vec![Statement::Directive(f.fold_directive(dir))],
|
Statement::Directive(dir) => vec![Statement::Directive(f.fold_directive(dir))],
|
||||||
|
Statement::Log(l) => vec![Statement::Log(l)],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,7 @@ impl<T: Field> From<FlatStatement<T>> for Statement<T> {
|
||||||
e => Statement::Constraint(LinComb::from(e).into(), var.into(), None),
|
e => Statement::Constraint(LinComb::from(e).into(), var.into(), None),
|
||||||
},
|
},
|
||||||
FlatStatement::Directive(ds) => Statement::Directive(ds.into()),
|
FlatStatement::Directive(ds) => Statement::Directive(ds.into()),
|
||||||
|
FlatStatement::Log(l) => Statement::Log(l),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,10 +25,11 @@ impl Interpreter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpreter {
|
impl Interpreter {
|
||||||
pub fn execute<T: Field, I: IntoIterator<Item = Statement<T>>>(
|
pub fn execute<W: std::io::Write, T: Field, I: IntoIterator<Item = Statement<T>>>(
|
||||||
&self,
|
&self,
|
||||||
program: ProgIterator<T, I>,
|
program: ProgIterator<T, I>,
|
||||||
inputs: &[T],
|
inputs: &[T],
|
||||||
|
log_stream: &mut W,
|
||||||
) -> ExecutionResult<T> {
|
) -> ExecutionResult<T> {
|
||||||
self.check_inputs(&program, inputs)?;
|
self.check_inputs(&program, inputs)?;
|
||||||
let mut witness = BTreeMap::new();
|
let mut witness = BTreeMap::new();
|
||||||
|
@ -75,6 +76,9 @@ impl Interpreter {
|
||||||
witness.insert(*o, res[i].clone());
|
witness.insert(*o, res[i].clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Statement::Log(l) => {
|
||||||
|
writeln!(log_stream, "{}", l).map_err(|_| Error::LogStream)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,6 +277,7 @@ pub enum Error {
|
||||||
UnsatisfiedConstraint { error: Option<RuntimeError> },
|
UnsatisfiedConstraint { error: Option<RuntimeError> },
|
||||||
Solver,
|
Solver,
|
||||||
WrongInputCount { expected: usize, received: usize },
|
WrongInputCount { expected: usize, received: usize },
|
||||||
|
LogStream,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
|
@ -305,6 +310,7 @@ impl fmt::Display for Error {
|
||||||
received,
|
received,
|
||||||
if received == 1 { "" } else { "s" }
|
if received == 1 { "" } else { "s" }
|
||||||
),
|
),
|
||||||
|
Error::LogStream => write!(f, "Error writing a log to the log stream"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ pub use self::witness::Witness;
|
||||||
pub enum Statement<T> {
|
pub enum Statement<T> {
|
||||||
Constraint(QuadComb<T>, LinComb<T>, Option<RuntimeError>),
|
Constraint(QuadComb<T>, LinComb<T>, Option<RuntimeError>),
|
||||||
Directive(Directive<T>),
|
Directive(Directive<T>),
|
||||||
|
Log(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Field> Statement<T> {
|
impl<T: Field> Statement<T> {
|
||||||
|
@ -70,6 +71,7 @@ impl<T: Field> fmt::Display for Statement<T> {
|
||||||
match *self {
|
match *self {
|
||||||
Statement::Constraint(ref quad, ref lin, _) => write!(f, "{} == {}", quad, lin),
|
Statement::Constraint(ref quad, ref lin, _) => write!(f, "{} == {}", quad, lin),
|
||||||
Statement::Directive(ref s) => write!(f, "{}", s),
|
Statement::Directive(ref s) => write!(f, "{}", s),
|
||||||
|
Statement::Log(ref s) => write!(f, "{}", s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,7 @@ impl<T: Field> SMTLib2 for Statement<T> {
|
||||||
write!(f, " |~prime|))")
|
write!(f, " |~prime|))")
|
||||||
}
|
}
|
||||||
Statement::Directive(ref s) => s.to_smtlib2(f),
|
Statement::Directive(ref s) => s.to_smtlib2(f),
|
||||||
|
Statement::Log(_) => write!(f, ""),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,7 @@ pub fn visit_statement<T: Field, F: Visitor<T>>(f: &mut F, s: &Statement<T>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Statement::Directive(dir) => f.visit_directive(dir),
|
Statement::Directive(dir) => f.visit_directive(dir),
|
||||||
|
Statement::Log(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -168,6 +168,7 @@ impl<T: Field> Folder<T> for RedefinitionOptimizer<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Statement::Log(l) => vec![Statement::Log(l)],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2024,6 +2024,7 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
||||||
}),
|
}),
|
||||||
}.map_err(|e| vec![e])
|
}.map_err(|e| vec![e])
|
||||||
}
|
}
|
||||||
|
Statement::Log(l) => Ok(TypedStatement::Log(l)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,7 @@ impl<T: Field> FlatStatement<T> {
|
||||||
.collect(),
|
.collect(),
|
||||||
..d
|
..d
|
||||||
})),
|
})),
|
||||||
|
FlatStatement::Log(l) => Some(FlatStatement::Log(l)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -474,6 +474,7 @@ fn fold_statement<'ast, T: Field>(
|
||||||
f.fold_expression_list(statements_buffer, elist),
|
f.fold_expression_list(statements_buffer, elist),
|
||||||
)]
|
)]
|
||||||
}
|
}
|
||||||
|
typed_absy::TypedStatement::Log(l) => vec![zir::ZirStatement::Log(l)],
|
||||||
typed_absy::TypedStatement::PushCallLog(..) => vec![],
|
typed_absy::TypedStatement::PushCallLog(..) => vec![],
|
||||||
typed_absy::TypedStatement::PopCallLog => vec![],
|
typed_absy::TypedStatement::PopCallLog => vec![],
|
||||||
};
|
};
|
||||||
|
|
|
@ -641,6 +641,7 @@ pub enum TypedStatement<'ast, T> {
|
||||||
Vec<TypedStatement<'ast, T>>,
|
Vec<TypedStatement<'ast, T>>,
|
||||||
),
|
),
|
||||||
MultipleDefinition(Vec<TypedAssignee<'ast, T>>, TypedExpressionList<'ast, T>),
|
MultipleDefinition(Vec<TypedAssignee<'ast, T>>, TypedExpressionList<'ast, T>),
|
||||||
|
Log(String),
|
||||||
// Aux
|
// Aux
|
||||||
PushCallLog(
|
PushCallLog(
|
||||||
DeclarationFunctionKey<'ast, T>,
|
DeclarationFunctionKey<'ast, T>,
|
||||||
|
@ -707,6 +708,7 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedStatement<'ast, T> {
|
||||||
}
|
}
|
||||||
write!(f, " = {}", rhs)
|
write!(f, " = {}", rhs)
|
||||||
}
|
}
|
||||||
|
TypedStatement::Log(ref l) => write!(f, "log!({})", l),
|
||||||
TypedStatement::PushCallLog(ref key, ref generics) => write!(
|
TypedStatement::PushCallLog(ref key, ref generics) => write!(
|
||||||
f,
|
f,
|
||||||
"// PUSH CALL TO {}/{}::<{}>",
|
"// PUSH CALL TO {}/{}::<{}>",
|
||||||
|
|
|
@ -122,6 +122,7 @@ pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>(
|
||||||
variables.into_iter().map(|v| f.fold_variable(v)).collect(),
|
variables.into_iter().map(|v| f.fold_variable(v)).collect(),
|
||||||
f.fold_expression_list(elist),
|
f.fold_expression_list(elist),
|
||||||
),
|
),
|
||||||
|
ZirStatement::Log(l) => ZirStatement::Log(l),
|
||||||
};
|
};
|
||||||
vec![res]
|
vec![res]
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,6 +112,7 @@ pub enum ZirStatement<'ast, T> {
|
||||||
),
|
),
|
||||||
Assertion(BooleanExpression<'ast, T>, RuntimeError),
|
Assertion(BooleanExpression<'ast, T>, RuntimeError),
|
||||||
MultipleDefinition(Vec<ZirAssignee<'ast>>, ZirExpressionList<'ast, T>),
|
MultipleDefinition(Vec<ZirAssignee<'ast>>, ZirExpressionList<'ast, T>),
|
||||||
|
Log(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast, T: fmt::Display> fmt::Display for ZirStatement<'ast, T> {
|
impl<'ast, T: fmt::Display> fmt::Display for ZirStatement<'ast, T> {
|
||||||
|
@ -161,6 +162,7 @@ impl<'ast, T: fmt::Display> fmt::Display for ZirStatement<'ast, T> {
|
||||||
}
|
}
|
||||||
write!(f, " = {}", rhs)
|
write!(f, " = {}", rhs)
|
||||||
}
|
}
|
||||||
|
ZirStatement::Log(ref l) => write!(f, "log!({})", l),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,6 +147,7 @@ pub fn fold_statement<'ast, T: Field, F: ResultFolder<'ast, T>>(
|
||||||
.collect::<Result<_, _>>()?,
|
.collect::<Result<_, _>>()?,
|
||||||
f.fold_expression_list(elist)?,
|
f.fold_expression_list(elist)?,
|
||||||
),
|
),
|
||||||
|
ZirStatement::Log(l) => ZirStatement::Log(l),
|
||||||
};
|
};
|
||||||
Ok(vec![res])
|
Ok(vec![res])
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,12 +53,15 @@ vis = { vis_private | vis_public }
|
||||||
|
|
||||||
// Statements
|
// Statements
|
||||||
statement = { (return_statement // does not require subsequent newline
|
statement = { (return_statement // does not require subsequent newline
|
||||||
| (iteration_statement
|
| (log_statement
|
||||||
|
| iteration_statement
|
||||||
| definition_statement
|
| definition_statement
|
||||||
| expression_statement
|
| expression_statement
|
||||||
) ~ NEWLINE
|
) ~ NEWLINE
|
||||||
) ~ NEWLINE* }
|
) ~ NEWLINE* }
|
||||||
|
|
||||||
|
log_statement = { "log!(\"" ~ log_statement_content ~ "\")"}
|
||||||
|
log_statement_content = { ASCII_ALPHANUMERIC* }
|
||||||
iteration_statement = { "for" ~ ty ~ identifier ~ "in" ~ expression ~ ".." ~ expression ~ "do" ~ NEWLINE* ~ statement* ~ "endfor"}
|
iteration_statement = { "for" ~ ty ~ identifier ~ "in" ~ expression ~ ".." ~ expression ~ "do" ~ NEWLINE* ~ statement* ~ "endfor"}
|
||||||
return_statement = { "return" ~ expression_list}
|
return_statement = { "return" ~ expression_list}
|
||||||
definition_statement = { typed_identifier_or_assignee_list ~ "=" ~ expression } // declare and assign, so only identifiers are allowed, unlike `assignment_statement`
|
definition_statement = { typed_identifier_or_assignee_list ~ "=" ~ expression } // declare and assign, so only identifiers are allowed, unlike `assignment_statement`
|
||||||
|
|
|
@ -15,10 +15,11 @@ pub use ast::{
|
||||||
File, FromExpression, FunctionDefinition, HexLiteralExpression, HexNumberExpression,
|
File, FromExpression, FunctionDefinition, HexLiteralExpression, HexNumberExpression,
|
||||||
IdentifierExpression, IdentifierOrDecimal, IfElseExpression, ImportDirective, ImportSymbol,
|
IdentifierExpression, IdentifierOrDecimal, IfElseExpression, ImportDirective, ImportSymbol,
|
||||||
InlineArrayExpression, InlineStructExpression, InlineStructMember, InlineTupleExpression,
|
InlineArrayExpression, InlineStructExpression, InlineStructMember, InlineTupleExpression,
|
||||||
IterationStatement, LiteralExpression, Parameter, PostfixExpression, Range, RangeOrExpression,
|
IterationStatement, LiteralExpression, LogStatement, Parameter, PostfixExpression, Range,
|
||||||
ReturnStatement, Span, Spread, SpreadOrExpression, Statement, StructDefinition, StructField,
|
RangeOrExpression, ReturnStatement, Span, Spread, SpreadOrExpression, Statement,
|
||||||
SymbolDeclaration, TernaryExpression, ToExpression, Type, TypeDefinition, TypedIdentifier,
|
StructDefinition, StructField, SymbolDeclaration, TernaryExpression, ToExpression, Type,
|
||||||
TypedIdentifierOrAssignee, UnaryExpression, UnaryOperator, Underscore, Visibility,
|
TypeDefinition, TypedIdentifier, TypedIdentifierOrAssignee, UnaryExpression, UnaryOperator,
|
||||||
|
Underscore, Visibility,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod ast {
|
mod ast {
|
||||||
|
@ -365,6 +366,24 @@ mod ast {
|
||||||
Definition(DefinitionStatement<'ast>),
|
Definition(DefinitionStatement<'ast>),
|
||||||
Assertion(AssertionStatement<'ast>),
|
Assertion(AssertionStatement<'ast>),
|
||||||
Iteration(IterationStatement<'ast>),
|
Iteration(IterationStatement<'ast>),
|
||||||
|
Log(LogStatement<'ast>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromPest, PartialEq, Clone)]
|
||||||
|
#[pest_ast(rule(Rule::log_statement))]
|
||||||
|
pub struct LogStatement<'ast> {
|
||||||
|
pub content: LogStatementContent<'ast>,
|
||||||
|
#[pest_ast(outer())]
|
||||||
|
pub span: Span<'ast>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, FromPest, PartialEq, Clone)]
|
||||||
|
#[pest_ast(rule(Rule::log_statement_content))]
|
||||||
|
pub struct LogStatementContent<'ast> {
|
||||||
|
#[pest_ast(outer(with(span_into_str)))]
|
||||||
|
pub inner: String,
|
||||||
|
#[pest_ast(outer())]
|
||||||
|
pub span: Span<'ast>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, FromPest, PartialEq, Clone)]
|
#[derive(Debug, FromPest, PartialEq, Clone)]
|
||||||
|
|
|
@ -164,7 +164,7 @@ fn compile_and_run<T: Field>(t: Tests) {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let output = interpreter.execute(bin.clone(), &input);
|
let output = interpreter.execute(bin.clone(), &input, &mut std::io::sink());
|
||||||
|
|
||||||
use zokrates_abi::Decode;
|
use zokrates_abi::Decode;
|
||||||
let output: Result<Output, ir::Error> = output.map(|witness| Output {
|
let output: Result<Output, ir::Error> = output.map(|witness| Output {
|
||||||
|
|
Loading…
Reference in a new issue