merge master

This commit is contained in:
collin 2020-12-07 19:55:03 -05:00
commit e93100eb6a
35 changed files with 404 additions and 207 deletions

View File

@ -1,5 +1,5 @@
[hooks]
pre-commit = "cargo +nightly fmt --all -- --check"
pre-commit = "cargo +nightly clippy && cargo +nightly fmt --all -- --check"
[logging]
verbose = false

4
Cargo.lock generated
View File

@ -2478,9 +2478,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.59"
version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95"
checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779"
dependencies = [
"itoa",
"ryu",

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{FunctionInput, Identifier, Span, Statement, Type};
use crate::{Block, FunctionInput, Identifier, Span, Type};
use leo_grammar::functions::Function as GrammarFunction;
use serde::{Deserialize, Serialize};
@ -25,7 +25,7 @@ pub struct Function {
pub identifier: Identifier,
pub input: Vec<FunctionInput>,
pub output: Option<Type>,
pub statements: Vec<Statement>,
pub block: Block,
pub span: Span,
}
@ -43,13 +43,13 @@ impl<'ast> From<GrammarFunction<'ast>> for Function {
let parameters = function.parameters.into_iter().map(FunctionInput::from).collect();
let returns = function.returns.map(Type::from);
let statements = function.statements.into_iter().map(Statement::from).collect();
let block = Block::from(function.block);
Function {
identifier: function_name,
input: parameters,
output: returns,
statements,
block,
span: Span::from(function.span),
}
}
@ -88,16 +88,10 @@ impl Function {
let parameters = self.input.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",");
let returns = self.output.as_ref().map(|type_| type_.to_string());
let statements = self
.statements
.iter()
.map(|s| format!("\t{}\n", s))
.collect::<Vec<_>>()
.join("");
if returns.is_none() {
write!(f, "({}) {{\n{}}}", parameters, statements,)
write!(f, "({}) {}", parameters, self.block)
} else {
write!(f, "({}) -> {} {{\n{}}}", parameters, returns.unwrap(), statements,)
write!(f, "({}) -> {} {}", parameters, returns.unwrap(), self.block)
}
}
}

View File

