fix examples
This commit is contained in:
parent
60c63c1aef
commit
fec876a32a
14 changed files with 142 additions and 80 deletions
|
@ -1,5 +1,5 @@
|
||||||
def sub(field a) -> (field):
|
def sub(field a) -> (field):
|
||||||
field a = a + 3
|
a = a + 3
|
||||||
return a
|
return a
|
||||||
|
|
||||||
def main() -> (field):
|
def main() -> (field):
|
||||||
|
|
7
zokrates_cli/examples/error/duplicate_declaration.code
Normal file
7
zokrates_cli/examples/error/duplicate_declaration.code
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
def foo() -> (field):
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def main() -> (field):
|
||||||
|
bool a
|
||||||
|
field a = foo()
|
||||||
|
return 1
|
|
@ -4,7 +4,7 @@ def add(field a,field b) -> (field):
|
||||||
|
|
||||||
// Expected for inputs 1,1: c=4, d=7, e=10
|
// Expected for inputs 1,1: c=4, d=7, e=10
|
||||||
def main(field a,field b) -> (field):
|
def main(field a,field b) -> (field):
|
||||||
field c = add(a*2+3*b-a,b-1)
|
c = add(a*2+3*b-a,b-1)
|
||||||
field d = add(a*b+2, a*b*c)
|
d = add(a*b+2, a*b*c)
|
||||||
field e = add(add(a,d),add(a,b))
|
e = add(add(a,d),add(a,b))
|
||||||
return e
|
return e
|
||||||
|
|
|
@ -2,5 +2,5 @@ def add(field f,field g) -> (field):
|
||||||
return f+g
|
return f+g
|
||||||
|
|
||||||
def main(field a, field b) -> (field):
|
def main(field a, field b) -> (field):
|
||||||
field c = add(a,b)
|
c = add(a,b)
|
||||||
return c
|
return c
|
||||||
|
|
|
@ -4,10 +4,10 @@ def add(field a, field b) -> (field):
|
||||||
|
|
||||||
def main(field a, field b,field c, field d) -> (field):
|
def main(field a, field b,field c, field d) -> (field):
|
||||||
field g = a + b
|
field g = a + b
|
||||||
field x = add(a,b)
|
x = add(a,b)
|
||||||
field y = add(c,d)
|
y = add(c,d)
|
||||||
field g = add(x, g)
|
g = add(x, g)
|
||||||
g = add(x, g)
|
g = add(x, g)
|
||||||
field f = c + d + a
|
field f = c + d + a
|
||||||
field g = add(g+a, add(x,b))
|
g = add(g+a, add(x,b))
|
||||||
return x + y + g + f
|
return x + y + g + f
|
||||||
|
|
|
@ -6,6 +6,6 @@ def sub(field a, field b) -> (field):
|
||||||
return a-b
|
return a-b
|
||||||
|
|
||||||
def main(field a, field b) -> (field):
|
def main(field a, field b) -> (field):
|
||||||
field c = add(a,b)
|
c = add(a,b)
|
||||||
field d = sub(a,b)
|
d = sub(a,b)
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -2,7 +2,7 @@ def const() -> (field):
|
||||||
return 123123
|
return 123123
|
||||||
|
|
||||||
def add(field a,field b) -> (field):
|
def add(field a,field b) -> (field):
|
||||||
field a=const()
|
a=const()
|
||||||
return a+b
|
return a+b
|
||||||
|
|
||||||
def main(field a,field b) -> (field):
|
def main(field a,field b) -> (field):
|
||||||
|
|
|
@ -3,5 +3,5 @@ def main(field x) -> (field):
|
||||||
field b = a + x
|
field b = a + x
|
||||||
a = 7
|
a = 7
|
||||||
field c = a + b
|
field c = a + b
|
||||||
field a = a + 5
|
a = a + 5
|
||||||
return a + c
|
return a + c
|
||||||
|
|
|
@ -6,5 +6,5 @@ import "./or.code" as OR
|
||||||
def main(field a, field b, field car) -> (field, field):
|
def main(field a, field b, field car) -> (field, field):
|
||||||
out1, car1 = HALFADD(a, b)
|
out1, car1 = HALFADD(a, b)
|
||||||
out2, car2 = HALFADD(out1, car)
|
out2, car2 = HALFADD(out1, car)
|
||||||
field car3 = OR(car1, car2)
|
car3 = OR(car1, car2)
|
||||||
return out2, car3
|
return out2, car3
|
|
@ -1,7 +1,7 @@
|
||||||
def wtax(debt,wealth):
|
def wtax(field debt, field wealth) -> (field):
|
||||||
x = if wealth < debt then 0 else (wealth-debt) fi
|
field x = if wealth < debt then 0 else (wealth-debt) fi
|
||||||
return x
|
return x
|
||||||
|
|
||||||
def main(debt, wealth):
|
def main(private field debt, private field wealth) -> (field):
|
||||||
tax = wtax(debt,wealth)
|
field tax = wtax(debt,wealth)
|
||||||
return tax
|
return tax
|
|
@ -550,31 +550,31 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use self::glob::glob;
|
use self::glob::glob;
|
||||||
|
|
||||||
// #[test]
|
#[test]
|
||||||
// fn examples() {
|
fn examples() {
|
||||||
// for p in glob("./examples/**/*.code").expect("Failed to read glob pattern") {
|
for p in glob("./examples/**/*.code").expect("Failed to read glob pattern") {
|
||||||
// let path = match p {
|
let path = match p {
|
||||||
// Ok(x) => x,
|
Ok(x) => x,
|
||||||
// Err(why) => panic!("Error: {:?}", why),
|
Err(why) => panic!("Error: {:?}", why),
|
||||||
// };
|
};
|
||||||
|
|
||||||
// if path.to_str().unwrap().contains("error") {
|
if path.to_str().unwrap().contains("error") {
|
||||||
// continue
|
continue
|
||||||
// }
|
}
|
||||||
|
|
||||||
// println!("Testing {:?}", path);
|
println!("Testing {:?}", path);
|
||||||
|
|
||||||
// let file = File::open(path.clone()).unwrap();
|
let file = File::open(path.clone()).unwrap();
|
||||||
|
|
||||||
// let mut reader = BufReader::new(file);
|
let mut reader = BufReader::new(file);
|
||||||
// let location = path.parent().unwrap().to_path_buf().into_os_string().into_string().unwrap();
|
let location = path.parent().unwrap().to_path_buf().into_os_string().into_string().unwrap();
|
||||||
|
|
||||||
// let program_flattened: FlatProg<FieldPrime> =
|
let program_flattened: FlatProg<FieldPrime> =
|
||||||
// compile(&mut reader, Some(location), Some(fs_resolve), true, false).unwrap();
|
compile(&mut reader, Some(location), Some(fs_resolve), true, false).unwrap();
|
||||||
|
|
||||||
// let (..) = r1cs_program(&program_flattened);
|
let (..) = r1cs_program(&program_flattened);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn examples_with_input_success() {
|
fn examples_with_input_success() {
|
||||||
|
|
|
@ -501,7 +501,7 @@ impl Flattener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic!(
|
panic!(
|
||||||
"TypedFunction definition for function {} with {:?} argument(s) not found.",
|
"TypedFunction definition for function {} with {:?} argument(s) not found. Should have been detected during semantic checking.",
|
||||||
id,
|
id,
|
||||||
param_expressions
|
param_expressions
|
||||||
);
|
);
|
||||||
|
@ -743,7 +743,15 @@ impl Flattener {
|
||||||
expr_subbed,
|
expr_subbed,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
_ => panic!("Functions can only return expressions of type FieldElement")
|
TypedExpression::Boolean(e) => {
|
||||||
|
let expr_subbed = e.apply_substitution(&self.substitution);
|
||||||
|
self.flatten_boolean_expression(
|
||||||
|
functions_flattened,
|
||||||
|
arguments_flattened,
|
||||||
|
statements_flattened,
|
||||||
|
expr_subbed,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
|
@ -764,26 +772,35 @@ impl Flattener {
|
||||||
// define n variables with n the number of primitive types for v_type
|
// define n variables with n the number of primitive types for v_type
|
||||||
// assign them to the n primitive types for expr
|
// assign them to the n primitive types for expr
|
||||||
|
|
||||||
match expr {
|
let rhs = match expr {
|
||||||
TypedExpression::FieldElement(expr) => {
|
TypedExpression::FieldElement(expr) => {
|
||||||
let expr_subbed = expr.apply_substitution(&self.substitution);
|
let expr_subbed = expr.apply_substitution(&self.substitution);
|
||||||
let rhs = self.flatten_field_expression(
|
self.flatten_field_expression(
|
||||||
functions_flattened,
|
functions_flattened,
|
||||||
arguments_flattened,
|
arguments_flattened,
|
||||||
statements_flattened,
|
statements_flattened,
|
||||||
expr_subbed,
|
expr_subbed,
|
||||||
);
|
)
|
||||||
let var = self.use_variable(&v.id);
|
|
||||||
// handle return of function call
|
|
||||||
let var_to_replace = self.get_latest_var_substitution(&v.id);
|
|
||||||
if !(var == var_to_replace) && self.variables.contains(&var_to_replace) && !self.substitution.contains_key(&var_to_replace){
|
|
||||||
self.substitution.insert(var_to_replace.clone().to_string(),var.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
statements_flattened.push(FlatStatement::Definition(var, rhs));
|
|
||||||
},
|
},
|
||||||
_ => panic!("Definitions must have type FieldElement")
|
TypedExpression::Boolean(expr) => {
|
||||||
|
let expr_subbed = expr.apply_substitution(&self.substitution);
|
||||||
|
self.flatten_boolean_expression(
|
||||||
|
functions_flattened,
|
||||||
|
arguments_flattened,
|
||||||
|
statements_flattened,
|
||||||
|
expr_subbed,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let var = self.use_variable(&v.id);
|
||||||
|
// handle return of function call
|
||||||
|
let var_to_replace = self.get_latest_var_substitution(&v.id);
|
||||||
|
if !(var == var_to_replace) && self.variables.contains(&var_to_replace) && !self.substitution.contains_key(&var_to_replace){
|
||||||
|
self.substitution.insert(var_to_replace.clone().to_string(),var.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statements_flattened.push(FlatStatement::Definition(var, rhs));
|
||||||
}
|
}
|
||||||
TypedStatement::Condition(expr1, expr2) => {
|
TypedStatement::Condition(expr1, expr2) => {
|
||||||
|
|
||||||
|
@ -831,7 +848,47 @@ impl Flattener {
|
||||||
};
|
};
|
||||||
statements_flattened.push(FlatStatement::Condition(lhs, rhs));
|
statements_flattened.push(FlatStatement::Condition(lhs, rhs));
|
||||||
},
|
},
|
||||||
_ => panic!("Conditions (Assertions) must be applied to expressions of type FieldElement")
|
(TypedExpression::Boolean(e1), TypedExpression::Boolean(e2)) => {
|
||||||
|
|
||||||
|
let e1_subbed = e1.apply_substitution(&self.substitution);
|
||||||
|
let e2_subbed = e2.apply_substitution(&self.substitution);
|
||||||
|
|
||||||
|
let (lhs, rhs) = if e1_subbed.is_linear() {
|
||||||
|
(
|
||||||
|
self.flatten_boolean_expression(
|
||||||
|
functions_flattened,
|
||||||
|
arguments_flattened,
|
||||||
|
statements_flattened,
|
||||||
|
e1_subbed
|
||||||
|
),
|
||||||
|
self.flatten_boolean_expression(
|
||||||
|
functions_flattened,
|
||||||
|
arguments_flattened,
|
||||||
|
statements_flattened,
|
||||||
|
e2_subbed,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else if e2_subbed.is_linear() {
|
||||||
|
(
|
||||||
|
self.flatten_boolean_expression(
|
||||||
|
functions_flattened,
|
||||||
|
arguments_flattened,
|
||||||
|
statements_flattened,
|
||||||
|
e2_subbed,
|
||||||
|
),
|
||||||
|
self.flatten_boolean_expression(
|
||||||
|
functions_flattened,
|
||||||
|
arguments_flattened,
|
||||||
|
statements_flattened,
|
||||||
|
e1_subbed,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
unimplemented!()
|
||||||
|
};
|
||||||
|
statements_flattened.push(FlatStatement::Condition(lhs, rhs));
|
||||||
|
},
|
||||||
|
_ => panic!("non matching types in condition should have been caught at semantic stage")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypedStatement::For(var, start, end, statements) => {
|
TypedStatement::For(var, start, end, statements) => {
|
||||||
|
@ -862,7 +919,7 @@ impl Flattener {
|
||||||
let rhs_subbed = rhs.apply_substitution(&self.substitution);
|
let rhs_subbed = rhs.apply_substitution(&self.substitution);
|
||||||
|
|
||||||
match rhs_subbed {
|
match rhs_subbed {
|
||||||
TypedExpressionList::FunctionCall(fun_id, exprs, types) => {
|
TypedExpressionList::FunctionCall(fun_id, exprs, _) => {
|
||||||
let rhs_flattened = self.flatten_function_call(
|
let rhs_flattened = self.flatten_function_call(
|
||||||
functions_flattened,
|
functions_flattened,
|
||||||
arguments_flattened,
|
arguments_flattened,
|
||||||
|
@ -872,21 +929,15 @@ impl Flattener {
|
||||||
&exprs,
|
&exprs,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// this will change for types that have multiple underlying fe
|
||||||
for (i, v) in vars.into_iter().enumerate() {
|
for (i, v) in vars.into_iter().enumerate() {
|
||||||
let var_type = &types[i];
|
let var = self.use_variable(&v.id);
|
||||||
|
// handle return of function call
|
||||||
match var_type {
|
let var_to_replace = self.get_latest_var_substitution(&v.id);
|
||||||
Type::FieldElement => {
|
if !(var == var_to_replace) && self.variables.contains(&var_to_replace) && !self.substitution.contains_key(&var_to_replace){
|
||||||
let var = self.use_variable(&v.id);
|
self.substitution.insert(var_to_replace.clone().to_string(),var.clone());
|
||||||
// handle return of function call
|
|
||||||
let var_to_replace = self.get_latest_var_substitution(&v.id);
|
|
||||||
if !(var == var_to_replace) && self.variables.contains(&var_to_replace) && !self.substitution.contains_key(&var_to_replace){
|
|
||||||
self.substitution.insert(var_to_replace.clone().to_string(),var.clone());
|
|
||||||
}
|
|
||||||
statements_flattened.push(FlatStatement::Definition(var, rhs_flattened.expressions[i].clone()));
|
|
||||||
},
|
|
||||||
_ => panic!("MultipleDefinition has to define expressions of type FieldElement")
|
|
||||||
}
|
}
|
||||||
|
statements_flattened.push(FlatStatement::Definition(var, rhs_flattened.expressions[i].clone()));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,7 +184,7 @@ impl Checker {
|
||||||
0 => {
|
0 => {
|
||||||
|
|
||||||
},
|
},
|
||||||
_ => panic!("dupllicate function declaration should have been caught")
|
_ => panic!("duplicate function declaration should have been caught")
|
||||||
}
|
}
|
||||||
|
|
||||||
self.enter_scope();
|
self.enter_scope();
|
||||||
|
@ -413,7 +413,20 @@ impl Checker {
|
||||||
(TypedExpression::Boolean(condition), TypedExpression::FieldElement(consequence), TypedExpression::FieldElement(alternative)) => {
|
(TypedExpression::Boolean(condition), TypedExpression::FieldElement(consequence), TypedExpression::FieldElement(alternative)) => {
|
||||||
Ok(FieldElementExpression::IfElse(box condition, box consequence, box alternative).into())
|
Ok(FieldElementExpression::IfElse(box condition, box consequence, box alternative).into())
|
||||||
},
|
},
|
||||||
_ => panic!("id else only for bool fe fe")
|
(condition, consequence, alternative) =>
|
||||||
|
Err(
|
||||||
|
Error {
|
||||||
|
message:
|
||||||
|
format!("if {{condition}} then {{consequence}} else {{alternative}} should have types {}, {}, {}, found {}, {}, {}",
|
||||||
|
Type::Boolean,
|
||||||
|
Type::FieldElement,
|
||||||
|
Type::FieldElement,
|
||||||
|
condition.get_type(),
|
||||||
|
consequence.get_type(),
|
||||||
|
alternative.get_type(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&Expression::Number(ref n) => Ok(FieldElementExpression::Number(n.clone()).into()),
|
&Expression::Number(ref n) => Ok(FieldElementExpression::Number(n.clone()).into()),
|
||||||
|
@ -443,9 +456,9 @@ impl Checker {
|
||||||
let f = &candidates[0];
|
let f = &candidates[0];
|
||||||
// the return count has to be 1
|
// the return count has to be 1
|
||||||
if f.signature.outputs.len() == 1 {
|
if f.signature.outputs.len() == 1 {
|
||||||
match f.signature.outputs[0] {
|
return match f.signature.outputs[0] {
|
||||||
Type::FieldElement => return Ok(FieldElementExpression::FunctionCall(f.id.clone(), arguments_checked).into()),
|
Type::FieldElement => Ok(FieldElementExpression::FunctionCall(f.id.clone(), arguments_checked).into()),
|
||||||
_ => panic!("cannot return booleans")
|
ref t => Err( Error { message: format!("Outside of assignments, functions must return a single element of type {}, found type {}", Type::FieldElement, t)})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(Error { message: format!("{} returns {} values but is called outside of a definition", f.id, f.signature.outputs.len()) })
|
Err(Error { message: format!("{} returns {} values but is called outside of a definition", f.id, f.signature.outputs.len()) })
|
||||||
|
|
|
@ -258,15 +258,6 @@ impl<T: Field> Typed for TypedExpression<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Field> TypedExpression<T> {
|
|
||||||
pub fn is_linear(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
TypedExpression::Boolean(e) => e.is_linear(),
|
|
||||||
TypedExpression::FieldElement(e) => e.is_linear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait MultiTyped
|
pub trait MultiTyped
|
||||||
{
|
{
|
||||||
fn get_types(&self) -> &Vec<Type>;
|
fn get_types(&self) -> &Vec<Type>;
|
||||||
|
|
Loading…
Reference in a new issue