wip
This commit is contained in:
parent
2e56d2f1cf
commit
14c845fe9c
20 changed files with 1814 additions and 1132 deletions
|
@ -213,10 +213,8 @@ fn check_with_arena<'ast, T: Field, E: Into<imports::Error>>(
|
|||
CompileErrors(errors.into_iter().map(|e| CompileError::from(e)).collect())
|
||||
})?;
|
||||
|
||||
let abi = typed_ast.abi();
|
||||
|
||||
// analyse (unroll and constant propagation)
|
||||
let typed_ast = typed_ast.analyse();
|
||||
let (typed_ast, abi) = typed_ast.analyse();
|
||||
|
||||
Ok((typed_ast, abi))
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use flat_absy::{
|
|||
FlatVariable,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use typed_absy::types::{FunctionKey, Signature, Type};
|
||||
use typed_absy::types::{ConcreteFunctionKey, ConcreteSignature, ConcreteType};
|
||||
use zokrates_field::Field;
|
||||
|
||||
/// A low level function that contains non-deterministic introduction of variables. It is carried out as is until
|
||||
|
@ -21,34 +21,34 @@ pub enum FlatEmbed {
|
|||
}
|
||||
|
||||
impl FlatEmbed {
|
||||
pub fn signature(&self) -> Signature {
|
||||
pub fn signature(&self) -> ConcreteSignature {
|
||||
match self {
|
||||
FlatEmbed::Unpack(bitwidth) => Signature::new()
|
||||
.inputs(vec![Type::FieldElement])
|
||||
.outputs(vec![Type::array(Type::Boolean, *bitwidth)]),
|
||||
FlatEmbed::U8ToBits => Signature::new()
|
||||
.inputs(vec![Type::uint(8)])
|
||||
.outputs(vec![Type::array(Type::Boolean, 8)]),
|
||||
FlatEmbed::U16ToBits => Signature::new()
|
||||
.inputs(vec![Type::uint(16)])
|
||||
.outputs(vec![Type::array(Type::Boolean, 16)]),
|
||||
FlatEmbed::U32ToBits => Signature::new()
|
||||
.inputs(vec![Type::uint(32)])
|
||||
.outputs(vec![Type::array(Type::Boolean, 32)]),
|
||||
FlatEmbed::U8FromBits => Signature::new()
|
||||
.outputs(vec![Type::uint(8)])
|
||||
.inputs(vec![Type::array(Type::Boolean, 8)]),
|
||||
FlatEmbed::U16FromBits => Signature::new()
|
||||
.outputs(vec![Type::uint(16)])
|
||||
.inputs(vec![Type::array(Type::Boolean, 16)]),
|
||||
FlatEmbed::U32FromBits => Signature::new()
|
||||
.outputs(vec![Type::uint(32)])
|
||||
.inputs(vec![Type::array(Type::Boolean, 32)]),
|
||||
FlatEmbed::Unpack(bitwidth) => ConcreteSignature::new()
|
||||
.inputs(vec![ConcreteType::FieldElement])
|
||||
.outputs(vec![ConcreteType::array(ConcreteType::Boolean, *bitwidth)]),
|
||||
FlatEmbed::U8ToBits => ConcreteSignature::new()
|
||||
.inputs(vec![ConcreteType::uint(8)])
|
||||
.outputs(vec![ConcreteType::array(ConcreteType::Boolean, 8usize)]),
|
||||
FlatEmbed::U16ToBits => ConcreteSignature::new()
|
||||
.inputs(vec![ConcreteType::uint(16)])
|
||||
.outputs(vec![ConcreteType::array(ConcreteType::Boolean, 16usize)]),
|
||||
FlatEmbed::U32ToBits => ConcreteSignature::new()
|
||||
.inputs(vec![ConcreteType::uint(32)])
|
||||
.outputs(vec![ConcreteType::array(ConcreteType::Boolean, 32usize)]),
|
||||
FlatEmbed::U8FromBits => ConcreteSignature::new()
|
||||
.outputs(vec![ConcreteType::uint(8)])
|
||||
.inputs(vec![ConcreteType::array(ConcreteType::Boolean, 8usize)]),
|
||||
FlatEmbed::U16FromBits => ConcreteSignature::new()
|
||||
.outputs(vec![ConcreteType::uint(16)])
|
||||
.inputs(vec![ConcreteType::array(ConcreteType::Boolean, 16usize)]),
|
||||
FlatEmbed::U32FromBits => ConcreteSignature::new()
|
||||
.outputs(vec![ConcreteType::uint(32)])
|
||||
.inputs(vec![ConcreteType::array(ConcreteType::Boolean, 32usize)]),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn key<T: Field>(&self) -> FunctionKey<'static> {
|
||||
FunctionKey::with_id(self.id()).signature(self.signature())
|
||||
pub fn key<T: Field>(&self) -> ConcreteFunctionKey<'static> {
|
||||
ConcreteFunctionKey::with_id(self.id()).signature(self.signature())
|
||||
}
|
||||
|
||||
pub fn id(&self) -> &'static str {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -4,28 +4,30 @@ use typed_absy::types::{StructType, UBitwidth};
|
|||
use zir;
|
||||
use zokrates_field::Field;
|
||||
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
|
||||
pub struct Flattener<T: Field> {
|
||||
phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
fn flatten_identifier_rec<'a>(
|
||||
id: zir::SourceIdentifier<'a>,
|
||||
ty: typed_absy::Type,
|
||||
) -> Vec<zir::Variable> {
|
||||
fn flatten_identifier_rec<'ast>(
|
||||
id: zir::SourceIdentifier<'ast>,
|
||||
ty: typed_absy::types::ConcreteType,
|
||||
) -> Vec<zir::Variable<'ast>> {
|
||||
match ty {
|
||||
typed_absy::Type::FieldElement => vec![zir::Variable {
|
||||
typed_absy::types::ConcreteType::FieldElement => vec![zir::Variable {
|
||||
id: zir::Identifier::Source(id),
|
||||
_type: zir::Type::FieldElement,
|
||||
}],
|
||||
typed_absy::Type::Boolean => vec![zir::Variable {
|
||||
typed_absy::types::ConcreteType::Boolean => vec![zir::Variable {
|
||||
id: zir::Identifier::Source(id),
|
||||
_type: zir::Type::Boolean,
|
||||
}],
|
||||
typed_absy::Type::Uint(bitwidth) => vec![zir::Variable {
|
||||
typed_absy::types::ConcreteType::Uint(bitwidth) => vec![zir::Variable {
|
||||
id: zir::Identifier::Source(id),
|
||||
_type: zir::Type::uint(bitwidth.to_usize()),
|
||||
}],
|
||||
typed_absy::Type::Array(array_type) => (0..array_type.size)
|
||||
typed_absy::types::ConcreteType::Array(array_type) => (0..array_type.size)
|
||||
.flat_map(|i| {
|
||||
flatten_identifier_rec(
|
||||
zir::SourceIdentifier::Select(box id.clone(), i),
|
||||
|
@ -33,7 +35,7 @@ fn flatten_identifier_rec<'a>(
|
|||
)
|
||||
})
|
||||
.collect(),
|
||||
typed_absy::Type::Struct(members) => members
|
||||
typed_absy::types::ConcreteType::Struct(members) => members
|
||||
.into_iter()
|
||||
.flat_map(|struct_member| {
|
||||
flatten_identifier_rec(
|
||||
|
@ -75,9 +77,12 @@ impl<'ast, T: Field> Flattener<T> {
|
|||
fold_function(self, f)
|
||||
}
|
||||
|
||||
fn fold_parameter(&mut self, p: typed_absy::Parameter<'ast>) -> Vec<zir::Parameter<'ast>> {
|
||||
fn fold_declaration_parameter(
|
||||
&mut self,
|
||||
p: typed_absy::DeclarationParameter<'ast>,
|
||||
) -> Vec<zir::Parameter<'ast>> {
|
||||
let private = p.private;
|
||||
self.fold_variable(p.id)
|
||||
self.fold_variable(p.id.try_into().unwrap())
|
||||
.into_iter()
|
||||
.map(|v| zir::Parameter { id: v, private })
|
||||
.collect()
|
||||
|
@ -87,10 +92,12 @@ impl<'ast, T: Field> Flattener<T> {
|
|||
zir::SourceIdentifier::Basic(n)
|
||||
}
|
||||
|
||||
fn fold_variable(&mut self, v: typed_absy::Variable<'ast>) -> Vec<zir::Variable<'ast>> {
|
||||
fn fold_variable(&mut self, v: typed_absy::Variable<'ast, T>) -> Vec<zir::Variable<'ast>> {
|
||||
let id = self.fold_name(v.id.clone());
|
||||
let ty = v.get_type();
|
||||
|
||||
let ty = typed_absy::types::ConcreteType::try_from(ty).unwrap();
|
||||
|
||||
flatten_identifier_rec(id, ty)
|
||||
}
|
||||
|
||||
|
@ -146,6 +153,8 @@ impl<'ast, T: Field> Flattener<T> {
|
|||
) -> zir::ZirExpressionList<'ast, T> {
|
||||
match es {
|
||||
typed_absy::TypedExpressionList::FunctionCall(id, arguments, _) => {
|
||||
let id = typed_absy::types::ConcreteFunctionKey::try_from(id).unwrap();
|
||||
|
||||
zir::ZirExpressionList::FunctionCall(
|
||||
self.fold_function_key(id),
|
||||
arguments
|
||||
|
@ -160,7 +169,7 @@ impl<'ast, T: Field> Flattener<T> {
|
|||
|
||||
fn fold_function_key(
|
||||
&mut self,
|
||||
k: typed_absy::types::FunctionKey<'ast>,
|
||||
k: typed_absy::types::ConcreteFunctionKey<'ast>,
|
||||
) -> zir::types::FunctionKey<'ast> {
|
||||
k.into()
|
||||
}
|
||||
|
@ -194,7 +203,7 @@ impl<'ast, T: Field> Flattener<T> {
|
|||
|
||||
fn fold_array_expression_inner(
|
||||
&mut self,
|
||||
ty: &typed_absy::Type,
|
||||
ty: &typed_absy::types::ConcreteType,
|
||||
size: usize,
|
||||
e: typed_absy::ArrayExpressionInner<'ast, T>,
|
||||
) -> Vec<zir::ZirExpression<'ast, T>> {
|
||||
|
@ -202,7 +211,7 @@ impl<'ast, T: Field> Flattener<T> {
|
|||
}
|
||||
fn fold_struct_expression_inner(
|
||||
&mut self,
|
||||
ty: &StructType,
|
||||
ty: &typed_absy::types::ConcreteStructType,
|
||||
e: typed_absy::StructExpressionInner<'ast, T>,
|
||||
) -> Vec<zir::ZirExpression<'ast, T>> {
|
||||
fold_struct_expression_inner(self, ty, e)
|
||||
|
@ -217,7 +226,12 @@ pub fn fold_module<'ast, T: Field>(
|
|||
functions: p
|
||||
.functions
|
||||
.into_iter()
|
||||
.map(|(key, fun)| (f.fold_function_key(key), f.fold_function_symbol(fun)))
|
||||
.map(|(key, fun)| {
|
||||
(
|
||||
f.fold_function_key(key.try_into().unwrap()),
|
||||
f.fold_function_symbol(fun),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
@ -267,14 +281,16 @@ pub fn fold_statement<'ast, T: Field>(
|
|||
|
||||
pub fn fold_array_expression_inner<'ast, T: Field>(
|
||||
f: &mut Flattener<T>,
|
||||
t: &typed_absy::Type,
|
||||
t: &typed_absy::types::ConcreteType,
|
||||
size: usize,
|
||||
e: typed_absy::ArrayExpressionInner<'ast, T>,
|
||||
) -> Vec<zir::ZirExpression<'ast, T>> {
|
||||
match e {
|
||||
typed_absy::ArrayExpressionInner::Identifier(id) => {
|
||||
let variables =
|
||||
flatten_identifier_rec(f.fold_name(id), typed_absy::Type::array(t.clone(), size));
|
||||
let variables = flatten_identifier_rec(
|
||||
f.fold_name(id),
|
||||
typed_absy::types::ConcreteType::array(t.clone(), size),
|
||||
);
|
||||
variables
|
||||
.into_iter()
|
||||
.map(|v| match v._type {
|
||||
|
@ -329,7 +345,11 @@ pub fn fold_array_expression_inner<'ast, T: Field>(
|
|||
let offset: usize = members
|
||||
.iter()
|
||||
.take_while(|member| member.id != id)
|
||||
.map(|member| member.ty.get_primitive_count())
|
||||
.map(|member| {
|
||||
typed_absy::types::ConcreteType::try_from(*member.ty)
|
||||
.unwrap()
|
||||
.get_primitive_count()
|
||||
})
|
||||
.sum();
|
||||
|
||||
// we also need the size of this member
|
||||
|
@ -339,12 +359,15 @@ pub fn fold_array_expression_inner<'ast, T: Field>(
|
|||
}
|
||||
typed_absy::ArrayExpressionInner::Select(box array, box index) => {
|
||||
let array = f.fold_array_expression(array);
|
||||
let index = f.fold_field_expression(index);
|
||||
let index = f.fold_uint_expression(index);
|
||||
|
||||
match index {
|
||||
zir::FieldElementExpression::Number(i) => {
|
||||
let size = t.get_primitive_count() * size;
|
||||
let start = i.to_dec_string().parse::<usize>().unwrap() * size;
|
||||
match index.into_inner() {
|
||||
zir::UExpressionInner::Value(i) => {
|
||||
let size = typed_absy::types::ConcreteType::try_from(*t)
|
||||
.unwrap()
|
||||
.get_primitive_count()
|
||||
* size;
|
||||
let start = i as usize * size;
|
||||
let end = start + size;
|
||||
array[start..end].to_vec()
|
||||
}
|
||||
|
@ -356,13 +379,15 @@ pub fn fold_array_expression_inner<'ast, T: Field>(
|
|||
|
||||
pub fn fold_struct_expression_inner<'ast, T: Field>(
|
||||
f: &mut Flattener<T>,
|
||||
t: &StructType,
|
||||
t: &typed_absy::types::ConcreteStructType,
|
||||
e: typed_absy::StructExpressionInner<'ast, T>,
|
||||
) -> Vec<zir::ZirExpression<'ast, T>> {
|
||||
match e {
|
||||
typed_absy::StructExpressionInner::Identifier(id) => {
|
||||
let variables =
|
||||
flatten_identifier_rec(f.fold_name(id), typed_absy::Type::struc(t.clone()));
|
||||
let variables = flatten_identifier_rec(
|
||||
f.fold_name(id),
|
||||
typed_absy::types::ConcreteType::struc(t.clone()),
|
||||
);
|
||||
variables
|
||||
.into_iter()
|
||||
.map(|v| match v._type {
|
||||
|
@ -417,30 +442,33 @@ pub fn fold_struct_expression_inner<'ast, T: Field>(
|
|||
let offset: usize = members
|
||||
.iter()
|
||||
.take_while(|member| member.id != id)
|
||||
.map(|member| member.ty.get_primitive_count())
|
||||
.map(|member| {
|
||||
typed_absy::types::ConcreteType::try_from(*member.ty)
|
||||
.unwrap()
|
||||
.get_primitive_count()
|
||||
})
|
||||
.sum();
|
||||
|
||||
// we also need the size of this member
|
||||
let size = t
|
||||
.iter()
|
||||
.find(|member| member.id == id)
|
||||
.unwrap()
|
||||
.ty
|
||||
.get_primitive_count();
|
||||
let size = typed_absy::types::ConcreteType::try_from(
|
||||
*t.iter().find(|member| member.id == id).unwrap().ty,
|
||||
)
|
||||
.unwrap()
|
||||
.get_primitive_count();
|
||||
|
||||
s[offset..offset + size].to_vec()
|
||||
}
|
||||
typed_absy::StructExpressionInner::Select(box array, box index) => {
|
||||
let array = f.fold_array_expression(array);
|
||||
let index = f.fold_field_expression(index);
|
||||
let index = f.fold_uint_expression(index);
|
||||
|
||||
match index {
|
||||
zir::FieldElementExpression::Number(i) => {
|
||||
match index.into_inner() {
|
||||
zir::UExpressionInner::Value(i) => {
|
||||
let size = t
|
||||
.iter()
|
||||
.map(|m| m.ty.get_primitive_count())
|
||||
.fold(0, |acc, current| acc + current);
|
||||
let start = i.to_dec_string().parse::<usize>().unwrap() * size;
|
||||
let start = i as usize * size;
|
||||
let end = start + size;
|
||||
array[start..end].to_vec()
|
||||
}
|
||||
|
@ -458,9 +486,12 @@ pub fn fold_field_expression<'ast, T: Field>(
|
|||
typed_absy::FieldElementExpression::Number(n) => zir::FieldElementExpression::Number(n),
|
||||
typed_absy::FieldElementExpression::Identifier(id) => {
|
||||
zir::FieldElementExpression::Identifier(
|
||||
flatten_identifier_rec(f.fold_name(id), typed_absy::Type::FieldElement)[0]
|
||||
.id
|
||||
.clone(),
|
||||
flatten_identifier_rec(
|
||||
f.fold_name(id),
|
||||
typed_absy::types::ConcreteType::FieldElement,
|
||||
)[0]
|
||||
.id
|
||||
.clone(),
|
||||
)
|
||||
}
|
||||
typed_absy::FieldElementExpression::Add(box e1, box e2) => {
|
||||
|
@ -503,26 +534,22 @@ pub fn fold_field_expression<'ast, T: Field>(
|
|||
let offset: usize = members
|
||||
.iter()
|
||||
.take_while(|member| member.id != id)
|
||||
.map(|member| member.ty.get_primitive_count())
|
||||
.map(|member| {
|
||||
typed_absy::types::ConcreteType::try_from(*member.ty)
|
||||
.unwrap()
|
||||
.get_primitive_count()
|
||||
})
|
||||
.sum();
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
s[offset].clone().try_into().unwrap()
|
||||
}
|
||||
typed_absy::FieldElementExpression::Select(box array, box index) => {
|
||||
let array = f.fold_array_expression(array);
|
||||
|
||||
let index = f.fold_field_expression(index);
|
||||
let index = f.fold_uint_expression(index);
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
match index {
|
||||
zir::FieldElementExpression::Number(i) => array
|
||||
[i.to_dec_string().parse::<usize>().unwrap()]
|
||||
.clone()
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
match index.into_inner() {
|
||||
zir::UExpressionInner::Value(i) => array[i as usize].clone().try_into().unwrap(),
|
||||
_ => unreachable!(""),
|
||||
}
|
||||
}
|
||||
|
@ -536,7 +563,7 @@ pub fn fold_boolean_expression<'ast, T: Field>(
|
|||
match e {
|
||||
typed_absy::BooleanExpression::Value(v) => zir::BooleanExpression::Value(v),
|
||||
typed_absy::BooleanExpression::Identifier(id) => zir::BooleanExpression::Identifier(
|
||||
flatten_identifier_rec(f.fold_name(id), typed_absy::Type::Boolean)[0]
|
||||
flatten_identifier_rec(f.fold_name(id), typed_absy::types::ConcreteType::Boolean)[0]
|
||||
.id
|
||||
.clone(),
|
||||
),
|
||||
|
@ -661,25 +688,21 @@ pub fn fold_boolean_expression<'ast, T: Field>(
|
|||
let offset: usize = members
|
||||
.iter()
|
||||
.take_while(|member| member.id != id)
|
||||
.map(|member| member.ty.get_primitive_count())
|
||||
.map(|member| {
|
||||
typed_absy::types::ConcreteType::try_from(*member.ty)
|
||||
.unwrap()
|
||||
.get_primitive_count()
|
||||
})
|
||||
.sum();
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
s[offset].clone().try_into().unwrap()
|
||||
}
|
||||
typed_absy::BooleanExpression::Select(box array, box index) => {
|
||||
let array = f.fold_array_expression(array);
|
||||
let index = f.fold_field_expression(index);
|
||||
let index = f.fold_uint_expression(index);
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
match index {
|
||||
zir::FieldElementExpression::Number(i) => array
|
||||
[i.to_dec_string().parse::<usize>().unwrap()]
|
||||
.clone()
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
match index.into_inner() {
|
||||
zir::UExpressionInner::Value(i) => array[i as usize].clone().try_into().unwrap(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -702,9 +725,12 @@ pub fn fold_uint_expression_inner<'ast, T: Field>(
|
|||
match e {
|
||||
typed_absy::UExpressionInner::Value(v) => zir::UExpressionInner::Value(v),
|
||||
typed_absy::UExpressionInner::Identifier(id) => zir::UExpressionInner::Identifier(
|
||||
flatten_identifier_rec(f.fold_name(id), typed_absy::Type::Uint(bitwidth))[0]
|
||||
.id
|
||||
.clone(),
|
||||
flatten_identifier_rec(
|
||||
f.fold_name(id),
|
||||
typed_absy::types::ConcreteType::Uint(bitwidth),
|
||||
)[0]
|
||||
.id
|
||||
.clone(),
|
||||
),
|
||||
typed_absy::UExpressionInner::Add(box left, box right) => {
|
||||
let left = f.fold_uint_expression(left);
|
||||
|
@ -764,16 +790,11 @@ pub fn fold_uint_expression_inner<'ast, T: Field>(
|
|||
}
|
||||
typed_absy::UExpressionInner::Select(box array, box index) => {
|
||||
let array = f.fold_array_expression(array);
|
||||
let index = f.fold_field_expression(index);
|
||||
let index = f.fold_uint_expression(index);
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
match index {
|
||||
zir::FieldElementExpression::Number(i) => {
|
||||
let e: zir::UExpression<_> = array[i.to_dec_string().parse::<usize>().unwrap()]
|
||||
.clone()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
match index.into_inner() {
|
||||
zir::UExpressionInner::Value(i) => {
|
||||
let e: zir::UExpression<_> = array[i as usize].clone().try_into().unwrap();
|
||||
e.into_inner()
|
||||
}
|
||||
_ => unreachable!(),
|
||||
|
@ -787,11 +808,13 @@ pub fn fold_uint_expression_inner<'ast, T: Field>(
|
|||
let offset: usize = members
|
||||
.iter()
|
||||
.take_while(|member| member.id != id)
|
||||
.map(|member| member.ty.get_primitive_count())
|
||||
.map(|member| {
|
||||
typed_absy::types::ConcreteType::try_from(*member.ty)
|
||||
.unwrap()
|
||||
.get_primitive_count()
|
||||
})
|
||||
.sum();
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
let res: zir::UExpression<'ast, T> = s[offset].clone().try_into().unwrap();
|
||||
|
||||
res.into_inner()
|
||||
|
@ -813,14 +836,16 @@ pub fn fold_function<'ast, T: Field>(
|
|||
arguments: fun
|
||||
.arguments
|
||||
.into_iter()
|
||||
.flat_map(|a| f.fold_parameter(a))
|
||||
.flat_map(|a| f.fold_declaration_parameter(a))
|
||||
.collect(),
|
||||
statements: fun
|
||||
.statements
|
||||
.into_iter()
|
||||
.flat_map(|s| f.fold_statement(s))
|
||||
.collect(),
|
||||
signature: fun.signature.into(),
|
||||
signature: typed_absy::types::ConcreteSignature::try_from(fun.signature)
|
||||
.unwrap()
|
||||
.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -828,14 +853,25 @@ pub fn fold_array_expression<'ast, T: Field>(
|
|||
f: &mut Flattener<T>,
|
||||
e: typed_absy::ArrayExpression<'ast, T>,
|
||||
) -> Vec<zir::ZirExpression<'ast, T>> {
|
||||
f.fold_array_expression_inner(&e.inner_type().clone(), e.size(), e.into_inner())
|
||||
let size = match e.size().into_inner() {
|
||||
typed_absy::UExpressionInner::Value(v) => v,
|
||||
_ => unreachable!(),
|
||||
} as usize;
|
||||
f.fold_array_expression_inner(
|
||||
&typed_absy::types::ConcreteType::try_from(e.inner_type().clone()).unwrap(),
|
||||
size,
|
||||
e.into_inner(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn fold_struct_expression<'ast, T: Field>(
|
||||
f: &mut Flattener<T>,
|
||||
e: typed_absy::StructExpression<'ast, T>,
|
||||
) -> Vec<zir::ZirExpression<'ast, T>> {
|
||||
f.fold_struct_expression_inner(&e.ty().clone(), e.into_inner())
|
||||
f.fold_struct_expression_inner(
|
||||
&typed_absy::types::ConcreteStructType::try_from(e.ty().clone()).unwrap(),
|
||||
e.into_inner(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn fold_function_symbol<'ast, T: Field>(
|
||||
|
@ -846,9 +882,10 @@ pub fn fold_function_symbol<'ast, T: Field>(
|
|||
typed_absy::TypedFunctionSymbol::Here(fun) => {
|
||||
zir::ZirFunctionSymbol::Here(f.fold_function(fun))
|
||||
}
|
||||
typed_absy::TypedFunctionSymbol::There(key, module) => {
|
||||
zir::ZirFunctionSymbol::There(f.fold_function_key(key), module)
|
||||
} // by default, do not fold modules recursively
|
||||
typed_absy::TypedFunctionSymbol::There(key, module) => zir::ZirFunctionSymbol::There(
|
||||
f.fold_function_key(typed_absy::types::ConcreteFunctionKey::try_from(key).unwrap()),
|
||||
module,
|
||||
), // by default, do not fold modules recursively
|
||||
typed_absy::TypedFunctionSymbol::Flat(flat) => zir::ZirFunctionSymbol::Flat(flat),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
use static_analysis::propagate_unroll::{Blocked, Output};
|
||||
use std::collections::HashMap;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use typed_absy::types::ConcreteFunctionKey;
|
||||
use typed_absy::types::{FunctionKey, Type, UBitwidth};
|
||||
use typed_absy::{folder::*, *};
|
||||
use zokrates_field::Field;
|
||||
|
@ -25,7 +27,7 @@ use zokrates_field::Field;
|
|||
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
||||
struct Location<'ast> {
|
||||
module: TypedModuleId,
|
||||
key: FunctionKey<'ast>,
|
||||
key: ConcreteFunctionKey<'ast>,
|
||||
}
|
||||
|
||||
impl<'ast> Location<'ast> {
|
||||
|
@ -37,11 +39,16 @@ impl<'ast> Location<'ast> {
|
|||
type CallCache<'ast, T> = HashMap<
|
||||
Location<'ast>,
|
||||
HashMap<
|
||||
FunctionKey<'ast>,
|
||||
ConcreteFunctionKey<'ast>,
|
||||
HashMap<Vec<TypedExpression<'ast, T>>, Vec<TypedExpression<'ast, T>>>,
|
||||
>,
|
||||
>;
|
||||
|
||||
enum InlineError<'ast, T> {
|
||||
Flat(FunctionKey<'ast, T>, Vec<TypedExpression<'ast, T>>),
|
||||
NonConstant(FunctionKey<'ast, T>, Vec<TypedExpression<'ast, T>>),
|
||||
}
|
||||
|
||||
/// An inliner
|
||||
#[derive(Debug)]
|
||||
pub struct Inliner<'ast, T: Field> {
|
||||
|
@ -52,9 +59,9 @@ pub struct Inliner<'ast, T: Field> {
|
|||
/// a buffer of statements to be added to the inlined statements
|
||||
statement_buffer: Vec<TypedStatement<'ast, T>>,
|
||||
/// the current call stack
|
||||
stack: Vec<(TypedModuleId, FunctionKey<'ast>, usize)>,
|
||||
stack: Vec<(TypedModuleId, ConcreteFunctionKey<'ast>, usize)>,
|
||||
/// the call count for each function
|
||||
call_count: HashMap<(TypedModuleId, FunctionKey<'ast>), usize>,
|
||||
call_count: HashMap<(TypedModuleId, ConcreteFunctionKey<'ast>), usize>,
|
||||
/// the cache for memoization: for each function body, tracks function calls
|
||||
call_cache: CallCache<'ast, T>,
|
||||
/// whether the inliner is blocked, and why
|
||||
|
@ -65,7 +72,7 @@ impl<'ast, T: Field> Inliner<'ast, T> {
|
|||
fn with_modules_and_module_id_and_key<S: Into<TypedModuleId>>(
|
||||
modules: TypedModules<'ast, T>,
|
||||
module_id: S,
|
||||
key: FunctionKey<'ast>,
|
||||
key: ConcreteFunctionKey<'ast>,
|
||||
) -> Self {
|
||||
Inliner {
|
||||
modules,
|
||||
|
@ -95,7 +102,11 @@ impl<'ast, T: Field> Inliner<'ast, T> {
|
|||
.0;
|
||||
|
||||
// initialize an inliner over all modules, starting from the main module
|
||||
Inliner::with_modules_and_module_id_and_key(p.modules, main_module_id, main_key.clone())
|
||||
Inliner::with_modules_and_module_id_and_key(
|
||||
p.modules,
|
||||
main_module_id,
|
||||
main_key.clone().try_into().unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn inline(&mut self, p: TypedProgram<'ast, T>) -> Output<'ast, T> {
|
||||
|
@ -162,22 +173,47 @@ impl<'ast, T: Field> Inliner<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_concrete_function(
|
||||
&self,
|
||||
key: ConcreteFunctionKey<'ast>,
|
||||
) -> TypedFunctionSymbol<'ast, T> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn try_inline_call(
|
||||
&mut self,
|
||||
key: FunctionKey<'ast, T>,
|
||||
expressions: Vec<TypedExpression<'ast, T>>,
|
||||
) -> Result<Vec<TypedExpression<'ast, T>>, InlineError<'ast, T>> {
|
||||
match ConcreteFunctionKey::try_from(key) {
|
||||
Ok(key) => self
|
||||
.try_inline_concrete_call(key, expressions)
|
||||
.map_err(|e| InlineError::Flat(e.0.into(), e.1)),
|
||||
Err(()) => {
|
||||
self.blocked = Some(Blocked::Inline);
|
||||
Err(InlineError::NonConstant(key, expressions))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// try to inline a call to function with key `key` in the stack of `self`
|
||||
/// if inlining succeeds, return the expressions returned by the function call
|
||||
/// if inlining fails (as in the case of flat function symbols), return the arguments to the function call for further processing
|
||||
fn try_inline_call(
|
||||
fn try_inline_concrete_call(
|
||||
&mut self,
|
||||
key: &FunctionKey<'ast>,
|
||||
key: ConcreteFunctionKey<'ast>,
|
||||
expressions: Vec<TypedExpression<'ast, T>>,
|
||||
) -> Result<Vec<TypedExpression<'ast, T>>, (FunctionKey<'ast>, Vec<TypedExpression<'ast, T>>)>
|
||||
{
|
||||
match self.call_cache().get(key).map(|m| m.get(&expressions)) {
|
||||
) -> Result<
|
||||
Vec<TypedExpression<'ast, T>>,
|
||||
(ConcreteFunctionKey<'ast>, Vec<TypedExpression<'ast, T>>),
|
||||
> {
|
||||
match self.call_cache().get(&key).map(|m| m.get(&expressions)) {
|
||||
Some(Some(exprs)) => return Ok(exprs.clone()),
|
||||
_ => {}
|
||||
};
|
||||
|
||||
// here we clone a function symbol, which is cheap except when it contains the function body, in which case we'd clone anyways
|
||||
let res = match self.module().functions.get(&key).unwrap().clone() {
|
||||
let res = match self.get_concrete_function(key) {
|
||||
// if the function called is in the same module, we can go ahead and inline in this module
|
||||
TypedFunctionSymbol::Here(function) => {
|
||||
let (current_module, current_key) =
|
||||
|
@ -200,7 +236,7 @@ impl<'ast, T: Field> Inliner<'ast, T> {
|
|||
.zip(expressions.clone())
|
||||
.map(|(a, e)| {
|
||||
TypedStatement::Definition(
|
||||
self.fold_assignee(TypedAssignee::Identifier(a.id.clone())),
|
||||
self.fold_assignee(TypedAssignee::Identifier(a.id.clone().into())),
|
||||
e,
|
||||
)
|
||||
})
|
||||
|
@ -233,24 +269,31 @@ impl<'ast, T: Field> Inliner<'ast, T> {
|
|||
}
|
||||
// if the function called is in some other module, we switch focus to that module and call the function locally there
|
||||
TypedFunctionSymbol::There(function_key, module_id) => {
|
||||
// switch focus to `module_id`
|
||||
let (current_module, current_key) =
|
||||
self.change_context(module_id, function_key.clone());
|
||||
// inline the call there
|
||||
let res = self.try_inline_call(&function_key, expressions.clone())?;
|
||||
// switch back focus
|
||||
self.change_context(current_module, current_key);
|
||||
Ok(res)
|
||||
unimplemented!()
|
||||
|
||||
// let function_key = function_key.try_into().unwrap();
|
||||
|
||||
// // switch focus to `module_id`
|
||||
// let (current_module, current_key) =
|
||||
// self.change_context(module_id, function_key.clone());
|
||||
// // inline the call there
|
||||
// let res = self.try_inline_call(&function_key, expressions.clone())?;
|
||||
// // switch back focus
|
||||
// self.change_context(current_module, current_key);
|
||||
// Ok(res)
|
||||
}
|
||||
// if the function is a flat symbol, replace the call with a call to the local function we provide so it can be inlined in flattening
|
||||
TypedFunctionSymbol::Flat(embed) => {
|
||||
// increase the number of calls for this function by one
|
||||
let _ = self
|
||||
.call_count
|
||||
.entry((self.module_id().clone(), embed.key::<T>().clone()))
|
||||
.entry((
|
||||
self.module_id().clone(),
|
||||
embed.key::<T>().clone().try_into().unwrap(),
|
||||
))
|
||||
.and_modify(|i| *i += 1)
|
||||
.or_insert(1);
|
||||
Err((embed.key::<T>(), expressions.clone()))
|
||||
Err((embed.key::<T>().try_into().unwrap(), expressions.clone()))
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -267,8 +310,8 @@ impl<'ast, T: Field> Inliner<'ast, T> {
|
|||
fn change_context(
|
||||
&mut self,
|
||||
module_id: TypedModuleId,
|
||||
function_key: FunctionKey<'ast>,
|
||||
) -> (TypedModuleId, FunctionKey<'ast>) {
|
||||
function_key: ConcreteFunctionKey<'ast>,
|
||||
) -> (TypedModuleId, ConcreteFunctionKey<'ast>) {
|
||||
let current_module = std::mem::replace(&mut self.location.module, module_id);
|
||||
let current_key = std::mem::replace(&mut self.location.key, function_key);
|
||||
(current_module, current_key)
|
||||
|
@ -281,7 +324,7 @@ impl<'ast, T: Field> Inliner<'ast, T> {
|
|||
fn call_cache(
|
||||
&mut self,
|
||||
) -> &HashMap<
|
||||
FunctionKey<'ast>,
|
||||
ConcreteFunctionKey<'ast>,
|
||||
HashMap<Vec<TypedExpression<'ast, T>>, Vec<TypedExpression<'ast, T>>>,
|
||||
> {
|
||||
self.call_cache
|
||||
|
@ -292,7 +335,7 @@ impl<'ast, T: Field> Inliner<'ast, T> {
|
|||
fn call_cache_mut(
|
||||
&mut self,
|
||||
) -> &mut HashMap<
|
||||
FunctionKey<'ast>,
|
||||
ConcreteFunctionKey<'ast>,
|
||||
HashMap<Vec<TypedExpression<'ast, T>>, Vec<TypedExpression<'ast, T>>>,
|
||||
> {
|
||||
self.call_cache.get_mut(&self.location).unwrap()
|
||||
|
@ -305,7 +348,10 @@ impl<'ast, T: Field> Inliner<'ast, T> {
|
|||
|
||||
impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
|
||||
// add extra statements before the modified statement
|
||||
fn fold_statement(&mut self, s: TypedStatement<'ast, T>) -> Vec<TypedStatement<'ast, T>> {
|
||||
fn fold_statement<'a>(
|
||||
&'a mut self,
|
||||
s: TypedStatement<'ast, T>,
|
||||
) -> Vec<TypedStatement<'ast, T>> {
|
||||
let folded = match s {
|
||||
TypedStatement::For(v, from, to, statements) => {
|
||||
self.blocked = Some(Blocked::Unroll);
|
||||
|
@ -319,7 +365,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
|
|||
.collect();
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
||||
match self.try_inline_call(&key, exps) {
|
||||
match self.try_inline_call(key, exps) {
|
||||
Ok(ret) => variables
|
||||
.into_iter()
|
||||
.zip(ret.into_iter())
|
||||
|
@ -327,16 +373,22 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
|
|||
TypedStatement::Definition(TypedAssignee::Identifier(v), e)
|
||||
})
|
||||
.collect(),
|
||||
Err((key, expressions)) => vec![TypedStatement::MultipleDefinition(
|
||||
variables,
|
||||
TypedExpressionList::FunctionCall(key, expressions, types),
|
||||
)],
|
||||
Err(e) => match e {
|
||||
InlineError::Flat(key, expressions)
|
||||
| InlineError::NonConstant(key, expressions) => {
|
||||
vec![TypedStatement::MultipleDefinition(
|
||||
variables,
|
||||
TypedExpressionList::FunctionCall(key, expressions, types),
|
||||
)]
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
s => fold_statement(self, s),
|
||||
};
|
||||
self.statement_buffer.drain(..).chain(folded).collect()
|
||||
unimplemented!()
|
||||
//self.statement_buffer.drain(..).chain(folded).collect()
|
||||
}
|
||||
|
||||
// prefix all names with the stack
|
||||
|
@ -356,28 +408,50 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
|
|||
FieldElementExpression::FunctionCall(key, exps) => {
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
||||
match self.try_inline_call(&key, exps) {
|
||||
match self.try_inline_call(key, exps) {
|
||||
Ok(mut ret) => match ret.pop().unwrap() {
|
||||
TypedExpression::FieldElement(e) => e,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Err((key, expressions)) => {
|
||||
let tys = key.signature.outputs.clone();
|
||||
let id = Identifier {
|
||||
id: CoreIdentifier::Call(key.clone()),
|
||||
version: *self
|
||||
.call_count
|
||||
.get(&(self.module_id().clone(), key.clone()))
|
||||
.unwrap(),
|
||||
stack: self.stack.clone(),
|
||||
};
|
||||
self.statement_buffer
|
||||
.push(TypedStatement::MultipleDefinition(
|
||||
vec![Variable::with_id_and_type(id.clone(), tys[0].clone())],
|
||||
TypedExpressionList::FunctionCall(key, expressions, tys),
|
||||
));
|
||||
FieldElementExpression::Identifier(id)
|
||||
}
|
||||
Err(e) => match e {
|
||||
InlineError::Flat(key, expressions) => {
|
||||
let key = ConcreteFunctionKey::try_from(key).unwrap();
|
||||
let tys = key.signature.outputs.clone();
|
||||
let id = Identifier {
|
||||
id: CoreIdentifier::Call(key.clone()),
|
||||
version: *self
|
||||
.call_count
|
||||
.get(&(self.module_id().clone(), key.clone()))
|
||||
.unwrap(),
|
||||
stack: self.stack.clone(),
|
||||
};
|
||||
self.statement_buffer
|
||||
.push(TypedStatement::MultipleDefinition(
|
||||
vec![Variable::with_id_and_type(
|
||||
id.clone(),
|
||||
tys[0].clone().into(),
|
||||
)],
|
||||
TypedExpressionList::FunctionCall(
|
||||
key.into(),
|
||||
expressions,
|
||||
tys.into_iter().map(|t| t.into()).collect(),
|
||||
),
|
||||
));
|
||||
|
||||
self.call_cache_mut()
|
||||
.entry(key.clone())
|
||||
.or_insert_with(|| HashMap::new())
|
||||
.insert(
|
||||
expressions,
|
||||
vec![FieldElementExpression::Identifier(id.clone()).into()],
|
||||
);
|
||||
|
||||
FieldElementExpression::Identifier(id)
|
||||
}
|
||||
InlineError::NonConstant(key, expressions) => {
|
||||
FieldElementExpression::FunctionCall(key, expressions)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
e => fold_field_expression(self, e),
|
||||
|
@ -393,41 +467,51 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
|
|||
BooleanExpression::FunctionCall(key, exps) => {
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
||||
match self.try_inline_call(&key, exps) {
|
||||
match self.try_inline_call(key, exps) {
|
||||
Ok(mut ret) => match ret.pop().unwrap() {
|
||||
TypedExpression::Boolean(e) => e,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Err((key, expressions)) => {
|
||||
let tys = key.signature.outputs.clone();
|
||||
let id = Identifier {
|
||||
id: CoreIdentifier::Call(key.clone()),
|
||||
version: *self
|
||||
.call_count
|
||||
.get(&(self.module_id().clone(), key.clone()))
|
||||
.unwrap(),
|
||||
stack: self.stack.clone(),
|
||||
};
|
||||
self.statement_buffer
|
||||
.push(TypedStatement::MultipleDefinition(
|
||||
vec![Variable::with_id_and_type(id.clone(), tys[0].clone())],
|
||||
TypedExpressionList::FunctionCall(
|
||||
key.clone(),
|
||||
expressions.clone(),
|
||||
tys,
|
||||
),
|
||||
));
|
||||
Err(e) => match e {
|
||||
InlineError::Flat(key, expressions) => {
|
||||
let key = ConcreteFunctionKey::try_from(key).unwrap();
|
||||
|
||||
self.call_cache_mut()
|
||||
.entry(key.clone())
|
||||
.or_insert_with(|| HashMap::new())
|
||||
.insert(
|
||||
expressions,
|
||||
vec![BooleanExpression::Identifier(id.clone()).into()],
|
||||
);
|
||||
let tys = key.signature.outputs.clone();
|
||||
let id = Identifier {
|
||||
id: CoreIdentifier::Call(key.clone()),
|
||||
version: *self
|
||||
.call_count
|
||||
.get(&(self.module_id().clone(), key.clone()))
|
||||
.unwrap(),
|
||||
stack: self.stack.clone(),
|
||||
};
|
||||
self.statement_buffer
|
||||
.push(TypedStatement::MultipleDefinition(
|
||||
vec![Variable::with_id_and_type(
|
||||
id.clone(),
|
||||
tys[0].clone().into(),
|
||||
)],
|
||||
TypedExpressionList::FunctionCall(
|
||||
key.into(),
|
||||
expressions,
|
||||
tys.into_iter().map(|t| t.into()).collect(),
|
||||
),
|
||||
));
|
||||
|
||||
BooleanExpression::Identifier(id)
|
||||
}
|
||||
self.call_cache_mut()
|
||||
.entry(key.clone())
|
||||
.or_insert_with(|| HashMap::new())
|
||||
.insert(
|
||||
expressions,
|
||||
vec![BooleanExpression::Identifier(id.clone()).into()],
|
||||
);
|
||||
|
||||
BooleanExpression::Identifier(id)
|
||||
}
|
||||
InlineError::NonConstant(key, expressions) => {
|
||||
BooleanExpression::FunctionCall(key, expressions)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
e => fold_boolean_expression(self, e),
|
||||
|
@ -437,51 +521,61 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
|
|||
// inline calls which return an array
|
||||
fn fold_array_expression_inner(
|
||||
&mut self,
|
||||
ty: &Type,
|
||||
size: usize,
|
||||
ty: &Type<'ast, T>,
|
||||
size: UExpression<'ast, T>,
|
||||
e: ArrayExpressionInner<'ast, T>,
|
||||
) -> ArrayExpressionInner<'ast, T> {
|
||||
match e {
|
||||
ArrayExpressionInner::FunctionCall(key, exps) => {
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
||||
match self.try_inline_call(&key, exps) {
|
||||
match self.try_inline_call(key, exps) {
|
||||
Ok(mut ret) => match ret.pop().unwrap() {
|
||||
TypedExpression::Array(e) => e.into_inner(),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Err((embed_key, expressions)) => {
|
||||
let tys = key.signature.outputs.clone();
|
||||
let id = Identifier {
|
||||
id: CoreIdentifier::Call(key.clone()),
|
||||
version: *self
|
||||
.call_count
|
||||
.get(&(self.module_id().clone(), embed_key.clone()))
|
||||
.unwrap(),
|
||||
stack: self.stack.clone(),
|
||||
};
|
||||
self.statement_buffer
|
||||
.push(TypedStatement::MultipleDefinition(
|
||||
vec![Variable::with_id_and_type(id.clone(), tys[0].clone())],
|
||||
TypedExpressionList::FunctionCall(
|
||||
embed_key.clone(),
|
||||
expressions.clone(),
|
||||
tys,
|
||||
),
|
||||
));
|
||||
Err(e) => match e {
|
||||
InlineError::Flat(key, expressions) => {
|
||||
let key = ConcreteFunctionKey::try_from(key).unwrap();
|
||||
|
||||
let out = ArrayExpressionInner::Identifier(id);
|
||||
let tys = key.signature.outputs.clone();
|
||||
let id = Identifier {
|
||||
id: CoreIdentifier::Call(key.clone()),
|
||||
version: *self
|
||||
.call_count
|
||||
.get(&(self.module_id().clone(), key.clone()))
|
||||
.unwrap(),
|
||||
stack: self.stack.clone(),
|
||||
};
|
||||
self.statement_buffer
|
||||
.push(TypedStatement::MultipleDefinition(
|
||||
vec![Variable::with_id_and_type(
|
||||
id.clone(),
|
||||
tys[0].clone().into(),
|
||||
)],
|
||||
TypedExpressionList::FunctionCall(
|
||||
key.into(),
|
||||
expressions.clone(),
|
||||
tys.into_iter().map(|t| t.into()).collect(),
|
||||
),
|
||||
));
|
||||
|
||||
self.call_cache_mut()
|
||||
.entry(key.clone())
|
||||
.or_insert_with(|| HashMap::new())
|
||||
.insert(
|
||||
expressions,
|
||||
vec![out.clone().annotate(ty.clone(), size).into()],
|
||||
);
|
||||
let out = ArrayExpressionInner::Identifier(id);
|
||||
|
||||
out
|
||||
}
|
||||
self.call_cache_mut()
|
||||
.entry(key.clone())
|
||||
.or_insert_with(|| HashMap::new())
|
||||
.insert(
|
||||
expressions,
|
||||
vec![out.clone().annotate(ty.clone().into(), size).into()],
|
||||
);
|
||||
|
||||
out
|
||||
}
|
||||
InlineError::NonConstant(key, expressions) => {
|
||||
ArrayExpressionInner::FunctionCall(key, expressions)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
// default
|
||||
|
@ -491,35 +585,57 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
|
|||
|
||||
fn fold_struct_expression_inner(
|
||||
&mut self,
|
||||
ty: &StructType,
|
||||
ty: &StructType<'ast, T>,
|
||||
e: StructExpressionInner<'ast, T>,
|
||||
) -> StructExpressionInner<'ast, T> {
|
||||
match e {
|
||||
StructExpressionInner::FunctionCall(key, exps) => {
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
||||
match self.try_inline_call(&key, exps) {
|
||||
match self.try_inline_call(key, exps) {
|
||||
Ok(mut ret) => match ret.pop().unwrap() {
|
||||
TypedExpression::Struct(e) => e.into_inner(),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Err((key, expressions)) => {
|
||||
let tys = key.signature.outputs.clone();
|
||||
let id = Identifier {
|
||||
id: CoreIdentifier::Call(key.clone()),
|
||||
version: *self
|
||||
.call_count
|
||||
.get(&(self.module_id().clone(), key.clone()))
|
||||
.unwrap(),
|
||||
stack: self.stack.clone(),
|
||||
};
|
||||
self.statement_buffer
|
||||
.push(TypedStatement::MultipleDefinition(
|
||||
vec![Variable::with_id_and_type(id.clone(), tys[0].clone())],
|
||||
TypedExpressionList::FunctionCall(key, expressions, tys),
|
||||
));
|
||||
StructExpressionInner::Identifier(id)
|
||||
}
|
||||
Err(e) => match e {
|
||||
InlineError::Flat(key, expressions) => {
|
||||
let key = ConcreteFunctionKey::try_from(key).unwrap();
|
||||
|
||||
let tys = key.signature.outputs.clone();
|
||||
let id = Identifier {
|
||||
id: CoreIdentifier::Call(key.clone()),
|
||||
version: *self
|
||||
.call_count
|
||||
.get(&(self.module_id().clone(), key.clone()))
|
||||
.unwrap(),
|
||||
stack: self.stack.clone(),
|
||||
};
|
||||
self.statement_buffer
|
||||
.push(TypedStatement::MultipleDefinition(
|
||||
vec![Variable::with_id_and_type(
|
||||
id.clone(),
|
||||
tys[0].clone().into(),
|
||||
)],
|
||||
TypedExpressionList::FunctionCall(
|
||||
key.into(),
|
||||
expressions,
|
||||
tys.into_iter().map(|t| t.into()).collect(),
|
||||
),
|
||||
));
|
||||
|
||||
let out = StructExpressionInner::Identifier(id);
|
||||
|
||||
self.call_cache_mut()
|
||||
.entry(key.clone())
|
||||
.or_insert_with(|| HashMap::new())
|
||||
.insert(expressions, vec![out.clone().annotate(ty.clone()).into()]);
|
||||
|
||||
out
|
||||
}
|
||||
InlineError::NonConstant(key, expressions) => {
|
||||
StructExpressionInner::FunctionCall(key, expressions)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
// default
|
||||
|
@ -536,40 +652,50 @@ impl<'ast, T: Field> Folder<'ast, T> for Inliner<'ast, T> {
|
|||
UExpressionInner::FunctionCall(key, exps) => {
|
||||
let exps: Vec<_> = exps.into_iter().map(|e| self.fold_expression(e)).collect();
|
||||
|
||||
match self.try_inline_call(&key, exps) {
|
||||
match self.try_inline_call(key, exps) {
|
||||
Ok(mut ret) => match ret.pop().unwrap() {
|
||||
TypedExpression::Uint(e) => e.into_inner(),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
Err((embed_key, expressions)) => {
|
||||
let tys = key.signature.outputs.clone();
|
||||
let id = Identifier {
|
||||
id: CoreIdentifier::Call(key.clone()),
|
||||
version: *self
|
||||
.call_count
|
||||
.get(&(self.module_id().clone(), embed_key.clone()))
|
||||
.unwrap(),
|
||||
stack: self.stack.clone(),
|
||||
};
|
||||
self.statement_buffer
|
||||
.push(TypedStatement::MultipleDefinition(
|
||||
vec![Variable::with_id_and_type(id.clone(), tys[0].clone())],
|
||||
TypedExpressionList::FunctionCall(
|
||||
embed_key.clone(),
|
||||
expressions.clone(),
|
||||
tys,
|
||||
),
|
||||
));
|
||||
Err(e) => match e {
|
||||
InlineError::Flat(embed_key, expressions) => {
|
||||
let key = ConcreteFunctionKey::try_from(key).unwrap();
|
||||
|
||||
let out = UExpressionInner::Identifier(id);
|
||||
let tys = key.signature.outputs.clone();
|
||||
let id = Identifier {
|
||||
id: CoreIdentifier::Call(key.clone()),
|
||||
version: *self
|
||||
.call_count
|
||||
.get(&(self.module_id().clone(), key.clone().into()))
|
||||
.unwrap(),
|
||||
stack: self.stack.clone(),
|
||||
};
|
||||
self.statement_buffer
|
||||
.push(TypedStatement::MultipleDefinition(
|
||||
vec![Variable::with_id_and_type(
|
||||
id.clone(),
|
||||
tys[0].clone().into(),
|
||||
)],
|
||||
TypedExpressionList::FunctionCall(
|
||||
embed_key.clone().into(),
|
||||
expressions.clone(),
|
||||
tys.into_iter().map(|t| t.into()).collect(),
|
||||
),
|
||||
));
|
||||
|
||||
self.call_cache_mut()
|
||||
.entry(key.clone())
|
||||
.or_insert_with(|| HashMap::new())
|
||||
.insert(expressions, vec![out.clone().annotate(size).into()]);
|
||||
let out = UExpressionInner::Identifier(id);
|
||||
|
||||
out
|
||||
}
|
||||
self.call_cache_mut()
|
||||
.entry(key.clone())
|
||||
.or_insert_with(|| HashMap::new())
|
||||
.insert(expressions, vec![out.clone().annotate(size).into()]);
|
||||
|
||||
out
|
||||
}
|
||||
InlineError::NonConstant(key, expressions) => {
|
||||
UExpressionInner::FunctionCall(key, expressions)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
// default
|
||||
|
|
|
@ -17,9 +17,7 @@ mod unroll;
|
|||
mod variable_access_remover;
|
||||
|
||||
use self::flatten_complex_types::Flattener;
|
||||
use self::inline::Inliner;
|
||||
use self::propagate_unroll::PropagatedUnroller;
|
||||
use self::propagation::Propagator;
|
||||
use self::redefinition::RedefinitionOptimizer;
|
||||
use self::return_binder::ReturnBinder;
|
||||
use self::uint_optimizer::UintOptimizer;
|
||||
|
@ -27,7 +25,7 @@ use self::unconstrained_vars::UnconstrainedVariableDetector;
|
|||
use self::variable_access_remover::VariableAccessRemover;
|
||||
use crate::flat_absy::FlatProg;
|
||||
use crate::ir::Prog;
|
||||
use crate::typed_absy::TypedProgram;
|
||||
use crate::typed_absy::{abi::Abi, TypedProgram};
|
||||
use zir::ZirProgram;
|
||||
use zokrates_field::Field;
|
||||
|
||||
|
@ -36,9 +34,12 @@ pub trait Analyse {
|
|||
}
|
||||
|
||||
impl<'ast, T: Field> TypedProgram<'ast, T> {
|
||||
pub fn analyse(self) -> ZirProgram<'ast, T> {
|
||||
pub fn analyse(self) -> (ZirProgram<'ast, T>, Abi) {
|
||||
// propagated unrolling
|
||||
let r = PropagatedUnroller::unroll(self).unwrap_or_else(|e| panic!(e));
|
||||
|
||||
let abi = r.abi().unwrap();
|
||||
|
||||
// return binding
|
||||
let r = ReturnBinder::bind(r);
|
||||
|
||||
|
@ -60,7 +61,7 @@ impl<'ast, T: Field> TypedProgram<'ast, T> {
|
|||
// optimize uint expressions
|
||||
let zir = UintOptimizer::optimize(zir);
|
||||
|
||||
zir
|
||||
(zir, abi)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
|
|||
.collect();
|
||||
|
||||
fn process_u_from_bits<'ast, T: Field>(
|
||||
variables: Vec<Variable<'ast>>,
|
||||
variables: Vec<Variable<'ast, T>>,
|
||||
arguments: Vec<TypedExpression<'ast, T>>,
|
||||
bitwidth: UBitwidth,
|
||||
) -> TypedExpression<'ast, T> {
|
||||
|
@ -183,7 +183,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
|
|||
}
|
||||
|
||||
fn process_u_to_bits<'ast, T: Field>(
|
||||
variables: Vec<Variable<'ast>>,
|
||||
variables: Vec<Variable<'ast, T>>,
|
||||
arguments: Vec<TypedExpression<'ast, T>>,
|
||||
bitwidth: UBitwidth,
|
||||
) -> TypedExpression<'ast, T> {
|
||||
|
@ -213,7 +213,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
|
|||
.map(|v| BooleanExpression::Value(v).into())
|
||||
.collect(),
|
||||
)
|
||||
.annotate(Type::Boolean, bitwidth.to_usize())
|
||||
.annotate(Type::Boolean, bitwidth.to_usize() as u32)
|
||||
.into()
|
||||
}
|
||||
_ => unreachable!("should be a uint value"),
|
||||
|
@ -282,7 +282,10 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
|
|||
})
|
||||
.collect(),
|
||||
)
|
||||
.annotate(Type::Boolean, T::get_required_bits())
|
||||
.annotate(
|
||||
Type::Boolean,
|
||||
T::get_required_bits() as u32,
|
||||
)
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
@ -505,45 +508,59 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
|
|||
}
|
||||
UExpressionInner::Select(box array, box index) => {
|
||||
let array = self.fold_array_expression(array);
|
||||
let index = self.fold_field_expression(index);
|
||||
let index = self.fold_uint_expression(index);
|
||||
|
||||
let inner_type = array.inner_type().clone();
|
||||
let size = array.size();
|
||||
|
||||
match (array.into_inner(), index) {
|
||||
(ArrayExpressionInner::Value(v), FieldElementExpression::Number(n)) => {
|
||||
let n_as_usize = n.to_dec_string().parse::<usize>().unwrap();
|
||||
if n_as_usize < size {
|
||||
UExpression::try_from(v[n_as_usize].clone())
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
} else {
|
||||
unreachable!(
|
||||
match size.into_inner() {
|
||||
UExpressionInner::Value(size) => {
|
||||
match (array.into_inner(), index.into_inner()) {
|
||||
(ArrayExpressionInner::Value(v), UExpressionInner::Value(n)) => {
|
||||
if n < size {
|
||||
UExpression::try_from(v[n as usize].clone())
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
} else {
|
||||
unreachable!(
|
||||
"out of bounds index ({} >= {}) found during static analysis",
|
||||
n_as_usize, size
|
||||
n, size
|
||||
);
|
||||
}
|
||||
}
|
||||
(ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => {
|
||||
match self.constants.get(&TypedAssignee::Select(
|
||||
box TypedAssignee::Identifier(Variable::array(
|
||||
id.clone(),
|
||||
inner_type.clone(),
|
||||
size,
|
||||
)),
|
||||
box FieldElementExpression::Number(n.clone()).into(),
|
||||
)) {
|
||||
Some(e) => match e {
|
||||
TypedExpression::Uint(e) => e.clone().into_inner(),
|
||||
_ => unreachable!(""),
|
||||
},
|
||||
None => UExpressionInner::Select(
|
||||
box ArrayExpressionInner::Identifier(id).annotate(inner_type, size),
|
||||
box FieldElementExpression::Number(n),
|
||||
}
|
||||
}
|
||||
(ArrayExpressionInner::Identifier(id), UExpressionInner::Value(n)) => {
|
||||
match self.constants.get(&TypedAssignee::Select(
|
||||
box TypedAssignee::Identifier(Variable::array(
|
||||
id.clone(),
|
||||
inner_type.clone(),
|
||||
(size as u32).into(),
|
||||
)),
|
||||
box UExpressionInner::Value(n.clone())
|
||||
.annotate(UBitwidth::B32)
|
||||
.into(),
|
||||
)) {
|
||||
Some(e) => match e {
|
||||
TypedExpression::Uint(e) => e.clone().into_inner(),
|
||||
_ => unreachable!(""),
|
||||
},
|
||||
None => UExpressionInner::Select(
|
||||
box ArrayExpressionInner::Identifier(id)
|
||||
.annotate(inner_type, size as u32),
|
||||
box UExpressionInner::Value(n).annotate(UBitwidth::B32),
|
||||
),
|
||||
}
|
||||
}
|
||||
(a, i) => UExpressionInner::Select(
|
||||
box a.annotate(inner_type, size as u32),
|
||||
box i.annotate(UBitwidth::B32),
|
||||
),
|
||||
}
|
||||
}
|
||||
(a, i) => UExpressionInner::Select(box a.annotate(inner_type, size), box i),
|
||||
size => fold_uint_expression_inner(
|
||||
self,
|
||||
bitwidth,
|
||||
UExpressionInner::Select(box array, box index),
|
||||
),
|
||||
}
|
||||
}
|
||||
UExpressionInner::FunctionCall(key, arguments) => {
|
||||
|
@ -647,45 +664,54 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
|
|||
}
|
||||
FieldElementExpression::Select(box array, box index) => {
|
||||
let array = self.fold_array_expression(array);
|
||||
let index = self.fold_field_expression(index);
|
||||
let index = self.fold_uint_expression(index);
|
||||
|
||||
let inner_type = array.inner_type().clone();
|
||||
let size = array.size();
|
||||
|
||||
match (array.into_inner(), index) {
|
||||
(ArrayExpressionInner::Value(v), FieldElementExpression::Number(n)) => {
|
||||
let n_as_usize = n.to_dec_string().parse::<usize>().unwrap();
|
||||
if n_as_usize < size {
|
||||
FieldElementExpression::try_from(v[n_as_usize].clone()).unwrap()
|
||||
} else {
|
||||
unreachable!(
|
||||
match size.into_inner() {
|
||||
UExpressionInner::Value(size) => {
|
||||
match (array.into_inner(), index.into_inner()) {
|
||||
(ArrayExpressionInner::Value(v), UExpressionInner::Value(n)) => {
|
||||
if n < size {
|
||||
FieldElementExpression::try_from(v[n as usize].clone()).unwrap()
|
||||
} else {
|
||||
unreachable!(
|
||||
"out of bounds index ({} >= {}) found during static analysis",
|
||||
n_as_usize, size
|
||||
n, size
|
||||
);
|
||||
}
|
||||
}
|
||||
(ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => {
|
||||
match self.constants.get(&TypedAssignee::Select(
|
||||
box TypedAssignee::Identifier(Variable::array(
|
||||
id.clone(),
|
||||
inner_type.clone(),
|
||||
size,
|
||||
)),
|
||||
box FieldElementExpression::Number(n.clone()).into(),
|
||||
)) {
|
||||
Some(e) => match e {
|
||||
TypedExpression::FieldElement(e) => e.clone(),
|
||||
_ => unreachable!("??"),
|
||||
},
|
||||
None => FieldElementExpression::Select(
|
||||
box ArrayExpressionInner::Identifier(id).annotate(inner_type, size),
|
||||
box FieldElementExpression::Number(n),
|
||||
}
|
||||
}
|
||||
(ArrayExpressionInner::Identifier(id), UExpressionInner::Value(n)) => {
|
||||
match self.constants.get(&TypedAssignee::Select(
|
||||
box TypedAssignee::Identifier(Variable::array(
|
||||
id.clone(),
|
||||
inner_type.clone(),
|
||||
(size as u32).into(),
|
||||
)),
|
||||
box UExpressionInner::Value(n.clone()).annotate(UBitwidth::B32),
|
||||
)) {
|
||||
Some(e) => match e {
|
||||
TypedExpression::FieldElement(e) => e.clone(),
|
||||
_ => unreachable!("??"),
|
||||
},
|
||||
None => FieldElementExpression::Select(
|
||||
box ArrayExpressionInner::Identifier(id)
|
||||
.annotate(inner_type, size as u32),
|
||||
box UExpressionInner::Value(n).annotate(UBitwidth::B32),
|
||||
),
|
||||
}
|
||||
}
|
||||
(a, i) => FieldElementExpression::Select(
|
||||
box a.annotate(inner_type, size as u32),
|
||||
box i.annotate(UBitwidth::B32),
|
||||
),
|
||||
}
|
||||
}
|
||||
(a, i) => {
|
||||
FieldElementExpression::Select(box a.annotate(inner_type, size), box i)
|
||||
}
|
||||
size => fold_field_expression(
|
||||
self,
|
||||
FieldElementExpression::Select(box array, box index),
|
||||
),
|
||||
}
|
||||
}
|
||||
FieldElementExpression::Member(box s, m) => {
|
||||
|
@ -725,8 +751,8 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
|
|||
|
||||
fn fold_array_expression_inner(
|
||||
&mut self,
|
||||
ty: &Type,
|
||||
size: usize,
|
||||
ty: &Type<'ast, T>,
|
||||
size: UExpression<'ast, T>,
|
||||
e: ArrayExpressionInner<'ast, T>,
|
||||
) -> ArrayExpressionInner<'ast, T> {
|
||||
match e {
|
||||
|
@ -747,45 +773,52 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
|
|||
}
|
||||
ArrayExpressionInner::Select(box array, box index) => {
|
||||
let array = self.fold_array_expression(array);
|
||||
let index = self.fold_field_expression(index);
|
||||
let index = self.fold_uint_expression(index);
|
||||
|
||||
let inner_type = array.inner_type().clone();
|
||||
let size = array.size();
|
||||
|
||||
match (array.into_inner(), index) {
|
||||
(ArrayExpressionInner::Value(v), FieldElementExpression::Number(n)) => {
|
||||
let n_as_usize = n.to_dec_string().parse::<usize>().unwrap();
|
||||
if n_as_usize < size {
|
||||
ArrayExpression::try_from(v[n_as_usize].clone())
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
} else {
|
||||
unreachable!(
|
||||
"out of bounds index ({} >= {}) found during static analysis",
|
||||
n_as_usize, size
|
||||
);
|
||||
match size.into_inner() {
|
||||
UExpressionInner::Value(size) => match (array.into_inner(), index.into_inner())
|
||||
{
|
||||
(ArrayExpressionInner::Value(v), UExpressionInner::Value(n)) => {
|
||||
if n < size {
|
||||
ArrayExpression::try_from(v[n as usize].clone())
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
} else {
|
||||
unreachable!(
|
||||
"out of bounds index ({} >= {}) found during static analysis",
|
||||
n, size
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
(ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => {
|
||||
match self.constants.get(&TypedAssignee::Select(
|
||||
box TypedAssignee::Identifier(Variable::array(
|
||||
id.clone(),
|
||||
inner_type.clone(),
|
||||
size,
|
||||
)),
|
||||
box FieldElementExpression::Number(n.clone()).into(),
|
||||
)) {
|
||||
Some(e) => match e {
|
||||
TypedExpression::Array(e) => e.clone().into_inner(),
|
||||
_ => unreachable!("should be an array"),
|
||||
},
|
||||
None => ArrayExpressionInner::Select(
|
||||
box ArrayExpressionInner::Identifier(id).annotate(inner_type, size),
|
||||
box FieldElementExpression::Number(n),
|
||||
),
|
||||
(ArrayExpressionInner::Identifier(id), UExpressionInner::Value(n)) => {
|
||||
match self.constants.get(&TypedAssignee::Select(
|
||||
box TypedAssignee::Identifier(Variable::array(
|
||||
id.clone(),
|
||||
inner_type.clone(),
|
||||
(size as u32).into(),
|
||||
)),
|
||||
box UExpressionInner::Value(n).annotate(UBitwidth::B32).into(),
|
||||
)) {
|
||||
Some(e) => match e {
|
||||
TypedExpression::Array(e) => e.clone().into_inner(),
|
||||
_ => unreachable!("should be an array"),
|
||||
},
|
||||
None => ArrayExpressionInner::Select(
|
||||
box ArrayExpressionInner::Identifier(id)
|
||||
.annotate(inner_type, size as u32),
|
||||
box (n as u32).into(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
(a, i) => ArrayExpressionInner::Select(box a.annotate(inner_type, size), box i),
|
||||
(a, i) => ArrayExpressionInner::Select(
|
||||
box a.annotate(inner_type, size as u32),
|
||||
box i.annotate(UBitwidth::B32),
|
||||
),
|
||||
},
|
||||
size => fold_array_expression_inner(self, ty, size.annotate(UBitwidth::B32), e),
|
||||
}
|
||||
}
|
||||
ArrayExpressionInner::IfElse(box condition, box consequence, box alternative) => {
|
||||
|
@ -839,7 +872,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
|
|||
|
||||
fn fold_struct_expression_inner(
|
||||
&mut self,
|
||||
ty: &StructType,
|
||||
ty: &StructType<'ast, T>,
|
||||
e: StructExpressionInner<'ast, T>,
|
||||
) -> StructExpressionInner<'ast, T> {
|
||||
match e {
|
||||
|
@ -859,47 +892,58 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
|
|||
}
|
||||
StructExpressionInner::Select(box array, box index) => {
|
||||
let array = self.fold_array_expression(array);
|
||||
let index = self.fold_field_expression(index);
|
||||
let index = self.fold_uint_expression(index);
|
||||
|
||||
let inner_type = array.inner_type().clone();
|
||||
let size = array.size();
|
||||
|
||||
match (array.into_inner(), index) {
|
||||
(ArrayExpressionInner::Value(v), FieldElementExpression::Number(n)) => {
|
||||
let n_as_usize = n.to_dec_string().parse::<usize>().unwrap();
|
||||
if n_as_usize < size {
|
||||
StructExpression::try_from(v[n_as_usize].clone())
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
} else {
|
||||
unreachable!(
|
||||
"out of bounds index ({} >= {}) found during static analysis",
|
||||
n_as_usize, size
|
||||
);
|
||||
match size.into_inner() {
|
||||
UExpressionInner::Value(size) => match (array.into_inner(), index.into_inner())
|
||||
{
|
||||
(ArrayExpressionInner::Value(v), UExpressionInner::Value(n)) => {
|
||||
if n < size {
|
||||
StructExpression::try_from(v[n as usize].clone())
|
||||
.unwrap()
|
||||
.into_inner()
|
||||
} else {
|
||||
unreachable!(
|
||||
"out of bounds index ({} >= {}) found during static analysis",
|
||||
n, size
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
(ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => {
|
||||
match self.constants.get(&TypedAssignee::Select(
|
||||
box TypedAssignee::Identifier(Variable::array(
|
||||
id.clone(),
|
||||
inner_type.clone(),
|
||||
size,
|
||||
)),
|
||||
box FieldElementExpression::Number(n.clone()).into(),
|
||||
)) {
|
||||
Some(e) => match e {
|
||||
TypedExpression::Struct(e) => e.clone().into_inner(),
|
||||
_ => unreachable!("should be a struct"),
|
||||
},
|
||||
None => StructExpressionInner::Select(
|
||||
box ArrayExpressionInner::Identifier(id).annotate(inner_type, size),
|
||||
box FieldElementExpression::Number(n),
|
||||
),
|
||||
(ArrayExpressionInner::Identifier(id), UExpressionInner::Value(n)) => {
|
||||
match self.constants.get(&TypedAssignee::Select(
|
||||
box TypedAssignee::Identifier(Variable::array(
|
||||
id.clone(),
|
||||
inner_type.clone(),
|
||||
(size as u32).into(),
|
||||
)),
|
||||
box UExpressionInner::Value(n.clone())
|
||||
.annotate(UBitwidth::B32)
|
||||
.into(),
|
||||
)) {
|
||||
Some(e) => match e {
|
||||
TypedExpression::Struct(e) => e.clone().into_inner(),
|
||||
_ => unreachable!("should be a struct"),
|
||||
},
|
||||
None => StructExpressionInner::Select(
|
||||
box ArrayExpressionInner::Identifier(id)
|
||||
.annotate(inner_type, size as u32),
|
||||
box UExpressionInner::Value(n).annotate(UBitwidth::B32),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
(a, i) => {
|
||||
StructExpressionInner::Select(box a.annotate(inner_type, size), box i)
|
||||
}
|
||||
(a, i) => StructExpressionInner::Select(
|
||||
box a.annotate(inner_type, size as u32),
|
||||
box i.annotate(UBitwidth::B32),
|
||||
),
|
||||
},
|
||||
size => fold_struct_expression_inner(
|
||||
self,
|
||||
ty,
|
||||
StructExpressionInner::Select(box array, box index),
|
||||
),
|
||||
}
|
||||
}
|
||||
StructExpressionInner::IfElse(box condition, box consequence, box alternative) => {
|
||||
|
@ -1092,43 +1136,55 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
|
|||
}
|
||||
BooleanExpression::Select(box array, box index) => {
|
||||
let array = self.fold_array_expression(array);
|
||||
let index = self.fold_field_expression(index);
|
||||
let index = self.fold_uint_expression(index);
|
||||
|
||||
let inner_type = array.inner_type().clone();
|
||||
let size = array.size();
|
||||
|
||||
match (array.into_inner(), index) {
|
||||
(ArrayExpressionInner::Value(v), FieldElementExpression::Number(n)) => {
|
||||
let n_as_usize = n.to_dec_string().parse::<usize>().unwrap();
|
||||
if n_as_usize < size {
|
||||
BooleanExpression::try_from(v[n_as_usize].clone()).unwrap()
|
||||
} else {
|
||||
unreachable!(
|
||||
"out of bounds index ({} >= {}) found during static analysis",
|
||||
n_as_usize, size
|
||||
);
|
||||
match size.into_inner() {
|
||||
UExpressionInner::Value(size) => match (array.into_inner(), index.into_inner())
|
||||
{
|
||||
(ArrayExpressionInner::Value(v), UExpressionInner::Value(n)) => {
|
||||
if n < size {
|
||||
BooleanExpression::try_from(v[n as usize].clone()).unwrap()
|
||||
} else {
|
||||
unreachable!(
|
||||
"out of bounds index ({} >= {}) found during static analysis",
|
||||
n, size
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
(ArrayExpressionInner::Identifier(id), FieldElementExpression::Number(n)) => {
|
||||
match self.constants.get(&TypedAssignee::Select(
|
||||
box TypedAssignee::Identifier(Variable::array(
|
||||
id.clone(),
|
||||
inner_type.clone(),
|
||||
size,
|
||||
)),
|
||||
box FieldElementExpression::Number(n.clone()).into(),
|
||||
)) {
|
||||
Some(e) => match e {
|
||||
TypedExpression::Boolean(e) => e.clone(),
|
||||
_ => unreachable!("Should be a boolean"),
|
||||
},
|
||||
None => BooleanExpression::Select(
|
||||
box ArrayExpressionInner::Identifier(id).annotate(inner_type, size),
|
||||
box FieldElementExpression::Number(n),
|
||||
),
|
||||
(ArrayExpressionInner::Identifier(id), UExpressionInner::Value(n)) => {
|
||||
match self.constants.get(&TypedAssignee::Select(
|
||||
box TypedAssignee::Identifier(Variable::array(
|
||||
id.clone(),
|
||||
inner_type.clone(),
|
||||
(size as u32).into(),
|
||||
)),
|
||||
box UExpressionInner::Value(n.clone())
|
||||
.annotate(UBitwidth::B32)
|
||||
.into(),
|
||||
)) {
|
||||
Some(e) => match e {
|
||||
TypedExpression::Boolean(e) => e.clone(),
|
||||
_ => unreachable!("Should be a boolean"),
|
||||
},
|
||||
None => BooleanExpression::Select(
|
||||
box ArrayExpressionInner::Identifier(id)
|
||||
.annotate(inner_type, size as u32),
|
||||
box UExpressionInner::Value(n.clone()).annotate(UBitwidth::B32),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
(a, i) => BooleanExpression::Select(box a.annotate(inner_type, size), box i),
|
||||
(a, i) => BooleanExpression::Select(
|
||||
box a.annotate(inner_type, size as u32),
|
||||
box i.annotate(UBitwidth::B32),
|
||||
),
|
||||
},
|
||||
size => fold_boolean_expression(
|
||||
self,
|
||||
BooleanExpression::Select(box array, box index),
|
||||
),
|
||||
}
|
||||
}
|
||||
BooleanExpression::Member(box s, m) => {
|
||||
|
|
|
@ -31,7 +31,7 @@ impl<'ast> Unroller<'ast> {
|
|||
}
|
||||
}
|
||||
|
||||
fn issue_next_ssa_variable(&mut self, v: Variable<'ast>) -> Variable<'ast> {
|
||||
fn issue_next_ssa_variable<T: Field>(&mut self, v: Variable<'ast, T>) -> Variable<'ast, T> {
|
||||
let res = match self.substitution.get(&v.id.id) {
|
||||
Some(i) => Variable {
|
||||
id: Identifier {
|
||||
|
@ -79,162 +79,164 @@ impl<'ast> Unroller<'ast> {
|
|||
let head = indices.remove(0);
|
||||
let tail = indices;
|
||||
|
||||
match head {
|
||||
Access::Select(head) => {
|
||||
statements.insert(TypedStatement::Assertion(
|
||||
BooleanExpression::Lt(
|
||||
box head.clone(),
|
||||
box FieldElementExpression::Number(T::from(size)),
|
||||
)
|
||||
.into(),
|
||||
));
|
||||
unimplemented!()
|
||||
|
||||
ArrayExpressionInner::Value(
|
||||
(0..size)
|
||||
.map(|i| match inner_ty {
|
||||
Type::Array(..) => ArrayExpression::if_else(
|
||||
BooleanExpression::FieldEq(
|
||||
box FieldElementExpression::Number(T::from(i)),
|
||||
box head.clone(),
|
||||
),
|
||||
match Self::choose_many(
|
||||
ArrayExpression::select(
|
||||
base.clone(),
|
||||
FieldElementExpression::Number(T::from(i)),
|
||||
)
|
||||
.into(),
|
||||
tail.clone(),
|
||||
new_expression.clone(),
|
||||
statements,
|
||||
) {
|
||||
TypedExpression::Array(e) => e,
|
||||
e => unreachable!(
|
||||
"the interior was expected to be an array, was {}",
|
||||
e.get_type()
|
||||
),
|
||||
},
|
||||
ArrayExpression::select(
|
||||
base.clone(),
|
||||
FieldElementExpression::Number(T::from(i)),
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
Type::Struct(..) => StructExpression::if_else(
|
||||
BooleanExpression::FieldEq(
|
||||
box FieldElementExpression::Number(T::from(i)),
|
||||
box head.clone(),
|
||||
),
|
||||
match Self::choose_many(
|
||||
StructExpression::select(
|
||||
base.clone(),
|
||||
FieldElementExpression::Number(T::from(i)),
|
||||
)
|
||||
.into(),
|
||||
tail.clone(),
|
||||
new_expression.clone(),
|
||||
statements,
|
||||
) {
|
||||
TypedExpression::Struct(e) => e,
|
||||
e => unreachable!(
|
||||
"the interior was expected to be a struct, was {}",
|
||||
e.get_type()
|
||||
),
|
||||
},
|
||||
StructExpression::select(
|
||||
base.clone(),
|
||||
FieldElementExpression::Number(T::from(i)),
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
Type::FieldElement => FieldElementExpression::if_else(
|
||||
BooleanExpression::FieldEq(
|
||||
box FieldElementExpression::Number(T::from(i)),
|
||||
box head.clone(),
|
||||
),
|
||||
match Self::choose_many(
|
||||
FieldElementExpression::select(
|
||||
base.clone(),
|
||||
FieldElementExpression::Number(T::from(i)),
|
||||
)
|
||||
.into(),
|
||||
tail.clone(),
|
||||
new_expression.clone(),
|
||||
statements,
|
||||
) {
|
||||
TypedExpression::FieldElement(e) => e,
|
||||
e => unreachable!(
|
||||
"the interior was expected to be a field, was {}",
|
||||
e.get_type()
|
||||
),
|
||||
},
|
||||
FieldElementExpression::select(
|
||||
base.clone(),
|
||||
FieldElementExpression::Number(T::from(i)),
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
Type::Boolean => BooleanExpression::if_else(
|
||||
BooleanExpression::FieldEq(
|
||||
box FieldElementExpression::Number(T::from(i)),
|
||||
box head.clone(),
|
||||
),
|
||||
match Self::choose_many(
|
||||
BooleanExpression::select(
|
||||
base.clone(),
|
||||
FieldElementExpression::Number(T::from(i)),
|
||||
)
|
||||
.into(),
|
||||
tail.clone(),
|
||||
new_expression.clone(),
|
||||
statements,
|
||||
) {
|
||||
TypedExpression::Boolean(e) => e,
|
||||
e => unreachable!(
|
||||
"the interior was expected to be a boolean, was {}",
|
||||
e.get_type()
|
||||
),
|
||||
},
|
||||
BooleanExpression::select(
|
||||
base.clone(),
|
||||
FieldElementExpression::Number(T::from(i)),
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
Type::Uint(..) => UExpression::if_else(
|
||||
BooleanExpression::FieldEq(
|
||||
box FieldElementExpression::Number(T::from(i)),
|
||||
box head.clone(),
|
||||
),
|
||||
match Self::choose_many(
|
||||
UExpression::select(
|
||||
base.clone(),
|
||||
FieldElementExpression::Number(T::from(i)),
|
||||
)
|
||||
.into(),
|
||||
tail.clone(),
|
||||
new_expression.clone(),
|
||||
statements,
|
||||
) {
|
||||
TypedExpression::Uint(e) => e,
|
||||
e => unreachable!(
|
||||
"the interior was expected to be a uint, was {}",
|
||||
e.get_type()
|
||||
),
|
||||
},
|
||||
UExpression::select(
|
||||
base.clone(),
|
||||
FieldElementExpression::Number(T::from(i)),
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
.annotate(inner_ty.clone(), size)
|
||||
.into()
|
||||
}
|
||||
Access::Member(..) => unreachable!("can't get a member from an array"),
|
||||
}
|
||||
// match head {
|
||||
// Access::Select(head) => {
|
||||
// statements.insert(TypedStatement::Assertion(
|
||||
// BooleanExpression::Lt(
|
||||
// box head.clone(),
|
||||
// box FieldElementExpression::Number(T::from(size)),
|
||||
// )
|
||||
// .into(),
|
||||
// ));
|
||||
|
||||
// ArrayExpressionInner::Value(
|
||||
// (0..size)
|
||||
// .map(|i| match inner_ty {
|
||||
// Type::Array(..) => ArrayExpression::if_else(
|
||||
// BooleanExpression::FieldEq(
|
||||
// box FieldElementExpression::Number(T::from(i)),
|
||||
// box head.clone(),
|
||||
// ),
|
||||
// match Self::choose_many(
|
||||
// ArrayExpression::select(
|
||||
// base.clone(),
|
||||
// FieldElementExpression::Number(T::from(i)),
|
||||
// )
|
||||
// .into(),
|
||||
// tail.clone(),
|
||||
// new_expression.clone(),
|
||||
// statements,
|
||||
// ) {
|
||||
// TypedExpression::Array(e) => e,
|
||||
// e => unreachable!(
|
||||
// "the interior was expected to be an array, was {}",
|
||||
// e.get_type()
|
||||
// ),
|
||||
// },
|
||||
// ArrayExpression::select(
|
||||
// base.clone(),
|
||||
// FieldElementExpression::Number(T::from(i)),
|
||||
// ),
|
||||
// )
|
||||
// .into(),
|
||||
// Type::Struct(..) => StructExpression::if_else(
|
||||
// BooleanExpression::FieldEq(
|
||||
// box FieldElementExpression::Number(T::from(i)),
|
||||
// box head.clone(),
|
||||
// ),
|
||||
// match Self::choose_many(
|
||||
// StructExpression::select(
|
||||
// base.clone(),
|
||||
// FieldElementExpression::Number(T::from(i)),
|
||||
// )
|
||||
// .into(),
|
||||
// tail.clone(),
|
||||
// new_expression.clone(),
|
||||
// statements,
|
||||
// ) {
|
||||
// TypedExpression::Struct(e) => e,
|
||||
// e => unreachable!(
|
||||
// "the interior was expected to be a struct, was {}",
|
||||
// e.get_type()
|
||||
// ),
|
||||
// },
|
||||
// StructExpression::select(
|
||||
// base.clone(),
|
||||
// FieldElementExpression::Number(T::from(i)),
|
||||
// ),
|
||||
// )
|
||||
// .into(),
|
||||
// Type::FieldElement => FieldElementExpression::if_else(
|
||||
// BooleanExpression::FieldEq(
|
||||
// box FieldElementExpression::Number(T::from(i)),
|
||||
// box head.clone(),
|
||||
// ),
|
||||
// match Self::choose_many(
|
||||
// FieldElementExpression::select(
|
||||
// base.clone(),
|
||||
// FieldElementExpression::Number(T::from(i)),
|
||||
// )
|
||||
// .into(),
|
||||
// tail.clone(),
|
||||
// new_expression.clone(),
|
||||
// statements,
|
||||
// ) {
|
||||
// TypedExpression::FieldElement(e) => e,
|
||||
// e => unreachable!(
|
||||
// "the interior was expected to be a field, was {}",
|
||||
// e.get_type()
|
||||
// ),
|
||||
// },
|
||||
// FieldElementExpression::select(
|
||||
// base.clone(),
|
||||
// FieldElementExpression::Number(T::from(i)),
|
||||
// ),
|
||||
// )
|
||||
// .into(),
|
||||
// Type::Boolean => BooleanExpression::if_else(
|
||||
// BooleanExpression::FieldEq(
|
||||
// box FieldElementExpression::Number(T::from(i)),
|
||||
// box head.clone(),
|
||||
// ),
|
||||
// match Self::choose_many(
|
||||
// BooleanExpression::select(
|
||||
// base.clone(),
|
||||
// FieldElementExpression::Number(T::from(i)),
|
||||
// )
|
||||
// .into(),
|
||||
// tail.clone(),
|
||||
// new_expression.clone(),
|
||||
// statements,
|
||||
// ) {
|
||||
// TypedExpression::Boolean(e) => e,
|
||||
// e => unreachable!(
|
||||
// "the interior was expected to be a boolean, was {}",
|
||||
// e.get_type()
|
||||
// ),
|
||||
// },
|
||||
// BooleanExpression::select(
|
||||
// base.clone(),
|
||||
// FieldElementExpression::Number(T::from(i)),
|
||||
// ),
|
||||
// )
|
||||
// .into(),
|
||||
// Type::Uint(..) => UExpression::if_else(
|
||||
// BooleanExpression::FieldEq(
|
||||
// box FieldElementExpression::Number(T::from(i)),
|
||||
// box head.clone(),
|
||||
// ),
|
||||
// match Self::choose_many(
|
||||
// UExpression::select(
|
||||
// base.clone(),
|
||||
// FieldElementExpression::Number(T::from(i)),
|
||||
// )
|
||||
// .into(),
|
||||
// tail.clone(),
|
||||
// new_expression.clone(),
|
||||
// statements,
|
||||
// ) {
|
||||
// TypedExpression::Uint(e) => e,
|
||||
// e => unreachable!(
|
||||
// "the interior was expected to be a uint, was {}",
|
||||
// e.get_type()
|
||||
// ),
|
||||
// },
|
||||
// UExpression::select(
|
||||
// base.clone(),
|
||||
// FieldElementExpression::Number(T::from(i)),
|
||||
// ),
|
||||
// )
|
||||
// .into(),
|
||||
// })
|
||||
// .collect(),
|
||||
// )
|
||||
// .annotate(inner_ty.clone(), size)
|
||||
// .into()
|
||||
// }
|
||||
// Access::Member(..) => unreachable!("can't get a member from an array"),
|
||||
// }
|
||||
}
|
||||
TypedExpression::Struct(base) => {
|
||||
let members = match base.get_type() {
|
||||
|
@ -355,12 +357,12 @@ impl<'ast> Unroller<'ast> {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
enum Access<'ast, T: Field> {
|
||||
Select(FieldElementExpression<'ast, T>),
|
||||
Select(UExpression<'ast, T>),
|
||||
Member(MemberId),
|
||||
}
|
||||
/// Turn an assignee into its representation as a base variable and a list accesses
|
||||
/// a[2][3][4] -> (a, [2, 3, 4])
|
||||
fn linear<'ast, T: Field>(a: TypedAssignee<'ast, T>) -> (Variable, Vec<Access<'ast, T>>) {
|
||||
fn linear<'ast, T: Field>(a: TypedAssignee<'ast, T>) -> (Variable<'ast, T>, Vec<Access<'ast, T>>) {
|
||||
match a {
|
||||
TypedAssignee::Identifier(v) => (v, vec![]),
|
||||
TypedAssignee::Select(box array, box index) => {
|
||||
|
@ -415,7 +417,7 @@ impl<'ast, T: Field> Folder<'ast, T> for Unroller<'ast> {
|
|||
let indices = indices
|
||||
.into_iter()
|
||||
.map(|a| match a {
|
||||
Access::Select(i) => Access::Select(self.fold_field_expression(i)),
|
||||
Access::Select(i) => Access::Select(self.fold_uint_expression(i)),
|
||||
a => a,
|
||||
})
|
||||
.collect();
|
||||
|
|
|
@ -29,22 +29,27 @@ impl<'ast, T: Field> VariableAccessRemover<'ast, T> {
|
|||
fn select<U: Select<'ast, T> + IfElse<'ast, T>>(
|
||||
&mut self,
|
||||
a: ArrayExpression<'ast, T>,
|
||||
i: FieldElementExpression<'ast, T>,
|
||||
i: UExpression<'ast, T>,
|
||||
) -> U {
|
||||
match i {
|
||||
FieldElementExpression::Number(i) => U::select(a, FieldElementExpression::Number(i)),
|
||||
match i.into_inner() {
|
||||
UExpressionInner::Value(i) => {
|
||||
U::select(a, UExpressionInner::Value(i).annotate(UBitwidth::B32))
|
||||
}
|
||||
i => {
|
||||
let size = match a.get_type().clone() {
|
||||
Type::Array(array_ty) => array_ty.size,
|
||||
Type::Array(array_ty) => match array_ty.size.into_inner() {
|
||||
UExpressionInner::Value(size) => size as u32,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
self.statements.push(TypedStatement::Assertion(
|
||||
(0..size)
|
||||
.map(|index| {
|
||||
BooleanExpression::FieldEq(
|
||||
box i.clone(),
|
||||
box FieldElementExpression::Number(index.into()).into(),
|
||||
BooleanExpression::UintEq(
|
||||
box i.clone().annotate(UBitwidth::B32),
|
||||
box index.into(),
|
||||
)
|
||||
})
|
||||
.fold(None, |acc, e| match acc {
|
||||
|
@ -56,14 +61,19 @@ impl<'ast, T: Field> VariableAccessRemover<'ast, T> {
|
|||
));
|
||||
|
||||
(0..size)
|
||||
.map(|i| U::select(a.clone(), FieldElementExpression::Number(i.into())))
|
||||
.map(|i| {
|
||||
U::select(
|
||||
a.clone(),
|
||||
UExpressionInner::Value(i.into()).annotate(UBitwidth::B32),
|
||||
)
|
||||
})
|
||||
.enumerate()
|
||||
.rev()
|
||||
.fold(None, |acc, (index, res)| match acc {
|
||||
Some(acc) => Some(U::if_else(
|
||||
BooleanExpression::FieldEq(
|
||||
box i.clone(),
|
||||
box FieldElementExpression::Number(index.into()),
|
||||
BooleanExpression::UintEq(
|
||||
box i.clone().annotate(UBitwidth::B32),
|
||||
box (index as u32).into(),
|
||||
),
|
||||
res,
|
||||
acc,
|
||||
|
@ -99,8 +109,8 @@ impl<'ast, T: Field> Folder<'ast, T> for VariableAccessRemover<'ast, T> {
|
|||
|
||||
fn fold_array_expression_inner(
|
||||
&mut self,
|
||||
ty: &Type,
|
||||
size: usize,
|
||||
ty: &Type<'ast, T>,
|
||||
size: UExpression<'ast, T>,
|
||||
e: ArrayExpressionInner<'ast, T>,
|
||||
) -> ArrayExpressionInner<'ast, T> {
|
||||
match e {
|
||||
|
@ -113,7 +123,7 @@ impl<'ast, T: Field> Folder<'ast, T> for VariableAccessRemover<'ast, T> {
|
|||
|
||||
fn fold_struct_expression_inner(
|
||||
&mut self,
|
||||
ty: &StructType,
|
||||
ty: &StructType<'ast, T>,
|
||||
e: StructExpressionInner<'ast, T>,
|
||||
) -> StructExpressionInner<'ast, T> {
|
||||
match e {
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
use typed_absy::types::ConcreteSignature;
|
||||
use typed_absy::types::ConcreteType;
|
||||
use typed_absy::types::Signature;
|
||||
use typed_absy::Type;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
|
||||
pub struct AbiInput {
|
||||
pub name: String,
|
||||
pub public: bool,
|
||||
#[serde(flatten)]
|
||||
pub ty: Type,
|
||||
pub ty: ConcreteType,
|
||||
}
|
||||
|
||||
pub type AbiOutput = Type;
|
||||
pub type AbiOutput = ConcreteType;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
|
||||
pub struct Abi {
|
||||
|
@ -18,7 +19,7 @@ pub struct Abi {
|
|||
}
|
||||
|
||||
impl Abi {
|
||||
pub fn signature(&self) -> Signature {
|
||||
pub fn signature(&self) -> ConcreteSignature {
|
||||
Signature {
|
||||
inputs: self.inputs.iter().map(|i| i.ty.clone()).collect(),
|
||||
outputs: self.outputs.clone(),
|
||||
|
|
|
@ -23,9 +23,9 @@ pub trait Folder<'ast, T: Field>: Sized {
|
|||
fold_function(self, f)
|
||||
}
|
||||
|
||||
fn fold_parameter(&mut self, p: Parameter<'ast>) -> Parameter<'ast> {
|
||||
fn fold_parameter(&mut self, p: DeclarationParameter<'ast>) -> DeclarationParameter<'ast> {
|
||||
Parameter {
|
||||
id: self.fold_variable(p.id),
|
||||
id: self.fold_declaration_variable(p.id),
|
||||
..p
|
||||
}
|
||||
}
|
||||
|
@ -34,19 +34,34 @@ pub trait Folder<'ast, T: Field>: Sized {
|
|||
n
|
||||
}
|
||||
|
||||
fn fold_variable(&mut self, v: Variable<'ast>) -> Variable<'ast> {
|
||||
fn fold_variable(&mut self, v: Variable<'ast, T>) -> Variable<'ast, T> {
|
||||
Variable {
|
||||
id: self.fold_name(v.id),
|
||||
..v
|
||||
ty: self.fold_type(v.ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_declaration_variable(&mut self, v: Variable<'ast, T>) -> Variable<'ast, T> {
|
||||
DeclarationVariable {
|
||||
id: self.fold_name(v.id),
|
||||
ty: self.fold_declaration_type(v.ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_type(&mut self, t: Type<T>) -> Type<T> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn fold_declaration_type(&mut self, t: DeclarationType) -> DeclarationType {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn fold_assignee(&mut self, a: TypedAssignee<'ast, T>) -> TypedAssignee<'ast, T> {
|
||||
match a {
|
||||
TypedAssignee::Identifier(v) => TypedAssignee::Identifier(self.fold_variable(v)),
|
||||
TypedAssignee::Select(box a, box index) => TypedAssignee::Select(
|
||||
box self.fold_assignee(a),
|
||||
box self.fold_field_expression(index),
|
||||
box self.fold_uint_expression(index),
|
||||
),
|
||||
TypedAssignee::Member(box s, m) => TypedAssignee::Member(box self.fold_assignee(s), m),
|
||||
}
|
||||
|
@ -121,15 +136,15 @@ pub trait Folder<'ast, T: Field>: Sized {
|
|||
|
||||
fn fold_array_expression_inner(
|
||||
&mut self,
|
||||
ty: &Type,
|
||||
size: usize,
|
||||
ty: &Type<'ast, T>,
|
||||
size: UExpression<'ast, T>,
|
||||
e: ArrayExpressionInner<'ast, T>,
|
||||
) -> ArrayExpressionInner<'ast, T> {
|
||||
fold_array_expression_inner(self, ty, size, e)
|
||||
}
|
||||
fn fold_struct_expression_inner(
|
||||
&mut self,
|
||||
ty: &StructType,
|
||||
ty: &StructType<'ast, T>,
|
||||
e: StructExpressionInner<'ast, T>,
|
||||
) -> StructExpressionInner<'ast, T> {
|
||||
fold_struct_expression_inner(self, ty, e)
|
||||
|
@ -185,8 +200,8 @@ pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>(
|
|||
|
||||
pub fn fold_array_expression_inner<'ast, T: Field, F: Folder<'ast, T>>(
|
||||
f: &mut F,
|
||||
_: &Type,
|
||||
_: usize,
|
||||
_: &Type<'ast, T>,
|
||||
_: UExpression<'ast, T>,
|
||||
e: ArrayExpressionInner<'ast, T>,
|
||||
) -> ArrayExpressionInner<'ast, T> {
|
||||
match e {
|
||||
|
@ -211,7 +226,7 @@ pub fn fold_array_expression_inner<'ast, T: Field, F: Folder<'ast, T>>(
|
|||
}
|
||||
ArrayExpressionInner::Select(box array, box index) => {
|
||||
let array = f.fold_array_expression(array);
|
||||
let index = f.fold_field_expression(index);
|
||||
let index = f.fold_uint_expression(index);
|
||||
ArrayExpressionInner::Select(box array, box index)
|
||||
}
|
||||
}
|
||||
|
@ -219,7 +234,7 @@ pub fn fold_array_expression_inner<'ast, T: Field, F: Folder<'ast, T>>(
|
|||
|
||||
pub fn fold_struct_expression_inner<'ast, T: Field, F: Folder<'ast, T>>(
|
||||
f: &mut F,
|
||||
_: &StructType,
|
||||
_: &StructType<'ast, T>,
|
||||
e: StructExpressionInner<'ast, T>,
|
||||
) -> StructExpressionInner<'ast, T> {
|
||||
match e {
|
||||
|
@ -244,7 +259,7 @@ pub fn fold_struct_expression_inner<'ast, T: Field, F: Folder<'ast, T>>(
|
|||
}
|
||||
StructExpressionInner::Select(box array, box index) => {
|
||||
let array = f.fold_array_expression(array);
|
||||
let index = f.fold_field_expression(index);
|
||||
let index = f.fold_uint_expression(index);
|
||||
StructExpressionInner::Select(box array, box index)
|
||||
}
|
||||
}
|
||||
|
@ -300,7 +315,7 @@ pub fn fold_field_expression<'ast, T: Field, F: Folder<'ast, T>>(
|
|||
}
|
||||
FieldElementExpression::Select(box array, box index) => {
|
||||
let array = f.fold_array_expression(array);
|
||||
let index = f.fold_field_expression(index);
|
||||
let index = f.fold_uint_expression(index);
|
||||
FieldElementExpression::Select(box array, box index)
|
||||
}
|
||||
}
|
||||
|
@ -388,7 +403,7 @@ pub fn fold_boolean_expression<'ast, T: Field, F: Folder<'ast, T>>(
|
|||
}
|
||||
BooleanExpression::Select(box array, box index) => {
|
||||
let array = f.fold_array_expression(array);
|
||||
let index = f.fold_field_expression(index);
|
||||
let index = f.fold_uint_expression(index);
|
||||
BooleanExpression::Select(box array, box index)
|
||||
}
|
||||
}
|
||||
|
@ -471,7 +486,7 @@ pub fn fold_uint_expression_inner<'ast, T: Field, F: Folder<'ast, T>>(
|
|||
}
|
||||
UExpressionInner::Select(box array, box index) => {
|
||||
let array = f.fold_array_expression(array);
|
||||
let index = f.fold_field_expression(index);
|
||||
let index = f.fold_uint_expression(index);
|
||||
UExpressionInner::Select(box array, box index)
|
||||
}
|
||||
UExpressionInner::IfElse(box cond, box cons, box alt) => {
|
||||
|
@ -510,8 +525,11 @@ pub fn fold_array_expression<'ast, T: Field, F: Folder<'ast, T>>(
|
|||
f: &mut F,
|
||||
e: ArrayExpression<'ast, T>,
|
||||
) -> ArrayExpression<'ast, T> {
|
||||
let size = f.fold_uint_expression(e.size);
|
||||
|
||||
ArrayExpression {
|
||||
inner: f.fold_array_expression_inner(&e.ty, e.size, e.inner),
|
||||
inner: f.fold_array_expression_inner(&e.ty, size, e.inner),
|
||||
size,
|
||||
..e
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
use std::fmt;
|
||||
use typed_absy::types::FunctionKey;
|
||||
use typed_absy::types::ConcreteFunctionKey;
|
||||
use typed_absy::TypedModuleId;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Hash, Eq)]
|
||||
pub enum CoreIdentifier<'ast> {
|
||||
Source(&'ast str),
|
||||
Internal(&'static str, usize),
|
||||
Call(FunctionKey<'ast>),
|
||||
Call(ConcreteFunctionKey<'ast>),
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for CoreIdentifier<'ast> {
|
||||
|
@ -27,7 +27,7 @@ pub struct Identifier<'ast> {
|
|||
/// the version of the variable, used after SSA transformation
|
||||
pub version: usize,
|
||||
/// the call stack of the variable, used when inlining
|
||||
pub stack: Vec<(TypedModuleId, FunctionKey<'ast>, usize)>,
|
||||
pub stack: Vec<(TypedModuleId, ConcreteFunctionKey<'ast>, usize)>,
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for Identifier<'ast> {
|
||||
|
@ -78,7 +78,7 @@ impl<'ast> Identifier<'ast> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn stack(mut self, stack: Vec<(TypedModuleId, FunctionKey<'ast>, usize)>) -> Self {
|
||||
pub fn stack(mut self, stack: Vec<(TypedModuleId, ConcreteFunctionKey<'ast>, usize)>) -> Self {
|
||||
self.stack = stack;
|
||||
self
|
||||
}
|
||||
|
|
|
@ -15,16 +15,18 @@ mod uint;
|
|||
mod variable;
|
||||
|
||||
pub use self::identifier::CoreIdentifier;
|
||||
pub use self::parameter::Parameter;
|
||||
pub use self::types::{Signature, StructType, Type, UBitwidth};
|
||||
pub use self::variable::Variable;
|
||||
pub use self::parameter::{DeclarationParameter, GParameter, Parameter};
|
||||
use self::types::{DeclarationFunctionKey, DeclarationSignature, GSignature, GStructType, GType};
|
||||
pub use self::types::{DeclarationType, Signature, StructType, Type, UBitwidth};
|
||||
|
||||
pub use self::variable::{DeclarationVariable, GVariable, Variable};
|
||||
use std::path::PathBuf;
|
||||
pub use typed_absy::uint::{bitwidth, UExpression, UExpressionInner, UMetadata};
|
||||
|
||||
use crate::typed_absy::types::{FunctionKey, MemberId};
|
||||
use embed::FlatEmbed;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::fmt;
|
||||
use zokrates_field::Field;
|
||||
|
||||
|
@ -43,7 +45,8 @@ pub type TypedModules<'ast, T> = HashMap<TypedModuleId, TypedModule<'ast, T>>;
|
|||
/// # Remarks
|
||||
/// * It is the role of the semantic checker to make sure there are no duplicates for a given `FunctionKey`
|
||||
/// in a given `TypedModule`, hence the use of a HashMap
|
||||
pub type TypedFunctionSymbols<'ast, T> = HashMap<FunctionKey<'ast>, TypedFunctionSymbol<'ast, T>>;
|
||||
pub type TypedFunctionSymbols<'ast, T> =
|
||||
HashMap<DeclarationFunctionKey<'ast>, TypedFunctionSymbol<'ast, T>>;
|
||||
|
||||
/// A typed program as a collection of modules, one of them being the main
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
|
@ -53,7 +56,7 @@ pub struct TypedProgram<'ast, T> {
|
|||
}
|
||||
|
||||
impl<'ast, T: Field> TypedProgram<'ast, T> {
|
||||
pub fn abi(&self) -> Abi {
|
||||
pub fn abi(&self) -> Result<Abi, ()> {
|
||||
let main = self.modules[&self.main]
|
||||
.functions
|
||||
.iter()
|
||||
|
@ -65,18 +68,25 @@ impl<'ast, T: Field> TypedProgram<'ast, T> {
|
|||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
Abi {
|
||||
Ok(Abi {
|
||||
inputs: main
|
||||
.arguments
|
||||
.iter()
|
||||
.map(|p| AbiInput {
|
||||
public: !p.private,
|
||||
name: p.id.id.to_string(),
|
||||
ty: p.id._type.clone(),
|
||||
.map(|p| {
|
||||
types::ConcreteType::try_from(p.id._type.clone()).map(|ty| AbiInput {
|
||||
public: !p.private,
|
||||
name: p.id.id.to_string(),
|
||||
ty,
|
||||
})
|
||||
})
|
||||
.collect(),
|
||||
outputs: main.signature.outputs.clone(),
|
||||
}
|
||||
.collect::<Result<_, ()>>()?,
|
||||
outputs: main
|
||||
.signature
|
||||
.outputs
|
||||
.iter()
|
||||
.map(|ty| types::ConcreteType::try_from(ty.clone()))
|
||||
.collect::<Result<_, ()>>()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,7 +122,7 @@ pub struct TypedModule<'ast, T> {
|
|||
#[derive(Clone, PartialEq)]
|
||||
pub enum TypedFunctionSymbol<'ast, T> {
|
||||
Here(TypedFunction<'ast, T>),
|
||||
There(FunctionKey<'ast>, TypedModuleId),
|
||||
There(DeclarationFunctionKey<'ast>, TypedModuleId),
|
||||
Flat(FlatEmbed),
|
||||
}
|
||||
|
||||
|
@ -128,7 +138,10 @@ impl<'ast, T: fmt::Debug> fmt::Debug for TypedFunctionSymbol<'ast, T> {
|
|||
}
|
||||
|
||||
impl<'ast, T: Field> TypedFunctionSymbol<'ast, T> {
|
||||
pub fn signature<'a>(&'a self, modules: &'a TypedModules<T>) -> Signature {
|
||||
pub fn signature<'a>(
|
||||
&'a self,
|
||||
modules: &'a TypedModules<'ast, T>,
|
||||
) -> DeclarationSignature<'ast> {
|
||||
match self {
|
||||
TypedFunctionSymbol::Here(f) => f.signature.clone(),
|
||||
TypedFunctionSymbol::There(key, module_id) => modules
|
||||
|
@ -139,7 +152,7 @@ impl<'ast, T: Field> TypedFunctionSymbol<'ast, T> {
|
|||
.unwrap()
|
||||
.signature(&modules)
|
||||
.clone(),
|
||||
TypedFunctionSymbol::Flat(flat_fun) => flat_fun.signature(),
|
||||
TypedFunctionSymbol::Flat(flat_fun) => flat_fun.signature().try_into().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,11 +198,11 @@ impl<'ast, T: fmt::Debug> fmt::Debug for TypedModule<'ast, T> {
|
|||
#[derive(Clone, PartialEq)]
|
||||
pub struct TypedFunction<'ast, T> {
|
||||
/// Arguments of the function
|
||||
pub arguments: Vec<Parameter<'ast>>,
|
||||
pub arguments: Vec<DeclarationParameter<'ast>>,
|
||||
/// Vector of statements that are executed when running the function
|
||||
pub statements: Vec<TypedStatement<'ast, T>>,
|
||||
/// function signature
|
||||
pub signature: Signature,
|
||||
pub signature: DeclarationSignature<'ast>,
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Display> fmt::Display for TypedFunction<'ast, T> {
|
||||
|
@ -251,16 +264,13 @@ impl<'ast, T: fmt::Debug> fmt::Debug for TypedFunction<'ast, T> {
|
|||
/// Something we can assign to.
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
pub enum TypedAssignee<'ast, T> {
|
||||
Identifier(Variable<'ast>),
|
||||
Select(
|
||||
Box<TypedAssignee<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
Identifier(Variable<'ast, T>),
|
||||
Select(Box<TypedAssignee<'ast, T>>, Box<UExpression<'ast, T>>),
|
||||
Member(Box<TypedAssignee<'ast, T>>, MemberId),
|
||||
}
|
||||
|
||||
impl<'ast, T> Typed for TypedAssignee<'ast, T> {
|
||||
fn get_type(&self) -> Type {
|
||||
impl<'ast, T> Typed<'ast, T> for TypedAssignee<'ast, T> {
|
||||
fn get_type(&self) -> Type<'ast, T> {
|
||||
match *self {
|
||||
TypedAssignee::Identifier(ref v) => v.get_type(),
|
||||
TypedAssignee::Select(ref a, _) => {
|
||||
|
@ -311,15 +321,15 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedAssignee<'ast, T> {
|
|||
pub enum TypedStatement<'ast, T> {
|
||||
Return(Vec<TypedExpression<'ast, T>>),
|
||||
Definition(TypedAssignee<'ast, T>, TypedExpression<'ast, T>),
|
||||
Declaration(Variable<'ast>),
|
||||
Declaration(Variable<'ast, T>),
|
||||
Assertion(BooleanExpression<'ast, T>),
|
||||
For(
|
||||
Variable<'ast>,
|
||||
Variable<'ast, T>,
|
||||
UExpression<'ast, T>,
|
||||
UExpression<'ast, T>,
|
||||
Vec<TypedStatement<'ast, T>>,
|
||||
),
|
||||
MultipleDefinition(Vec<Variable<'ast>>, TypedExpressionList<'ast, T>),
|
||||
MultipleDefinition(Vec<Variable<'ast, T>>, TypedExpressionList<'ast, T>),
|
||||
}
|
||||
|
||||
impl<'ast, T: fmt::Debug> fmt::Debug for TypedStatement<'ast, T> {
|
||||
|
@ -407,8 +417,8 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedStatement<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait Typed {
|
||||
fn get_type(&self) -> Type;
|
||||
pub trait Typed<'ast, T> {
|
||||
fn get_type(&self) -> Type<'ast, T>;
|
||||
}
|
||||
|
||||
/// A typed expression
|
||||
|
@ -531,8 +541,8 @@ impl<'ast, T: fmt::Debug> fmt::Debug for StructExpression<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> Typed for TypedExpression<'ast, T> {
|
||||
fn get_type(&self) -> Type {
|
||||
impl<'ast, T> Typed<'ast, T> for TypedExpression<'ast, T> {
|
||||
fn get_type(&self) -> Type<'ast, T> {
|
||||
match *self {
|
||||
TypedExpression::Boolean(ref e) => e.get_type(),
|
||||
TypedExpression::FieldElement(ref e) => e.get_type(),
|
||||
|
@ -543,47 +553,51 @@ impl<'ast, T> Typed for TypedExpression<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> Typed for ArrayExpression<'ast, T> {
|
||||
fn get_type(&self) -> Type {
|
||||
impl<'ast, T> Typed<'ast, T> for ArrayExpression<'ast, T> {
|
||||
fn get_type(&self) -> Type<'ast, T> {
|
||||
Type::array(self.ty.clone(), self.size)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> Typed for StructExpression<'ast, T> {
|
||||
fn get_type(&self) -> Type {
|
||||
impl<'ast, T> Typed<'ast, T> for StructExpression<'ast, T> {
|
||||
fn get_type(&self) -> Type<'ast, T> {
|
||||
Type::Struct(self.ty.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> Typed for FieldElementExpression<'ast, T> {
|
||||
fn get_type(&self) -> Type {
|
||||
impl<'ast, T> Typed<'ast, T> for FieldElementExpression<'ast, T> {
|
||||
fn get_type(&self) -> Type<'ast, T> {
|
||||
Type::FieldElement
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> Typed for UExpression<'ast, T> {
|
||||
fn get_type(&self) -> Type {
|
||||
impl<'ast, T> Typed<'ast, T> for UExpression<'ast, T> {
|
||||
fn get_type(&self) -> Type<'ast, T> {
|
||||
Type::Uint(self.bitwidth)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> Typed for BooleanExpression<'ast, T> {
|
||||
fn get_type(&self) -> Type {
|
||||
impl<'ast, T> Typed<'ast, T> for BooleanExpression<'ast, T> {
|
||||
fn get_type(&self) -> Type<'ast, T> {
|
||||
Type::Boolean
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MultiTyped {
|
||||
fn get_types(&self) -> &Vec<Type>;
|
||||
pub trait MultiTyped<'ast, T> {
|
||||
fn get_types(&self) -> &Vec<Type<'ast, T>>;
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
pub enum TypedExpressionList<'ast, T> {
|
||||
FunctionCall(FunctionKey<'ast>, Vec<TypedExpression<'ast, T>>, Vec<Type>),
|
||||
FunctionCall(
|
||||
FunctionKey<'ast, T>,
|
||||
Vec<TypedExpression<'ast, T>>,
|
||||
Vec<Type<'ast, T>>,
|
||||
),
|
||||
}
|
||||
|
||||
impl<'ast, T> MultiTyped for TypedExpressionList<'ast, T> {
|
||||
fn get_types(&self) -> &Vec<Type> {
|
||||
impl<'ast, T> MultiTyped<'ast, T> for TypedExpressionList<'ast, T> {
|
||||
fn get_types(&self) -> &Vec<Type<'ast, T>> {
|
||||
match *self {
|
||||
TypedExpressionList::FunctionCall(_, _, ref types) => types,
|
||||
}
|
||||
|
@ -620,12 +634,9 @@ pub enum FieldElementExpression<'ast, T> {
|
|||
Box<FieldElementExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
FunctionCall(FunctionKey<'ast>, Vec<TypedExpression<'ast, T>>),
|
||||
FunctionCall(FunctionKey<'ast, T>, Vec<TypedExpression<'ast, T>>),
|
||||
Member(Box<StructExpression<'ast, T>>, MemberId),
|
||||
Select(
|
||||
Box<ArrayExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
Select(Box<ArrayExpression<'ast, T>>, Box<UExpression<'ast, T>>),
|
||||
}
|
||||
|
||||
/// An expression of type `bool`
|
||||
|
@ -678,11 +689,8 @@ pub enum BooleanExpression<'ast, T> {
|
|||
Box<BooleanExpression<'ast, T>>,
|
||||
),
|
||||
Member(Box<StructExpression<'ast, T>>, MemberId),
|
||||
FunctionCall(FunctionKey<'ast>, Vec<TypedExpression<'ast, T>>),
|
||||
Select(
|
||||
Box<ArrayExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
FunctionCall(FunctionKey<'ast, T>, Vec<TypedExpression<'ast, T>>),
|
||||
Select(Box<ArrayExpression<'ast, T>>, Box<UExpression<'ast, T>>),
|
||||
}
|
||||
|
||||
/// An expression of type `array`
|
||||
|
@ -692,8 +700,8 @@ pub enum BooleanExpression<'ast, T> {
|
|||
/// type checking
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
pub struct ArrayExpression<'ast, T> {
|
||||
size: usize,
|
||||
ty: Type,
|
||||
size: UExpression<'ast, T>,
|
||||
ty: Type<'ast, T>,
|
||||
inner: ArrayExpressionInner<'ast, T>,
|
||||
}
|
||||
|
||||
|
@ -701,23 +709,24 @@ pub struct ArrayExpression<'ast, T> {
|
|||
pub enum ArrayExpressionInner<'ast, T> {
|
||||
Identifier(Identifier<'ast>),
|
||||
Value(Vec<TypedExpression<'ast, T>>),
|
||||
FunctionCall(FunctionKey<'ast>, Vec<TypedExpression<'ast, T>>),
|
||||
FunctionCall(FunctionKey<'ast, T>, Vec<TypedExpression<'ast, T>>),
|
||||
IfElse(
|
||||
Box<BooleanExpression<'ast, T>>,
|
||||
Box<ArrayExpression<'ast, T>>,
|
||||
Box<ArrayExpression<'ast, T>>,
|
||||
),
|
||||
Member(Box<StructExpression<'ast, T>>, MemberId),
|
||||
Select(
|
||||
Box<ArrayExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
Select(Box<ArrayExpression<'ast, T>>, Box<UExpression<'ast, T>>),
|
||||
}
|
||||
|
||||
impl<'ast, T> ArrayExpressionInner<'ast, T> {
|
||||
pub fn annotate(self, ty: Type, size: usize) -> ArrayExpression<'ast, T> {
|
||||
pub fn annotate<S: Into<UExpression<'ast, T>>>(
|
||||
self,
|
||||
ty: Type<'ast, T>,
|
||||
size: S,
|
||||
) -> ArrayExpression<'ast, T> {
|
||||
ArrayExpression {
|
||||
size,
|
||||
size: size.into(),
|
||||
ty,
|
||||
inner: self,
|
||||
}
|
||||
|
@ -725,11 +734,11 @@ impl<'ast, T> ArrayExpressionInner<'ast, T> {
|
|||
}
|
||||
|
||||
impl<'ast, T> ArrayExpression<'ast, T> {
|
||||
pub fn inner_type(&self) -> &Type {
|
||||
pub fn inner_type(&self) -> &Type<'ast, T> {
|
||||
&self.ty
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
pub fn size(&self) -> UExpression<'ast, T> {
|
||||
self.size
|
||||
}
|
||||
|
||||
|
@ -744,12 +753,12 @@ impl<'ast, T> ArrayExpression<'ast, T> {
|
|||
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
pub struct StructExpression<'ast, T> {
|
||||
ty: StructType,
|
||||
ty: StructType<'ast, T>,
|
||||
inner: StructExpressionInner<'ast, T>,
|
||||
}
|
||||
|
||||
impl<'ast, T> StructExpression<'ast, T> {
|
||||
pub fn ty(&self) -> &StructType {
|
||||
pub fn ty(&self) -> &StructType<'ast, T> {
|
||||
&self.ty
|
||||
}
|
||||
|
||||
|
@ -766,21 +775,18 @@ impl<'ast, T> StructExpression<'ast, T> {
|
|||
pub enum StructExpressionInner<'ast, T> {
|
||||
Identifier(Identifier<'ast>),
|
||||
Value(Vec<TypedExpression<'ast, T>>),
|
||||
FunctionCall(FunctionKey<'ast>, Vec<TypedExpression<'ast, T>>),
|
||||
FunctionCall(FunctionKey<'ast, T>, Vec<TypedExpression<'ast, T>>),
|
||||
IfElse(
|
||||
Box<BooleanExpression<'ast, T>>,
|
||||
Box<StructExpression<'ast, T>>,
|
||||
Box<StructExpression<'ast, T>>,
|
||||
),
|
||||
Member(Box<StructExpression<'ast, T>>, MemberId),
|
||||
Select(
|
||||
Box<ArrayExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
Select(Box<ArrayExpression<'ast, T>>, Box<UExpression<'ast, T>>),
|
||||
}
|
||||
|
||||
impl<'ast, T> StructExpressionInner<'ast, T> {
|
||||
pub fn annotate(self, ty: StructType) -> StructExpression<'ast, T> {
|
||||
pub fn annotate(self, ty: StructType<'ast, T>) -> StructExpression<'ast, T> {
|
||||
StructExpression { ty, inner: self }
|
||||
}
|
||||
}
|
||||
|
@ -1212,23 +1218,23 @@ impl<'ast, T> IfElse<'ast, T> for StructExpression<'ast, T> {
|
|||
}
|
||||
|
||||
pub trait Select<'ast, T> {
|
||||
fn select(array: ArrayExpression<'ast, T>, index: FieldElementExpression<'ast, T>) -> Self;
|
||||
fn select(array: ArrayExpression<'ast, T>, index: UExpression<'ast, T>) -> Self;
|
||||
}
|
||||
|
||||
impl<'ast, T> Select<'ast, T> for FieldElementExpression<'ast, T> {
|
||||
fn select(array: ArrayExpression<'ast, T>, index: FieldElementExpression<'ast, T>) -> Self {
|
||||
fn select(array: ArrayExpression<'ast, T>, index: UExpression<'ast, T>) -> Self {
|
||||
FieldElementExpression::Select(box array, box index)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> Select<'ast, T> for BooleanExpression<'ast, T> {
|
||||
fn select(array: ArrayExpression<'ast, T>, index: FieldElementExpression<'ast, T>) -> Self {
|
||||
fn select(array: ArrayExpression<'ast, T>, index: UExpression<'ast, T>) -> Self {
|
||||
BooleanExpression::Select(box array, box index)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> Select<'ast, T> for UExpression<'ast, T> {
|
||||
fn select(array: ArrayExpression<'ast, T>, index: FieldElementExpression<'ast, T>) -> Self {
|
||||
fn select(array: ArrayExpression<'ast, T>, index: UExpression<'ast, T>) -> Self {
|
||||
let bitwidth = match array.inner_type().clone() {
|
||||
Type::Uint(bitwidth) => bitwidth,
|
||||
_ => unreachable!(),
|
||||
|
@ -1239,7 +1245,7 @@ impl<'ast, T> Select<'ast, T> for UExpression<'ast, T> {
|
|||
}
|
||||
|
||||
impl<'ast, T> Select<'ast, T> for ArrayExpression<'ast, T> {
|
||||
fn select(array: ArrayExpression<'ast, T>, index: FieldElementExpression<'ast, T>) -> Self {
|
||||
fn select(array: ArrayExpression<'ast, T>, index: UExpression<'ast, T>) -> Self {
|
||||
let (ty, size) = match array.inner_type() {
|
||||
Type::Array(array_type) => (array_type.ty.clone(), array_type.size.clone()),
|
||||
_ => unreachable!(),
|
||||
|
@ -1250,7 +1256,7 @@ impl<'ast, T> Select<'ast, T> for ArrayExpression<'ast, T> {
|
|||
}
|
||||
|
||||
impl<'ast, T> Select<'ast, T> for StructExpression<'ast, T> {
|
||||
fn select(array: ArrayExpression<'ast, T>, index: FieldElementExpression<'ast, T>) -> Self {
|
||||
fn select(array: ArrayExpression<'ast, T>, index: UExpression<'ast, T>) -> Self {
|
||||
let members = match array.inner_type().clone() {
|
||||
Type::Struct(members) => members,
|
||||
_ => unreachable!(),
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
use crate::typed_absy::Variable;
|
||||
use crate::typed_absy::GVariable;
|
||||
use std::fmt;
|
||||
use typed_absy::types::Constant;
|
||||
use typed_absy::TryFrom;
|
||||
use typed_absy::UExpression;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct Parameter<'ast> {
|
||||
pub id: Variable<'ast>,
|
||||
pub struct GParameter<'ast, S> {
|
||||
pub id: GVariable<'ast, S>,
|
||||
pub private: bool,
|
||||
}
|
||||
|
||||
impl<'ast> Parameter<'ast> {
|
||||
impl<'ast, S> GParameter<'ast, S> {
|
||||
#[cfg(test)]
|
||||
pub fn private(v: Variable<'ast>) -> Self {
|
||||
pub fn private(v: GVariable<'ast, S>) -> Self {
|
||||
Parameter {
|
||||
id: v,
|
||||
private: true,
|
||||
|
@ -17,14 +20,32 @@ impl<'ast> Parameter<'ast> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for Parameter<'ast> {
|
||||
pub type DeclarationParameter<'ast> = GParameter<'ast, Constant<'ast>>;
|
||||
pub type ConcreteParameter<'ast> = GParameter<'ast, usize>;
|
||||
pub type Parameter<'ast, T> = GParameter<'ast, UExpression<'ast, T>>;
|
||||
|
||||
impl<'ast, T> TryFrom<Parameter<'ast, T>> for ConcreteParameter<'ast> {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(t: Parameter<'ast, T>) -> Result<Self, Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> From<ConcreteParameter<'ast>> for Parameter<'ast, T> {
|
||||
fn from(t: ConcreteParameter<'ast>) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, S> fmt::Display for GParameter<'ast, S> {
|
||||
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<'ast> fmt::Debug for Parameter<'ast> {
|
||||
impl<'ast, S> fmt::Debug for GParameter<'ast, S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Parameter(variable: {:?})", self.id)
|
||||
}
|
||||
|
|
|
@ -1,49 +1,119 @@
|
|||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
use std::path::PathBuf;
|
||||
use typed_absy::TryFrom;
|
||||
use typed_absy::UExpression;
|
||||
|
||||
pub type Identifier<'ast> = &'ast str;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum Constant<'ast> {
|
||||
Generic(Identifier<'ast>),
|
||||
Concrete(u32),
|
||||
}
|
||||
|
||||
impl<'ast> From<u32> for Constant<'ast> {
|
||||
fn from(e: u32) -> Self {
|
||||
Constant::Concrete(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<Identifier<'ast>> for Constant<'ast> {
|
||||
fn from(e: Identifier<'ast>) -> Self {
|
||||
Constant::Generic(e)
|
||||
}
|
||||
}
|
||||
|
||||
pub type MemberId = String;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
|
||||
pub struct StructMember {
|
||||
pub struct GStructMember<S> {
|
||||
#[serde(rename = "name")]
|
||||
pub id: MemberId,
|
||||
#[serde(flatten)]
|
||||
pub ty: Box<Type>,
|
||||
pub ty: Box<GType<S>>,
|
||||
}
|
||||
|
||||
pub type DeclarationStructMember<'ast> = GStructMember<Constant<'ast>>;
|
||||
pub type ConcreteStructMember = GStructMember<usize>;
|
||||
pub type StructMember<'ast, T> = GStructMember<UExpression<'ast, T>>;
|
||||
|
||||
impl<'ast, T> TryFrom<StructMember<'ast, T>> for ConcreteStructMember {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(t: StructMember<'ast, T>) -> Result<Self, Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> From<ConcreteStructMember> for StructMember<'ast, T> {
|
||||
fn from(t: ConcreteStructMember) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
|
||||
pub struct GArrayType<S> {
|
||||
pub size: S,
|
||||
#[serde(flatten)]
|
||||
pub ty: Box<Type>,
|
||||
pub ty: Box<GType<S>>,
|
||||
}
|
||||
|
||||
pub type ArrayType = GArrayType<usize>;
|
||||
pub type DeclarationArrayType<'ast> = GArrayType<Constant<'ast>>;
|
||||
pub type ConcreteArrayType = GArrayType<usize>;
|
||||
pub type ArrayType<'ast, T> = GArrayType<UExpression<'ast, T>>;
|
||||
|
||||
pub type UArrayType<'ast, T> = GArrayType<UExpression<'ast, T>>;
|
||||
impl<'ast, T> TryFrom<ArrayType<'ast, T>> for ConcreteArrayType {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(t: ArrayType<'ast, T>) -> Result<Self, Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> From<ConcreteArrayType> for ArrayType<'ast, T> {
|
||||
fn from(t: ConcreteArrayType) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Hash, Serialize, Deserialize, PartialOrd, Ord)]
|
||||
pub struct StructType {
|
||||
pub struct GStructType<S> {
|
||||
#[serde(skip)]
|
||||
pub module: PathBuf,
|
||||
pub name: String,
|
||||
pub members: Vec<StructMember>,
|
||||
pub members: Vec<GStructMember<S>>,
|
||||
}
|
||||
|
||||
impl PartialEq for StructType {
|
||||
pub type DeclarationStructType<'ast> = GStructType<Constant<'ast>>;
|
||||
pub type ConcreteStructType = GStructType<usize>;
|
||||
pub type StructType<'ast, T> = GStructType<UExpression<'ast, T>>;
|
||||
|
||||
impl<'ast, T> TryFrom<StructType<'ast, T>> for ConcreteStructType {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(t: StructType<'ast, T>) -> Result<Self, Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> From<ConcreteStructType> for StructType<'ast, T> {
|
||||
fn from(t: ConcreteStructType) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> PartialEq for GStructType<S> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.members.eq(&other.members)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for StructType {}
|
||||
impl<S> Eq for GStructType<S> {}
|
||||
|
||||
impl StructType {
|
||||
pub fn new(module: PathBuf, name: String, members: Vec<StructMember>) -> Self {
|
||||
StructType {
|
||||
impl<S> GStructType<S> {
|
||||
pub fn new(module: PathBuf, name: String, members: Vec<GStructMember<S>>) -> Self {
|
||||
GStructType {
|
||||
module,
|
||||
name,
|
||||
members,
|
||||
|
@ -54,13 +124,13 @@ impl StructType {
|
|||
self.members.len()
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> std::slice::Iter<StructMember> {
|
||||
pub fn iter(&self) -> std::slice::Iter<GStructMember<S>> {
|
||||
self.members.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for StructType {
|
||||
type Item = StructMember;
|
||||
impl<S> IntoIterator for GStructType<S> {
|
||||
type Item = GStructMember<S>;
|
||||
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
|
@ -101,47 +171,120 @@ impl fmt::Display for UBitwidth {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
|
||||
#[derive(Clone, Hash, Serialize, Deserialize)]
|
||||
#[serde(tag = "type", content = "components")]
|
||||
pub enum Type {
|
||||
pub enum GType<S> {
|
||||
#[serde(rename = "field")]
|
||||
FieldElement,
|
||||
#[serde(rename = "bool")]
|
||||
Boolean,
|
||||
#[serde(rename = "array")]
|
||||
Array(ArrayType),
|
||||
Array(GArrayType<S>),
|
||||
#[serde(rename = "struct")]
|
||||
Struct(StructType),
|
||||
Struct(GStructType<S>),
|
||||
#[serde(rename = "u")]
|
||||
Uint(UBitwidth),
|
||||
}
|
||||
|
||||
pub type DeclarationType<'ast> = GType<Constant<'ast>>;
|
||||
pub type ConcreteType = GType<usize>;
|
||||
pub type Type<'ast, T> = GType<UExpression<'ast, T>>;
|
||||
|
||||
// we have a looser equality relationship for generic types: an array of unknown size of a given type is equal to any arrays of that type
|
||||
impl<'ast, T> PartialEq for Type<'ast, T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for ConcreteType {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> Eq for Type<'ast, T> {}
|
||||
|
||||
impl Eq for ConcreteType {}
|
||||
|
||||
impl<'ast, T> PartialOrd for Type<'ast, T> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for ConcreteType {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> Ord for Type<'ast, T> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for ConcreteType {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> TryFrom<Type<'ast, T>> for ConcreteType {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(t: Type<'ast, T>) -> Result<Self, Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> TryFrom<DeclarationType<'ast>> for ConcreteType {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(t: DeclarationType<'ast>) -> Result<Self, Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> From<ConcreteType> for Type<'ast, T> {
|
||||
fn from(t: ConcreteType) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> From<DeclarationType<'ast>> for Type<'ast, T> {
|
||||
fn from(t: DeclarationType<'ast>) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> GArrayType<S> {
|
||||
pub fn new(ty: Type, size: S) -> Self {
|
||||
GArrayType {
|
||||
pub fn new(ty: GType<S>, size: S) -> Self {
|
||||
ArrayType {
|
||||
ty: Box::new(ty),
|
||||
size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StructMember {
|
||||
pub fn new(id: String, ty: Type) -> Self {
|
||||
StructMember {
|
||||
impl<S> GStructMember<S> {
|
||||
pub fn new(id: String, ty: GType<S>) -> Self {
|
||||
GStructMember {
|
||||
id,
|
||||
ty: Box::new(ty),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Type {
|
||||
impl<S> fmt::Display for GType<S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Type::FieldElement => write!(f, "field"),
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
Type::Uint(ref bitwidth) => write!(f, "u{}", bitwidth),
|
||||
Type::Array(ref array_type) => write!(f, "{}[{}]", array_type.ty, array_type.size),
|
||||
Type::Struct(ref struct_type) => write!(
|
||||
GType::FieldElement => write!(f, "field"),
|
||||
GType::Boolean => write!(f, "bool"),
|
||||
GType::Uint(ref bitwidth) => write!(f, "u{}", bitwidth),
|
||||
GType::Array(ref array_type) => write!(f, "{}[{}]", array_type.ty, array_type.size),
|
||||
GType::Struct(ref struct_type) => write!(
|
||||
f,
|
||||
"{} {{{}}}",
|
||||
struct_type.name,
|
||||
|
@ -156,14 +299,14 @@ impl fmt::Display for Type {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Type {
|
||||
impl<S> fmt::Debug for GType<S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Type::FieldElement => write!(f, "field"),
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
Type::Uint(ref bitwidth) => write!(f, "u{}", bitwidth),
|
||||
Type::Array(ref array_type) => write!(f, "{}[{}]", array_type.ty, array_type.size),
|
||||
Type::Struct(ref struct_type) => write!(
|
||||
GType::FieldElement => write!(f, "field"),
|
||||
GType::Boolean => write!(f, "bool"),
|
||||
GType::Uint(ref bitwidth) => write!(f, "u{}", bitwidth),
|
||||
GType::Array(ref array_type) => write!(f, "{}[{}]", array_type.ty, array_type.size),
|
||||
GType::Struct(ref struct_type) => write!(
|
||||
f,
|
||||
"{} {{{}}}",
|
||||
struct_type.name,
|
||||
|
@ -178,26 +321,26 @@ impl fmt::Debug for Type {
|
|||
}
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn array(ty: Type, size: usize) -> Self {
|
||||
Type::Array(ArrayType::new(ty, size))
|
||||
impl<S> GType<S> {
|
||||
pub fn array<U: Into<S>>(ty: GType<S>, size: U) -> Self {
|
||||
GType::Array(ArrayType::new(ty, size.into()))
|
||||
}
|
||||
|
||||
pub fn struc(struct_ty: StructType) -> Self {
|
||||
Type::Struct(struct_ty)
|
||||
pub fn struc(struct_ty: GStructType<S>) -> Self {
|
||||
GType::Struct(struct_ty)
|
||||
}
|
||||
|
||||
pub fn uint<W: Into<UBitwidth>>(b: W) -> Self {
|
||||
Type::Uint(b.into())
|
||||
GType::Uint(b.into())
|
||||
}
|
||||
|
||||
fn to_slug(&self) -> String {
|
||||
match self {
|
||||
Type::FieldElement => String::from("f"),
|
||||
Type::Boolean => String::from("b"),
|
||||
Type::Uint(bitwidth) => format!("u{}", bitwidth),
|
||||
Type::Array(array_type) => format!("{}[{}]", array_type.ty.to_slug(), array_type.size),
|
||||
Type::Struct(struct_type) => format!(
|
||||
GType::FieldElement => String::from("f"),
|
||||
GType::Boolean => String::from("b"),
|
||||
GType::Uint(bitwidth) => format!("u{}", bitwidth),
|
||||
GType::Array(array_type) => format!("{}[{}]", array_type.ty.to_slug(), array_type.size),
|
||||
GType::Struct(struct_type) => format!(
|
||||
"{{{}}}",
|
||||
struct_type
|
||||
.iter()
|
||||
|
@ -207,15 +350,17 @@ impl Type {
|
|||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ConcreteType {
|
||||
// the number of field elements the type maps to
|
||||
pub fn get_primitive_count(&self) -> usize {
|
||||
match self {
|
||||
Type::FieldElement => 1,
|
||||
Type::Boolean => 1,
|
||||
Type::Uint(_) => 1,
|
||||
Type::Array(array_type) => array_type.size * array_type.ty.get_primitive_count(),
|
||||
Type::Struct(struct_type) => struct_type
|
||||
GType::FieldElement => 1,
|
||||
GType::Boolean => 1,
|
||||
GType::Uint(_) => 1,
|
||||
GType::Array(array_type) => array_type.size * array_type.ty.get_primitive_count(),
|
||||
GType::Struct(struct_type) => struct_type
|
||||
.iter()
|
||||
.map(|member| member.ty.get_primitive_count())
|
||||
.sum(),
|
||||
|
@ -226,25 +371,51 @@ impl Type {
|
|||
pub type FunctionIdentifier<'ast> = &'ast str;
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
|
||||
pub struct FunctionKey<'ast> {
|
||||
pub struct GFunctionKey<'ast, S> {
|
||||
pub id: FunctionIdentifier<'ast>,
|
||||
pub signature: Signature,
|
||||
pub signature: GSignature<S>,
|
||||
}
|
||||
|
||||
impl<'ast> FunctionKey<'ast> {
|
||||
pub fn with_id<S: Into<Identifier<'ast>>>(id: S) -> Self {
|
||||
FunctionKey {
|
||||
pub type DeclarationFunctionKey<'ast> = GFunctionKey<'ast, Constant<'ast>>;
|
||||
pub type ConcreteFunctionKey<'ast> = GFunctionKey<'ast, usize>;
|
||||
pub type FunctionKey<'ast, T> = GFunctionKey<'ast, UExpression<'ast, T>>;
|
||||
|
||||
impl<'ast, T> TryFrom<FunctionKey<'ast, T>> for ConcreteFunctionKey<'ast> {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(t: FunctionKey<'ast, T>) -> Result<Self, Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> TryFrom<DeclarationFunctionKey<'ast>> for ConcreteFunctionKey<'ast> {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(t: DeclarationFunctionKey<'ast>) -> Result<Self, Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> From<ConcreteFunctionKey<'ast>> for FunctionKey<'ast, T> {
|
||||
fn from(t: ConcreteFunctionKey<'ast>) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, S> GFunctionKey<'ast, S> {
|
||||
pub fn with_id<U: Into<Identifier<'ast>>>(id: U) -> Self {
|
||||
GFunctionKey {
|
||||
id: id.into(),
|
||||
signature: Signature::new(),
|
||||
signature: GSignature::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signature(mut self, signature: Signature) -> Self {
|
||||
pub fn signature(mut self, signature: GSignature<S>) -> Self {
|
||||
self.signature = signature;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn id<S: Into<Identifier<'ast>>>(mut self, id: S) -> Self {
|
||||
pub fn id<U: Into<Identifier<'ast>>>(mut self, id: U) -> Self {
|
||||
self.id = id.into();
|
||||
self
|
||||
}
|
||||
|
@ -254,19 +425,81 @@ impl<'ast> FunctionKey<'ast> {
|
|||
}
|
||||
}
|
||||
|
||||
pub use self::signature::Signature;
|
||||
pub use self::signature::{ConcreteSignature, DeclarationSignature, GSignature, Signature};
|
||||
|
||||
pub mod signature {
|
||||
use super::*;
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
use std::hash::Hasher;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Ord, PartialOrd)]
|
||||
pub struct Signature {
|
||||
pub inputs: Vec<Type>,
|
||||
pub outputs: Vec<Type>,
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct GSignature<S> {
|
||||
pub inputs: Vec<GType<S>>,
|
||||
pub outputs: Vec<GType<S>>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Signature {
|
||||
impl<S> PartialOrd for GSignature<S> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Ord for GSignature<S> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.partial_cmp(other).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> PartialEq for GSignature<S> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Eq for GSignature<S> {}
|
||||
|
||||
impl<S> std::hash::Hash for GSignature<S> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub type DeclarationSignature<'ast> = GSignature<Constant<'ast>>;
|
||||
pub type ConcreteSignature = GSignature<usize>;
|
||||
pub type Signature<'ast, T> = GSignature<UExpression<'ast, T>>;
|
||||
|
||||
impl<'ast> TryFrom<ConcreteSignature> for DeclarationSignature<'ast> {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(t: ConcreteSignature) -> Result<Self, Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> TryFrom<Signature<'ast, T>> for ConcreteSignature {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(t: Signature<'ast, T>) -> Result<Self, Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> TryFrom<DeclarationSignature<'ast>> for ConcreteSignature {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(t: DeclarationSignature<'ast>) -> Result<Self, Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> From<ConcreteSignature> for Signature<'ast, T> {
|
||||
fn from(t: ConcreteSignature) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> fmt::Debug for GSignature<S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
|
@ -276,7 +509,7 @@ pub mod signature {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Signature {
|
||||
impl<S> fmt::Display for GSignature<S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "(")?;
|
||||
for (i, t) in self.inputs.iter().enumerate() {
|
||||
|
@ -303,7 +536,7 @@ pub mod signature {
|
|||
}
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
impl<S> GSignature<S> {
|
||||
/// Returns a slug for a signature, with the following encoding:
|
||||
/// i{inputs}o{outputs} where {inputs} and {outputs} each encode a list of types.
|
||||
/// A list of types is encoded by compressing sequences of the same type like so:
|
||||
|
@ -347,19 +580,19 @@ pub mod signature {
|
|||
format!("i{}o{}", to_slug(&self.inputs), to_slug(&self.outputs))
|
||||
}
|
||||
|
||||
pub fn new() -> Signature {
|
||||
Signature {
|
||||
pub fn new() -> GSignature<S> {
|
||||
Self {
|
||||
inputs: vec![],
|
||||
outputs: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inputs(mut self, inputs: Vec<Type>) -> Self {
|
||||
pub fn inputs(mut self, inputs: Vec<GType<S>>) -> Self {
|
||||
self.inputs = inputs;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn outputs(mut self, outputs: Vec<Type>) -> Self {
|
||||
pub fn outputs(mut self, outputs: Vec<GType<S>>) -> Self {
|
||||
self.outputs = outputs;
|
||||
self
|
||||
}
|
||||
|
|
|
@ -82,6 +82,12 @@ pub struct UExpression<'ast, T> {
|
|||
pub inner: UExpressionInner<'ast, T>,
|
||||
}
|
||||
|
||||
impl<'ast, T> From<u32> for UExpression<'ast, T> {
|
||||
fn from(u: u32) -> Self {
|
||||
UExpressionInner::Value(u).annotate(UBitwidth::B32)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum UExpressionInner<'ast, T> {
|
||||
Identifier(Identifier<'ast>),
|
||||
|
@ -101,17 +107,14 @@ pub enum UExpressionInner<'ast, T> {
|
|||
Box<UExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
FunctionCall(FunctionKey<'ast>, Vec<TypedExpression<'ast, T>>),
|
||||
FunctionCall(FunctionKey<'ast, T>, Vec<TypedExpression<'ast, T>>),
|
||||
IfElse(
|
||||
Box<BooleanExpression<'ast, T>>,
|
||||
Box<UExpression<'ast, T>>,
|
||||
Box<UExpression<'ast, T>>,
|
||||
),
|
||||
Member(Box<StructExpression<'ast, T>>, MemberId),
|
||||
Select(
|
||||
Box<ArrayExpression<'ast, T>>,
|
||||
Box<FieldElementExpression<'ast, T>>,
|
||||
),
|
||||
Select(Box<ArrayExpression<'ast, T>>, Box<UExpression<'ast, T>>),
|
||||
}
|
||||
|
||||
impl<'ast, T> UExpressionInner<'ast, T> {
|
||||
|
|
|
@ -1,76 +1,94 @@
|
|||
use crate::typed_absy::types::Type;
|
||||
use crate::typed_absy::types::GType;
|
||||
use crate::typed_absy::Identifier;
|
||||
use std::fmt;
|
||||
use typed_absy::types::{StructType, UBitwidth};
|
||||
use typed_absy::types::{Constant, GStructType, UBitwidth};
|
||||
use typed_absy::TryFrom;
|
||||
use typed_absy::UExpression;
|
||||
|
||||
#[derive(Clone, PartialEq, Hash, Eq)]
|
||||
pub struct Variable<'ast> {
|
||||
pub struct GVariable<'ast, S> {
|
||||
pub id: Identifier<'ast>,
|
||||
pub _type: Type,
|
||||
pub _type: GType<S>,
|
||||
}
|
||||
|
||||
impl<'ast> Variable<'ast> {
|
||||
pub fn field_element<I: Into<Identifier<'ast>>>(id: I) -> Variable<'ast> {
|
||||
Self::with_id_and_type(id, Type::FieldElement)
|
||||
pub type DeclarationVariable<'ast> = GVariable<'ast, Constant<'ast>>;
|
||||
pub type ConcreteVariable<'ast> = GVariable<'ast, usize>;
|
||||
pub type Variable<'ast, T> = GVariable<'ast, UExpression<'ast, T>>;
|
||||
|
||||
impl<'ast, T> TryFrom<Variable<'ast, T>> for ConcreteVariable<'ast> {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(t: Variable<'ast, T>) -> Result<Self, Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> TryFrom<DeclarationVariable<'ast>> for ConcreteVariable<'ast> {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(t: DeclarationVariable<'ast>) -> Result<Self, Self::Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> From<ConcreteVariable<'ast>> for Variable<'ast, T> {
|
||||
fn from(t: ConcreteVariable<'ast>) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> From<DeclarationVariable<'ast>> for Variable<'ast, T> {
|
||||
fn from(t: DeclarationVariable<'ast>) -> Self {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, S> GVariable<'ast, S> {
|
||||
pub fn field_element<I: Into<Identifier<'ast>>>(id: I) -> Self {
|
||||
Self::with_id_and_type(id, GType::FieldElement)
|
||||
}
|
||||
|
||||
pub fn boolean<I: Into<Identifier<'ast>>>(id: I) -> Variable<'ast> {
|
||||
Self::with_id_and_type(id, Type::Boolean)
|
||||
pub fn boolean<I: Into<Identifier<'ast>>>(id: I) -> Self {
|
||||
Self::with_id_and_type(id, GType::Boolean)
|
||||
}
|
||||
|
||||
pub fn uint<I: Into<Identifier<'ast>>, W: Into<UBitwidth>>(
|
||||
id: I,
|
||||
bitwidth: W,
|
||||
) -> Variable<'ast> {
|
||||
Self::with_id_and_type(id, Type::uint(bitwidth))
|
||||
pub fn uint<I: Into<Identifier<'ast>>, W: Into<UBitwidth>>(id: I, bitwidth: W) -> Self {
|
||||
Self::with_id_and_type(id, GType::uint(bitwidth))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn field_array<I: Into<Identifier<'ast>>>(id: I, size: usize) -> Variable<'ast> {
|
||||
Self::array(id, Type::FieldElement, size)
|
||||
pub fn field_array<I: Into<Identifier<'ast>>>(id: I, size: S) -> Self {
|
||||
Self::array(id, GType::FieldElement, size)
|
||||
}
|
||||
|
||||
pub fn array<I: Into<Identifier<'ast>>>(id: I, ty: Type, size: usize) -> Variable<'ast> {
|
||||
Self::with_id_and_type(id, Type::array(ty, size))
|
||||
pub fn array<I: Into<Identifier<'ast>>>(id: I, ty: GType<S>, size: S) -> Self {
|
||||
Self::with_id_and_type(id, GType::array(ty, size))
|
||||
}
|
||||
|
||||
pub fn struc<I: Into<Identifier<'ast>>>(id: I, ty: StructType) -> Variable<'ast> {
|
||||
Self::with_id_and_type(id, Type::Struct(ty))
|
||||
pub fn struc<I: Into<Identifier<'ast>>>(id: I, ty: GStructType<S>) -> Self {
|
||||
Self::with_id_and_type(id, GType::Struct(ty))
|
||||
}
|
||||
|
||||
pub fn with_id_and_type<I: Into<Identifier<'ast>>>(id: I, _type: Type) -> Variable<'ast> {
|
||||
Variable {
|
||||
pub fn with_id_and_type<I: Into<Identifier<'ast>>>(id: I, _type: GType<S>) -> Self {
|
||||
GVariable {
|
||||
id: id.into(),
|
||||
_type,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_type(&self) -> Type {
|
||||
pub fn get_type(&self) -> GType<S> {
|
||||
self._type.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for Variable<'ast> {
|
||||
impl<'ast, S> fmt::Display for GVariable<'ast, S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} {}", self._type, self.id,)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Debug for Variable<'ast> {
|
||||
impl<'ast, S> fmt::Debug for GVariable<'ast, S> {
|
||||
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<'ast> {
|
||||
// fn from(v: absy::Variable) -> Variable {
|
||||
// Variable::with_id_and_type(
|
||||
// Identifier {
|
||||
// id: v.id,
|
||||
// version: 0,
|
||||
// stack: vec![],
|
||||
// },
|
||||
// v._type,
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
use typed_absy;
|
||||
use zir;
|
||||
|
||||
impl<'ast> From<typed_absy::types::FunctionKey<'ast>> for zir::types::FunctionKey<'ast> {
|
||||
fn from(k: typed_absy::types::FunctionKey<'ast>) -> zir::types::FunctionKey<'ast> {
|
||||
impl<'ast> From<typed_absy::types::ConcreteFunctionKey<'ast>> for zir::types::FunctionKey<'ast> {
|
||||
fn from(k: typed_absy::types::ConcreteFunctionKey<'ast>) -> zir::types::FunctionKey<'ast> {
|
||||
zir::types::FunctionKey {
|
||||
id: k.id,
|
||||
signature: k.signature.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<typed_absy::types::Signature> for zir::types::Signature {
|
||||
fn from(s: typed_absy::types::Signature) -> zir::types::Signature {
|
||||
impl From<typed_absy::types::ConcreteSignature> for zir::types::Signature {
|
||||
fn from(s: typed_absy::types::ConcreteSignature) -> zir::types::Signature {
|
||||
zir::types::Signature {
|
||||
inputs: s.inputs.into_iter().flat_map(|t| from_type(t)).collect(),
|
||||
outputs: s.outputs.into_iter().flat_map(|t| from_type(t)).collect(),
|
||||
|
@ -18,16 +18,18 @@ impl From<typed_absy::types::Signature> for zir::types::Signature {
|
|||
}
|
||||
}
|
||||
|
||||
fn from_type(t: typed_absy::types::Type) -> Vec<zir::types::Type> {
|
||||
fn from_type(t: typed_absy::types::ConcreteType) -> Vec<zir::types::Type> {
|
||||
match t {
|
||||
typed_absy::Type::FieldElement => vec![zir::Type::FieldElement],
|
||||
typed_absy::Type::Boolean => vec![zir::Type::Boolean],
|
||||
typed_absy::Type::Uint(bitwidth) => vec![zir::Type::uint(bitwidth.to_usize())],
|
||||
typed_absy::Type::Array(array_type) => {
|
||||
typed_absy::types::ConcreteType::FieldElement => vec![zir::Type::FieldElement],
|
||||
typed_absy::types::ConcreteType::Boolean => vec![zir::Type::Boolean],
|
||||
typed_absy::types::ConcreteType::Uint(bitwidth) => {
|
||||
vec![zir::Type::uint(bitwidth.to_usize())]
|
||||
}
|
||||
typed_absy::types::ConcreteType::Array(array_type) => {
|
||||
let inner = from_type(*array_type.ty);
|
||||
(0..array_type.size).flat_map(|_| inner.clone()).collect()
|
||||
}
|
||||
typed_absy::Type::Struct(members) => members
|
||||
typed_absy::types::ConcreteType::Struct(members) => members
|
||||
.into_iter()
|
||||
.flat_map(|struct_member| from_type(*struct_member.ty))
|
||||
.collect(),
|
||||
|
|
|
@ -14,7 +14,7 @@ pub use zir::uint::{ShouldReduce, UExpression, UExpressionInner, UMetadata};
|
|||
|
||||
use embed::FlatEmbed;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::fmt;
|
||||
use zir::types::{FunctionKey, Signature};
|
||||
use zokrates_field::Field;
|
||||
|
@ -90,7 +90,7 @@ impl<'ast, T> ZirFunctionSymbol<'ast, T> {
|
|||
.unwrap()
|
||||
.signature(&modules)
|
||||
.clone(),
|
||||
ZirFunctionSymbol::Flat(flat_fun) => flat_fun.signature().into(),
|
||||
ZirFunctionSymbol::Flat(flat_fun) => flat_fun.signature().try_into().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ pub trait Field:
|
|||
+ Ord
|
||||
+ Display
|
||||
+ Debug
|
||||
+ Default
|
||||
+ Hash
|
||||
+ Add<Self, Output = Self>
|
||||
+ for<'a> Add<&'a Self, Output = Self>
|
||||
+ Sub<Self, Output = Self>
|
||||
|
|
Loading…
Reference in a new issue