@ -0,0 +1,48 @@
// Copyright (C) 2019-2020 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::Statement;
use leo_grammar::statements::Block as GrammarBlock;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Block {
pub statements: Vec<Statement>,
}
impl<'ast> From<GrammarBlock<'ast>> for Block {
fn from(block: GrammarBlock<'ast>) -> Self {
Block {
statements: block.statements.into_iter().map(Statement::from).collect(),
}
}
}
impl fmt::Display for Block {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "{{")?;
if self.statements.is_empty() {
writeln!(f, "\t")?;
} else {
self.statements
.iter()
.try_for_each(|statement| writeln!(f, "\t{}", statement))?;
}
write!(f, "}}")
}
}

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{ConditionalStatement, Statement};
use crate::{Block, ConditionalStatement};
use leo_grammar::statements::ConditionalNestedOrEndStatement as GrammarConditionalNestedOrEndStatement;
use serde::{Deserialize, Serialize};
@ -23,7 +23,7 @@ use std::fmt;
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ConditionalNestedOrEndStatement {
Nested(Box<ConditionalStatement>),
End(Vec<Statement>),
End(Block),
}
impl<'ast> From<GrammarConditionalNestedOrEndStatement<'ast>> for ConditionalNestedOrEndStatement {
@ -32,8 +32,8 @@ impl<'ast> From<GrammarConditionalNestedOrEndStatement<'ast>> for ConditionalNes
GrammarConditionalNestedOrEndStatement::Nested(nested) => {
ConditionalNestedOrEndStatement::Nested(Box::new(ConditionalStatement::from(*nested)))
}
GrammarConditionalNestedOrEndStatement::End(statements) => {
ConditionalNestedOrEndStatement::End(statements.into_iter().map(Statement::from).collect())
GrammarConditionalNestedOrEndStatement::End(block) => {
ConditionalNestedOrEndStatement::End(Block::from(block))
}
}
}
@ -43,13 +43,7 @@ impl fmt::Display for ConditionalNestedOrEndStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ConditionalNestedOrEndStatement::Nested(ref nested) => write!(f, "else {}", nested),
ConditionalNestedOrEndStatement::End(ref statements) => {
writeln!(f, "else {{")?;
for statement in statements.iter() {
writeln!(f, "\t\t{}", statement)?;
}
write!(f, "\t}}")
}
ConditionalNestedOrEndStatement::End(ref block) => write!(f, "else {}", block),
}
}
}

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{ConditionalNestedOrEndStatement, Expression, Statement};
use crate::{Block, ConditionalNestedOrEndStatement, Expression};
use leo_grammar::statements::ConditionalStatement as GrammarConditionalStatement;
use serde::{Deserialize, Serialize};
@ -23,7 +23,7 @@ use std::fmt;
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ConditionalStatement {
pub condition: Expression,
pub statements: Vec<Statement>,
pub block: Block,
pub next: Option<ConditionalNestedOrEndStatement>,
}
@ -31,7 +31,7 @@ impl<'ast> From<GrammarConditionalStatement<'ast>> for ConditionalStatement {
fn from(statement: GrammarConditionalStatement<'ast>) -> Self {
ConditionalStatement {
condition: Expression::from(statement.condition),
statements: statement.statements.into_iter().map(Statement::from).collect(),
block: Block::from(statement.block),
next: statement
.next
.map(|n_or_e| Some(ConditionalNestedOrEndStatement::from(n_or_e)))
@ -42,13 +42,10 @@ impl<'ast> From<GrammarConditionalStatement<'ast>> for ConditionalStatement {
impl fmt::Display for ConditionalStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "if ({}) {{", self.condition)?;
for statement in self.statements.iter() {
writeln!(f, "\t\t{}", statement)?;
}
write!(f, "if ({}) {}", self.condition, self.block)?;
match self.next.clone() {
Some(n_or_e) => write!(f, "\t}} {}", n_or_e),
None => write!(f, "\t}}"),
Some(n_or_e) => write!(f, " {}", n_or_e),
None => write!(f, ""),
}
}
}

View File

@ -22,3 +22,6 @@ pub use conditional_statement::*;
pub mod statement;
pub use statement::*;
pub mod block;
pub use block::*;

View File

@ -14,7 +14,17 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{Assignee, ConditionalStatement, ConsoleFunctionCall, Declare, Expression, Identifier, Span, Variables};
use crate::{
Assignee,
Block,
ConditionalStatement,
ConsoleFunctionCall,
Declare,
Expression,
Identifier,
Span,
Variables,
};
use leo_grammar::{
console::ConsoleFunctionCall as GrammarConsoleFunctionCall,
operations::AssignOperation,
@ -38,7 +48,7 @@ pub enum Statement {
Definition(Declare, Variables, Expression, Span),
Assign(Assignee, Expression, Span),
Conditional(ConditionalStatement, Span),
Iteration(Identifier, Box<(Expression, Expression)>, Vec<Statement>, Span),
Iteration(Identifier, Box<(Expression, Expression)>, Block, Span),
Console(ConsoleFunctionCall),
Expression(Expression, Span),
}
@ -127,7 +137,7 @@ impl<'ast> From<ForStatement<'ast>> for Statement {
Statement::Iteration(
Identifier::from(statement.index),
Box::new((Expression::from(statement.start), Expression::from(statement.stop))),
statement.statements.into_iter().map(Statement::from).collect(),
Block::from(statement.block),
Span::from(statement.span),
)
}
@ -176,12 +186,8 @@ impl fmt::Display for Statement {
}
Statement::Assign(ref variable, ref statement, ref _span) => write!(f, "{} = {};", variable, statement),
Statement::Conditional(ref statement, ref _span) => write!(f, "{}", statement),
Statement::Iteration(ref var, ref start_stop, ref list, ref _span) => {
writeln!(f, "for {} in {}..{} {{", var, start_stop.0, start_stop.1)?;
for l in list {
writeln!(f, "\t\t{}", l)?;
}
write!(f, "\t}}")
Statement::Iteration(ref var, ref start_stop, ref block, ref _span) => {
write!(f, "for {} in {}..{} {}", var, start_stop.0, start_stop.1, block)
}
Statement::Console(ref console) => write!(f, "{}", console),
Statement::Expression(ref expression, ref _span) => write!(f, "{};", expression),

View File

@ -8,50 +8,52 @@
"identifier": "{\"name\":\"main\",\"span\":\"{\\\"text\\\":\\\" function main() {\\\",\\\"line\\\":1,\\\"start\\\":10,\\\"end\\\":14}\"}",
"input": [],
"output": null,
"statements": [
{
"Return": [
{
"Add": [[
{
"Implicit": [
"1",
{
"text": " return 1 + 1",
"line": 2,
"start": 12,
"end": 13
}
]
},
{
"Implicit": [
"1",
{
"text": " return 1 + 1",
"line": 2,
"start": 16,
"end": 17
}
]
}],
{
"text": " return 1 + 1",
"line": 2,
"start": 12,
"end": 17
}
]
},
{
"text": " return 1 + 1",
"line": 2,
"start": 5,
"end": 17
}
]
}
],
"block" : {
"statements": [
{
"Return": [
{
"Add": [[
{
"Implicit": [
"1",
{
"text": " return 1 + 1",
"line": 2,
"start": 12,
"end": 13
}
]
},
{
"Implicit": [
"1",
{
"text": " return 1 + 1",
"line": 2,
"start": 16,
"end": 17
}
]
}],
{
"text": " return 1 + 1",
"line": 2,
"start": 12,
"end": 17
}
]
},
{
"text": " return 1 + 1",
"line": 2,
"start": 5,
"end": 17
}
]
}
]
},
"span": {
"text": " function main() {",
"line": 1,

View File

@ -94,7 +94,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
let mut results = vec![];
let indicator = Boolean::constant(true);
for statement in function.statements.iter() {
for statement in function.block.statements.iter() {
let mut result = self.enforce_statement(
cs,
scope,

View File

@ -17,7 +17,7 @@
//! Enforces a branch of a conditional or iteration statement in a compiled Leo program.
use crate::{program::ConstrainedProgram, GroupType, IndicatorAndConstrainedValue, StatementResult};
use leo_ast::{Statement, Type};
use leo_ast::{Block, Type};
use snarkos_models::{
curves::{Field, PrimeField},
@ -28,19 +28,19 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
/// Evaluates a branch of one or more statements and returns a result in
/// the given scope.
#[allow(clippy::too_many_arguments)]
pub fn evaluate_branch<CS: ConstraintSystem<F>>(
pub fn evaluate_block<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
file_scope: &str,
function_scope: &str,
indicator: &Boolean,
statements: Vec<Statement>,
block: Block,
return_type: Option<Type>,
mut_self: bool,
) -> StatementResult<Vec<IndicatorAndConstrainedValue<F, G>>> {
let mut results = Vec::with_capacity(statements.len());
let mut results = Vec::with_capacity(block.statements.len());
// Evaluate statements. Only allow a single return argument to be returned.
for statement in statements.into_iter() {
for statement in block.statements.into_iter() {
let mut value = self.enforce_statement(
cs,
file_scope,

View File

@ -17,5 +17,5 @@
//! Methods to enforce constraints on a branch of a conditional or iteration statement
//! in a compiled Leo program.
pub mod branch;
pub use self::branch::*;
pub mod block;
pub use self::block::*;

View File

@ -89,12 +89,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
let mut results = vec![];
// Evaluate branch 1
let mut branch_1_result = self.evaluate_branch(
let mut branch_1_result = self.evaluate_block(
cs,
file_scope,
function_scope,
&branch_1_indicator,
statement.statements,
statement.block,
return_type.clone(),
mut_self,
)?;
@ -128,12 +128,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
mut_self,
span,
)?,
ConditionalNestedOrEndStatement::End(statements) => self.evaluate_branch(
ConditionalNestedOrEndStatement::End(block) => self.evaluate_block(
cs,
file_scope,
function_scope,
&branch_2_indicator,
statements,
block,
return_type,
mut_self,
)?,

View File

@ -25,7 +25,7 @@ use crate::{
Integer,
StatementResult,
};
use leo_ast::{Expression, Identifier, Span, Statement, Type};
use leo_ast::{Block, Expression, Identifier, Span, Type};
use snarkos_models::{
curves::{Field, PrimeField},
@ -46,7 +46,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
index: Identifier,
start: Expression,
stop: Expression,
statements: Vec<Statement>,
block: Block,
return_type: Option<Type>,
mut_self: bool,
span: &Span,
@ -68,12 +68,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
);
// Evaluate statements and possibly return early
let mut result = self.evaluate_branch(
let mut result = self.evaluate_block(
&mut cs.ns(|| format!("for loop iteration {} {}:{}", i, span.line, span.start)),
file_scope,
function_scope,
indicator,
statements.clone(),
block.clone(),
return_type.clone(),
mut_self,
)?;

View File

@ -19,8 +19,8 @@
pub mod assign;
pub use self::assign::*;
pub mod branch;
pub use self::branch::*;
pub mod block;
pub use self::block::*;
pub mod conditional;
pub use self::conditional::*;

View File

@ -96,7 +96,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
results.append(&mut result);
}
Statement::Iteration(index, start_stop, statements, span) => {
Statement::Iteration(index, start_stop, block, span) => {
let mut result = self.enforce_iteration_statement(
cs,
file_scope,
@ -105,7 +105,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
index,
start_stop.0,
start_stop.1,
statements,
block,
return_type,
mut_self,
&span,

View File

@ -229,8 +229,15 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
}
}
///
/// Modifies the `self` [ConstrainedValue] so there are no `mut` keywords wrapping the `self` value.
///
pub(crate) fn get_inner_mut(&mut self) {
if let ConstrainedValue::Mutable(inner) = self {
// Recursively remove `mut` keywords.
inner.get_inner_mut();
// Modify the value.
*self = *inner.clone()
}
}

View File

@ -0,0 +1,5 @@
function main () {
let mut x = 2u8;
let mut y = x;
let z = y / 2u8;
}

View File

@ -33,6 +33,14 @@ fn test_let_mut() {
assert_satisfied(program);
}
#[test]
fn test_let_mut_nested() {
let bytes = include_bytes!("let_mut_nested.leo");
let program = parse_program(bytes).unwrap();
assert_satisfied(program);
}
#[test]
fn test_const_fail() {
let bytes = include_bytes!("const.leo");

View File

@ -18,6 +18,7 @@ use crate::{CoreCircuit, CoreCircuitError, Value};
use leo_ast::{
ArrayDimensions,
Block,
Circuit,
CircuitMember,
Expression,
@ -105,23 +106,25 @@ impl CoreCircuit for Blake2sCircuit {
span: span.clone(),
}]),
)),
statements: vec![Statement::Return(
Expression::CoreFunctionCall(
Self::name(),
vec![
Expression::Identifier(Identifier {
name: "seed".to_owned(),
span: span.clone(),
}),
Expression::Identifier(Identifier {
name: "message".to_owned(),
span: span.clone(),
}),
],
block: Block {
statements: vec![Statement::Return(
Expression::CoreFunctionCall(
Self::name(),
vec![
Expression::Identifier(Identifier {
name: "seed".to_owned(),
span: span.clone(),
}),
Expression::Identifier(Identifier {
name: "message".to_owned(),
span: span.clone(),
}),
],
span.clone(),
),
span.clone(),
),
span.clone(),
)],
)],
},
span,
})],
}

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{ast::Rule, common::Identifier, functions::input::Input, statements::Statement, types::Type, SpanDef};
use crate::{ast::Rule, common::Identifier, functions::input::Input, statements::Block, types::Type, SpanDef};
use pest::Span;
use pest_ast::FromPest;
@ -26,7 +26,7 @@ pub struct Function<'ast> {
pub identifier: Identifier<'ast>,
pub parameters: Vec<Input<'ast>>,
pub returns: Option<Type<'ast>>,
pub statements: Vec<Statement<'ast>>,
pub block: Block<'ast>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,

View File

@ -396,9 +396,11 @@ statement = {
// Declared in statements/assign_statement.rs
statement_assign = { assignee ~ operation_assign ~ expression ~ LINE_END }
block = { "{" ~ NEWLINE* ~ statement* ~ NEWLINE* ~ "}" }
// Declared in statements/conditional_statement.rs
statement_conditional = {"if " ~ expression ~ "{" ~ NEWLINE* ~ statement+ ~ "}" ~ ("else " ~ conditional_nested_or_end_statement)?}
conditional_nested_or_end_statement = { statement_conditional | "{" ~ NEWLINE* ~ statement+ ~ "}"}
statement_conditional = {"if " ~ expression ~ block ~ ("else " ~ conditional_nested_or_end_statement)?}
conditional_nested_or_end_statement = { statement_conditional | block }
// Declared in statements/definition_statement.rs
statement_definition = { declare ~ variables ~ "=" ~ expression ~ LINE_END}
@ -407,7 +409,7 @@ statement_definition = { declare ~ variables ~ "=" ~ expression ~ LINE_END}
statement_expression = { expression ~ LINE_END }
// Declared in statements/for_statement.rs
statement_for = { "for " ~ identifier ~ "in " ~ expression ~ ".." ~ expression ~ "{" ~ NEWLINE* ~ statement+ ~ "}"}
statement_for = { "for " ~ identifier ~ "in " ~ expression ~ ".." ~ expression ~ block }
// Declared in statements/return_statement.rs
statement_return = { "return " ~ expression}
@ -418,7 +420,7 @@ statement_return = { "return " ~ expression}
test_function = { "test " ~ function }
// Declared in functions/function.rs
function = { "function " ~ identifier ~ input_tuple ~ ("->" ~ type_)? ~ "{" ~ NEWLINE* ~ statement* ~ NEWLINE* ~ "}" ~ NEWLINE* }
function = { "function " ~ identifier ~ input_tuple ~ ("->" ~ type_)? ~ block ~ NEWLINE* }
// Declared in functions/input/function_input.rs
function_input = { mutable? ~ identifier ~ ":" ~ type_ }

View File

@ -0,0 +1,45 @@
// Copyright (C) 2019-2020 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{ast::Rule, statements::Statement, SpanDef};
use pest::Span;
use pest_ast::FromPest;
use serde::Serialize;
use std::fmt;
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
#[pest_ast(rule(Rule::block))]
pub struct Block<'ast> {
pub statements: Vec<Statement<'ast>>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
}
impl<'ast> fmt::Display for Block<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "{{")?;
if self.statements.is_empty() {
writeln!(f, "\t")?;
} else {
self.statements
.iter()
.try_for_each(|statement| writeln!(f, "\t{}", statement))?;
}
write!(f, "}}")
}
}

View File

@ -16,7 +16,7 @@
use crate::{
ast::Rule,
statements::{ConditionalStatement, Statement},
statements::{Block, ConditionalStatement},
};
use pest_ast::FromPest;
@ -27,14 +27,14 @@ use std::fmt;
#[pest_ast(rule(Rule::conditional_nested_or_end_statement))]
pub enum ConditionalNestedOrEndStatement<'ast> {
Nested(Box<ConditionalStatement<'ast>>),
End(Vec<Statement<'ast>>),
End(Block<'ast>),
}
impl<'ast> fmt::Display for ConditionalNestedOrEndStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ConditionalNestedOrEndStatement::Nested(ref nested) => write!(f, "else {}", nested),
ConditionalNestedOrEndStatement::End(ref statements) => write!(f, "else {{\n \t{:#?}\n }}", statements),
ConditionalNestedOrEndStatement::End(ref block) => write!(f, "else {}", block),
}
}
}

View File

@ -17,7 +17,7 @@
use crate::{
ast::Rule,
expressions::Expression,
statements::{ConditionalNestedOrEndStatement, Statement},
statements::{Block, ConditionalNestedOrEndStatement},
SpanDef,
};
@ -30,7 +30,7 @@ use std::fmt;
#[pest_ast(rule(Rule::statement_conditional))]
pub struct ConditionalStatement<'ast> {
pub condition: Expression<'ast>,
pub statements: Vec<Statement<'ast>>,
pub block: Block<'ast>,
pub next: Option<ConditionalNestedOrEndStatement<'ast>>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
@ -39,11 +39,10 @@ pub struct ConditionalStatement<'ast> {
impl<'ast> fmt::Display for ConditionalStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "if ({}) {{", self.condition)?;
writeln!(f, "\t{:#?}", self.statements)?;
write!(f, "if ({}) {}", self.condition, self.block)?;
self.next
.as_ref()
.map(|n_or_e| write!(f, "}} {}", n_or_e))
.unwrap_or_else(|| write!(f, "}}"))
.map(|n_or_e| write!(f, " {}", n_or_e))
.unwrap_or_else(|| write!(f, ""))
}
}

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::{ast::Rule, common::Identifier, expressions::Expression, statements::Statement, SpanDef};
use crate::{ast::Rule, common::Identifier, expressions::Expression, statements::Block, SpanDef};
use pest::Span;
use pest_ast::FromPest;
@ -27,7 +27,7 @@ pub struct ForStatement<'ast> {
pub index: Identifier<'ast>,
pub start: Expression<'ast>,
pub stop: Expression<'ast>,
pub statements: Vec<Statement<'ast>>,
pub block: Block<'ast>,
#[pest_ast(outer())]
#[serde(with = "SpanDef")]
pub span: Span<'ast>,
@ -35,10 +35,6 @@ pub struct ForStatement<'ast> {
impl<'ast> fmt::Display for ForStatement<'ast> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"for {} in {}..{} {{ {:#?} }}",
self.index, self.start, self.stop, self.statements
)
write!(f, "for {} in {}..{} {}", self.index, self.start, self.stop, self.block)
}
}

