impl conditional if then else fi

This commit is contained in:
collin 2020-04-09 19:22:11 -07:00
parent 62fa83195e
commit d9b0fa993f
10 changed files with 160 additions and 90 deletions

View File

@ -1,2 +1 @@
x = 5 + a
return x ** 2 * 2
return if a then 1 else 0 fi

View File

@ -178,6 +178,7 @@ impl ResolvedProgram {
) -> Boolean {
match expression {
BooleanExpression::Variable(variable) => self.bool_from_variable(cs, variable),
BooleanExpression::Value(value) => Boolean::Constant(value),
BooleanExpression::Not(expression) => self.enforce_not(cs, *expression),
BooleanExpression::Or(left, right) => self.enforce_or(cs, *left, *right),
BooleanExpression::And(left, right) => self.enforce_and(cs, *left, *right),
@ -185,6 +186,16 @@ impl ResolvedProgram {
BooleanExpression::FieldEq(left, right) => {
self.enforce_field_equality(cs, *left, *right)
}
BooleanExpression::IfElse(first, second, third) => {
if self
.enforce_boolean_expression(cs, *first)
.eq(&Boolean::Constant(true))
{
self.enforce_boolean_expression(cs, *second)
} else {
self.enforce_boolean_expression(cs, *third)
}
}
_ => unimplemented!(),
}
}
@ -285,12 +296,22 @@ impl ResolvedProgram {
) -> UInt32 {
match expression {
FieldExpression::Variable(variable) => self.u32_from_variable(cs, variable),
FieldExpression::Number(number) => UInt32::constant(number),
FieldExpression::Add(left, right) => self.enforce_add(cs, *left, *right),
FieldExpression::Sub(left, right) => self.enforce_sub(cs, *left, *right),
FieldExpression::Mul(left, right) => self.enforce_mul(cs, *left, *right),
FieldExpression::Div(left, right) => self.enforce_div(cs, *left, *right),
FieldExpression::Pow(left, right) => self.enforce_pow(cs, *left, *right),
_ => unimplemented!(),
FieldExpression::IfElse(first, second, third) => {
if self
.enforce_boolean_expression(cs, *first)
.eq(&Boolean::Constant(true))
{
self.enforce_field_expression(cs, *second)
} else {
self.enforce_field_expression(cs, *third)
}
}
}
}
@ -309,7 +330,7 @@ impl ResolvedProgram {
let res =
resolved_program.enforce_boolean_expression(cs, boolean_expression);
println!(
"variable boolean result: {} = {}",
" variable boolean result: {} = {}",
variable.0,
res.get_value().unwrap()
);
@ -376,12 +397,12 @@ impl ResolvedProgram {
Expression::Boolean(boolean_expression) => {
let res = resolved_program
.enforce_boolean_expression(cs, boolean_expression);
println!("boolean result: {}\n", res.get_value().unwrap());
println!("\n Boolean result = {}", res.get_value().unwrap());
}
Expression::FieldElement(field_expression) => {
let res =
resolved_program.enforce_field_expression(cs, field_expression);
println!("field result: {}\n", res.value.unwrap());
println!("\n Field result = {}", res.value.unwrap());
}
Expression::Variable(variable) => {
match resolved_program
@ -391,11 +412,11 @@ impl ResolvedProgram {
.clone()
{
ResolvedValue::Boolean(boolean) => println!(
"variable result: {}\n",
"\n Variable result = {}",
boolean.get_value().unwrap()
),
ResolvedValue::FieldElement(field_element) => println!(
"variable field result: {}\n",
"\n Variable field result = {}",
field_element.value.unwrap()
),
}

View File

@ -1,61 +0,0 @@
// use snarkos_errors::gadgets::SynthesisError;
// use snarkos_models::{
// curves::Field,
// gadgets::{
// r1cs::ConstraintSystem,
// utilities::uint32::UInt32
// }
// };
// use snarkos_models::gadgets::utilities::boolean::Boolean;
//
// impl UInt32 {
// pub fn and<F: Field, CS: ConstraintSystem<F>>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError> {
// let value= match (self.value, other.valoue) {
// (Some(a), Some(b)) => Some(a & b),
// _=> None,
// };
//
// let bits = self
// .bits
// .iter()
// .zip(other.bits.iter())
// .enumerate()
// .map(|(i, (a, b)) | Boolean::and(cs.ns(|| format!("and of bit gadget {}", i)), a, b))
// .collect();
//
// Ok(UInt32 { bits, value })
// }
//
// fn recursive_add<F: Field, CS: ConstraintSystem<F>>(mut cs: CS, a: &Self, b: &Self) -> Result<Self, SynthesisError> {
// let uncommon_bits = a.xor(cs.ns(|| format!("{} ^ {}", a.value.unwrap(), b.value.unwrap())),&b)?;
// let common_bits = a.and(cs.ns(|| format!("{} & {}", a.value.unwrap(), b.value.unwrap())), &b)?;
//
// if common_bits.value == 0 {
// return Ok(uncommon_bits)
// }
// let shifted_common_bits = common_bits.rotr(common_bits.bits.len() - 1);
// return Self::recursive_add(cs.ns(|| format!("recursive add {} + {}", uncommon_bits.value, shifted_common_bits.value)), &uncommon_bits, &shifted_common_bits)
// }
//
// pub fn add<F: Field, CS: ConstraintSystem<F>>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError> {
// let new_value = match (self.value, other.value) {
// (Some(a), Some(b)) => Some(a + b),
// _ => None,
// };
//
// return Self::recursive_add(cs.ns( || format!("recursive add {} + {}", self.value, other.value)), &self, &other)
//
// // let bits = self
// // .bits
// // .iter()
// // .zip(other.bits.iter())
// // .enumerate()
// // .map(|(i, (a, b))| Boo)
// }
//
// pub fn sub<F: Field, CS: ConstraintSystem<F>>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError> {}
//
// pub fn mul<F: Field, CS: ConstraintSystem<F>>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError> {}
//
// pub fn div<F: Field, CS: ConstraintSystem<F>>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError> {}
// }

View File

@ -10,9 +10,6 @@ pub use self::types::*;
pub mod constraints;
pub use self::constraints::*;
pub mod gadgets;
pub use self::gadgets::*;
pub mod types_display;
pub use self::types_display::*;

View File

@ -33,11 +33,13 @@ pub struct Variable(pub String);
pub enum FieldExpression {
Variable(Variable),
Number(u32),
// Operators
Add(Box<FieldExpression>, Box<FieldExpression>),
Sub(Box<FieldExpression>, Box<FieldExpression>),
Mul(Box<FieldExpression>, Box<FieldExpression>),
Div(Box<FieldExpression>, Box<FieldExpression>),
Pow(Box<FieldExpression>, Box<FieldExpression>),
// Conditionals
IfElse(
Box<BooleanExpression>,
Box<FieldExpression>,
@ -61,6 +63,12 @@ pub enum BooleanExpression {
Gt(Box<FieldExpression>, Box<FieldExpression>),
Leq(Box<FieldExpression>, Box<FieldExpression>),
Lt(Box<FieldExpression>, Box<FieldExpression>),
// Conditionals
IfElse(
Box<BooleanExpression>,
Box<BooleanExpression>,
Box<BooleanExpression>,
),
}
/// Expression that evaluates to a value

View File

@ -24,7 +24,9 @@ impl<'ast> fmt::Display for FieldExpression {
FieldExpression::Mul(ref lhs, ref rhs) => write!(f, "{} * {}", lhs, rhs),
FieldExpression::Div(ref lhs, ref rhs) => write!(f, "{} / {}", lhs, rhs),
FieldExpression::Pow(ref lhs, ref rhs) => write!(f, "{} ** {}", lhs, rhs),
FieldExpression::IfElse(ref _a, ref _b, ref _c) => unimplemented!(),
FieldExpression::IfElse(ref a, ref b, ref c) => {
write!(f, "if {} then {} else {} fi", a, b, c)
}
}
}
}
@ -44,6 +46,9 @@ impl<'ast> fmt::Display for BooleanExpression {
BooleanExpression::Gt(ref lhs, ref rhs) => write!(f, "{} > {}", lhs, rhs),
BooleanExpression::Leq(ref lhs, ref rhs) => write!(f, "{} <= {}", lhs, rhs),
BooleanExpression::Lt(ref lhs, ref rhs) => write!(f, "{} < {}", lhs, rhs),
BooleanExpression::IfElse(ref a, ref b, ref c) => {
write!(f, "if {} then {} else {} fi", a, b, c)
}
}
}
}

View File

@ -5,7 +5,6 @@
//! @author Collin Chin <collin@aleo.org>
//! @date 2020
use crate::aleo_program::{BooleanExpression, Statement};
use crate::{aleo_program::types, ast};
impl<'ast> From<ast::Field<'ast>> for types::FieldExpression {
@ -64,7 +63,7 @@ impl<'ast> From<ast::Variable<'ast>> for types::Expression {
impl<'ast> From<ast::NotExpression<'ast>> for types::Expression {
fn from(expression: ast::NotExpression<'ast>) -> Self {
types::Expression::Boolean(BooleanExpression::Not(Box::new(
types::Expression::Boolean(types::BooleanExpression::Not(Box::new(
types::BooleanExpression::from(*expression.expression),
)))
}
@ -119,7 +118,7 @@ impl<'ast> types::BooleanExpression {
Box::new(types::BooleanExpression::Variable(lhs)),
Box::new(rhs),
)
}
} //TODO: check case for two variables?
// Field equality
(types::Expression::FieldElement(lhs), types::Expression::FieldElement(rhs)) => {
types::BooleanExpression::FieldEq(Box::new(lhs), Box::new(rhs))
@ -215,6 +214,69 @@ impl<'ast> From<ast::BinaryExpression<'ast>> for types::Expression {
}
}
impl<'ast> From<ast::TernaryExpression<'ast>> for types::Expression {
fn from(expression: ast::TernaryExpression<'ast>) -> Self {
// Evaluate expressions to find out result type
let first = types::BooleanExpression::from(*expression.first);
let second = types::Expression::from(*expression.second);
let third = types::Expression::from(*expression.third);
match (second, third) {
// Boolean Result
(types::Expression::Boolean(second), types::Expression::Boolean(third)) => {
types::Expression::Boolean(types::BooleanExpression::IfElse(
Box::new(first),
Box::new(second),
Box::new(third),
))
}
(types::Expression::Boolean(second), types::Expression::Variable(third)) => {
types::Expression::Boolean(types::BooleanExpression::IfElse(
Box::new(first),
Box::new(second),
Box::new(types::BooleanExpression::Variable(third)),
))
}
(types::Expression::Variable(second), types::Expression::Boolean(third)) => {
types::Expression::Boolean(types::BooleanExpression::IfElse(
Box::new(first),
Box::new(types::BooleanExpression::Variable(second)),
Box::new(third),
))
}
// Field Result
(types::Expression::FieldElement(second), types::Expression::FieldElement(third)) => {
types::Expression::FieldElement(types::FieldExpression::IfElse(
Box::new(first),
Box::new(second),
Box::new(third),
))
}
(types::Expression::FieldElement(second), types::Expression::Variable(third)) => {
types::Expression::FieldElement(types::FieldExpression::IfElse(
Box::new(first),
Box::new(second),
Box::new(types::FieldExpression::Variable(third)),
))
}
(types::Expression::Variable(second), types::Expression::FieldElement(third)) => {
types::Expression::FieldElement(types::FieldExpression::IfElse(
Box::new(first),
Box::new(types::FieldExpression::Variable(second)),
Box::new(third),
))
}
(second, third) => unimplemented!(
"pattern if {} then {} else {} unimplemented",
first,
second,
third
),
}
}
}
impl<'ast> From<ast::Expression<'ast>> for types::Expression {
fn from(expression: ast::Expression<'ast>) -> Self {
match expression {
@ -222,6 +284,7 @@ impl<'ast> From<ast::Expression<'ast>> for types::Expression {
ast::Expression::Variable(variable) => types::Expression::from(variable),
ast::Expression::Not(expression) => types::Expression::from(expression),
ast::Expression::Binary(expression) => types::Expression::from(expression),
ast::Expression::Ternary(expression) => types::Expression::from(expression),
}
}
}
@ -259,7 +322,7 @@ impl<'ast> From<ast::Statement<'ast>> for types::Statement {
impl<'ast> From<ast::File<'ast>> for types::Program {
fn from(file: ast::File<'ast>) -> Self {
// 1. compile ast -> aleo program representation
let statements: Vec<Statement> = file
let statements: Vec<types::Statement> = file
.statements
.into_iter()
.map(|statement| types::Statement::from(statement))

View File

@ -76,6 +76,12 @@ fn parse_term(pair: Pair<Rule>) -> Box<Expression> {
let expression = parse_term(inner.next().unwrap());
Expression::Not(NotExpression { operation, expression, span })
},
Rule::expression_conditional => {
println!("conditional expression");
Expression::Ternary(
TernaryExpression::from_pest(&mut pair.into_inner()).unwrap(),
)
}
Rule::expression => Expression::from_pest(&mut pair.into_inner()).unwrap(), // Parenthesis case
// Rule::expression_increment => {
@ -315,6 +321,16 @@ pub struct BinaryExpression<'ast> {
pub span: Span<'ast>,
}
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::expression_conditional))]
pub struct TernaryExpression<'ast> {
pub first: Box<Expression<'ast>>,
pub second: Box<Expression<'ast>>,
pub third: Box<Expression<'ast>>,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
// #[derive(Clong, Debug, PartialEq)]
// pub struct IdentifierExpression<'ast> {
// pub value: String,
@ -327,6 +343,7 @@ pub enum Expression<'ast> {
Variable(Variable<'ast>),
Not(NotExpression<'ast>),
Binary(BinaryExpression<'ast>),
Ternary(TernaryExpression<'ast>),
// Increment(IncrementExpression<'ast>),
// Decrement(DecrementExpression<'ast>),
}
@ -346,12 +363,27 @@ impl<'ast> Expression<'ast> {
})
}
pub fn ternary(
first: Box<Expression<'ast>>,
second: Box<Expression<'ast>>,
third: Box<Expression<'ast>>,
span: Span<'ast>,
) -> Self {
Expression::Ternary(TernaryExpression {
first,
second,
third,
span,
})
}
pub fn span(&self) -> &Span<'ast> {
match self {
Expression::Value(expression) => &expression.span(),
Expression::Variable(expression) => &expression.span,
Expression::Not(expression) => &expression.span,
Expression::Binary(expression) => &expression.span,
Expression::Ternary(expression) => &expression.span,
// Expression::Increment(expression) => &expression.span,
// Expression::Decrement(expression) => &expression.span,
}
@ -367,6 +399,11 @@ impl<'ast> fmt::Display for Expression<'ast> {
Expression::Binary(ref expression) => {
write!(f, "{} == {}", expression.left, expression.right)
}
Expression::Ternary(ref expression) => write!(
f,
"if {} then {} else {} fi",
expression.first, expression.second, expression.third
),
}
}
}

View File

@ -72,13 +72,24 @@ variable = @{ ((!protected_name ~ ASCII_ALPHA) | (protected_name ~ (ASCII_ALPHAN
// Consider structs, conditionals, postfix, primary, inline array, array initializer, and unary
expression_primitive = { value | variable }
expression_not = { operation_pre_not ~ expression_term }
expression_term = { expression_primitive | expression_not | ("(" ~ expression ~ ")") }
expression_term = { ("(" ~ expression ~ ")") | expression_conditional | expression_primitive | expression_not}
expression = { expression_term ~ (operation_binary ~ expression_term)* }
// expression_increment = { expression ~ operation_post_increment }
// expression_decrement = { expression ~ operation_post_decrement }
// Conditionals
expression_conditional = { "if" ~ expression ~ "then" ~ expression ~ "else" ~ expression ~ "fi"}
// conditional_if = { "if" }
// conditional_else = { "else" }
//
// conditional_for = { "for" }
//
// conditional = { conditional_if | conditional_else | conditional_for }
expression_tuple = _{ (expression ~ ("," ~ expression)*)? }
/// Statements
@ -93,16 +104,6 @@ statement = { (statement_return | (statement_assign) ~ NEWLINE) ~ NEWLINE* }
COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) }
WHITESPACE = _{ " " | "\t" ~ NEWLINE }
// /// Conditionals
//
// conditional_if = { "if" }
// conditional_else = { "else" }
//
// conditional_for = { "for" }
//
// conditional = { conditional_if | conditional_else | conditional_for }
// /// Helpers
//
// helper_range = { expression+ ~ ".." ~ expression+ } // Confirm that '+' is the correct repetition

View File

@ -13,4 +13,4 @@ pub mod ast;
pub mod aleo_program;
pub mod zokrates_program;
// pub mod zokrates_program;