add tests, add book entry, fix inference
This commit is contained in:
parent
e5184a236b
commit
1cd049ac93
16 changed files with 179 additions and 37 deletions
|
@ -79,12 +79,18 @@ impl<T: Field> fmt::Display for Value<T> {
|
|||
),
|
||||
Value::Tuple(elements) => {
|
||||
write!(f, "(")?;
|
||||
for (i, e) in elements.iter().enumerate() {
|
||||
write!(f, "{},", e)?;
|
||||
if i < elements.len() - 1 {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
}
|
||||
match elements.len() {
|
||||
1 => write!(f, "{},", elements[0]),
|
||||
_ => write!(
|
||||
f,
|
||||
"{}",
|
||||
elements
|
||||
.iter()
|
||||
.map(|e| e.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
}?;
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,9 +107,18 @@ field[3] a = [1, 2, 3]
|
|||
field[2] b = a[1..3] // initialize an array copying a slice from `a`
|
||||
```
|
||||
|
||||
### Tuples
|
||||
A tuple is a composite datatype representing a numbered collection of values.
|
||||
The following code shows an example of how to use tuples.
|
||||
|
||||
```zokrates
|
||||
{{#include ../../../zokrates_cli/examples/book/tuples.zok}}
|
||||
```
|
||||
|
||||
In tuple types and values, the trailing comma is optional, unless the tuple contains a single element, in which case it is mandatory.
|
||||
|
||||
### Structs
|
||||
A struct is a composite datatype representing a named collection of variables. Structs can be generic over constants, in order to wrap arrays of generic size. For more details on generic array sizes, see [constant generics](../language/generics.md)
|
||||
The contained variables can be of any type.
|
||||
A struct is a composite datatype representing a named collection of values. Structs can be generic over constants, in order to wrap arrays of generic size. For more details on generic array sizes, see [constant generics](../language/generics.md). The contained variables can be of any type.
|
||||
|
||||
The following code shows an example of how to use structs.
|
||||
|
||||
|
|
4
zokrates_cli/examples/book/tuples.zok
Normal file
4
zokrates_cli/examples/book/tuples.zok
Normal file
|
@ -0,0 +1,4 @@
|
|||
def main() -> bool:
|
||||
(field[2], bool) v = ([1, 2], true)
|
||||
v.0 = [42, 43]
|
||||
return v.1
|
|
@ -643,12 +643,18 @@ impl<'ast> fmt::Display for Expression<'ast> {
|
|||
}
|
||||
Expression::InlineTuple(ref exprs) => {
|
||||
write!(f, "(")?;
|
||||
for (i, e) in exprs.iter().enumerate() {
|
||||
write!(f, "{},", e)?;
|
||||
if i < exprs.len() - 1 {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
}
|
||||
match exprs.len() {
|
||||
1 => write!(f, "{},", exprs[0]),
|
||||
_ => write!(
|
||||
f,
|
||||
"{}",
|
||||
exprs
|
||||
.iter()
|
||||
.map(|e| e.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
}?;
|
||||
write!(f, ")")
|
||||
}
|
||||
Expression::ArrayInitializer(ref e, ref count) => write!(f, "[{}; {}]", e, count),
|
||||
|
|
|
@ -25,12 +25,18 @@ impl<'ast> fmt::Display for UnresolvedType<'ast> {
|
|||
UnresolvedType::Array(ref ty, ref size) => write!(f, "{}[{}]", ty, size),
|
||||
UnresolvedType::Tuple(ref elements) => {
|
||||
write!(f, "(")?;
|
||||
for (i, e) in elements.iter().enumerate() {
|
||||
write!(f, "{},", e)?;
|
||||
if i < elements.len() {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
}
|
||||
match elements.len() {
|
||||
1 => write!(f, "{},", elements[0]),
|
||||
_ => write!(
|
||||
f,
|
||||
"{}",
|
||||
elements
|
||||
.iter()
|
||||
.map(|e| e.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
}?;
|
||||
write!(f, ")")
|
||||
}
|
||||
UnresolvedType::User(ref id, ref generics) => {
|
||||
|
|
|
@ -2817,6 +2817,9 @@ impl<'ast, T: Field> Checker<'ast, T> {
|
|||
(TypedExpression::Struct(e1), TypedExpression::Struct(e2)) => {
|
||||
Ok(BooleanExpression::StructEq(box e1, box e2).into())
|
||||
}
|
||||
(TypedExpression::Tuple(e1), TypedExpression::Tuple(e2)) => {
|
||||
Ok(BooleanExpression::TupleEq(box e1, box e2).into())
|
||||
}
|
||||
(TypedExpression::Uint(e1), TypedExpression::Uint(e2))
|
||||
if e1.get_type() == e2.get_type() =>
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::typed_absy::types::{
|
||||
ArrayType, DeclarationArrayType, DeclarationConstant, DeclarationStructMember,
|
||||
DeclarationStructType, DeclarationType, GArrayType, GStructType, GTupleType, GType,
|
||||
GenericIdentifier, StructType, TupleType, Type,
|
||||
DeclarationStructType, DeclarationTupleType, DeclarationType, GArrayType, GStructType,
|
||||
GTupleType, GType, GenericIdentifier, StructType, TupleType, Type,
|
||||
};
|
||||
use crate::typed_absy::UBitwidth;
|
||||
use crate::typed_absy::{
|
||||
|
@ -40,7 +40,7 @@ trait IntegerInference: Sized {
|
|||
fn get_common_pattern(self, other: Self) -> Result<Self::Pattern, (Self, Self)>;
|
||||
}
|
||||
|
||||
impl<'ast, T> IntegerInference for Type<'ast, T> {
|
||||
impl<'ast, T: Clone> IntegerInference for Type<'ast, T> {
|
||||
type Pattern = DeclarationType<'ast, T>;
|
||||
|
||||
fn get_common_pattern(self, other: Self) -> Result<Self::Pattern, (Self, Self)> {
|
||||
|
@ -67,12 +67,16 @@ impl<'ast, T> IntegerInference for Type<'ast, T> {
|
|||
t.get_common_pattern(u)
|
||||
.map_err(|(t, u)| (Type::Struct(t), Type::Struct(u)))?,
|
||||
)),
|
||||
(Type::Tuple(t), Type::Tuple(u)) => Ok(DeclarationType::Tuple(
|
||||
t.get_common_pattern(u)
|
||||
.map_err(|(t, u)| (Type::Tuple(t), Type::Tuple(u)))?,
|
||||
)),
|
||||
(t, u) => Err((t, u)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> IntegerInference for ArrayType<'ast, T> {
|
||||
impl<'ast, T: Clone> IntegerInference for ArrayType<'ast, T> {
|
||||
type Pattern = DeclarationArrayType<'ast, T>;
|
||||
|
||||
fn get_common_pattern(self, other: Self) -> Result<Self::Pattern, (Self, Self)> {
|
||||
|
@ -88,7 +92,7 @@ impl<'ast, T> IntegerInference for ArrayType<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast, T> IntegerInference for StructType<'ast, T> {
|
||||
impl<'ast, T: Clone> IntegerInference for StructType<'ast, T> {
|
||||
type Pattern = DeclarationStructType<'ast, T>;
|
||||
|
||||
fn get_common_pattern(self, other: Self) -> Result<Self::Pattern, (Self, Self)> {
|
||||
|
@ -120,6 +124,22 @@ impl<'ast, T> IntegerInference for StructType<'ast, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Clone> IntegerInference for TupleType<'ast, T> {
|
||||
type Pattern = DeclarationTupleType<'ast, T>;
|
||||
|
||||
fn get_common_pattern(self, other: Self) -> Result<Self::Pattern, (Self, Self)> {
|
||||
Ok(DeclarationTupleType {
|
||||
elements: self
|
||||
.elements
|
||||
.iter()
|
||||
.zip(other.elements.iter())
|
||||
.map(|(t, u)| t.clone().get_common_pattern(u.clone()))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.map_err(|_| (self, other))?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast, T: Field> TypedExpression<'ast, T> {
|
||||
// return two TypedExpression, replacing IntExpression by FieldElement or Uint to try to align the two types if possible.
|
||||
// Post condition is that (lhs, rhs) cannot be made equal by further removing IntExpressions
|
||||
|
|
|
@ -1454,12 +1454,18 @@ impl<'ast, T: fmt::Display> fmt::Display for TupleExpression<'ast, T> {
|
|||
TupleExpressionInner::Identifier(ref var) => write!(f, "{}", var),
|
||||
TupleExpressionInner::Value(ref values) => {
|
||||
write!(f, "(")?;
|
||||
for (i, v) in values.iter().enumerate() {
|
||||
write!(f, "{},", v)?;
|
||||
if i < values.len() - 1 {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
}
|
||||
match values.len() {
|
||||
1 => write!(f, "{},", values[0]),
|
||||
_ => write!(
|
||||
f,
|
||||
"{}",
|
||||
values
|
||||
.iter()
|
||||
.map(|v| v.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
}?;
|
||||
write!(f, ")")
|
||||
}
|
||||
TupleExpressionInner::FunctionCall(ref function_call) => {
|
||||
|
|
|
@ -189,6 +189,7 @@ pub trait ResultFolder<'ast, T: Field>: Sized {
|
|||
match t {
|
||||
Array(array_type) => Ok(Array(self.fold_array_type(array_type)?)),
|
||||
Struct(struct_type) => Ok(Struct(self.fold_struct_type(struct_type)?)),
|
||||
Tuple(tuple_type) => Ok(Tuple(self.fold_tuple_type(tuple_type)?)),
|
||||
t => Ok(t),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -425,12 +425,18 @@ impl<'ast, S, R: PartialEq<S>> PartialEq<GTupleType<S>> for GTupleType<R> {
|
|||
impl<S: fmt::Display> fmt::Display for GTupleType<S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "(")?;
|
||||
for (i, e) in self.elements.iter().enumerate() {
|
||||
write!(f, "{},", e)?;
|
||||
if i < self.elements.len() - 1 {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
}
|
||||
match self.elements.len() {
|
||||
1 => write!(f, "{},", self.elements[0]),
|
||||
_ => write!(
|
||||
f,
|
||||
"{}",
|
||||
self.elements
|
||||
.iter()
|
||||
.map(|v| v.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
),
|
||||
}?;
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
|
|
5
zokrates_core_test/tests/tests/tuples/constant.json
Normal file
5
zokrates_core_test/tests/tests/tuples/constant.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/structs/constant.zok",
|
||||
"curves": ["Bn128"],
|
||||
"tests": []
|
||||
}
|
4
zokrates_core_test/tests/tests/tuples/constant.zok
Normal file
4
zokrates_core_test/tests/tests/tuples/constant.zok
Normal file
|
@ -0,0 +1,4 @@
|
|||
def main():
|
||||
State s = ([0; 16],)
|
||||
s.0[0] = 0x00000001
|
||||
return
|
40
zokrates_core_test/tests/tests/tuples/identity.json
Normal file
40
zokrates_core_test/tests/tests/tuples/identity.json
Normal file
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/structs/identity.zok",
|
||||
"curves": ["Bn128", "Bls12_381", "Bls12_377", "Bw6_761"],
|
||||
"tests": [
|
||||
{
|
||||
"input": {
|
||||
"values": ["42", "0"]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["42", "0"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"values": ["42", "1"]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": ["42", "1"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"input": {
|
||||
"values": ["42", "3"]
|
||||
},
|
||||
"output": {
|
||||
"Err": {
|
||||
"UnsatisfiedConstraint": {
|
||||
"left": "9",
|
||||
"right": "3",
|
||||
"error": "ArgumentBitness"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
2
zokrates_core_test/tests/tests/tuples/identity.zok
Normal file
2
zokrates_core_test/tests/tests/tuples/identity.zok
Normal file
|
@ -0,0 +1,2 @@
|
|||
def main((field, bool,) a) -> ((field, bool,)):
|
||||
return a
|
20
zokrates_core_test/tests/tests/tuples/member_order.json
Normal file
20
zokrates_core_test/tests/tests/tuples/member_order.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"entry_point": "./tests/tests/structs/member_order.zok",
|
||||
"curves": ["Bn128"],
|
||||
"tests": [
|
||||
{
|
||||
"abi": true,
|
||||
"input": {
|
||||
"values": [{
|
||||
"a":true,
|
||||
"b": "3"
|
||||
}]
|
||||
},
|
||||
"output": {
|
||||
"Ok": {
|
||||
"values": []
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
4
zokrates_core_test/tests/tests/tuples/member_order.zok
Normal file
4
zokrates_core_test/tests/tests/tuples/member_order.zok
Normal file
|
@ -0,0 +1,4 @@
|
|||
// this tests the abi, checking that the fields of a (field, bool) instance get encoded in the right order
|
||||
// if the the encoder reverses `0` and `1`, the boolean check ends up being done on the field value, which would fail
|
||||
def main((field, bool) f):
|
||||
return
|
Loading…
Reference in a new issue