View File

@ -37,3 +37,6 @@ pub use return_statement::*;
pub mod statement;
pub use statement::*;
pub mod block;
pub use block::*;

38
grammar/tests/display.rs Normal file
View File

@ -0,0 +1,38 @@
// Copyright (C) 2019-2020 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use from_pest::FromPest;
use leo_grammar::{
ast::{LanguageParser, Rule},
statements::ConditionalStatement,
};
use pest::*;
#[test]
fn conditional_statement_display() {
let input = r#"if (true) {
} else {
}"#;
let conditional_statement =
ConditionalStatement::from_pest(&mut LanguageParser::parse(Rule::statement_conditional, input).unwrap())
.unwrap();
let displayed = format!("{}", conditional_statement);
assert_eq!(input, displayed);
}

View File

@ -75,7 +75,7 @@ fn empty_def() {
input: "function x() {}",
rule: Rule::function,
tokens: [
function(0, 15, [identifier(9, 10, [])])
function(0, 15, [identifier(9, 10, []), block(13, 15, [])])
]
}
}
@ -87,7 +87,7 @@ fn returning_unit_type() {
input: "function x() -> () {}",
rule: Rule::function,
tokens: [
function(0, 21, [identifier(9, 10, []), type_(16, 18, [type_tuple(16, 18, [])])])
function(0, 21, [identifier(9, 10, []), type_(16, 18, [type_tuple(16, 18, [])]), block(19, 21, [])])
]
}
}
@ -99,8 +99,10 @@ fn returning_unit_value() {
input: "function x() { return () }",
rule: Rule::function,
tokens: [
function(0, 26, [identifier(9, 10, []), statement(15, 25, [
statement_return(15, 25, [expression(22, 25, [expression_term(22, 24, [expression_tuple(22, 24, [])])])])
function(0, 26, [identifier(9, 10, []), block(13, 26, [
statement(15, 25, [
statement_return(15, 25, [expression(22, 25, [expression_term(22, 24, [expression_tuple(22, 24, [])])])])
])
])])
]
}
@ -122,9 +124,11 @@ fn id_def() {
])
]),
type_(22, 24, [type_data(22, 24, [type_integer(22, 24, [type_integer_unsigned(22, 24, [type_u8(22, 24, [])])])])]),
statement(27, 36, [statement_return(27, 36, [
expression(34, 36, [expression_term(34, 35, [identifier(34, 35, [])])])
])])
block(25, 37, [
statement(27, 36, [statement_return(27, 36, [
expression(34, 36, [expression_term(34, 35, [identifier(34, 35, [])])])
])])
]),
])
]
}

View File

@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
mod display;
mod expression;
mod function;
mod serialization;

View File

@ -12,55 +12,62 @@
},
"parameters": [],
"returns": null,
"statements": [
{
"Return": {
"expression": {
"Binary": {
"operation": "Add",
"left": {
"Value": {
"Implicit": {
"Positive": {
"value": "1",
"span": {
"input": "1",
"start": 29,
"end": 30
"block": {
"statements": [
{
"Return": {
"expression": {
"Binary": {
"operation": "Add",
"left": {
"Value": {
"Implicit": {
"Positive": {
"value": "1",
"span": {
"input": "1",
"start": 29,
"end": 30
}
}
}
}
}
},
"right": {
"Value": {
"Implicit": {
"Positive": {
"value": "1",
"span": {
"input": "1",
"start": 33,
"end": 34
},
"right": {
"Value": {
"Implicit": {
"Positive": {
"value": "1",
"span": {
"input": "1",
"start": 33,
"end": 34
}
}
}
}
},
"span": {
"input": "1 + 1",
"start": 29,
"end": 34
}
},
"span": {
"input": "1 + 1",
"start": 29,
"end": 34
}
},
"span": {
"input": "return 1 + 1",
"start": 22,
"end": 34
}
},
"span": {
"input": "return 1 + 1",
"start": 22,
"end": 34
}
}
],
"span": {
"input": "{\n return 1 + 1\n}",
"start": 16,
"end": 36
}
],
},
"span": {
"input": "function main() {\n return 1 + 1\n}\n",
"start": 0,

View File

@ -19,3 +19,6 @@ pub use self::cli::*;
pub mod commands;
pub use self::commands::*;
pub mod updater;
pub use self::updater::*;

31
leo/errors/updater.rs Normal file
View File

@ -0,0 +1,31 @@
// Copyright (C) 2019-2020 Aleo Systems Inc.
// This file is part of the Leo library.
// The Leo library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// The Leo library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
#[derive(Debug, Error)]
pub enum UpdaterError {
#[error("{}: {}", _0, _1)]
Crate(&'static str, String),
#[error("The current version {} is more recent than the release version {}", _0, _1)]
OldReleaseVersion(String, String),
}
impl From<self_update::errors::Error> for UpdaterError {
fn from(error: self_update::errors::Error) -> Self {
tracing::error!("{}\n", error);
UpdaterError::Crate("self_update", error.to_string())
}
}

View File

@ -13,7 +13,7 @@
// You should have received a copy of the GNU General Public License
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::config::Config;
use crate::{config::Config, errors::UpdaterError};
use colored::Colorize;
use self_update::{backends::github, version::bump_is_greater, Status};
@ -27,7 +27,7 @@ impl Updater {
const LEO_REPO_OWNER: &'static str = "AleoHQ";
/// Show all available releases for `leo`.
pub fn show_available_releases() -> Result<(), self_update::errors::Error> {
pub fn show_available_releases() -> Result<(), UpdaterError> {
let releases = github::ReleaseList::configure()
.repo_owner(Self::LEO_REPO_OWNER)
.repo_name(Self::LEO_REPO_NAME)
@ -42,7 +42,7 @@ impl Updater {
}
/// Update `leo` to the latest release.
pub fn update_to_latest_release(show_output: bool) -> Result<Status, self_update::errors::Error> {
pub fn update_to_latest_release(show_output: bool) -> Result<Status, UpdaterError> {
let status = github::Update::configure()
.repo_owner(Self::LEO_REPO_OWNER)
.repo_name(Self::LEO_REPO_NAME)
@ -58,7 +58,7 @@ impl Updater {
}
/// Check if there is an available update for `leo` and return the newest release.
pub fn update_available() -> Result<Option<String>, self_update::errors::Error> {
pub fn update_available() -> Result<String, UpdaterError> {
let updater = github::Update::configure()
.repo_owner(Self::LEO_REPO_OWNER)
.repo_name(Self::LEO_REPO_NAME)
@ -70,9 +70,9 @@ impl Updater {
let latest_release = updater.get_latest_release()?;
if bump_is_greater(&current_version, &latest_release.version)? {
Ok(Some(latest_release.version))
Ok(latest_release.version)
} else {
Ok(None)
Err(UpdaterError::OldReleaseVersion(current_version, latest_release.version))
}
}
@ -89,7 +89,7 @@ impl Updater {
}
} else {
// If the auto update configuration is off, notify the user to update leo.
if let Some(latest_version) = Self::update_available().unwrap() {
if let Ok(latest_version) = Self::update_available() {
let mut message = "🟢 A new version is available! Run".bold().green().to_string();
message += &" `leo update` ".bold().white();
message += &format!("to update to v{}.", latest_version).bold().green();

View File

@ -19,6 +19,7 @@ use leo_ast::{
ArrayDimensions,
Assignee,
AssigneeAccess,
Block,
CircuitVariableDefinition,
ConditionalNestedOrEndStatement,
ConditionalStatement,
@ -42,7 +43,7 @@ pub struct Frame {
pub function_type: FunctionType,
pub self_type: Option<CircuitType>,
pub scopes: Vec<Scope>,
pub statements: Vec<Statement>,
pub block: Block,
pub type_assertions: Vec<TypeAssertion>,
pub user_defined_types: SymbolTable,
}
@ -77,7 +78,7 @@ impl Frame {
function_type,
self_type,
scopes,
statements: function.statements,
block: function.block,
type_assertions: vec![],
user_defined_types,
};
@ -117,7 +118,7 @@ impl Frame {
function_type,
self_type: Some(self_type),
scopes,
statements: function.statements,
block: function.block,
type_assertions: Vec::new(),
user_defined_types,
};
@ -230,7 +231,7 @@ impl Frame {
/// Collects a vector of `TypeAssertion` predicates from a vector of statements.
///
fn parse_statements(&mut self) -> Result<(), FrameError> {
for statement in self.statements.clone() {
for statement in self.block.statements.clone() {
self.parse_statement(&statement)?;
}
@ -248,8 +249,8 @@ impl Frame {
}
Statement::Assign(assignee, expression, span) => self.parse_assign(assignee, expression, span),
Statement::Conditional(conditional, span) => self.parse_statement_conditional(conditional, span),
Statement::Iteration(identifier, from_to, statements, span) => {
self.parse_iteration(identifier, from_to, statements, span)
Statement::Iteration(identifier, from_to, block, span) => {
self.parse_iteration(identifier, from_to, block, span)
}
Statement::Expression(expression, span) => self.parse_statement_expression(expression, span),
Statement::Console(_console_call) => Ok(()), // Console function calls do not generate type assertions.
@ -386,13 +387,13 @@ impl Frame {
///
/// Collects `TypeAssertion` predicates from a block of statements.
///
fn parse_block(&mut self, statements: &[Statement], _span: &Span) -> Result<(), FrameError> {
fn parse_block(&mut self, block: &Block, _span: &Span) -> Result<(), FrameError> {
// Push new scope.
let scope = Scope::new(self.scopes.last().cloned());
self.push_scope(scope);
// Parse all statements.
for statement in statements {
for statement in &block.statements {
self.parse_statement(&statement)?;
}
@ -420,7 +421,7 @@ impl Frame {
self.assert_equal(boolean_type, condition, span);
// Parse conditional statements.
self.parse_block(&conditional.statements, span)?;
self.parse_block(&conditional.block, span)?;
// Parse conditional or end.
if let Some(cond_or_end) = &conditional.next {
@ -451,7 +452,7 @@ impl Frame {
&mut self,
identifier: &Identifier,
from_to: &(Expression, Expression),
statements: &[Statement],
statements: &Block,
span: &Span,
) -> Result<(), FrameError> {
// Insert variable into symbol table with u32 type.