From b423e532cb826567bd565eb560e5d7cbd315fdc9 Mon Sep 17 00:00:00 2001 From: collin Date: Mon, 15 Jun 2020 18:25:33 -0700 Subject: [PATCH 1/5] let and const wip --- ast/src/common/declare.rs | 18 +++++++++++++ ast/src/common/mod.rs | 3 +++ ast/src/leo.pest | 15 ++++++++--- ast/src/statements/definition_statement.rs | 2 ++ .../multiple_assignment_statement.rs | 2 ++ compiler/src/constraints/statement.rs | 6 +++-- types/src/common/declare.rs | 27 +++++++++++++++++++ types/src/common/mod.rs | 3 +++ types/src/statements/statement.rs | 9 ++++--- 9 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 ast/src/common/declare.rs create mode 100644 types/src/common/declare.rs diff --git a/ast/src/common/declare.rs b/ast/src/common/declare.rs new file mode 100644 index 0000000000..344f9c5c73 --- /dev/null +++ b/ast/src/common/declare.rs @@ -0,0 +1,18 @@ +use crate::ast::Rule; + +use pest_ast::FromPest; + +#[derive(Clone, Debug, FromPest, PartialEq)] +#[pest_ast(rule(Rule::declare))] +pub enum Declare { + Const(Const), + Let(Let), +} + +#[derive(Clone, Debug, FromPest, PartialEq)] +#[pest_ast(rule(Rule::const_))] +pub struct Const {} + +#[derive(Clone, Debug, FromPest, PartialEq)] +#[pest_ast(rule(Rule::let_))] +pub struct Let {} diff --git a/ast/src/common/mod.rs b/ast/src/common/mod.rs index fb64745c9a..54945c1bf4 100644 --- a/ast/src/common/mod.rs +++ b/ast/src/common/mod.rs @@ -1,6 +1,9 @@ pub mod assignee; pub use assignee::*; +pub mod declare; +pub use declare::*; + pub mod eoi; pub use eoi::*; diff --git a/ast/src/leo.pest b/ast/src/leo.pest index 35bb6dd60e..281db8827f 100644 --- a/ast/src/leo.pest +++ b/ast/src/leo.pest @@ -8,7 +8,11 @@ file = { SOI ~ NEWLINE* ~ import* ~ NEWLINE* ~ circuit_definition* ~ NEWLINE* ~ // Declared in common/identifier.rs identifier = @{ ((!protected_name ~ ASCII_ALPHA) | (protected_name ~ (ASCII_ALPHANUMERIC | "_"))) ~ (ASCII_ALPHANUMERIC | "_")* } -protected_name = { "let" | "for"| "if" | "else" | "as" | "return" } +protected_name = { + "for"| "if" | "else" | "as" | "return" + | declare | mutable | static_ | value_boolean + | type_self | type_array | type_data +} // Declared in common/line_end.rs LINE_END = { ";" ~ NEWLINE* } @@ -36,6 +40,11 @@ static_ = { "static" } // Declared in common/variable.rs variable = { mutable? ~ identifier ~ (":" ~ type_)? } +// Declared in common/declare.rs +declare = { let_ | const_ } +const_ = { "const" } +let_ = { "let" } + /// Operations // Declared in operations/not_operation.rs @@ -249,7 +258,7 @@ statement_conditional = {"if" ~ (expression | "(" ~ expression ~ ")") ~ "{" ~ NE conditional_nested_or_end_statement = { statement_conditional | "{" ~ NEWLINE* ~ statement+ ~ "}"} // Declared in statements/definition_statement.rs -statement_definition = { "let" ~ variable ~ "=" ~ expression ~ LINE_END} +statement_definition = { declare ~ variable ~ "=" ~ expression ~ LINE_END} // Declared in statements/expression_statement.rs statement_expression = { expression ~ LINE_END } @@ -258,7 +267,7 @@ statement_expression = { expression ~ LINE_END } statement_for = { "for" ~ identifier ~ "in" ~ expression ~ ".." ~ expression ~ "{" ~ NEWLINE* ~ statement+ ~ "}"} // Declared in statements/multiple_assignment_statement.rs -statement_multiple_assignment = { "let" ~ "(" ~ variable_tuple ~ ")" ~ "=" ~ identifier ~ "(" ~ expression_tuple ~ ")" ~ LINE_END} +statement_multiple_assignment = { declare ~ "(" ~ variable_tuple ~ ")" ~ "=" ~ identifier ~ "(" ~ expression_tuple ~ ")" ~ LINE_END} variable_tuple = _{ variable ~ ("," ~ variable)* } // Declared in statements/return_statement.rs diff --git a/ast/src/statements/definition_statement.rs b/ast/src/statements/definition_statement.rs index bb539a3119..93d24de8f3 100644 --- a/ast/src/statements/definition_statement.rs +++ b/ast/src/statements/definition_statement.rs @@ -4,6 +4,7 @@ use crate::{ expressions::Expression, }; +use crate::common::Declare; use pest::Span; use pest_ast::FromPest; use std::fmt; @@ -11,6 +12,7 @@ use std::fmt; #[derive(Clone, Debug, FromPest, PartialEq)] #[pest_ast(rule(Rule::statement_definition))] pub struct DefinitionStatement<'ast> { + pub declare: Declare, pub variable: Variable<'ast>, pub expression: Expression<'ast>, pub line_end: LineEnd, diff --git a/ast/src/statements/multiple_assignment_statement.rs b/ast/src/statements/multiple_assignment_statement.rs index e61814f400..55582fee4d 100644 --- a/ast/src/statements/multiple_assignment_statement.rs +++ b/ast/src/statements/multiple_assignment_statement.rs @@ -4,6 +4,7 @@ use crate::{ expressions::Expression, }; +use crate::common::Declare; use pest::Span; use pest_ast::FromPest; use std::fmt; @@ -11,6 +12,7 @@ use std::fmt; #[derive(Clone, Debug, FromPest, PartialEq)] #[pest_ast(rule(Rule::statement_multiple_assignment))] pub struct MultipleAssignmentStatement<'ast> { + pub declare: Declare, pub variables: Vec>, pub function_name: Identifier<'ast>, pub arguments: Vec>, diff --git a/compiler/src/constraints/statement.rs b/compiler/src/constraints/statement.rs index 5fc5e77b10..bdcc0332f4 100644 --- a/compiler/src/constraints/statement.rs +++ b/compiler/src/constraints/statement.rs @@ -10,6 +10,7 @@ use leo_types::{ Assignee, ConditionalNestedOrEndStatement, ConditionalStatement, + Declare, Expression, Identifier, Integer, @@ -221,6 +222,7 @@ impl> ConstrainedProgram { cs: &mut CS, file_scope: String, function_scope: String, + declare: Declare, variable: Variable, expression: Expression, ) -> Result<(), StatementError> { @@ -484,8 +486,8 @@ impl> ConstrainedProgram { Statement::Return(expressions) => { res = Some(self.enforce_return_statement(cs, file_scope, function_scope, expressions, return_types)?); } - Statement::Definition(variable, expression) => { - self.enforce_definition_statement(cs, file_scope, function_scope, variable, expression)?; + Statement::Definition(declare, variable, expression) => { + self.enforce_definition_statement(cs, file_scope, function_scope, declare, variable, expression)?; } Statement::Assign(variable, expression) => { self.enforce_assign_statement(cs, file_scope, function_scope, indicator, variable, expression)?; diff --git a/types/src/common/declare.rs b/types/src/common/declare.rs new file mode 100644 index 0000000000..d543100fd1 --- /dev/null +++ b/types/src/common/declare.rs @@ -0,0 +1,27 @@ +use leo_ast::common::Declare as AstDeclare; + +use std::fmt; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Declare { + Const, + Let, +} + +impl<'ast> From for Declare { + fn from(declare: AstDeclare) -> Self { + match declare { + AstDeclare::Const(_) => Declare::Const, + AstDeclare::Let(_) => Declare::Let, + } + } +} + +impl fmt::Display for Declare { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Declare::Const => write!(f, "const"), + Declare::Let => write!(f, "let"), + } + } +} diff --git a/types/src/common/mod.rs b/types/src/common/mod.rs index a338bc954f..047ca0b8fd 100644 --- a/types/src/common/mod.rs +++ b/types/src/common/mod.rs @@ -1,6 +1,9 @@ pub mod assignee; pub use assignee::*; +pub mod declare; +pub use declare::*; + pub mod identifier; pub use identifier::*; diff --git a/types/src/statements/statement.rs b/types/src/statements/statement.rs index fd34134acd..1ce46adf14 100644 --- a/types/src/statements/statement.rs +++ b/types/src/statements/statement.rs @@ -1,4 +1,4 @@ -use crate::{Assignee, ConditionalStatement, Expression, Identifier, Integer, Variable}; +use crate::{Assignee, ConditionalStatement, Declare, Expression, Identifier, Integer, Variable}; use leo_ast::{ operations::AssignOperation, statements::{ @@ -19,7 +19,7 @@ use std::fmt; #[derive(Clone, PartialEq, Eq)] pub enum Statement { Return(Vec), - Definition(Variable, Expression), + Definition(Declare, Variable, Expression), Assign(Assignee, Expression), MultipleAssign(Vec, Expression), Conditional(ConditionalStatement), @@ -43,6 +43,7 @@ impl<'ast> From> for Statement { impl<'ast> From> for Statement { fn from(statement: DefinitionStatement<'ast>) -> Self { Statement::Definition( + Declare::from(statement.declare), Variable::from(statement.variable), Expression::from(statement.expression), ) @@ -176,7 +177,9 @@ impl fmt::Display for Statement { } write!(f, ")\n") } - Statement::Definition(ref variable, ref expression) => write!(f, "let {} = {};", variable, expression), + Statement::Definition(ref declare, ref variable, ref expression) => { + write!(f, "{} {} = {};", declare, variable, expression) + } Statement::Assign(ref variable, ref statement) => write!(f, "{} = {};", variable, statement), Statement::MultipleAssign(ref assignees, ref function) => { write!(f, "let (")?; From eeaef7863226aa5a00216af2e5f61256a86cd6f8 Mon Sep 17 00:00:00 2001 From: collin Date: Mon, 15 Jun 2020 19:25:16 -0700 Subject: [PATCH 2/5] impl allocate value for let definition --- compiler/src/constraints/statement.rs | 6 +- compiler/src/constraints/value.rs | 42 +++++++++++ compiler/src/errors/constraints/value.rs | 4 + types/src/integer.rs | 93 ++++++++++++++---------- 4 files changed, 104 insertions(+), 41 deletions(-) diff --git a/compiler/src/constraints/statement.rs b/compiler/src/constraints/statement.rs index bdcc0332f4..825b70669f 100644 --- a/compiler/src/constraints/statement.rs +++ b/compiler/src/constraints/statement.rs @@ -230,7 +230,7 @@ impl> ConstrainedProgram { if let Some(ref _type) = variable._type { expected_types.push(_type.clone()); } - let value = self.enforce_expression( + let mut value = self.enforce_expression( cs, file_scope.clone(), function_scope.clone(), @@ -238,6 +238,10 @@ impl> ConstrainedProgram { expression, )?; + if let Declare::Let = declare { + value = value.allocate_value(cs)?; + } + self.store_definition(function_scope, variable, value) } diff --git a/compiler/src/constraints/value.rs b/compiler/src/constraints/value.rs index bf658c4691..53366e7c67 100644 --- a/compiler/src/constraints/value.rs +++ b/compiler/src/constraints/value.rs @@ -9,6 +9,7 @@ use snarkos_models::{ gadgets::{ r1cs::ConstraintSystem, utilities::{ + alloc::AllocGadget, boolean::Boolean, eq::ConditionalEqGadget, select::CondSelectGadget, @@ -105,6 +106,47 @@ impl> ConstrainedValue { *self = *inner.clone() } } + + pub(crate) fn allocate_value>(&self, mut cs: CS) -> Result { + Ok(match self { + ConstrainedValue::Boolean(ref boolean) => { + let option = boolean.get_value(); + let allocated = Boolean::alloc(cs, || option.ok_or(SynthesisError::AssignmentMissing))?; + + ConstrainedValue::Boolean(allocated) + } + ConstrainedValue::Integer(ref integer) => { + let integer_type = integer.get_type(); + let option = integer.get_value(); + let name = format!("clone {}", integer); + let allocated = Integer::allocate_type(&mut cs, integer_type, name, option)?; + + ConstrainedValue::Integer(allocated) + } + ConstrainedValue::Field(ref field) => { + let option = field.get_value().map(|v| format!("{}", v)); + let allocated = FieldType::alloc(cs, || option.ok_or(SynthesisError::AssignmentMissing))?; + + ConstrainedValue::Field(allocated) + } + ConstrainedValue::Group(ref group) => { + let string = format!("{}", group); + let allocated = G::alloc(cs, || Ok(string))?; + + ConstrainedValue::Group(allocated) + } + ConstrainedValue::Array(ref array) => { + let allocated = array + .iter() + .enumerate() + .map(|(i, value)| value.allocate_value(cs.ns(|| format!("allocate {}", i)))) + .collect::>, ValueError>>()?; + + ConstrainedValue::Array(allocated) + } + _ => unimplemented!("cannot allocate non-primitive value"), + }) + } } impl> fmt::Display for ConstrainedValue { diff --git a/compiler/src/errors/constraints/value.rs b/compiler/src/errors/constraints/value.rs index ad25aa443a..b8eda405df 100644 --- a/compiler/src/errors/constraints/value.rs +++ b/compiler/src/errors/constraints/value.rs @@ -1,6 +1,7 @@ use crate::errors::{FieldError, GroupError}; use leo_types::IntegerError; +use snarkos_errors::gadgets::SynthesisError; use std::{num::ParseIntError, str::ParseBoolError}; #[derive(Debug, Error)] @@ -19,4 +20,7 @@ pub enum ValueError { #[error("{}", _0)] ParseIntError(#[from] ParseIntError), + + #[error("{}", _0)] + SynthesisError(#[from] SynthesisError), } diff --git a/types/src/integer.rs b/types/src/integer.rs index fe3e4dad1a..3f04b72085 100644 --- a/types/src/integer.rs +++ b/types/src/integer.rs @@ -58,16 +58,20 @@ impl<'ast> Integer { } impl Integer { - pub fn to_usize(&self) -> usize { + pub fn get_value(&self) -> Option { match self { - Integer::U8(u8) => u8.value.unwrap() as usize, - Integer::U16(u16) => u16.value.unwrap() as usize, - Integer::U32(u32) => u32.value.unwrap() as usize, - Integer::U64(u64) => u64.value.unwrap() as usize, - Integer::U128(u128) => u128.value.unwrap() as usize, + Integer::U8(u8) => u8.value.map(|v| v as u128), + Integer::U16(u16) => u16.value.map(|v| v as u128), + Integer::U32(u32) => u32.value.map(|v| v as u128), + Integer::U64(u64) => u64.value.map(|v| v as u128), + Integer::U128(u128) => u128.value.map(|v| v as u128), } } + pub fn to_usize(&self) -> usize { + self.get_value().unwrap() as usize + } + pub fn get_type(&self) -> IntegerType { match self { Integer::U8(_u8) => IntegerType::U8, @@ -78,6 +82,47 @@ impl Integer { } } + pub fn allocate_type>( + cs: &mut CS, + integer_type: IntegerType, + name: String, + option: Option, + ) -> Result { + Ok(match integer_type { + IntegerType::U8 => { + let u8_option = option.map(|integer| integer as u8); + let u8_result = UInt8::alloc(cs.ns(|| name), || u8_option.ok_or(SynthesisError::AssignmentMissing))?; + + Integer::U8(u8_result) + } + IntegerType::U16 => { + let u16_option = option.map(|integer| integer as u16); + let u16_result = UInt16::alloc(cs.ns(|| name), || u16_option.ok_or(SynthesisError::AssignmentMissing))?; + + Integer::U16(u16_result) + } + IntegerType::U32 => { + let u32_option = option.map(|integer| integer as u32); + let u32_result = UInt32::alloc(cs.ns(|| name), || u32_option.ok_or(SynthesisError::AssignmentMissing))?; + + Integer::U32(u32_result) + } + IntegerType::U64 => { + let u64_option = option.map(|integer| integer as u64); + let u64_result = UInt64::alloc(cs.ns(|| name), || u64_option.ok_or(SynthesisError::AssignmentMissing))?; + + Integer::U64(u64_result) + } + IntegerType::U128 => { + let u128_option = option.map(|integer| integer as u128); + let u128_result = + UInt128::alloc(cs.ns(|| name), || u128_option.ok_or(SynthesisError::AssignmentMissing))?; + + Integer::U128(u128_result) + } + }) + } + pub fn from_input>( cs: &mut CS, integer_type: IntegerType, @@ -85,7 +130,7 @@ impl Integer { integer_value: Option, ) -> Result { // Check that the input value is the correct type - let integer_option = match integer_value { + let option = match integer_value { Some(input) => { if let InputValue::Integer(_type_, integer) = input { Some(integer) @@ -96,39 +141,7 @@ impl Integer { None => None, }; - Ok(match integer_type { - IntegerType::U8 => { - let u8_option = integer_option.map(|integer| integer as u8); - let u8_result = UInt8::alloc(cs.ns(|| name), || u8_option.ok_or(SynthesisError::AssignmentMissing))?; - - Integer::U8(u8_result) - } - IntegerType::U16 => { - let u16_option = integer_option.map(|integer| integer as u16); - let u16_result = UInt16::alloc(cs.ns(|| name), || u16_option.ok_or(SynthesisError::AssignmentMissing))?; - - Integer::U16(u16_result) - } - IntegerType::U32 => { - let u32_option = integer_option.map(|integer| integer as u32); - let u32_result = UInt32::alloc(cs.ns(|| name), || u32_option.ok_or(SynthesisError::AssignmentMissing))?; - - Integer::U32(u32_result) - } - IntegerType::U64 => { - let u64_option = integer_option.map(|integer| integer as u64); - let u64_result = UInt64::alloc(cs.ns(|| name), || u64_option.ok_or(SynthesisError::AssignmentMissing))?; - - Integer::U64(u64_result) - } - IntegerType::U128 => { - let u128_option = integer_option.map(|integer| integer as u128); - let u128_result = - UInt128::alloc(cs.ns(|| name), || u128_option.ok_or(SynthesisError::AssignmentMissing))?; - - Integer::U128(u128_result) - } - }) + Self::allocate_type(cs, integer_type, name, option) } pub fn add>( From 7248814ac749d5d5a911ca96cc027578f3a8d3c6 Mon Sep 17 00:00:00 2001 From: collin Date: Tue, 16 Jun 2020 09:49:45 -0700 Subject: [PATCH 3/5] impl let/const for circuits and value wrappers --- ast/src/leo.pest | 2 +- compiler/src/constraints/statement.rs | 2 +- compiler/src/constraints/value.rs | 75 ++++++++++++++------- compiler/tests/array/multi.leo | 4 +- compiler/tests/boolean/all.leo | 6 +- compiler/tests/function/scope_fail.leo | 2 +- compiler/tests/function/value_unchanged.leo | 2 +- compiler/tests/group/add.leo | 4 +- compiler/tests/group/assert_eq_false.leo | 4 +- compiler/tests/group/assert_eq_true.leo | 4 +- compiler/tests/group/eq_false.leo | 4 +- compiler/tests/group/eq_true.leo | 4 +- compiler/tests/group/sub.leo | 4 +- compiler/tests/group/ternary.leo | 4 +- 14 files changed, 74 insertions(+), 47 deletions(-) diff --git a/ast/src/leo.pest b/ast/src/leo.pest index 281db8827f..caaefc02cd 100644 --- a/ast/src/leo.pest +++ b/ast/src/leo.pest @@ -11,7 +11,7 @@ identifier = @{ ((!protected_name ~ ASCII_ALPHA) | (protected_name ~ (ASCII_ALPH protected_name = { "for"| "if" | "else" | "as" | "return" | declare | mutable | static_ | value_boolean - | type_self | type_array | type_data + | type_array | type_data } // Declared in common/line_end.rs diff --git a/compiler/src/constraints/statement.rs b/compiler/src/constraints/statement.rs index 825b70669f..add36fa538 100644 --- a/compiler/src/constraints/statement.rs +++ b/compiler/src/constraints/statement.rs @@ -239,7 +239,7 @@ impl> ConstrainedProgram { )?; if let Declare::Let = declare { - value = value.allocate_value(cs)?; + value.allocate_value(cs)?; } self.store_definition(function_scope, variable, value) diff --git a/compiler/src/constraints/value.rs b/compiler/src/constraints/value.rs index 53366e7c67..77a9cf31a4 100644 --- a/compiler/src/constraints/value.rs +++ b/compiler/src/constraints/value.rs @@ -107,45 +107,72 @@ impl> ConstrainedValue { } } - pub(crate) fn allocate_value>(&self, mut cs: CS) -> Result { - Ok(match self { - ConstrainedValue::Boolean(ref boolean) => { + pub(crate) fn allocate_value>(&mut self, mut cs: CS) -> Result<(), ValueError> { + match self { + // allocated values + ConstrainedValue::Boolean(boolean) => { let option = boolean.get_value(); - let allocated = Boolean::alloc(cs, || option.ok_or(SynthesisError::AssignmentMissing))?; - ConstrainedValue::Boolean(allocated) + *boolean = Boolean::alloc(cs, || option.ok_or(SynthesisError::AssignmentMissing))?; } - ConstrainedValue::Integer(ref integer) => { + ConstrainedValue::Integer(integer) => { let integer_type = integer.get_type(); let option = integer.get_value(); let name = format!("clone {}", integer); - let allocated = Integer::allocate_type(&mut cs, integer_type, name, option)?; - ConstrainedValue::Integer(allocated) + *integer = Integer::allocate_type(&mut cs, integer_type, name, option)?; } - ConstrainedValue::Field(ref field) => { + ConstrainedValue::Field(field) => { let option = field.get_value().map(|v| format!("{}", v)); - let allocated = FieldType::alloc(cs, || option.ok_or(SynthesisError::AssignmentMissing))?; - ConstrainedValue::Field(allocated) + *field = FieldType::alloc(cs, || option.ok_or(SynthesisError::AssignmentMissing))?; } - ConstrainedValue::Group(ref group) => { - let string = format!("{}", group); - let allocated = G::alloc(cs, || Ok(string))?; + ConstrainedValue::Group(group) => { + let string = format!("{}", group); // may need to implement u256 -> decimal formatting - ConstrainedValue::Group(allocated) + *group = G::alloc(cs, || Ok(string))?; } - ConstrainedValue::Array(ref array) => { - let allocated = array - .iter() + // value wrappers + ConstrainedValue::Array(array) => { + array + .iter_mut() .enumerate() - .map(|(i, value)| value.allocate_value(cs.ns(|| format!("allocate {}", i)))) - .collect::>, ValueError>>()?; - - ConstrainedValue::Array(allocated) + .map(|(i, value)| value.allocate_value(cs.ns(|| format!("allocate array member {}", i)))) + .collect::>()?; } - _ => unimplemented!("cannot allocate non-primitive value"), - }) + ConstrainedValue::CircuitExpression(_id, members) => { + members + .iter_mut() + .enumerate() + .map(|(i, member)| { + member + .1 + .allocate_value(cs.ns(|| format!("allocate circuit member {}", i))) + }) + .collect::>()?; + } + ConstrainedValue::Return(array) => { + array + .iter_mut() + .enumerate() + .map(|(i, value)| value.allocate_value(cs.ns(|| format!("allocate return member {}", i)))) + .collect::>()?; + } + ConstrainedValue::Mutable(value) => { + value.allocate_value(cs)?; + } + ConstrainedValue::Static(value) => { + value.allocate_value(cs)?; + } + // empty wrappers + ConstrainedValue::CircuitDefinition(_) => {} + ConstrainedValue::Function(_, _) => {} + ConstrainedValue::Unresolved(_) => { + return Err(ValueError::SynthesisError(SynthesisError::AssignmentMissing)); + } + } + + Ok(()) } } diff --git a/compiler/tests/array/multi.leo b/compiler/tests/array/multi.leo index 32465a0717..7dc37aa8d4 100644 --- a/compiler/tests/array/multi.leo +++ b/compiler/tests/array/multi.leo @@ -1,8 +1,8 @@ // Multidimensional array syntax in leo function main() -> u32[3][2] { - let m = [[0u32, 0u32, 0u32], [0u32, 0u32, 0u32]]; // inline + const m = [[0u32, 0u32, 0u32], [0u32, 0u32, 0u32]]; // inline - let m: u32[3][2] = [[0; 3]; 2]; // initializer + const m: u32[3][2] = [[0; 3]; 2]; // initializer return m } \ No newline at end of file diff --git a/compiler/tests/boolean/all.leo b/compiler/tests/boolean/all.leo index fde553f2a3..ef95729b4e 100644 --- a/compiler/tests/boolean/all.leo +++ b/compiler/tests/boolean/all.leo @@ -1,8 +1,8 @@ // !(true && (false || true)) function main() -> bool { - let a = true; - let b = false || a; - let c = !(true && b); + const a = true; + const b = false || a; + const c = !(true && b); return c } \ No newline at end of file diff --git a/compiler/tests/function/scope_fail.leo b/compiler/tests/function/scope_fail.leo index 1361a80812..e25a0f1e6b 100644 --- a/compiler/tests/function/scope_fail.leo +++ b/compiler/tests/function/scope_fail.leo @@ -3,6 +3,6 @@ function foo() -> field { } function main() -> field { - let myGlobal = 42field; + const myGlobal = 42field; return foo() } \ No newline at end of file diff --git a/compiler/tests/function/value_unchanged.leo b/compiler/tests/function/value_unchanged.leo index c986efa816..46bcd78f1b 100644 --- a/compiler/tests/function/value_unchanged.leo +++ b/compiler/tests/function/value_unchanged.leo @@ -12,7 +12,7 @@ function bad_mutate(mut x: u32) { } function main() -> u32 { - let a = 1; + let a = 1u32; bad_mutate(a); return a // <- returns 1 diff --git a/compiler/tests/group/add.leo b/compiler/tests/group/add.leo index 19496a03f7..28cbcd67b8 100644 --- a/compiler/tests/group/add.leo +++ b/compiler/tests/group/add.leo @@ -1,6 +1,6 @@ function main() -> group { - let point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; - let point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; + const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; + const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; return point_1 + point_2 } \ No newline at end of file diff --git a/compiler/tests/group/assert_eq_false.leo b/compiler/tests/group/assert_eq_false.leo index 1ac3f02fd7..5e130610aa 100644 --- a/compiler/tests/group/assert_eq_false.leo +++ b/compiler/tests/group/assert_eq_false.leo @@ -1,6 +1,6 @@ function main() { - let point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; - let point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; + const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; + const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; assert_eq!(point_1, point_2); } \ No newline at end of file diff --git a/compiler/tests/group/assert_eq_true.leo b/compiler/tests/group/assert_eq_true.leo index b940016ce0..fecce61611 100644 --- a/compiler/tests/group/assert_eq_true.leo +++ b/compiler/tests/group/assert_eq_true.leo @@ -1,6 +1,6 @@ function main() { - let point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; - let point_2 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; + const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; + const point_2 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; assert_eq!(point_1, point_2); } \ No newline at end of file diff --git a/compiler/tests/group/eq_false.leo b/compiler/tests/group/eq_false.leo index 62630c66ac..004c44b731 100644 --- a/compiler/tests/group/eq_false.leo +++ b/compiler/tests/group/eq_false.leo @@ -1,6 +1,6 @@ function main() -> bool { - let point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; - let point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; + const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; + const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; return point_1 == point_2 } \ No newline at end of file diff --git a/compiler/tests/group/eq_true.leo b/compiler/tests/group/eq_true.leo index d98a3ca492..490c0e9432 100644 --- a/compiler/tests/group/eq_true.leo +++ b/compiler/tests/group/eq_true.leo @@ -1,6 +1,6 @@ function main() -> bool { - let point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; - let point_2 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; + const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; + const point_2 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; return point_1 == point_2 } \ No newline at end of file diff --git a/compiler/tests/group/sub.leo b/compiler/tests/group/sub.leo index d1c582e635..a1f95b5a3c 100644 --- a/compiler/tests/group/sub.leo +++ b/compiler/tests/group/sub.leo @@ -1,6 +1,6 @@ function main() -> group { - let point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; - let point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; + const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; + const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; return point_1 - point_2 } \ No newline at end of file diff --git a/compiler/tests/group/ternary.leo b/compiler/tests/group/ternary.leo index 1841fc6bd8..094cede5b2 100644 --- a/compiler/tests/group/ternary.leo +++ b/compiler/tests/group/ternary.leo @@ -1,6 +1,6 @@ function main (b: bool) -> group { - let point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; - let point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; + const point_1 = (7374112779530666882856915975292384652154477718021969292781165691637980424078, 3435195339177955418892975564890903138308061187980579490487898366607011481796)group; + const point_2 = (1005842117974384149622370061042978581211342111653966059496918451529532134799, 79389132189982034519597104273449021362784864778548730890166152019533697186)group; return if b ? point_1 : point_2 } \ No newline at end of file From c45e0df7f63cfc293930d3eae4a1b25016489432 Mon Sep 17 00:00:00 2001 From: collin Date: Tue, 16 Jun 2020 12:55:59 -0700 Subject: [PATCH 4/5] update readme --- README.md | 71 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index de809774b4..ad936ce566 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,55 @@ # The Leo Programming Language + +## Compiler Architecture + + +![~mermaid diagram 1~](/.resources/README-md-1.png) +
+ Mermaid markup + +```mermaid +graph LR + Pass1(Syntax Parser) -- ast --> Pass2(Type Resolver) + + Pass2 -- imports --> Pass3(Import Resolver) + Pass3 -- statements --> Pass4 + + Pass2 -- statements --> Pass4(Synthesizer) + + Pass4 -- constraints --> Pass5(Circuit) +``` + +
+ + +## Language Specification + * Programs should be formatted: 1. Import definitions 2. Circuit definitions 3. Function definitions +## Defining Variables +Leo supports `let` and `const` keywords for variable definition. + +```let a = true;``` defines an **allocated** program variable `a` with boolean value `true`. + +```const a = true;``` defines a **constant** program variable `a` with boolean value `true`. + +**Allocated** variables define private variables in the constraint system. Their value is constrained in the circuit on initialization. + +**Constant** variables do not define a variable in the constraint system. Their value is constrained in the circuit on computation with an **allocated** variable. +**Constant** variables can be mutable. They do not have the same functionality as `const` variables in other languages. +```rust +function addOne() -> { + let a = 0u8; // allocated, value enforced on this line + const b = 1u8; // constant, value not enforced yet + + return a + b // allocated, computed value is enforced to be the sum of both values +} +``` +Computations are expressed in terms of arithmetic circuits, in particular rank-1 quadratic constraint systems. Thus computing on an allocated variable always results in another allocated variable. + ## Mutability * All defined variables in Leo are immutable by default. * Variables can be made mutable with the `mut` keyword. @@ -31,7 +77,7 @@ function main() -> bool { ``` ## Numbers -* The definition of a number must include an explict type. +* The definition of a number must include an explicit type. * After assignment, you can choose to explicitly add the type or let the compiler interpret implicitly. * Type casting is not supported. * Comparators are not supported. @@ -134,7 +180,14 @@ function main() -> u32[3][2] { ## Conditionals +Branching in Leo is different than traditional programming languages. Leo developers should keep in mind that every program compiles to a circuit which represents +all possible evaluations. + ### If Else Ternary Expression +Ternary `if [cond] ? [first] : [second];` expressions are the cheapest form of conditional. +Since `first` and `second` are expressions, we can resolve their values before proceeding execution. +In the underlying circuit, this is a single bit multiplexer. + ```rust function main() -> u32 { let y = if 3==3 ? 1 : 5; @@ -143,14 +196,15 @@ function main() -> u32 { ``` ### If Else Conditional Statement -** **Experimental** ** -The current constraint system is not optimized for statement branching. Please use the ternary expression above until this feature is stable. +Leo supports the traditional `if [cond] { [first] } else { [second] }` which can be chained using `else if`. +Since `first` and `second` are one or more statements, they resolve to separate circuits which will all be evaluated. +In the underlying circuit this can be thought of as a demultiplexer. ```rust function main(a: bool, b: bool) -> u32 { let mut res = 0u32; - if (a) { + if a { res = 1; - } else if (b) { + } else if b { res = 2; } else { res = 3; @@ -217,7 +271,7 @@ function main() -> u32[3] { } ``` -### Main function inputs +### Function inputs Main function inputs are allocated private variables in the program's constraint system. `a` is implicitly private. ```rust @@ -225,7 +279,7 @@ function main(a: field) -> field { return a } ``` -Function inputs are passed by value. +Normal function inputs are passed by value. ```rust function test(mut a: u32) { a = 0; @@ -547,4 +601,5 @@ cargo install --path . - Change `target` directory to some other directory to avoid collision. - Figure out how `leo prove` should take in assignments. -- Come up with a serialization format for `.leo.pk`, `.leo.vk`, and `.leo.proof`. \ No newline at end of file +- Come up with a serialization format for `.leo.pk`, `.leo.vk`, and `.leo.proof`. + From a5a8ba74de36abc09295bb0f96306f52fa7b4876 Mon Sep 17 00:00:00 2001 From: collin Date: Wed, 17 Jun 2020 19:25:13 -0700 Subject: [PATCH 5/5] fix imports --- ast/src/statements/definition_statement.rs | 3 +-- ast/src/statements/multiple_assignment_statement.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ast/src/statements/definition_statement.rs b/ast/src/statements/definition_statement.rs index 93d24de8f3..a3ad1e11e4 100644 --- a/ast/src/statements/definition_statement.rs +++ b/ast/src/statements/definition_statement.rs @@ -1,10 +1,9 @@ use crate::{ ast::Rule, - common::{LineEnd, Variable}, + common::{Declare, LineEnd, Variable}, expressions::Expression, }; -use crate::common::Declare; use pest::Span; use pest_ast::FromPest; use std::fmt; diff --git a/ast/src/statements/multiple_assignment_statement.rs b/ast/src/statements/multiple_assignment_statement.rs index 55582fee4d..f64b811726 100644 --- a/ast/src/statements/multiple_assignment_statement.rs +++ b/ast/src/statements/multiple_assignment_statement.rs @@ -1,10 +1,9 @@ use crate::{ ast::Rule, - common::{Identifier, LineEnd, Variable}, + common::{Declare, Identifier, LineEnd, Variable}, expressions::Expression, }; -use crate::common::Declare; use pest::Span; use pest_ast::FromPest; use std::fmt;