make typed ast string free. wip
This commit is contained in:
parent
1be802c1d8
commit
8ba7611aa0
13 changed files with 835 additions and 748 deletions
|
@ -150,16 +150,14 @@ pub fn compile_aux<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(
|
|||
)?;
|
||||
|
||||
// check semantics
|
||||
let typed_ast = Checker::new()
|
||||
.check_program(program_ast)
|
||||
.map_err(|errors| {
|
||||
CompileErrors(
|
||||
errors
|
||||
.into_iter()
|
||||
.map(|e| CompileErrorInner::from(e).with_context(&location))
|
||||
.collect(),
|
||||
)
|
||||
})?;
|
||||
let typed_ast = Checker::check(program_ast).map_err(|errors| {
|
||||
CompileErrors(
|
||||
errors
|
||||
.into_iter()
|
||||
.map(|e| CompileErrorInner::from(e).with_context(&location))
|
||||
.collect(),
|
||||
)
|
||||
})?;
|
||||
|
||||
// analyse (unroll and constant propagation)
|
||||
let typed_ast = typed_ast.analyse();
|
||||
|
|
|
@ -17,13 +17,13 @@ use zokrates_field::field::Field;
|
|||
|
||||
/// Flattener, computes flattened program.
|
||||
#[derive(Debug)]
|
||||
pub struct Flattener {
|
||||
pub struct Flattener<'ast> {
|
||||
/// Index of the next introduced variable while processing the program.
|
||||
next_var_idx: usize,
|
||||
///
|
||||
bijection: BiMap<String, FlatVariable>,
|
||||
bijection: BiMap<Identifier<'ast>, FlatVariable>,
|
||||
}
|
||||
impl Flattener {
|
||||
impl<'ast> Flattener<'ast> {
|
||||
pub fn flatten<T: Field>(p: TypedProg<T>) -> FlatProg<T> {
|
||||
Flattener::new().flatten_program(p)
|
||||
}
|
||||
|
@ -34,78 +34,78 @@ impl Flattener {
|
|||
///
|
||||
/// * `bits` - Number of bits needed to represent the maximum value.
|
||||
|
||||
fn new() -> Flattener {
|
||||
fn new() -> Flattener<'ast> {
|
||||
Flattener {
|
||||
next_var_idx: 0,
|
||||
bijection: BiMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Loads the code library
|
||||
fn load_corelib<T: Field>(&mut self, functions_flattened: &mut Vec<FlatFunction<T>>) -> () {
|
||||
// Load type casting functions
|
||||
functions_flattened.push(cast(&Type::Boolean, &Type::FieldElement));
|
||||
// /// Loads the code library
|
||||
// fn load_corelib<T: Field>(&mut self, functions_flattened: &mut Vec<FlatFunction<T>>) -> () {
|
||||
// // Load type casting functions
|
||||
// functions_flattened.push(cast(&Type::Boolean, &Type::FieldElement));
|
||||
|
||||
// Load IfElse helper
|
||||
let ie = TypedFunction {
|
||||
id: "_if_else_field".to_string(),
|
||||
arguments: vec![
|
||||
Parameter {
|
||||
id: Variable {
|
||||
id: "condition".to_string(),
|
||||
_type: Type::Boolean,
|
||||
},
|
||||
private: true,
|
||||
},
|
||||
Parameter {
|
||||
id: Variable {
|
||||
id: "consequence".to_string(),
|
||||
_type: Type::FieldElement,
|
||||
},
|
||||
private: true,
|
||||
},
|
||||
Parameter {
|
||||
id: Variable {
|
||||
id: "alternative".to_string(),
|
||||
_type: Type::FieldElement,
|
||||
},
|
||||
private: true,
|
||||
},
|
||||
],
|
||||
statements: vec![
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(Variable::field_element("condition_as_field")),
|
||||
FieldElementExpression::FunctionCall(
|
||||
"_bool_to_field".to_string(),
|
||||
vec![BooleanExpression::Identifier("condition".to_string()).into()],
|
||||
)
|
||||
.into(),
|
||||
),
|
||||
TypedStatement::Return(vec![FieldElementExpression::Add(
|
||||
box FieldElementExpression::Mult(
|
||||
box FieldElementExpression::Identifier("condition_as_field".to_string()),
|
||||
box FieldElementExpression::Identifier("consequence".to_string()),
|
||||
),
|
||||
box FieldElementExpression::Mult(
|
||||
box FieldElementExpression::Sub(
|
||||
box FieldElementExpression::Number(T::one()),
|
||||
box FieldElementExpression::Identifier(
|
||||
"condition_as_field".to_string(),
|
||||
),
|
||||
),
|
||||
box FieldElementExpression::Identifier("alternative".to_string()),
|
||||
),
|
||||
)
|
||||
.into()]),
|
||||
],
|
||||
signature: Signature::new()
|
||||
.inputs(vec![Type::Boolean, Type::FieldElement, Type::FieldElement])
|
||||
.outputs(vec![Type::FieldElement]),
|
||||
};
|
||||
// // Load IfElse helper
|
||||
// let ie = TypedFunction {
|
||||
// id: "_if_else_field".to_string(),
|
||||
// arguments: vec![
|
||||
// Parameter {
|
||||
// id: Variable {
|
||||
// id: "condition".to_string(),
|
||||
// _type: Type::Boolean,
|
||||
// },
|
||||
// private: true,
|
||||
// },
|
||||
// Parameter {
|
||||
// id: Variable {
|
||||
// id: "consequence".to_string(),
|
||||
// _type: Type::FieldElement,
|
||||
// },
|
||||
// private: true,
|
||||
// },
|
||||
// Parameter {
|
||||
// id: Variable {
|
||||
// id: "alternative".to_string(),
|
||||
// _type: Type::FieldElement,
|
||||
// },
|
||||
// private: true,
|
||||
// },
|
||||
// ],
|
||||
// statements: vec![
|
||||
// TypedStatement::Definition(
|
||||
// TypedAssignee::Identifier(Variable::field_element("condition_as_field")),
|
||||
// FieldElementExpression::FunctionCall(
|
||||
// "_bool_to_field".to_string(),
|
||||
// vec![BooleanExpression::Identifier("condition".to_string()).into()],
|
||||
// )
|
||||
// .into(),
|
||||
// ),
|
||||
// TypedStatement::Return(vec![FieldElementExpression::Add(
|
||||
// box FieldElementExpression::Mult(
|
||||
// box FieldElementExpression::Identifier("condition_as_field".to_string()),
|
||||
// box FieldElementExpression::Identifier("consequence".to_string()),
|
||||
// ),
|
||||
// box FieldElementExpression::Mult(
|
||||
// box FieldElementExpression::Sub(
|
||||
// box FieldElementExpression::Number(T::one()),
|
||||
// box FieldElementExpression::Identifier(
|
||||
// "condition_as_field".to_string(),
|
||||
// ),
|
||||
// ),
|
||||
// box FieldElementExpression::Identifier("alternative".to_string()),
|
||||
// ),
|
||||
// )
|
||||
// .into()]),
|
||||
// ],
|
||||
// signature: Signature::new()
|
||||
// .inputs(vec![Type::Boolean, Type::FieldElement, Type::FieldElement])
|
||||
// .outputs(vec![Type::FieldElement]),
|
||||
// };
|
||||
|
||||
let ief = self.flatten_function(functions_flattened, ie);
|
||||
functions_flattened.push(ief);
|
||||
}
|
||||
// let ief = self.flatten_function(functions_flattened, ie);
|
||||
// functions_flattened.push(ief);
|
||||
// }
|
||||
|
||||
/// Flattens a boolean expression
|
||||
///
|
||||
|
@ -122,7 +122,7 @@ impl Flattener {
|
|||
&mut self,
|
||||
functions_flattened: &Vec<FlatFunction<T>>,
|
||||
statements_flattened: &mut Vec<FlatStatement<T>>,
|
||||
expression: BooleanExpression<T>,
|
||||
expression: BooleanExpression<'ast, T>,
|
||||
) -> FlatExpression<T> {
|
||||
// those will be booleans in the future
|
||||
match expression {
|
||||
|
@ -407,7 +407,7 @@ impl Flattener {
|
|||
statements_flattened: &mut Vec<FlatStatement<T>>,
|
||||
id: &String,
|
||||
return_types: Vec<Type>,
|
||||
param_expressions: &Vec<TypedExpression<T>>,
|
||||
param_expressions: &Vec<TypedExpression<'ast, T>>,
|
||||
) -> FlatExpressionList<T> {
|
||||
let passed_signature = Signature::new()
|
||||
.inputs(param_expressions.iter().map(|e| e.get_type()).collect())
|
||||
|
@ -509,7 +509,7 @@ impl Flattener {
|
|||
&mut self,
|
||||
functions_flattened: &Vec<FlatFunction<T>>,
|
||||
statements_flattened: &mut Vec<FlatStatement<T>>,
|
||||
expr: TypedExpression<T>,
|
||||
expr: TypedExpression<'ast, T>,
|
||||
) -> Vec<FlatExpression<T>> {
|
||||
match expr {
|
||||
TypedExpression::FieldElement(e) => {
|
||||
|
@ -528,7 +528,7 @@ impl Flattener {
|
|||
&mut self,
|
||||
functions_flattened: &Vec<FlatFunction<T>>,
|
||||
statements_flattened: &mut Vec<FlatStatement<T>>,
|
||||
expr: FieldElementExpression<T>,
|
||||
expr: FieldElementExpression<'ast, T>,
|
||||
) -> FlatExpression<T> {
|
||||
match expr {
|
||||
FieldElementExpression::Number(x) => FlatExpression::Number(x), // force to be a field element
|
||||
|
@ -724,10 +724,11 @@ impl Flattener {
|
|||
FieldElementExpression::Number(n) => match array {
|
||||
FieldElementArrayExpression::Identifier(size, id) => {
|
||||
assert!(n < T::from(size));
|
||||
FlatExpression::Identifier(
|
||||
self.get_latest_var_substitution(&format!("{}_c{}", id, n))
|
||||
.clone(),
|
||||
)
|
||||
unimplemented!()
|
||||
// FlatExpression::Identifier(
|
||||
// self.get_latest_var_substitution(&format!("{}_c{}", id, n))
|
||||
// .clone(),
|
||||
// )
|
||||
}
|
||||
FieldElementArrayExpression::Value(size, expressions) => {
|
||||
assert!(n < T::from(size));
|
||||
|
@ -804,10 +805,11 @@ impl Flattener {
|
|||
),
|
||||
box match array.clone() {
|
||||
FieldElementArrayExpression::Identifier(_, id) => {
|
||||
FieldElementExpression::Identifier(format!(
|
||||
"{}_c{}",
|
||||
id, i
|
||||
))
|
||||
unimplemented!()
|
||||
// FieldElementExpression::Identifier(format!(
|
||||
// "{}_c{}",
|
||||
// id, i
|
||||
// ))
|
||||
}
|
||||
FieldElementArrayExpression::Value(size, expressions) => {
|
||||
assert_eq!(size, expressions.len());
|
||||
|
@ -856,17 +858,20 @@ impl Flattener {
|
|||
&mut self,
|
||||
functions_flattened: &Vec<FlatFunction<T>>,
|
||||
statements_flattened: &mut Vec<FlatStatement<T>>,
|
||||
expr: FieldElementArrayExpression<T>,
|
||||
expr: FieldElementArrayExpression<'ast, T>,
|
||||
) -> Vec<FlatExpression<T>> {
|
||||
match expr {
|
||||
FieldElementArrayExpression::Identifier(size, x) => (0..size)
|
||||
.map(|index| {
|
||||
FlatExpression::Identifier(
|
||||
self.get_latest_var_substitution(&format!("{}_c{}", x, index))
|
||||
.clone(),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
FieldElementArrayExpression::Identifier(size, x) => {
|
||||
unimplemented!()
|
||||
// (0..size)
|
||||
// .map(|index| {
|
||||
// FlatExpression::Identifier(
|
||||
// self.get_latest_var_substitution(&format!("{}_c{}", x, index))
|
||||
// .clone(),
|
||||
// )
|
||||
// })
|
||||
// .collect()
|
||||
}
|
||||
FieldElementArrayExpression::Value(size, values) => {
|
||||
assert_eq!(size, values.len());
|
||||
values
|
||||
|
@ -923,7 +928,7 @@ impl Flattener {
|
|||
&mut self,
|
||||
functions_flattened: &Vec<FlatFunction<T>>,
|
||||
statements_flattened: &mut Vec<FlatStatement<T>>,
|
||||
stat: TypedStatement<T>,
|
||||
stat: TypedStatement<'ast, T>,
|
||||
) {
|
||||
match stat {
|
||||
TypedStatement::Return(exprs) => {
|
||||
|
@ -971,12 +976,13 @@ impl Flattener {
|
|||
match index {
|
||||
box FieldElementExpression::Number(n) => match array {
|
||||
box TypedAssignee::Identifier(id) => {
|
||||
let debug_name = format!("{}_c{}", id.id, n);
|
||||
let var = self.use_variable(&debug_name);
|
||||
statements_flattened.push(FlatStatement::Definition(
|
||||
var,
|
||||
rhs[0].clone(),
|
||||
));
|
||||
unimplemented!()
|
||||
// let debug_name = format!("{}_c{}", id.id, n);
|
||||
// let var = self.use_variable(&debug_name);
|
||||
// statements_flattened.push(FlatStatement::Definition(
|
||||
// var,
|
||||
// rhs[0].clone(),
|
||||
// ));
|
||||
}
|
||||
_ => panic!("no multidimension array for now"),
|
||||
},
|
||||
|
@ -1037,13 +1043,15 @@ impl Flattener {
|
|||
rhs,
|
||||
);
|
||||
|
||||
let var =
|
||||
self.use_variable(&format!("{}_c{}", array, i));
|
||||
unimplemented!()
|
||||
|
||||
statements_flattened.push(FlatStatement::Definition(
|
||||
var,
|
||||
rhs_flattened,
|
||||
));
|
||||
// let var =
|
||||
// self.use_variable(&format!("{}_c{}", array, i));
|
||||
|
||||
// statements_flattened.push(FlatStatement::Definition(
|
||||
// var,
|
||||
// rhs_flattened,
|
||||
// ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1056,8 +1064,10 @@ impl Flattener {
|
|||
TypedAssignee::Identifier(ref v) => format!("{}_c{}", v.id, index),
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
let var = self.use_variable(&debug_name);
|
||||
statements_flattened.push(FlatStatement::Definition(var, r));
|
||||
unimplemented!()
|
||||
|
||||
// let var = self.use_variable(&debug_name);
|
||||
// statements_flattened.push(FlatStatement::Definition(var, r));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1185,12 +1195,13 @@ impl Flattener {
|
|||
match v.get_type() {
|
||||
Type::FieldElementArray(size) => {
|
||||
for index in 0..size {
|
||||
let debug_name = format!("{}_c{}", v.id, index);
|
||||
let var = self.use_variable(&debug_name);
|
||||
statements_flattened.push(FlatStatement::Definition(
|
||||
var,
|
||||
iterator.next().unwrap(),
|
||||
));
|
||||
unimplemented!()
|
||||
// let debug_name = format!("{}_c{}", v.id, index);
|
||||
// let var = self.use_variable(&debug_name);
|
||||
// statements_flattened.push(FlatStatement::Definition(
|
||||
// var,
|
||||
// iterator.next().unwrap(),
|
||||
// ));
|
||||
}
|
||||
}
|
||||
Type::Boolean | Type::FieldElement => {
|
||||
|
@ -1221,7 +1232,7 @@ impl Flattener {
|
|||
fn flatten_function<T: Field>(
|
||||
&mut self,
|
||||
functions_flattened: &mut Vec<FlatFunction<T>>,
|
||||
funct: TypedFunction<T>,
|
||||
funct: TypedFunction<'ast, T>,
|
||||
) -> FlatFunction<T> {
|
||||
self.bijection = BiMap::new();
|
||||
|
||||
|
@ -1249,10 +1260,11 @@ impl Flattener {
|
|||
}
|
||||
Type::FieldElementArray(size) => {
|
||||
for i in 0..size {
|
||||
arguments_flattened.push(FlatParameter {
|
||||
id: self.use_variable(&format!("{}_c{}", arg.id.id, i)),
|
||||
private: arg.private,
|
||||
})
|
||||
unimplemented!()
|
||||
// arguments_flattened.push(FlatParameter {
|
||||
// id: self.use_variable(&format!("{}_c{}", arg.id.id, i)),
|
||||
// private: arg.private,
|
||||
// })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1276,10 +1288,10 @@ impl Flattener {
|
|||
/// # Arguments
|
||||
///
|
||||
/// * `prog` - `Prog`ram that will be flattened.
|
||||
fn flatten_program<T: Field>(&mut self, prog: TypedProg<T>) -> FlatProg<T> {
|
||||
fn flatten_program<T: Field>(&mut self, prog: TypedProg<'ast, T>) -> FlatProg<T> {
|
||||
let mut functions_flattened = Vec::new();
|
||||
|
||||
self.load_corelib(&mut functions_flattened);
|
||||
//self.load_corelib(&mut functions_flattened);
|
||||
|
||||
for func in prog.imported_functions {
|
||||
functions_flattened.push(func);
|
||||
|
@ -1299,11 +1311,11 @@ impl Flattener {
|
|||
/// # Arguments
|
||||
///
|
||||
/// * `name` - a String that holds the name of the variable
|
||||
fn use_variable(&mut self, name: &String) -> FlatVariable {
|
||||
fn use_variable(&mut self, name: &Identifier<'ast>) -> FlatVariable {
|
||||
// issue the variable we'll use
|
||||
let var = self.issue_new_variable();
|
||||
|
||||
self.bijection.insert(name.to_string(), var);
|
||||
self.bijection.insert(*name, var);
|
||||
var
|
||||
}
|
||||
|
||||
|
@ -1314,13 +1326,14 @@ impl Flattener {
|
|||
}
|
||||
|
||||
fn use_sym(&mut self) -> FlatVariable {
|
||||
let name = format!("sym_{}", self.next_var_idx);
|
||||
let var = self.issue_new_variable();
|
||||
self.bijection.insert(name, var);
|
||||
var
|
||||
unimplemented!()
|
||||
// let name = format!("sym_{}", self.next_var_idx);
|
||||
// let var = self.issue_new_variable();
|
||||
// self.bijection.insert(&name, var);
|
||||
// var
|
||||
}
|
||||
|
||||
fn get_latest_var_substitution(&mut self, name: &String) -> FlatVariable {
|
||||
fn get_latest_var_substitution(&mut self, name: &Identifier<'ast>) -> FlatVariable {
|
||||
// start with the variable name
|
||||
self.bijection.get_by_left(name).unwrap().clone()
|
||||
}
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
//! @date 2017
|
||||
|
||||
use crate::absy::variable::Variable;
|
||||
use crate::absy::Identifier;
|
||||
use crate::absy::*;
|
||||
use crate::typed_absy::*;
|
||||
use crate::types::Signature;
|
||||
use absy::Identifier;
|
||||
use std::collections::HashSet;
|
||||
use std::fmt;
|
||||
use zokrates_field::field::Field;
|
||||
|
@ -99,7 +99,6 @@ impl<'ast> FunctionQuery<'ast> {
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
||||
pub struct ScopedVariable<'ast> {
|
||||
id: Variable<'ast>,
|
||||
level: usize,
|
||||
|
@ -120,7 +119,7 @@ impl<'ast> Eq for ScopedVariable<'ast> {}
|
|||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct FunctionDeclaration {
|
||||
id: String,
|
||||
id: String, // we use strings here as flat functions are still using strings
|
||||
signature: Signature,
|
||||
}
|
||||
|
||||
|
@ -132,21 +131,27 @@ pub struct Checker<'ast> {
|
|||
}
|
||||
|
||||
impl<'ast> Checker<'ast> {
|
||||
pub fn new() -> Checker<'ast> {
|
||||
fn new() -> Checker<'ast> {
|
||||
let scope = HashSet::new();
|
||||
|
||||
Checker {
|
||||
scope: HashSet::new(),
|
||||
scope: scope,
|
||||
functions: HashSet::new(),
|
||||
level: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_program<T: 'ast + Field>(
|
||||
pub fn check<T: Field>(prog: Prog<'ast, T>) -> Result<TypedProg<'ast, T>, Vec<Error>> {
|
||||
Checker::new().check_program(prog)
|
||||
}
|
||||
|
||||
fn check_program<T: Field>(
|
||||
&mut self,
|
||||
prog: Prog<'ast, T>,
|
||||
) -> Result<TypedProg<T>, Vec<Error>> {
|
||||
) -> Result<TypedProg<'ast, T>, Vec<Error>> {
|
||||
for func in &prog.imported_functions {
|
||||
self.functions.insert(FunctionDeclaration {
|
||||
id: func.id.to_string(),
|
||||
id: func.id.to_string(), // we use strings here as flat absy is still string based
|
||||
signature: func.signature.clone(),
|
||||
});
|
||||
}
|
||||
|
@ -217,7 +222,7 @@ impl<'ast> Checker<'ast> {
|
|||
fn check_function<T: Field>(
|
||||
&mut self,
|
||||
funct_node: FunctionNode<'ast, T>,
|
||||
) -> Result<TypedFunction<T>, Vec<Error>> {
|
||||
) -> Result<TypedFunction<'ast, T>, Vec<Error>> {
|
||||
let mut errors = vec![];
|
||||
let pos = funct_node.pos();
|
||||
let funct = funct_node.value;
|
||||
|
@ -225,7 +230,7 @@ impl<'ast> Checker<'ast> {
|
|||
assert_eq!(funct.arguments.len(), funct.signature.inputs.len());
|
||||
|
||||
let query = FunctionQuery::new(
|
||||
funct.id.clone(),
|
||||
funct.id,
|
||||
&funct.signature.inputs,
|
||||
&funct
|
||||
.signature
|
||||
|
@ -252,13 +257,13 @@ impl<'ast> Checker<'ast> {
|
|||
_ => panic!("duplicate function declaration should have been caught"),
|
||||
}
|
||||
|
||||
for arg in funct.arguments.clone() {
|
||||
self.insert_scope(arg.value.id.value);
|
||||
for arg in &funct.arguments {
|
||||
self.insert_scope(arg.value.id.value.clone());
|
||||
}
|
||||
|
||||
let mut statements_checked = vec![];
|
||||
|
||||
for stat in funct.statements.iter() {
|
||||
for stat in funct.statements.into_iter() {
|
||||
match self.check_statement(stat, &funct.signature.outputs) {
|
||||
Ok(statement) => {
|
||||
statements_checked.push(statement);
|
||||
|
@ -287,14 +292,16 @@ impl<'ast> Checker<'ast> {
|
|||
|
||||
fn check_statement<T: Field>(
|
||||
&mut self,
|
||||
stat: &StatementNode<'ast, T>,
|
||||
stat: StatementNode<'ast, T>,
|
||||
header_return_types: &Vec<Type>,
|
||||
) -> Result<TypedStatement<T>, Error> {
|
||||
) -> Result<TypedStatement<'ast, T>, Error> {
|
||||
let pos = stat.pos();
|
||||
|
||||
match stat.value {
|
||||
Statement::Return(ref list) => {
|
||||
let mut expression_list_checked = vec![];
|
||||
for e in list.value.expressions.clone() {
|
||||
let e_checked = self.check_expression(&e)?;
|
||||
let e_checked = self.check_expression(e)?;
|
||||
expression_list_checked.push(e_checked);
|
||||
}
|
||||
|
||||
|
@ -306,7 +313,7 @@ impl<'ast> Checker<'ast> {
|
|||
match return_statement_types == *header_return_types {
|
||||
true => Ok(TypedStatement::Return(expression_list_checked)),
|
||||
false => Err(Error {
|
||||
pos: Some(stat.pos()),
|
||||
pos: Some(pos),
|
||||
message: format!(
|
||||
"Expected ({}) in return statement, found ({})",
|
||||
header_return_types
|
||||
|
@ -326,11 +333,11 @@ impl<'ast> Checker<'ast> {
|
|||
Statement::Declaration(ref var) => match self.insert_scope(var.clone().value) {
|
||||
true => Ok(TypedStatement::Declaration(var.value.clone().into())),
|
||||
false => Err(Error {
|
||||
pos: Some(stat.pos()),
|
||||
pos: Some(pos),
|
||||
message: format!("Duplicate declaration for variable named {}", var.value.id),
|
||||
}),
|
||||
},
|
||||
Statement::Definition(ref assignee, ref expr) => {
|
||||
Statement::Definition(assignee, expr) => {
|
||||
// we create multidef when rhs is a function call to benefit from inference
|
||||
// check rhs is not a function call here
|
||||
match expr.value {
|
||||
|
@ -339,11 +346,11 @@ impl<'ast> Checker<'ast> {
|
|||
}
|
||||
|
||||
// check the expression to be assigned
|
||||
let checked_expr = self.check_expression(&expr)?;
|
||||
let checked_expr = self.check_expression(expr)?;
|
||||
let expression_type = checked_expr.get_type();
|
||||
|
||||
// check that the assignee is declared and is well formed
|
||||
let var = self.check_assignee(&assignee)?;
|
||||
let var = self.check_assignee(assignee)?;
|
||||
|
||||
let var_type = var.get_type();
|
||||
|
||||
|
@ -351,35 +358,35 @@ impl<'ast> Checker<'ast> {
|
|||
match var_type == expression_type {
|
||||
true => Ok(TypedStatement::Definition(var, checked_expr)),
|
||||
false => Err(Error {
|
||||
pos: Some(stat.pos()),
|
||||
pos: Some(pos),
|
||||
message: format!(
|
||||
"Expression {} of type {} cannot be assigned to {} of type {}",
|
||||
expr, expression_type, assignee, var_type
|
||||
checked_expr, expression_type, var, var_type
|
||||
),
|
||||
}),
|
||||
}
|
||||
}
|
||||
Statement::Condition(ref lhs, ref rhs) => {
|
||||
let checked_lhs = self.check_expression(&lhs)?;
|
||||
let checked_rhs = self.check_expression(&rhs)?;
|
||||
Statement::Condition(lhs, rhs) => {
|
||||
let checked_lhs = self.check_expression(lhs)?;
|
||||
let checked_rhs = self.check_expression(rhs)?;
|
||||
|
||||
match (checked_lhs.clone(), checked_rhs.clone()) {
|
||||
(ref r, ref l) if r.get_type() == l.get_type() => {
|
||||
Ok(TypedStatement::Condition(checked_lhs, checked_rhs))
|
||||
}
|
||||
(e1, e2) => Err(Error {
|
||||
pos: Some(stat.pos()),
|
||||
pos: Some(pos),
|
||||
message: format!(
|
||||
"Cannot compare {} of type {:?} to {} of type {:?}",
|
||||
lhs,
|
||||
checked_lhs,
|
||||
e1.get_type(),
|
||||
rhs,
|
||||
checked_rhs,
|
||||
e2.get_type(),
|
||||
),
|
||||
}),
|
||||
}
|
||||
}
|
||||
Statement::For(ref var, ref from, ref to, ref statements) => {
|
||||
Statement::For(var, from, to, statements) => {
|
||||
self.enter_scope();
|
||||
|
||||
self.check_for_var(&var)?;
|
||||
|
@ -401,23 +408,23 @@ impl<'ast> Checker<'ast> {
|
|||
checked_statements,
|
||||
))
|
||||
}
|
||||
Statement::MultipleDefinition(ref assignees, ref rhs) => {
|
||||
Statement::MultipleDefinition(assignees, rhs) => {
|
||||
match rhs.value {
|
||||
// Right side has to be a function call
|
||||
Expression::FunctionCall(ref fun_id, ref arguments) => {
|
||||
Expression::FunctionCall(fun_id, arguments) => {
|
||||
// find lhs types
|
||||
let mut vars_types: Vec<Option<Type>> = vec![];
|
||||
let mut var_names = vec![];
|
||||
for assignee in assignees {
|
||||
let (name, t) = match assignee.value {
|
||||
Assignee::Identifier(ref name) => {
|
||||
Assignee::Identifier(name) => {
|
||||
Ok((name, match self.get_scope(&name) {
|
||||
None => None,
|
||||
Some(sv) => Some(sv.id.get_type())
|
||||
}))
|
||||
}
|
||||
ref a => Err(Error {
|
||||
pos: Some(stat.pos()),
|
||||
pos: Some(pos),
|
||||
message: format!("Left hand side of function return assignment must be a list of identifiers, found {}", a)})
|
||||
}?;
|
||||
vars_types.push(t);
|
||||
|
@ -426,7 +433,7 @@ impl<'ast> Checker<'ast> {
|
|||
// find arguments types
|
||||
let mut arguments_checked = vec![];
|
||||
for arg in arguments {
|
||||
let arg_checked = self.check_expression(&arg)?;
|
||||
let arg_checked = self.check_expression(arg)?;
|
||||
arguments_checked.push(arg_checked);
|
||||
}
|
||||
|
||||
|
@ -434,32 +441,36 @@ impl<'ast> Checker<'ast> {
|
|||
arguments_checked.iter().map(|a| a.get_type()).collect();
|
||||
|
||||
let query = FunctionQuery::new(&fun_id, &arguments_types, &vars_types);
|
||||
let candidates = self.find_candidates(&query).clone();
|
||||
let candidates = self.find_candidates(&query);
|
||||
|
||||
match candidates.len() {
|
||||
// the function has to be defined
|
||||
1 => {
|
||||
let f = &candidates[0];
|
||||
|
||||
let lhs = var_names.iter().enumerate().map(|(index, name)|
|
||||
Variable::new(**name, f.signature.outputs[index].clone())
|
||||
);
|
||||
// we can infer the left hand side to be typed as the return values
|
||||
let lhs: Vec<_> = var_names.iter().enumerate().map(|(index, name)|
|
||||
Variable::new(*name, f.signature.outputs[index].clone())
|
||||
).collect();
|
||||
|
||||
// we can infer the left hand side to be typed as the return values
|
||||
for var in lhs.clone() {
|
||||
self.insert_scope(var);
|
||||
}
|
||||
let assignees: Vec<_> = lhs.iter().map(|v| v.clone().into()).collect();
|
||||
|
||||
Ok(TypedStatement::MultipleDefinition(lhs.map(|v| v.into()).collect(), TypedExpressionList::FunctionCall(f.id.to_string(), arguments_checked, f.signature.outputs.clone())))
|
||||
let call = TypedExpressionList::FunctionCall(f.id.to_string(), arguments_checked, f.signature.outputs.clone());
|
||||
|
||||
for var in lhs {
|
||||
self.insert_scope(var);
|
||||
}
|
||||
|
||||
Ok(TypedStatement::MultipleDefinition(assignees, call))
|
||||
},
|
||||
0 => Err(Error { pos: Some(stat.pos()),
|
||||
0 => Err(Error { pos: Some(pos),
|
||||
message: format!("Function definition for function {} with signature {} not found.", fun_id, query) }),
|
||||
_ => Err(Error { pos: Some(stat.pos()),
|
||||
_ => Err(Error { pos: Some(pos),
|
||||
message: format!("Function call for function {} with arguments {:?} is ambiguous.", fun_id, arguments_types) }),
|
||||
}
|
||||
}
|
||||
_ => Err(Error {
|
||||
pos: Some(stat.pos()),
|
||||
pos: Some(pos),
|
||||
message: format!("{} should be a FunctionCall", rhs),
|
||||
}),
|
||||
}
|
||||
|
@ -469,29 +480,35 @@ impl<'ast> Checker<'ast> {
|
|||
|
||||
fn check_assignee<T: Field>(
|
||||
&mut self,
|
||||
assignee: &AssigneeNode<T>,
|
||||
) -> Result<TypedAssignee<T>, Error> {
|
||||
assignee: AssigneeNode<'ast, T>,
|
||||
) -> Result<TypedAssignee<'ast, T>, Error> {
|
||||
let pos = assignee.pos();
|
||||
// check that the assignee is declared
|
||||
match assignee.value {
|
||||
Assignee::Identifier(ref variable_name) => match self.get_scope(&variable_name) {
|
||||
Some(var) => Ok(TypedAssignee::Identifier(var.id.clone().into())),
|
||||
Assignee::Identifier(variable_name) => match self.get_scope(&variable_name) {
|
||||
Some(var) => Ok(TypedAssignee::Identifier(
|
||||
crate::typed_absy::Variable::with_id_and_type(
|
||||
variable_name.into(),
|
||||
var.id.get_type(),
|
||||
),
|
||||
)),
|
||||
None => Err(Error {
|
||||
pos: Some(assignee.pos()),
|
||||
message: format!("Undeclared variable: {:?}", variable_name),
|
||||
}),
|
||||
},
|
||||
Assignee::ArrayElement(ref assignee, ref index) => {
|
||||
let checked_assignee = self.check_assignee(&assignee)?;
|
||||
let checked_index = self.check_expression(&index)?;
|
||||
Assignee::ArrayElement(box assignee, box index) => {
|
||||
let checked_assignee = self.check_assignee(assignee)?;
|
||||
let checked_index = self.check_expression(index)?;
|
||||
|
||||
let checked_typed_index = match checked_index {
|
||||
TypedExpression::FieldElement(e) => Ok(e),
|
||||
e => Err(Error {
|
||||
pos: Some(assignee.pos()),
|
||||
pos: Some(pos),
|
||||
|
||||
message: format!(
|
||||
"Expected array {} index to have type field, found {}",
|
||||
assignee,
|
||||
checked_assignee,
|
||||
e.get_type()
|
||||
),
|
||||
}),
|
||||
|
@ -507,38 +524,39 @@ impl<'ast> Checker<'ast> {
|
|||
|
||||
fn check_expression<T: Field>(
|
||||
&mut self,
|
||||
expr: &ExpressionNode<T>,
|
||||
) -> Result<TypedExpression<T>, Error> {
|
||||
match &expr.value {
|
||||
&Expression::Identifier(ref name) => {
|
||||
expr: ExpressionNode<'ast, T>,
|
||||
) -> Result<TypedExpression<'ast, T>, Error> {
|
||||
let pos = expr.pos();
|
||||
|
||||
match expr.value {
|
||||
Expression::Identifier(name) => {
|
||||
// check that `id` is defined in the scope
|
||||
match self.get_scope(&name) {
|
||||
Some(v) => match v.id.get_type() {
|
||||
Type::Boolean => Ok(BooleanExpression::Identifier(name.to_string()).into()),
|
||||
Type::Boolean => Ok(BooleanExpression::Identifier(name.into()).into()),
|
||||
Type::FieldElement => {
|
||||
Ok(FieldElementExpression::Identifier(name.to_string()).into())
|
||||
Ok(FieldElementExpression::Identifier(name.into()).into())
|
||||
}
|
||||
Type::FieldElementArray(n) => {
|
||||
Ok(FieldElementArrayExpression::Identifier(n, name.to_string()).into())
|
||||
Ok(FieldElementArrayExpression::Identifier(n, name.into()).into())
|
||||
}
|
||||
},
|
||||
None => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
|
||||
pos: Some(pos),
|
||||
message: format!("Identifier is undefined"),
|
||||
}),
|
||||
}
|
||||
}
|
||||
&Expression::Add(ref e1, ref e2) => {
|
||||
let e1_checked = self.check_expression(&e1)?;
|
||||
let e2_checked = self.check_expression(&e2)?;
|
||||
Expression::Add(box e1, box e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(FieldElementExpression::Add(box e1, box e2).into())
|
||||
}
|
||||
(t1, t2) => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
pos: Some(pos),
|
||||
|
||||
message: format!(
|
||||
"Expected only field elements, found {:?}, {:?}",
|
||||
|
@ -548,16 +566,16 @@ impl<'ast> Checker<'ast> {
|
|||
}),
|
||||
}
|
||||
}
|
||||
&Expression::Sub(ref e1, ref e2) => {
|
||||
let e1_checked = self.check_expression(&e1)?;
|
||||
let e2_checked = self.check_expression(&e2)?;
|
||||
Expression::Sub(box e1, box e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(FieldElementExpression::Sub(box e1, box e2).into())
|
||||
}
|
||||
(t1, t2) => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
pos: Some(pos),
|
||||
|
||||
message: format!(
|
||||
"Expected only field elements, found {:?}, {:?}",
|
||||
|
@ -567,16 +585,16 @@ impl<'ast> Checker<'ast> {
|
|||
}),
|
||||
}
|
||||
}
|
||||
&Expression::Mult(ref e1, ref e2) => {
|
||||
let e1_checked = self.check_expression(&e1)?;
|
||||
let e2_checked = self.check_expression(&e2)?;
|
||||
Expression::Mult(box e1, box e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(FieldElementExpression::Mult(box e1, box e2).into())
|
||||
}
|
||||
(t1, t2) => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
pos: Some(pos),
|
||||
|
||||
message: format!(
|
||||
"Expected only field elements, found {:?}, {:?}",
|
||||
|
@ -586,16 +604,16 @@ impl<'ast> Checker<'ast> {
|
|||
}),
|
||||
}
|
||||
}
|
||||
&Expression::Div(ref e1, ref e2) => {
|
||||
let e1_checked = self.check_expression(&e1)?;
|
||||
let e2_checked = self.check_expression(&e2)?;
|
||||
Expression::Div(box e1, box e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(FieldElementExpression::Div(box e1, box e2).into())
|
||||
}
|
||||
(t1, t2) => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
pos: Some(pos),
|
||||
|
||||
message: format!(
|
||||
"Expected only field elements, found {:?}, {:?}",
|
||||
|
@ -605,16 +623,16 @@ impl<'ast> Checker<'ast> {
|
|||
}),
|
||||
}
|
||||
}
|
||||
&Expression::Pow(ref e1, ref e2) => {
|
||||
let e1_checked = self.check_expression(&e1)?;
|
||||
let e2_checked = self.check_expression(&e2)?;
|
||||
Expression::Pow(box e1, box e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => Ok(
|
||||
TypedExpression::FieldElement(FieldElementExpression::Pow(box e1, box e2)),
|
||||
),
|
||||
(t1, t2) => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
pos: Some(pos),
|
||||
|
||||
message: format!(
|
||||
"Expected only field elements, found {:?}, {:?}",
|
||||
|
@ -624,10 +642,10 @@ impl<'ast> Checker<'ast> {
|
|||
}),
|
||||
}
|
||||
}
|
||||
&Expression::IfElse(ref condition, ref consequence, ref alternative) => {
|
||||
let condition_checked = self.check_expression(&condition)?;
|
||||
let consequence_checked = self.check_expression(&consequence)?;
|
||||
let alternative_checked = self.check_expression(&alternative)?;
|
||||
Expression::IfElse(box condition, box consequence, box alternative) => {
|
||||
let condition_checked = self.check_expression(condition)?;
|
||||
let consequence_checked = self.check_expression(consequence)?;
|
||||
let alternative_checked = self.check_expression(alternative)?;
|
||||
|
||||
match condition_checked {
|
||||
TypedExpression::Boolean(condition) => {
|
||||
|
@ -644,13 +662,13 @@ impl<'ast> Checker<'ast> {
|
|||
_ => unimplemented!()
|
||||
}
|
||||
false => Err(Error {
|
||||
pos: Some(alternative.pos()),
|
||||
pos: Some(pos),
|
||||
message: format!("{{consequence}} and {{alternative}} in `if/else` expression should have the same type, found {}, {}", consequence_type, alternative_type)
|
||||
})
|
||||
}
|
||||
}
|
||||
c => Err(Error {
|
||||
pos: Some(condition.pos()),
|
||||
pos: Some(pos),
|
||||
message: format!(
|
||||
"{{condition}} after `if` should be a boolean, found {}",
|
||||
c.get_type()
|
||||
|
@ -658,12 +676,12 @@ impl<'ast> Checker<'ast> {
|
|||
}),
|
||||
}
|
||||
}
|
||||
&Expression::Number(ref n) => Ok(FieldElementExpression::Number(n.clone()).into()),
|
||||
&Expression::FunctionCall(ref fun_id, ref arguments) => {
|
||||
Expression::Number(ref n) => Ok(FieldElementExpression::Number(n.clone()).into()),
|
||||
Expression::FunctionCall(fun_id, arguments) => {
|
||||
// check the arguments
|
||||
let mut arguments_checked = vec![];
|
||||
for arg in arguments {
|
||||
let arg_checked = self.check_expression(&arg.clone())?;
|
||||
let arg_checked = self.check_expression(arg)?;
|
||||
arguments_checked.push(arg_checked);
|
||||
}
|
||||
|
||||
|
@ -701,7 +719,7 @@ impl<'ast> Checker<'ast> {
|
|||
_ => unimplemented!(),
|
||||
},
|
||||
n => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
pos: Some(pos),
|
||||
|
||||
message: format!(
|
||||
"{} returns {} values but is called outside of a definition",
|
||||
|
@ -711,7 +729,7 @@ impl<'ast> Checker<'ast> {
|
|||
}
|
||||
}
|
||||
0 => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
pos: Some(pos),
|
||||
|
||||
message: format!(
|
||||
"Function definition for function {} with signature {} not found.",
|
||||
|
@ -721,15 +739,15 @@ impl<'ast> Checker<'ast> {
|
|||
_ => panic!("duplicate definition should have been caught before the call"),
|
||||
}
|
||||
}
|
||||
&Expression::Lt(ref e1, ref e2) => {
|
||||
let e1_checked = self.check_expression(&e1)?;
|
||||
let e2_checked = self.check_expression(&e2)?;
|
||||
Expression::Lt(box e1, box e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(BooleanExpression::Lt(box e1, box e2).into())
|
||||
}
|
||||
(e1, e2) => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
pos: Some(pos),
|
||||
message: format!(
|
||||
"Cannot compare {} of type {} to {} of type {}",
|
||||
e1,
|
||||
|
@ -740,15 +758,15 @@ impl<'ast> Checker<'ast> {
|
|||
}),
|
||||
}
|
||||
}
|
||||
&Expression::Le(ref e1, ref e2) => {
|
||||
let e1_checked = self.check_expression(&e1)?;
|
||||
let e2_checked = self.check_expression(&e2)?;
|
||||
Expression::Le(box e1, box e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(BooleanExpression::Le(box e1, box e2).into())
|
||||
}
|
||||
(e1, e2) => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
pos: Some(pos),
|
||||
message: format!(
|
||||
"Cannot compare {} of type {} to {} of type {}",
|
||||
e1,
|
||||
|
@ -759,15 +777,15 @@ impl<'ast> Checker<'ast> {
|
|||
}),
|
||||
}
|
||||
}
|
||||
&Expression::Eq(ref e1, ref e2) => {
|
||||
let e1_checked = self.check_expression(&e1)?;
|
||||
let e2_checked = self.check_expression(&e2)?;
|
||||
Expression::Eq(box e1, box e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(BooleanExpression::Eq(box e1, box e2).into())
|
||||
}
|
||||
(e1, e2) => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
pos: Some(pos),
|
||||
message: format!(
|
||||
"Cannot compare {} of type {} to {} of type {}",
|
||||
e1,
|
||||
|
@ -778,15 +796,15 @@ impl<'ast> Checker<'ast> {
|
|||
}),
|
||||
}
|
||||
}
|
||||
&Expression::Ge(ref e1, ref e2) => {
|
||||
let e1_checked = self.check_expression(&e1)?;
|
||||
let e2_checked = self.check_expression(&e2)?;
|
||||
Expression::Ge(box e1, box e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(BooleanExpression::Ge(box e1, box e2).into())
|
||||
}
|
||||
(e1, e2) => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
pos: Some(pos),
|
||||
message: format!(
|
||||
"Cannot compare {} of type {} to {} of type {}",
|
||||
e1,
|
||||
|
@ -797,15 +815,15 @@ impl<'ast> Checker<'ast> {
|
|||
}),
|
||||
}
|
||||
}
|
||||
&Expression::Gt(ref e1, ref e2) => {
|
||||
let e1_checked = self.check_expression(&e1)?;
|
||||
let e2_checked = self.check_expression(&e2)?;
|
||||
Expression::Gt(box e1, box e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
|
||||
Ok(BooleanExpression::Gt(box e1, box e2).into())
|
||||
}
|
||||
(e1, e2) => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
pos: Some(pos),
|
||||
message: format!(
|
||||
"Cannot compare {} of type {} to {} of type {}",
|
||||
e1,
|
||||
|
@ -816,16 +834,16 @@ impl<'ast> Checker<'ast> {
|
|||
}),
|
||||
}
|
||||
}
|
||||
&Expression::Select(ref array, ref index) => {
|
||||
let array = self.check_expression(&array)?;
|
||||
let index = self.check_expression(&index)?;
|
||||
Expression::Select(box array, box index) => {
|
||||
let array = self.check_expression(array)?;
|
||||
let index = self.check_expression(index)?;
|
||||
match (array.clone(), index.clone()) {
|
||||
(
|
||||
TypedExpression::FieldElementArray(ref a),
|
||||
TypedExpression::FieldElement(ref i),
|
||||
) => Ok(FieldElementExpression::Select(box a.clone(), box i.clone()).into()),
|
||||
(a, e) => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
pos: Some(pos),
|
||||
message: format!(
|
||||
"Cannot access element {} on expression of type {}",
|
||||
e,
|
||||
|
@ -834,7 +852,7 @@ impl<'ast> Checker<'ast> {
|
|||
}),
|
||||
}
|
||||
}
|
||||
&Expression::InlineArray(ref expressions) => {
|
||||
Expression::InlineArray(expressions) => {
|
||||
// we should have at least one expression
|
||||
let size = expressions.len();
|
||||
assert!(size > 0);
|
||||
|
@ -856,7 +874,7 @@ impl<'ast> Checker<'ast> {
|
|||
let unwrapped_e = match e {
|
||||
TypedExpression::FieldElement(e) => Ok(e),
|
||||
e => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
pos: Some(pos),
|
||||
|
||||
message: format!(
|
||||
"Expected {} to have type {}, but type is {}",
|
||||
|
@ -872,7 +890,7 @@ impl<'ast> Checker<'ast> {
|
|||
Ok(FieldElementArrayExpression::Value(size, unwrapped_expressions).into())
|
||||
}
|
||||
_ => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
pos: Some(pos),
|
||||
|
||||
message: format!(
|
||||
"Only arrays of {} are supported, found {}",
|
||||
|
@ -882,15 +900,15 @@ impl<'ast> Checker<'ast> {
|
|||
}),
|
||||
}
|
||||
}
|
||||
&Expression::And(ref e1, ref e2) => {
|
||||
let e1_checked = self.check_expression(&e1)?;
|
||||
let e2_checked = self.check_expression(&e2)?;
|
||||
Expression::And(box e1, box e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::Boolean(e1), TypedExpression::Boolean(e2)) => {
|
||||
Ok(BooleanExpression::And(box e1, box e2).into())
|
||||
}
|
||||
(e1, e2) => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
pos: Some(pos),
|
||||
|
||||
message: format!(
|
||||
"cannot apply boolean operators to {} and {}",
|
||||
|
@ -900,26 +918,26 @@ impl<'ast> Checker<'ast> {
|
|||
}),
|
||||
}
|
||||
}
|
||||
&Expression::Or(ref e1, ref e2) => {
|
||||
let e1_checked = self.check_expression(&e1)?;
|
||||
let e2_checked = self.check_expression(&e2)?;
|
||||
Expression::Or(box e1, box e2) => {
|
||||
let e1_checked = self.check_expression(e1)?;
|
||||
let e2_checked = self.check_expression(e2)?;
|
||||
match (e1_checked, e2_checked) {
|
||||
(TypedExpression::Boolean(e1), TypedExpression::Boolean(e2)) => {
|
||||
Ok(BooleanExpression::Or(box e1, box e2).into())
|
||||
}
|
||||
(e1, e2) => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
pos: Some(pos),
|
||||
|
||||
message: format!("cannot compare {} to {}", e1.get_type(), e2.get_type()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
&Expression::Not(ref e) => {
|
||||
Expression::Not(box e) => {
|
||||
let e_checked = self.check_expression(e)?;
|
||||
match e_checked {
|
||||
TypedExpression::Boolean(e) => Ok(BooleanExpression::Not(box e).into()),
|
||||
e => Err(Error {
|
||||
pos: Some(expr.pos()),
|
||||
pos: Some(pos),
|
||||
|
||||
message: format!("cannot negate {}", e.get_type()),
|
||||
}),
|
||||
|
@ -928,7 +946,7 @@ impl<'ast> Checker<'ast> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_scope(&self, variable_name: &'ast str) -> Option<&ScopedVariable> {
|
||||
fn get_scope(&self, variable_name: &Identifier<'ast>) -> Option<&ScopedVariable> {
|
||||
self.scope.get(&ScopedVariable {
|
||||
id: Variable::new(variable_name.clone(), Type::FieldElement),
|
||||
level: 0,
|
||||
|
|
|
@ -21,8 +21,8 @@ impl DeadCode {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Folder<T> for DeadCode {
|
||||
fn fold_program(&mut self, p: TypedProg<T>) -> TypedProg<T> {
|
||||
impl<'ast, T: Field> Folder<'ast, T> for DeadCode {
|
||||
fn fold_program(&mut self, p: TypedProg<'ast, T>) -> TypedProg<'ast, T> {
|
||||
let p = fold_program(self, p);
|
||||
// only keep functions which are being called, or `main`
|
||||
|
||||
|
@ -37,7 +37,7 @@ impl<T: Field> Folder<T> for DeadCode {
|
|||
}
|
||||
|
||||
// add extra statements before the modified statement
|
||||
fn fold_statement(&mut self, s: TypedStatement<T>) -> Vec<TypedStatement<T>> {
|
||||
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
|
||||
match s {
|
||||
TypedStatement::MultipleDefinition(variables, elist) => match elist {
|
||||
TypedExpressionList::FunctionCall(id, exps, types) => {
|
||||
|
@ -59,7 +59,10 @@ impl<T: Field> Folder<T> for DeadCode {
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_field_expression(&mut self, e: FieldElementExpression<T>) -> FieldElementExpression<T> {
|
||||
fn fold_field_expression(
|
||||
&mut self,
|
||||
e: FieldElementExpression<'ast, T>,
|
||||
) -> FieldElementExpression<'ast, T> {
|
||||
match e {
|
||||
FieldElementExpression::FunctionCall(id, exps) => {
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
@ -78,8 +81,8 @@ impl<T: Field> Folder<T> for DeadCode {
|
|||
|
||||
fn fold_field_array_expression(
|
||||
&mut self,
|
||||
e: FieldElementArrayExpression<T>,
|
||||
) -> FieldElementArrayExpression<T> {
|
||||
e: FieldElementArrayExpression<'ast, T>,
|
||||
) -> FieldElementArrayExpression<'ast, T> {
|
||||
match e {
|
||||
FieldElementArrayExpression::FunctionCall(size, id, exps) => {
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
|
|
@ -1,326 +1,326 @@
|
|||
use crate::typed_absy::folder::*;
|
||||
use crate::typed_absy::Folder;
|
||||
use crate::typed_absy::*;
|
||||
use crate::types::{Signature, Type};
|
||||
use std::collections::HashMap;
|
||||
use zokrates_field::field::Field;
|
||||
// use crate::typed_absy::folder::*;
|
||||
// use crate::typed_absy::Folder;
|
||||
// use crate::typed_absy::*;
|
||||
// use crate::types::{Signature, Type};
|
||||
// use std::collections::HashMap;
|
||||
// use zokrates_field::field::Field;
|
||||
|
||||
pub struct Inliner<T: Field> {
|
||||
functions: Vec<TypedFunction<T>>,
|
||||
statements_buffer: Vec<TypedStatement<T>>,
|
||||
context: Vec<(String, usize)>,
|
||||
call_count: HashMap<String, usize>,
|
||||
}
|
||||
// pub struct Inliner<'ast, T: Field> {
|
||||
// functions: Vec<TypedFunction<'ast, T>>,
|
||||
// statements_buffer: Vec<TypedStatement<'ast, T>>,
|
||||
// context: Vec<(String, usize)>,
|
||||
// call_count: HashMap<String, usize>,
|
||||
// }
|
||||
|
||||
impl<T: Field> Inliner<T> {
|
||||
pub fn new() -> Self {
|
||||
Inliner {
|
||||
functions: vec![],
|
||||
statements_buffer: vec![],
|
||||
context: vec![],
|
||||
call_count: HashMap::new(),
|
||||
}
|
||||
}
|
||||
// impl<'ast, T: Field> Inliner<'ast, T> {
|
||||
// pub fn new() -> Self {
|
||||
// Inliner {
|
||||
// functions: vec![],
|
||||
// statements_buffer: vec![],
|
||||
// context: vec![],
|
||||
// call_count: HashMap::new(),
|
||||
// }
|
||||
// }
|
||||
|
||||
fn should_inline(
|
||||
&self,
|
||||
function: &Option<TypedFunction<T>>,
|
||||
arguments: &Vec<TypedExpression<T>>,
|
||||
) -> bool {
|
||||
// we should define a heuristic here
|
||||
// currently it doesn't seem like there's a tradeoff as everything gets inlined in flattening anyway (apart from compiling performance, as inlining
|
||||
// in flattening should be faster and less memory intensive)
|
||||
// however, using backends such as bellman, we could avoid flattening and "stream" the computation
|
||||
// at proving time, the tradeoff becomes code size (not inlining keeps only one copy of each function) vs optimisation
|
||||
// (inlining enables constant propagation through function calls, which cannot be achieved by our final optimiser in some cases)
|
||||
// for now, we inline functions whose non-array parameters are constant, as this covers our main use case for inlining: propagation of
|
||||
// constant array indices
|
||||
match function {
|
||||
Some(..) => {
|
||||
// check whether non-array arguments are constant
|
||||
arguments.iter().all(|e| match e {
|
||||
TypedExpression::FieldElementArray(..) => true,
|
||||
TypedExpression::FieldElement(FieldElementExpression::Number(..)) => true,
|
||||
TypedExpression::Boolean(BooleanExpression::Value(..)) => true,
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
// fn should_inline(
|
||||
// &self,
|
||||
// function: &Option<TypedFunction<T>>,
|
||||
// arguments: &Vec<TypedExpression<T>>,
|
||||
// ) -> bool {
|
||||
// // we should define a heuristic here
|
||||
// // currently it doesn't seem like there's a tradeoff as everything gets inlined in flattening anyway (apart from compiling performance, as inlining
|
||||
// // in flattening should be faster and less memory intensive)
|
||||
// // however, using backends such as bellman, we could avoid flattening and "stream" the computation
|
||||
// // at proving time, the tradeoff becomes code size (not inlining keeps only one copy of each function) vs optimisation
|
||||
// // (inlining enables constant propagation through function calls, which cannot be achieved by our final optimiser in some cases)
|
||||
// // for now, we inline functions whose non-array parameters are constant, as this covers our main use case for inlining: propagation of
|
||||
// // constant array indices
|
||||
// match function {
|
||||
// Some(..) => {
|
||||
// // check whether non-array arguments are constant
|
||||
// arguments.iter().all(|e| match e {
|
||||
// TypedExpression::FieldElementArray(..) => true,
|
||||
// TypedExpression::FieldElement(FieldElementExpression::Number(..)) => true,
|
||||
// TypedExpression::Boolean(BooleanExpression::Value(..)) => true,
|
||||
// _ => false,
|
||||
// })
|
||||
// }
|
||||
// None => false,
|
||||
// }
|
||||
// }
|
||||
|
||||
// inline a call to `function` taking `expressions` as inputs
|
||||
// this function mutates `self.call` by incrementing the counter for `function`, and mutates `self.context`
|
||||
fn inline_call(
|
||||
&mut self,
|
||||
function: &TypedFunction<T>,
|
||||
expressions: Vec<TypedExpression<T>>,
|
||||
) -> Vec<TypedExpression<T>> {
|
||||
self.call_count
|
||||
.entry(function.to_slug())
|
||||
.and_modify(|i| *i += 1)
|
||||
.or_insert(1);
|
||||
self.context.push((
|
||||
function.to_slug(),
|
||||
*self.call_count.get(&function.to_slug()).unwrap(),
|
||||
));
|
||||
// // inline a call to `function` taking `expressions` as inputs
|
||||
// // this function mutates `self.call` by incrementing the counter for `function`, and mutates `self.context`
|
||||
// fn inline_call(
|
||||
// &mut self,
|
||||
// function: &TypedFunction<T>,
|
||||
// expressions: Vec<TypedExpression<T>>,
|
||||
// ) -> Vec<TypedExpression<T>> {
|
||||
// self.call_count
|
||||
// .entry(function.to_slug())
|
||||
// .and_modify(|i| *i += 1)
|
||||
// .or_insert(1);
|
||||
// self.context.push((
|
||||
// function.to_slug(),
|
||||
// *self.call_count.get(&function.to_slug()).unwrap(),
|
||||
// ));
|
||||
|
||||
// add definitions for the inputs
|
||||
let mut inputs_bindings = function
|
||||
.arguments
|
||||
.iter()
|
||||
.zip(expressions)
|
||||
.map(|(a, e)| {
|
||||
TypedStatement::Definition(
|
||||
TypedAssignee::Identifier(self.fold_variable(a.id.clone())),
|
||||
e,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
self.statements_buffer.append(&mut inputs_bindings);
|
||||
// // add definitions for the inputs
|
||||
// let mut inputs_bindings = function
|
||||
// .arguments
|
||||
// .iter()
|
||||
// .zip(expressions)
|
||||
// .map(|(a, e)| {
|
||||
// TypedStatement::Definition(
|
||||
// TypedAssignee::Identifier(self.fold_variable(a.id.clone())),
|
||||
// e,
|
||||
// )
|
||||
// })
|
||||
// .collect();
|
||||
// self.statements_buffer.append(&mut inputs_bindings);
|
||||
|
||||
// filter out the return statement and keep it aside
|
||||
let (mut statements, ret): (Vec<_>, Vec<_>) = function
|
||||
.statements
|
||||
.clone()
|
||||
.into_iter()
|
||||
.flat_map(|s| self.fold_statement(s))
|
||||
.partition(|s| match s {
|
||||
TypedStatement::Return(..) => false,
|
||||
_ => true,
|
||||
});
|
||||
// // filter out the return statement and keep it aside
|
||||
// let (mut statements, ret): (Vec<_>, Vec<_>) = function
|
||||
// .statements
|
||||
// .clone()
|
||||
// .into_iter()
|
||||
// .flat_map(|s| self.fold_statement(s))
|
||||
// .partition(|s| match s {
|
||||
// TypedStatement::Return(..) => false,
|
||||
// _ => true,
|
||||
// });
|
||||
|
||||
// add all statements to the buffer
|
||||
self.statements_buffer.append(&mut statements);
|
||||
// // add all statements to the buffer
|
||||
// self.statements_buffer.append(&mut statements);
|
||||
|
||||
// remove this call from the context
|
||||
self.context.pop();
|
||||
// // remove this call from the context
|
||||
// self.context.pop();
|
||||
|
||||
match ret[0].clone() {
|
||||
TypedStatement::Return(exprs) => exprs,
|
||||
_ => panic!(""),
|
||||
}
|
||||
}
|
||||
// match ret[0].clone() {
|
||||
// TypedStatement::Return(exprs) => exprs,
|
||||
// _ => panic!(""),
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn inline(prog: TypedProg<T>) -> TypedProg<T> {
|
||||
Inliner::new().fold_program(prog)
|
||||
}
|
||||
}
|
||||
// pub fn inline(prog: TypedProg<T>) -> TypedProg<T> {
|
||||
// Inliner::new().fold_program(prog)
|
||||
// }
|
||||
// }
|
||||
|
||||
impl<T: Field> Folder<T> for Inliner<T> {
|
||||
// store the list of functions
|
||||
fn fold_program(&mut self, p: TypedProg<T>) -> TypedProg<T> {
|
||||
self.functions = p.functions.clone();
|
||||
fold_program(self, p)
|
||||
}
|
||||
// impl<T: Field> Folder<T> for Inliner<T> {
|
||||
// // store the list of functions
|
||||
// fn fold_program(&mut self, p: TypedProg<T>) -> TypedProg<T> {
|
||||
// self.functions = p.functions.clone();
|
||||
// fold_program(self, p)
|
||||
// }
|
||||
|
||||
// add extra statements before the modified statement
|
||||
fn fold_statement(&mut self, s: TypedStatement<T>) -> Vec<TypedStatement<T>> {
|
||||
let mut statements = match s {
|
||||
TypedStatement::MultipleDefinition(variables, elist) => {
|
||||
match elist {
|
||||
TypedExpressionList::FunctionCall(id, exps, types) => {
|
||||
let variables: Vec<_> = variables
|
||||
.into_iter()
|
||||
.map(|a| self.fold_variable(a))
|
||||
.collect();
|
||||
let exps: Vec<_> =
|
||||
exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
// // add extra statements before the modified statement
|
||||
// fn fold_statement(&mut self, s: TypedStatement<T>) -> Vec<TypedStatement<T>> {
|
||||
// let mut statements = match s {
|
||||
// TypedStatement::MultipleDefinition(variables, elist) => {
|
||||
// match elist {
|
||||
// TypedExpressionList::FunctionCall(id, exps, types) => {
|
||||
// let variables: Vec<_> = variables
|
||||
// .into_iter()
|
||||
// .map(|a| self.fold_variable(a))
|
||||
// .collect();
|
||||
// let exps: Vec<_> =
|
||||
// exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
||||
let passed_signature = Signature::new()
|
||||
.inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
.outputs(types.clone());
|
||||
// let passed_signature = Signature::new()
|
||||
// .inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
// .outputs(types.clone());
|
||||
|
||||
// find the function
|
||||
let function = self
|
||||
.functions
|
||||
.iter()
|
||||
.find(|f| f.id == id && f.signature == passed_signature)
|
||||
.cloned();
|
||||
// // find the function
|
||||
// let function = self
|
||||
// .functions
|
||||
// .iter()
|
||||
// .find(|f| f.id == id && f.signature == passed_signature)
|
||||
// .cloned();
|
||||
|
||||
match self.should_inline(&function, &exps) {
|
||||
true => {
|
||||
let ret = self.inline_call(&function.unwrap(), exps);
|
||||
variables
|
||||
.into_iter()
|
||||
.zip(ret.into_iter())
|
||||
.map(|(v, e)| {
|
||||
TypedStatement::Definition(TypedAssignee::Identifier(v), e)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
false => vec![TypedStatement::MultipleDefinition(
|
||||
variables,
|
||||
TypedExpressionList::FunctionCall(id, exps, types),
|
||||
)],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
s => fold_statement(self, s),
|
||||
};
|
||||
// match self.should_inline(&function, &exps) {
|
||||
// true => {
|
||||
// let ret = self.inline_call(&function.unwrap(), exps);
|
||||
// variables
|
||||
// .into_iter()
|
||||
// .zip(ret.into_iter())
|
||||
// .map(|(v, e)| {
|
||||
// TypedStatement::Definition(TypedAssignee::Identifier(v), e)
|
||||
// })
|
||||
// .collect()
|
||||
// }
|
||||
// false => vec![TypedStatement::MultipleDefinition(
|
||||
// variables,
|
||||
// TypedExpressionList::FunctionCall(id, exps, types),
|
||||
// )],
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// s => fold_statement(self, s),
|
||||
// };
|
||||
|
||||
// add the result of folding to the buffer
|
||||
self.statements_buffer.append(&mut statements);
|
||||
// return the whole buffer
|
||||
self.statements_buffer.drain(..).collect()
|
||||
}
|
||||
// // add the result of folding to the buffer
|
||||
// self.statements_buffer.append(&mut statements);
|
||||
// // return the whole buffer
|
||||
// self.statements_buffer.drain(..).collect()
|
||||
// }
|
||||
|
||||
// prefix all names with the context
|
||||
fn fold_name(&mut self, n: String) -> String {
|
||||
match self.context.len() {
|
||||
0 => n,
|
||||
_ => format!(
|
||||
"{}_{}",
|
||||
self.context
|
||||
.iter()
|
||||
.map(|(s, i)| format!("{}_{}", s, i))
|
||||
.collect::<Vec<_>>()
|
||||
.join("_"),
|
||||
n
|
||||
),
|
||||
}
|
||||
}
|
||||
// // prefix all names with the context
|
||||
// fn fold_name(&mut self, n: String) -> String {
|
||||
// match self.context.len() {
|
||||
// 0 => n,
|
||||
// _ => format!(
|
||||
// "{}_{}",
|
||||
// self.context
|
||||
// .iter()
|
||||
// .map(|(s, i)| format!("{}_{}", s, i))
|
||||
// .collect::<Vec<_>>()
|
||||
// .join("_"),
|
||||
// n
|
||||
// ),
|
||||
// }
|
||||
// }
|
||||
|
||||
// inline calls which return a field element
|
||||
fn fold_field_expression(&mut self, e: FieldElementExpression<T>) -> FieldElementExpression<T> {
|
||||
match e {
|
||||
FieldElementExpression::FunctionCall(id, exps) => {
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
// // inline calls which return a field element
|
||||
// fn fold_field_expression(&mut self, e: FieldElementExpression<T>) -> FieldElementExpression<T> {
|
||||
// match e {
|
||||
// FieldElementExpression::FunctionCall(id, exps) => {
|
||||
// let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
||||
let passed_signature = Signature::new()
|
||||
.inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
.outputs(vec![Type::FieldElement]);
|
||||
// let passed_signature = Signature::new()
|
||||
// .inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
// .outputs(vec![Type::FieldElement]);
|
||||
|
||||
// find the function
|
||||
let function = self
|
||||
.functions
|
||||
.iter()
|
||||
.find(|f| f.id == id && f.signature == passed_signature)
|
||||
.cloned();
|
||||
// // find the function
|
||||
// let function = self
|
||||
// .functions
|
||||
// .iter()
|
||||
// .find(|f| f.id == id && f.signature == passed_signature)
|
||||
// .cloned();
|
||||
|
||||
match self.should_inline(&function, &exps) {
|
||||
true => {
|
||||
let ret = self.inline_call(&function.unwrap(), exps);
|
||||
// unwrap the result to return a field element
|
||||
match ret[0].clone() {
|
||||
TypedExpression::FieldElement(e) => e,
|
||||
_ => panic!(""),
|
||||
}
|
||||
}
|
||||
false => FieldElementExpression::FunctionCall(id, exps),
|
||||
}
|
||||
}
|
||||
// default
|
||||
e => fold_field_expression(self, e),
|
||||
}
|
||||
}
|
||||
// match self.should_inline(&function, &exps) {
|
||||
// true => {
|
||||
// let ret = self.inline_call(&function.unwrap(), exps);
|
||||
// // unwrap the result to return a field element
|
||||
// match ret[0].clone() {
|
||||
// TypedExpression::FieldElement(e) => e,
|
||||
// _ => panic!(""),
|
||||
// }
|
||||
// }
|
||||
// false => FieldElementExpression::FunctionCall(id, exps),
|
||||
// }
|
||||
// }
|
||||
// // default
|
||||
// e => fold_field_expression(self, e),
|
||||
// }
|
||||
// }
|
||||
|
||||
// inline calls which return a field element array
|
||||
fn fold_field_array_expression(
|
||||
&mut self,
|
||||
e: FieldElementArrayExpression<T>,
|
||||
) -> FieldElementArrayExpression<T> {
|
||||
match e {
|
||||
FieldElementArrayExpression::FunctionCall(size, id, exps) => {
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
// // inline calls which return a field element array
|
||||
// fn fold_field_array_expression(
|
||||
// &mut self,
|
||||
// e: FieldElementArrayExpression<T>,
|
||||
// ) -> FieldElementArrayExpression<T> {
|
||||
// match e {
|
||||
// FieldElementArrayExpression::FunctionCall(size, id, exps) => {
|
||||
// let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
||||
let passed_signature = Signature::new()
|
||||
.inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
.outputs(vec![Type::FieldElementArray(size)]);
|
||||
// let passed_signature = Signature::new()
|
||||
// .inputs(exps.iter().map(|e| e.get_type()).collect())
|
||||
// .outputs(vec![Type::FieldElementArray(size)]);
|
||||
|
||||
// find the function
|
||||
let function = self
|
||||
.functions
|
||||
.iter()
|
||||
.find(|f| f.id == id && f.signature == passed_signature)
|
||||
.cloned();
|
||||
// // find the function
|
||||
// let function = self
|
||||
// .functions
|
||||
// .iter()
|
||||
// .find(|f| f.id == id && f.signature == passed_signature)
|
||||
// .cloned();
|
||||
|
||||
match self.should_inline(&function, &exps) {
|
||||
true => {
|
||||
let ret = self.inline_call(&function.unwrap(), exps);
|
||||
// unwrap the result to return a field element
|
||||
match ret[0].clone() {
|
||||
TypedExpression::FieldElementArray(e) => e,
|
||||
_ => panic!(""),
|
||||
}
|
||||
}
|
||||
false => FieldElementArrayExpression::FunctionCall(size, id, exps),
|
||||
}
|
||||
}
|
||||
// default
|
||||
e => fold_field_array_expression(self, e),
|
||||
}
|
||||
}
|
||||
}
|
||||
// match self.should_inline(&function, &exps) {
|
||||
// true => {
|
||||
// let ret = self.inline_call(&function.unwrap(), exps);
|
||||
// // unwrap the result to return a field element
|
||||
// match ret[0].clone() {
|
||||
// TypedExpression::FieldElementArray(e) => e,
|
||||
// _ => panic!(""),
|
||||
// }
|
||||
// }
|
||||
// false => FieldElementArrayExpression::FunctionCall(size, id, exps),
|
||||
// }
|
||||
// }
|
||||
// // default
|
||||
// e => fold_field_array_expression(self, e),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use zokrates_field::field::FieldPrime;
|
||||
// #[cfg(test)]
|
||||
// mod tests {
|
||||
// use super::*;
|
||||
// use zokrates_field::field::FieldPrime;
|
||||
|
||||
#[cfg(test)]
|
||||
mod heuristics {
|
||||
use super::*;
|
||||
// #[cfg(test)]
|
||||
// mod heuristics {
|
||||
// use super::*;
|
||||
|
||||
#[test]
|
||||
fn inline_constant_field() {
|
||||
let f: TypedFunction<FieldPrime> = TypedFunction {
|
||||
id: String::from("foo"),
|
||||
arguments: vec![
|
||||
Parameter::private(Variable::field_element("a")),
|
||||
Parameter::private(Variable::field_array("b", 3)),
|
||||
],
|
||||
statements: vec![TypedStatement::Return(vec![
|
||||
FieldElementExpression::Select(
|
||||
box FieldElementArrayExpression::Identifier(3, String::from("b")),
|
||||
box FieldElementExpression::Identifier(String::from("a")),
|
||||
)
|
||||
.into(),
|
||||
])],
|
||||
signature: Signature::new()
|
||||
.inputs(vec![Type::FieldElement, Type::FieldElementArray(3)])
|
||||
.outputs(vec![Type::FieldElement]),
|
||||
};
|
||||
// #[test]
|
||||
// fn inline_constant_field() {
|
||||
// let f: TypedFunction<FieldPrime> = TypedFunction {
|
||||
// id: String::from("foo"),
|
||||
// arguments: vec![
|
||||
// Parameter::private(Variable::field_element("a")),
|
||||
// Parameter::private(Variable::field_array("b", 3)),
|
||||
// ],
|
||||
// statements: vec![TypedStatement::Return(vec![
|
||||
// FieldElementExpression::Select(
|
||||
// box FieldElementArrayExpression::Identifier(3, String::from("b")),
|
||||
// box FieldElementExpression::Identifier(String::from("a")),
|
||||
// )
|
||||
// .into(),
|
||||
// ])],
|
||||
// signature: Signature::new()
|
||||
// .inputs(vec![Type::FieldElement, Type::FieldElementArray(3)])
|
||||
// .outputs(vec![Type::FieldElement]),
|
||||
// };
|
||||
|
||||
let arguments = vec![
|
||||
FieldElementExpression::Number(FieldPrime::from(0)).into(),
|
||||
FieldElementArrayExpression::Identifier(3, String::from("random")).into(),
|
||||
];
|
||||
// let arguments = vec![
|
||||
// FieldElementExpression::Number(FieldPrime::from(0)).into(),
|
||||
// FieldElementArrayExpression::Identifier(3, String::from("random")).into(),
|
||||
// ];
|
||||
|
||||
let i = Inliner::new();
|
||||
// let i = Inliner::new();
|
||||
|
||||
assert!(i.should_inline(&Some(f), &arguments));
|
||||
}
|
||||
// assert!(i.should_inline(&Some(f), &arguments));
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn no_inline_non_constant_field() {
|
||||
let f: TypedFunction<FieldPrime> = TypedFunction {
|
||||
id: String::from("foo"),
|
||||
arguments: vec![
|
||||
Parameter::private(Variable::field_element("a")),
|
||||
Parameter::private(Variable::field_array("b", 3)),
|
||||
],
|
||||
statements: vec![TypedStatement::Return(vec![
|
||||
FieldElementExpression::Select(
|
||||
box FieldElementArrayExpression::Identifier(3, String::from("b")),
|
||||
box FieldElementExpression::Identifier(String::from("a")),
|
||||
)
|
||||
.into(),
|
||||
])],
|
||||
signature: Signature::new()
|
||||
.inputs(vec![Type::FieldElement, Type::FieldElementArray(3)])
|
||||
.outputs(vec![Type::FieldElement]),
|
||||
};
|
||||
// #[test]
|
||||
// fn no_inline_non_constant_field() {
|
||||
// let f: TypedFunction<FieldPrime> = TypedFunction {
|
||||
// id: String::from("foo"),
|
||||
// arguments: vec![
|
||||
// Parameter::private(Variable::field_element("a")),
|
||||
// Parameter::private(Variable::field_array("b", 3)),
|
||||
// ],
|
||||
// statements: vec![TypedStatement::Return(vec![
|
||||
// FieldElementExpression::Select(
|
||||
// box FieldElementArrayExpression::Identifier(3, String::from("b")),
|
||||
// box FieldElementExpression::Identifier(String::from("a")),
|
||||
// )
|
||||
// .into(),
|
||||
// ])],
|
||||
// signature: Signature::new()
|
||||
// .inputs(vec![Type::FieldElement, Type::FieldElementArray(3)])
|
||||
// .outputs(vec![Type::FieldElement]),
|
||||
// };
|
||||
|
||||
let arguments = vec![
|
||||
FieldElementExpression::Identifier(String::from("notconstant")).into(),
|
||||
FieldElementArrayExpression::Identifier(3, String::from("random")).into(),
|
||||
];
|
||||
// let arguments = vec![
|
||||
// FieldElementExpression::Identifier(String::from("notconstant")).into(),
|
||||
// FieldElementArrayExpression::Identifier(3, String::from("random")).into(),
|
||||
// ];
|
||||
|
||||
let i = Inliner::new();
|
||||
// let i = Inliner::new();
|
||||
|
||||
assert!(!i.should_inline(&Some(f), &arguments));
|
||||
}
|
||||
}
|
||||
}
|
||||
// assert!(!i.should_inline(&Some(f), &arguments));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
|
||||
mod dead_code;
|
||||
mod flat_propagation;
|
||||
mod inline;
|
||||
//mod inline;
|
||||
mod power_check;
|
||||
mod propagation;
|
||||
mod unroll;
|
||||
|
||||
use self::dead_code::DeadCode;
|
||||
use self::inline::Inliner;
|
||||
//use self::inline::Inliner;
|
||||
use self::power_check::PowerChecker;
|
||||
use self::propagation::Propagator;
|
||||
use self::unroll::Unroller;
|
||||
|
@ -24,15 +24,17 @@ pub trait Analyse {
|
|||
fn analyse(self) -> Self;
|
||||
}
|
||||
|
||||
impl<T: Field> Analyse for TypedProg<T> {
|
||||
impl<'ast, T: Field> Analyse for TypedProg<'ast, T> {
|
||||
fn analyse(self) -> Self {
|
||||
let r = PowerChecker::check(self);
|
||||
// unroll
|
||||
println!("{}", r);
|
||||
let r = Unroller::unroll(r);
|
||||
println!("{}", r);
|
||||
//propagate a first time for constants to reach function calls
|
||||
let r = Propagator::propagate(r);
|
||||
// apply inlining strategy
|
||||
let r = Inliner::inline(r);
|
||||
//let r = Inliner::inline(r);
|
||||
// Propagate again
|
||||
let r = Propagator::propagate(r);
|
||||
// remove unused functions
|
||||
|
|
|
@ -15,8 +15,11 @@ impl PowerChecker {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Folder<T> for PowerChecker {
|
||||
fn fold_field_expression(&mut self, e: FieldElementExpression<T>) -> FieldElementExpression<T> {
|
||||
impl<'ast, T: Field> Folder<'ast, T> for PowerChecker {
|
||||
fn fold_field_expression(
|
||||
&mut self,
|
||||
e: FieldElementExpression<'ast, T>,
|
||||
) -> FieldElementExpression<'ast, T> {
|
||||
match e {
|
||||
FieldElementExpression::Pow(box FieldElementExpression::Identifier(..), _) | FieldElementExpression::Pow(box FieldElementExpression::Number(..), _)=> {
|
||||
fold_field_expression(self, e)
|
||||
|
|
|
@ -9,29 +9,29 @@ use crate::typed_absy::*;
|
|||
use std::collections::HashMap;
|
||||
use zokrates_field::field::Field;
|
||||
|
||||
pub struct Propagator<T: Field> {
|
||||
constants: HashMap<TypedAssignee<T>, TypedExpression<T>>,
|
||||
pub struct Propagator<'ast, T: Field> {
|
||||
constants: HashMap<TypedAssignee<'ast, T>, TypedExpression<'ast, T>>,
|
||||
}
|
||||
|
||||
impl<T: Field> Propagator<T> {
|
||||
impl<'ast, T: Field> Propagator<'ast, T> {
|
||||
fn new() -> Self {
|
||||
Propagator {
|
||||
constants: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn propagate(p: TypedProg<T>) -> TypedProg<T> {
|
||||
pub fn propagate(p: TypedProg<'ast, T>) -> TypedProg<'ast, T> {
|
||||
Propagator::new().fold_program(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Folder<T> for Propagator<T> {
|
||||
fn fold_function(&mut self, f: TypedFunction<T>) -> TypedFunction<T> {
|
||||
impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
|
||||
fn fold_function(&mut self, f: TypedFunction<'ast, T>) -> TypedFunction<'ast, T> {
|
||||
self.constants = HashMap::new();
|
||||
fold_function(self, f)
|
||||
}
|
||||
|
||||
fn fold_statement(&mut self, s: TypedStatement<T>) -> Vec<TypedStatement<T>> {
|
||||
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
|
||||
let res = match s {
|
||||
TypedStatement::Declaration(v) => Some(TypedStatement::Declaration(v)),
|
||||
TypedStatement::Return(expressions) => Some(TypedStatement::Return(expressions.into_iter().map(|e| self.fold_expression(e)).collect())),
|
||||
|
@ -116,7 +116,10 @@ impl<T: Field> Folder<T> for Propagator<T> {
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_field_expression(&mut self, e: FieldElementExpression<T>) -> FieldElementExpression<T> {
|
||||
fn fold_field_expression(
|
||||
&mut self,
|
||||
e: FieldElementExpression<'ast, T>,
|
||||
) -> FieldElementExpression<'ast, T> {
|
||||
match e {
|
||||
FieldElementExpression::Identifier(id) => {
|
||||
match self
|
||||
|
@ -241,8 +244,8 @@ impl<T: Field> Folder<T> for Propagator<T> {
|
|||
|
||||
fn fold_field_array_expression(
|
||||
&mut self,
|
||||
e: FieldElementArrayExpression<T>,
|
||||
) -> FieldElementArrayExpression<T> {
|
||||
e: FieldElementArrayExpression<'ast, T>,
|
||||
) -> FieldElementArrayExpression<'ast, T> {
|
||||
match e {
|
||||
FieldElementArrayExpression::Identifier(size, id) => {
|
||||
match self
|
||||
|
@ -262,7 +265,10 @@ impl<T: Field> Folder<T> for Propagator<T> {
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_boolean_expression(&mut self, e: BooleanExpression<T>) -> BooleanExpression<T> {
|
||||
fn fold_boolean_expression(
|
||||
&mut self,
|
||||
e: BooleanExpression<'ast, T>,
|
||||
) -> BooleanExpression<'ast, T> {
|
||||
match e {
|
||||
BooleanExpression::Identifier(id) => match self
|
||||
.constants
|
||||
|
|
|
@ -10,27 +10,27 @@ use crate::types::Type;
|
|||
use std::collections::HashMap;
|
||||
use zokrates_field::field::Field;
|
||||
|
||||
pub struct Unroller {
|
||||
substitution: HashMap<String, usize>,
|
||||
pub struct Unroller<'ast> {
|
||||
substitution: HashMap<Identifier<'ast>, usize>,
|
||||
}
|
||||
|
||||
impl Unroller {
|
||||
impl<'ast> Unroller<'ast> {
|
||||
fn new() -> Self {
|
||||
Unroller {
|
||||
substitution: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn issue_next_ssa_variable(&mut self, v: Variable) -> Variable {
|
||||
fn issue_next_ssa_variable(&mut self, v: Variable<'ast>) -> Variable<'ast> {
|
||||
let res = match self.substitution.get(&v.id) {
|
||||
Some(i) => Variable {
|
||||
id: format!("{}_{}", v.id, i + 1),
|
||||
..v
|
||||
},
|
||||
None => Variable {
|
||||
id: format!("{}_{}", v.id, 0),
|
||||
id: Identifier {
|
||||
id: v.id.id,
|
||||
version: i + 1,
|
||||
},
|
||||
..v
|
||||
},
|
||||
None => Variable { ..v },
|
||||
};
|
||||
self.substitution
|
||||
.entry(v.id)
|
||||
|
@ -44,8 +44,8 @@ impl Unroller {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Folder<T> for Unroller {
|
||||
fn fold_statement(&mut self, s: TypedStatement<T>) -> Vec<TypedStatement<T>> {
|
||||
impl<'ast, T: Field> Folder<'ast, T> for Unroller<'ast> {
|
||||
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
|
||||
match s {
|
||||
TypedStatement::Declaration(_) => vec![],
|
||||
TypedStatement::Definition(TypedAssignee::Identifier(variable), expr) => {
|
||||
|
@ -156,7 +156,7 @@ impl<T: Field> Folder<T> for Unroller {
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_function(&mut self, f: TypedFunction<T>) -> TypedFunction<T> {
|
||||
fn fold_function(&mut self, f: TypedFunction<'ast, T>) -> TypedFunction<'ast, T> {
|
||||
self.substitution = HashMap::new();
|
||||
for arg in &f.arguments {
|
||||
self.substitution.insert(arg.id.id.clone(), 0);
|
||||
|
@ -165,8 +165,11 @@ impl<T: Field> Folder<T> for Unroller {
|
|||
fold_function(self, f)
|
||||
}
|
||||
|
||||
fn fold_name(&mut self, n: String) -> String {
|
||||
format!("{}_{}", n, self.substitution.get(&n).unwrap())
|
||||
fn fold_name(&mut self, n: Identifier<'ast>) -> Identifier<'ast> {
|
||||
Identifier {
|
||||
version: self.substitution.get(&n).unwrap_or(&0).clone(),
|
||||
..n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,34 +3,34 @@
|
|||
use crate::typed_absy::*;
|
||||
use zokrates_field::field::Field;
|
||||
|
||||
pub trait Folder<T: Field>: Sized {
|
||||
fn fold_program(&mut self, p: TypedProg<T>) -> TypedProg<T> {
|
||||
pub trait Folder<'ast, T: Field>: Sized {
|
||||
fn fold_program(&mut self, p: TypedProg<'ast, T>) -> TypedProg<'ast, T> {
|
||||
fold_program(self, p)
|
||||
}
|
||||
|
||||
fn fold_function(&mut self, f: TypedFunction<T>) -> TypedFunction<T> {
|
||||
fn fold_function(&mut self, f: TypedFunction<'ast, T>) -> TypedFunction<'ast, T> {
|
||||
fold_function(self, f)
|
||||
}
|
||||
|
||||
fn fold_parameter(&mut self, p: Parameter) -> Parameter {
|
||||
fn fold_parameter(&mut self, p: Parameter<'ast>) -> Parameter<'ast> {
|
||||
Parameter {
|
||||
id: self.fold_variable(p.id),
|
||||
..p
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_name(&mut self, n: String) -> String {
|
||||
fn fold_name(&mut self, n: Identifier<'ast>) -> Identifier<'ast> {
|
||||
n
|
||||
}
|
||||
|
||||
fn fold_variable(&mut self, v: Variable) -> Variable {
|
||||
fn fold_variable(&mut self, v: Variable<'ast>) -> Variable<'ast> {
|
||||
Variable {
|
||||
id: self.fold_name(v.id),
|
||||
..v
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_assignee(&mut self, a: TypedAssignee<T>) -> TypedAssignee<T> {
|
||||
fn fold_assignee(&mut self, a: TypedAssignee<'ast, T>) -> TypedAssignee<'ast, T> {
|
||||
match a {
|
||||
TypedAssignee::Identifier(v) => TypedAssignee::Identifier(self.fold_variable(v)),
|
||||
TypedAssignee::ArrayElement(box a, box index) => TypedAssignee::ArrayElement(
|
||||
|
@ -40,11 +40,11 @@ pub trait Folder<T: Field>: Sized {
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_statement(&mut self, s: TypedStatement<T>) -> Vec<TypedStatement<T>> {
|
||||
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
|
||||
fold_statement(self, s)
|
||||
}
|
||||
|
||||
fn fold_expression(&mut self, e: TypedExpression<T>) -> TypedExpression<T> {
|
||||
fn fold_expression(&mut self, e: TypedExpression<'ast, T>) -> TypedExpression<'ast, T> {
|
||||
match e {
|
||||
TypedExpression::FieldElement(e) => self.fold_field_expression(e).into(),
|
||||
TypedExpression::Boolean(e) => self.fold_boolean_expression(e).into(),
|
||||
|
@ -52,7 +52,10 @@ pub trait Folder<T: Field>: Sized {
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_expression_list(&mut self, es: TypedExpressionList<T>) -> TypedExpressionList<T> {
|
||||
fn fold_expression_list(
|
||||
&mut self,
|
||||
es: TypedExpressionList<'ast, T>,
|
||||
) -> TypedExpressionList<'ast, T> {
|
||||
match es {
|
||||
TypedExpressionList::FunctionCall(id, arguments, types) => {
|
||||
TypedExpressionList::FunctionCall(
|
||||
|
@ -67,21 +70,30 @@ pub trait Folder<T: Field>: Sized {
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_field_expression(&mut self, e: FieldElementExpression<T>) -> FieldElementExpression<T> {
|
||||
fn fold_field_expression(
|
||||
&mut self,
|
||||
e: FieldElementExpression<'ast, T>,
|
||||
) -> FieldElementExpression<'ast, T> {
|
||||
fold_field_expression(self, e)
|
||||
}
|
||||
fn fold_boolean_expression(&mut self, e: BooleanExpression<T>) -> BooleanExpression<T> {
|
||||
fn fold_boolean_expression(
|
||||
&mut self,
|
||||
e: BooleanExpression<'ast, T>,
|
||||
) -> BooleanExpression<'ast, T> {
|
||||
fold_boolean_expression(self, e)
|
||||
}
|
||||
fn fold_field_array_expression(
|
||||
&mut self,
|
||||
e: FieldElementArrayExpression<T>,
|
||||
) -> FieldElementArrayExpression<T> {
|
||||
e: FieldElementArrayExpression<'ast, T>,
|
||||
) -> FieldElementArrayExpression<'ast, T> {
|
||||
fold_field_array_expression(self, e)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fold_program<T: Field, F: Folder<T>>(f: &mut F, p: TypedProg<T>) -> TypedProg<T> {
|
||||
pub fn fold_program<'ast, T: Field, F: Folder<'ast, T>>(
|
||||
f: &mut F,
|
||||
p: TypedProg<'ast, T>,
|
||||
) -> TypedProg<'ast, T> {
|
||||
TypedProg {
|
||||
functions: p
|
||||
.functions
|
||||
|
@ -92,10 +104,10 @@ pub fn fold_program<T: Field, F: Folder<T>>(f: &mut F, p: TypedProg<T>) -> Typed
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fold_statement<T: Field, F: Folder<T>>(
|
||||
pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>(
|
||||
f: &mut F,
|
||||
s: TypedStatement<T>,
|
||||
) -> Vec<TypedStatement<T>> {
|
||||
s: TypedStatement<'ast, T>,
|
||||
) -> Vec<TypedStatement<'ast, T>> {
|
||||
let res = match s {
|
||||
TypedStatement::Return(expressions) => TypedStatement::Return(
|
||||
expressions
|
||||
|
@ -127,10 +139,10 @@ pub fn fold_statement<T: Field, F: Folder<T>>(
|
|||
vec![res]
|
||||
}
|
||||
|
||||
pub fn fold_field_array_expression<T: Field, F: Folder<T>>(
|
||||
pub fn fold_field_array_expression<'ast, T: Field, F: Folder<'ast, T>>(
|
||||
f: &mut F,
|
||||
e: FieldElementArrayExpression<T>,
|
||||
) -> FieldElementArrayExpression<T> {
|
||||
e: FieldElementArrayExpression<'ast, T>,
|
||||
) -> FieldElementArrayExpression<'ast, T> {
|
||||
match e {
|
||||
FieldElementArrayExpression::Identifier(size, id) => {
|
||||
FieldElementArrayExpression::Identifier(size, f.fold_name(id))
|
||||
|
@ -156,10 +168,10 @@ pub fn fold_field_array_expression<T: Field, F: Folder<T>>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fold_field_expression<T: Field, F: Folder<T>>(
|
||||
pub fn fold_field_expression<'ast, T: Field, F: Folder<'ast, T>>(
|
||||
f: &mut F,
|
||||
e: FieldElementExpression<T>,
|
||||
) -> FieldElementExpression<T> {
|
||||
e: FieldElementExpression<'ast, T>,
|
||||
) -> FieldElementExpression<'ast, T> {
|
||||
match e {
|
||||
FieldElementExpression::Number(n) => FieldElementExpression::Number(n),
|
||||
FieldElementExpression::Identifier(id) => {
|
||||
|
@ -208,10 +220,10 @@ pub fn fold_field_expression<T: Field, F: Folder<T>>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fold_boolean_expression<T: Field, F: Folder<T>>(
|
||||
pub fn fold_boolean_expression<'ast, T: Field, F: Folder<'ast, T>>(
|
||||
f: &mut F,
|
||||
e: BooleanExpression<T>,
|
||||
) -> BooleanExpression<T> {
|
||||
e: BooleanExpression<'ast, T>,
|
||||
) -> BooleanExpression<'ast, T> {
|
||||
match e {
|
||||
BooleanExpression::Value(v) => BooleanExpression::Value(v),
|
||||
BooleanExpression::Identifier(id) => BooleanExpression::Identifier(f.fold_name(id)),
|
||||
|
@ -257,7 +269,10 @@ pub fn fold_boolean_expression<T: Field, F: Folder<T>>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn fold_function<T: Field, F: Folder<T>>(f: &mut F, fun: TypedFunction<T>) -> TypedFunction<T> {
|
||||
pub fn fold_function<'ast, T: Field, F: Folder<'ast, T>>(
|
||||
f: &mut F,
|
||||
fun: TypedFunction<'ast, T>,
|
||||
) -> TypedFunction<'ast, T> {
|
||||
TypedFunction {
|
||||
arguments: fun
|
||||
.arguments
|
||||
|
|
|
@ -21,15 +21,33 @@ use zokrates_field::field::Field;
|
|||
|
||||
pub use self::folder::Folder;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Hash, Eq, Copy)]
|
||||
pub struct Identifier<'ast> {
|
||||
pub id: &'ast str,
|
||||
pub version: usize,
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for Identifier<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}_{}", self.id, self.version)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<&'ast str> for Identifier<'ast> {
|
||||
fn from(id: &'ast str) -> Identifier<'ast> {
|
||||
Identifier { id, version: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct TypedProg<T: Field> {
|
||||
pub struct TypedProg<'ast, T: Field> {
|
||||
/// Functions of the program
|
||||
pub functions: Vec<TypedFunction<T>>,
|
||||
pub functions: Vec<TypedFunction<'ast, T>>,
|
||||
pub imports: Vec<Import>,
|
||||
pub imported_functions: Vec<FlatFunction<T>>,
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for TypedProg<T> {
|
||||
impl<'ast, T: Field> fmt::Display for TypedProg<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut res = vec![];
|
||||
res.extend(
|
||||
|
@ -54,7 +72,7 @@ impl<T: Field> fmt::Display for TypedProg<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for TypedProg<T> {
|
||||
impl<'ast, T: Field> fmt::Debug for TypedProg<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
|
@ -79,18 +97,18 @@ impl<T: Field> fmt::Debug for TypedProg<T> {
|
|||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct TypedFunction<T: Field> {
|
||||
pub struct TypedFunction<'ast, T: Field> {
|
||||
/// Name of the program
|
||||
pub id: String,
|
||||
/// Arguments of the function
|
||||
pub arguments: Vec<Parameter>,
|
||||
pub arguments: Vec<Parameter<'ast>>,
|
||||
/// Vector of statements that are executed when running the function
|
||||
pub statements: Vec<TypedStatement<T>>,
|
||||
pub statements: Vec<TypedStatement<'ast, T>>,
|
||||
/// function signature
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for TypedFunction<T> {
|
||||
impl<'ast, T: Field> fmt::Display for TypedFunction<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
|
@ -116,7 +134,7 @@ impl<T: Field> fmt::Display for TypedFunction<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for TypedFunction<T> {
|
||||
impl<'ast, T: Field> fmt::Debug for TypedFunction<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
|
@ -133,12 +151,15 @@ impl<T: Field> fmt::Debug for TypedFunction<T> {
|
|||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
pub enum TypedAssignee<T: Field> {
|
||||
Identifier(Variable),
|
||||
ArrayElement(Box<TypedAssignee<T>>, Box<FieldElementExpression<T>>),
|
||||
pub enum TypedAssignee<'ast, T: Field> {
|
||||
Identifier(Variable<'ast>),
|
||||
ArrayElement(
|
||||
Box<TypedAssignee<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
}
|
||||
|
||||
impl<T: Field> Typed for TypedAssignee<T> {
|
||||
impl<'ast, T: Field> Typed for TypedAssignee<'ast, T> {
|
||||
fn get_type(&self) -> Type {
|
||||
match *self {
|
||||
TypedAssignee::Identifier(ref v) => v.get_type(),
|
||||
|
@ -153,7 +174,7 @@ impl<T: Field> Typed for TypedAssignee<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for TypedAssignee<T> {
|
||||
impl<'ast, T: Field> fmt::Debug for TypedAssignee<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedAssignee::Identifier(ref s) => write!(f, "{}", s.id),
|
||||
|
@ -162,23 +183,23 @@ impl<T: Field> fmt::Debug for TypedAssignee<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for TypedAssignee<T> {
|
||||
impl<'ast, T: Field> fmt::Display for TypedAssignee<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum TypedStatement<T: Field> {
|
||||
Return(Vec<TypedExpression<T>>),
|
||||
Definition(TypedAssignee<T>, TypedExpression<T>),
|
||||
Declaration(Variable),
|
||||
Condition(TypedExpression<T>, TypedExpression<T>),
|
||||
For(Variable, T, T, Vec<TypedStatement<T>>),
|
||||
MultipleDefinition(Vec<Variable>, TypedExpressionList<T>),
|
||||
pub enum TypedStatement<'ast, T: Field> {
|
||||
Return(Vec<TypedExpression<'ast, T>>),
|
||||
Definition(TypedAssignee<'ast, T>, TypedExpression<'ast, T>),
|
||||
Declaration(Variable<'ast>),
|
||||
Condition(TypedExpression<'ast, T>, TypedExpression<'ast, T>),
|
||||
For(Variable<'ast>, T, T, Vec<TypedStatement<'ast, T>>),
|
||||
MultipleDefinition(Vec<Variable<'ast>>, TypedExpressionList<'ast, T>),
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for TypedStatement<T> {
|
||||
impl<'ast, T: Field> fmt::Debug for TypedStatement<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedStatement::Return(ref exprs) => {
|
||||
|
@ -212,7 +233,7 @@ impl<T: Field> fmt::Debug for TypedStatement<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for TypedStatement<T> {
|
||||
impl<'ast, T: Field> fmt::Display for TypedStatement<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedStatement::Return(ref exprs) => {
|
||||
|
@ -253,31 +274,31 @@ pub trait Typed {
|
|||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
pub enum TypedExpression<T: Field> {
|
||||
Boolean(BooleanExpression<T>),
|
||||
FieldElement(FieldElementExpression<T>),
|
||||
FieldElementArray(FieldElementArrayExpression<T>),
|
||||
pub enum TypedExpression<'ast, T: Field> {
|
||||
Boolean(BooleanExpression<'ast, T>),
|
||||
FieldElement(FieldElementExpression<'ast, T>),
|
||||
FieldElementArray(FieldElementArrayExpression<'ast, T>),
|
||||
}
|
||||
|
||||
impl<T: Field> From<BooleanExpression<T>> for TypedExpression<T> {
|
||||
fn from(e: BooleanExpression<T>) -> TypedExpression<T> {
|
||||
impl<'ast, T: Field> From<BooleanExpression<'ast, T>> for TypedExpression<'ast, T> {
|
||||
fn from(e: BooleanExpression<'ast, T>) -> TypedExpression<T> {
|
||||
TypedExpression::Boolean(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> From<FieldElementExpression<T>> for TypedExpression<T> {
|
||||
fn from(e: FieldElementExpression<T>) -> TypedExpression<T> {
|
||||
impl<'ast, T: Field> From<FieldElementExpression<'ast, T>> for TypedExpression<'ast, T> {
|
||||
fn from(e: FieldElementExpression<'ast, T>) -> TypedExpression<T> {
|
||||
TypedExpression::FieldElement(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> From<FieldElementArrayExpression<T>> for TypedExpression<T> {
|
||||
fn from(e: FieldElementArrayExpression<T>) -> TypedExpression<T> {
|
||||
impl<'ast, T: Field> From<FieldElementArrayExpression<'ast, T>> for TypedExpression<'ast, T> {
|
||||
fn from(e: FieldElementArrayExpression<'ast, T>) -> TypedExpression<T> {
|
||||
TypedExpression::FieldElementArray(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for TypedExpression<T> {
|
||||
impl<'ast, T: Field> fmt::Display for TypedExpression<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedExpression::Boolean(ref e) => write!(f, "{}", e),
|
||||
|
@ -287,7 +308,7 @@ impl<T: Field> fmt::Display for TypedExpression<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for TypedExpression<T> {
|
||||
impl<'ast, T: Field> fmt::Debug for TypedExpression<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedExpression::Boolean(ref e) => write!(f, "{:?}", e),
|
||||
|
@ -297,7 +318,7 @@ impl<T: Field> fmt::Debug for TypedExpression<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Typed for TypedExpression<T> {
|
||||
impl<'ast, T: Field> Typed for TypedExpression<'ast, T> {
|
||||
fn get_type(&self) -> Type {
|
||||
match *self {
|
||||
TypedExpression::Boolean(_) => Type::Boolean,
|
||||
|
@ -307,7 +328,7 @@ impl<T: Field> Typed for TypedExpression<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> Typed for FieldElementArrayExpression<T> {
|
||||
impl<'ast, T: Field> Typed for FieldElementArrayExpression<'ast, T> {
|
||||
fn get_type(&self) -> Type {
|
||||
match *self {
|
||||
FieldElementArrayExpression::Identifier(n, _) => Type::FieldElementArray(n),
|
||||
|
@ -323,11 +344,11 @@ pub trait MultiTyped {
|
|||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum TypedExpressionList<T: Field> {
|
||||
FunctionCall(String, Vec<TypedExpression<T>>, Vec<Type>),
|
||||
pub enum TypedExpressionList<'ast, T: Field> {
|
||||
FunctionCall(String, Vec<TypedExpression<'ast, T>>, Vec<Type>),
|
||||
}
|
||||
|
||||
impl<T: Field> MultiTyped for TypedExpressionList<T> {
|
||||
impl<'ast, T: Field> MultiTyped for TypedExpressionList<'ast, T> {
|
||||
fn get_types(&self) -> &Vec<Type> {
|
||||
match *self {
|
||||
TypedExpressionList::FunctionCall(_, _, ref types) => types,
|
||||
|
@ -336,84 +357,90 @@ impl<T: Field> MultiTyped for TypedExpressionList<T> {
|
|||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
pub enum FieldElementExpression<T: Field> {
|
||||
pub enum FieldElementExpression<'ast, T: Field> {
|
||||
Number(T),
|
||||
Identifier(String),
|
||||
Identifier(Identifier<'ast>),
|
||||
Add(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
Sub(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
Mult(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
Div(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
Pow(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
IfElse(
|
||||
Box<BooleanExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<BooleanExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
FunctionCall(String, Vec<TypedExpression<T>>),
|
||||
FunctionCall(String, Vec<TypedExpression<'ast, T>>),
|
||||
Select(
|
||||
Box<FieldElementArrayExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementArrayExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
pub enum BooleanExpression<T: Field> {
|
||||
Identifier(String),
|
||||
pub enum BooleanExpression<'ast, T: Field> {
|
||||
Identifier(Identifier<'ast>),
|
||||
Value(bool),
|
||||
Lt(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
Le(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
Eq(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
Ge(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
Gt(
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
Or(Box<BooleanExpression<T>>, Box<BooleanExpression<T>>),
|
||||
And(Box<BooleanExpression<T>>, Box<BooleanExpression<T>>),
|
||||
Not(Box<BooleanExpression<T>>),
|
||||
Or(
|
||||
Box<BooleanExpression<'ast, T>>,
|
||||
Box<BooleanExpression<'ast, T>>,
|
||||
),
|
||||
And(
|
||||
Box<BooleanExpression<'ast, T>>,
|
||||
Box<BooleanExpression<'ast, T>>,
|
||||
),
|
||||
Not(Box<BooleanExpression<'ast, T>>),
|
||||
}
|
||||
|
||||
// for now we store the array size in the variants
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
pub enum FieldElementArrayExpression<T: Field> {
|
||||
Identifier(usize, String),
|
||||
Value(usize, Vec<FieldElementExpression<T>>),
|
||||
FunctionCall(usize, String, Vec<TypedExpression<T>>),
|
||||
pub enum FieldElementArrayExpression<'ast, T: Field> {
|
||||
Identifier(usize, Identifier<'ast>),
|
||||
Value(usize, Vec<FieldElementExpression<'ast, T>>),
|
||||
FunctionCall(usize, String, Vec<TypedExpression<'ast, T>>),
|
||||
IfElse(
|
||||
Box<BooleanExpression<T>>,
|
||||
Box<FieldElementArrayExpression<T>>,
|
||||
Box<FieldElementArrayExpression<T>>,
|
||||
Box<BooleanExpression<'ast, T>>,
|
||||
Box<FieldElementArrayExpression<'ast, T>>,
|
||||
Box<FieldElementArrayExpression<'ast, T>>,
|
||||
),
|
||||
}
|
||||
|
||||
impl<T: Field> FieldElementArrayExpression<T> {
|
||||
impl<'ast, T: Field> FieldElementArrayExpression<'ast, T> {
|
||||
pub fn size(&self) -> usize {
|
||||
match *self {
|
||||
FieldElementArrayExpression::Identifier(s, _)
|
||||
|
@ -424,7 +451,7 @@ impl<T: Field> FieldElementArrayExpression<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for FieldElementExpression<T> {
|
||||
impl<'ast, T: Field> fmt::Display for FieldElementExpression<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
FieldElementExpression::Number(ref i) => write!(f, "{}", i),
|
||||
|
@ -456,7 +483,7 @@ impl<T: Field> fmt::Display for FieldElementExpression<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for BooleanExpression<T> {
|
||||
impl<'ast, T: Field> fmt::Display for BooleanExpression<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
BooleanExpression::Identifier(ref var) => write!(f, "{}", var),
|
||||
|
@ -473,7 +500,7 @@ impl<T: Field> fmt::Display for BooleanExpression<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for FieldElementArrayExpression<T> {
|
||||
impl<'ast, T: Field> fmt::Display for FieldElementArrayExpression<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
FieldElementArrayExpression::Identifier(_, ref var) => write!(f, "{}", var),
|
||||
|
@ -507,13 +534,13 @@ impl<T: Field> fmt::Display for FieldElementArrayExpression<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for BooleanExpression<T> {
|
||||
impl<'ast, T: Field> fmt::Debug for BooleanExpression<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for FieldElementExpression<T> {
|
||||
impl<'ast, T: Field> fmt::Debug for FieldElementExpression<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
FieldElementExpression::Number(ref i) => write!(f, "Num({})", i),
|
||||
|
@ -544,7 +571,7 @@ impl<T: Field> fmt::Debug for FieldElementExpression<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for FieldElementArrayExpression<T> {
|
||||
impl<'ast, T: Field> fmt::Debug for FieldElementArrayExpression<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
FieldElementArrayExpression::Identifier(_, ref var) => write!(f, "{:?}", var),
|
||||
|
@ -565,7 +592,7 @@ impl<T: Field> fmt::Debug for FieldElementArrayExpression<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for TypedExpressionList<T> {
|
||||
impl<'ast, T: Field> fmt::Display for TypedExpressionList<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedExpressionList::FunctionCall(ref i, ref p, _) => {
|
||||
|
@ -582,7 +609,7 @@ impl<T: Field> fmt::Display for TypedExpressionList<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Debug for TypedExpressionList<T> {
|
||||
impl<'ast, T: Field> fmt::Debug for TypedExpressionList<'ast, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
TypedExpressionList::FunctionCall(ref i, ref p, _) => {
|
||||
|
@ -594,7 +621,7 @@ impl<T: Field> fmt::Debug for TypedExpressionList<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> TypedFunction<T> {
|
||||
impl<'ast, T: Field> TypedFunction<'ast, T> {
|
||||
pub fn to_slug(&self) -> String {
|
||||
format!("{}_{}", self.id, self.signature.to_slug())
|
||||
}
|
||||
|
|
|
@ -2,15 +2,15 @@ use crate::absy;
|
|||
use crate::typed_absy::Variable;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Parameter {
|
||||
pub id: Variable,
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct Parameter<'ast> {
|
||||
pub id: Variable<'ast>,
|
||||
pub private: bool,
|
||||
}
|
||||
|
||||
impl Parameter {
|
||||
impl<'ast> Parameter<'ast> {
|
||||
#[cfg(test)]
|
||||
pub fn private(v: Variable) -> Self {
|
||||
pub fn private(v: Variable<'ast>) -> Self {
|
||||
Parameter {
|
||||
id: v,
|
||||
private: true,
|
||||
|
@ -18,20 +18,20 @@ impl Parameter {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Parameter {
|
||||
impl<'ast> fmt::Display for Parameter<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let visibility = if self.private { "private " } else { "" };
|
||||
write!(f, "{}{} {}", visibility, self.id.get_type(), self.id.id)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Parameter {
|
||||
impl<'ast> fmt::Debug for Parameter<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Parameter(variable: {:?})", self.id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<absy::Parameter<'ast>> for Parameter {
|
||||
impl<'ast> From<absy::Parameter<'ast>> for Parameter<'ast> {
|
||||
fn from(p: absy::Parameter<'ast>) -> Parameter {
|
||||
Parameter {
|
||||
private: p.private,
|
||||
|
|
|
@ -1,33 +1,29 @@
|
|||
use crate::absy;
|
||||
use crate::typed_absy::Identifier;
|
||||
use crate::types::Type;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Hash, Eq)]
|
||||
pub struct Variable {
|
||||
pub id: String,
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
pub struct Variable<'ast> {
|
||||
pub id: Identifier<'ast>,
|
||||
pub _type: Type,
|
||||
}
|
||||
|
||||
impl Variable {
|
||||
pub fn field_element<S: Into<String>>(id: S) -> Variable {
|
||||
Variable {
|
||||
id: id.into(),
|
||||
_type: Type::FieldElement,
|
||||
}
|
||||
impl<'ast> Variable<'ast> {
|
||||
pub fn field_element(id: Identifier<'ast>) -> Variable<'ast> {
|
||||
Self::with_id_and_type(id, Type::FieldElement)
|
||||
}
|
||||
|
||||
pub fn boolean<S: Into<String>>(id: S) -> Variable {
|
||||
Variable {
|
||||
id: id.into(),
|
||||
_type: Type::Boolean,
|
||||
}
|
||||
pub fn boolean(id: Identifier<'ast>) -> Variable<'ast> {
|
||||
Self::with_id_and_type(id, Type::Boolean)
|
||||
}
|
||||
|
||||
pub fn field_array<S: Into<String>>(id: S, size: usize) -> Variable {
|
||||
Variable {
|
||||
id: id.into(),
|
||||
_type: Type::FieldElementArray(size),
|
||||
}
|
||||
pub fn field_array(id: Identifier<'ast>, size: usize) -> Variable<'ast> {
|
||||
Self::with_id_and_type(id, Type::FieldElementArray(size))
|
||||
}
|
||||
|
||||
pub fn with_id_and_type(id: Identifier<'ast>, _type: Type) -> Variable<'ast> {
|
||||
Variable { id, _type }
|
||||
}
|
||||
|
||||
pub fn get_type(&self) -> Type {
|
||||
|
@ -35,23 +31,26 @@ impl Variable {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Variable {
|
||||
impl<'ast> fmt::Display for Variable<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} {}", self._type, self.id,)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Variable {
|
||||
impl<'ast> fmt::Debug for Variable<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Variable(type: {:?}, id: {:?})", self._type, self.id,)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<absy::Variable<'ast>> for Variable {
|
||||
impl<'ast> From<absy::Variable<'ast>> for Variable<'ast> {
|
||||
fn from(v: absy::Variable) -> Variable {
|
||||
Variable {
|
||||
id: v.id.to_string(),
|
||||
_type: v._type,
|
||||
}
|
||||
Variable::with_id_and_type(
|
||||
Identifier {
|
||||
id: v.id,
|
||||
version: 0,
|
||||
},
|
||||
v._type,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue