mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-29 05:02:52 +03:00
Merge pull request #495 from AleoHQ/statement-breakout
Statement Breakout
This commit is contained in:
commit
4c4338e38a
@ -17,12 +17,6 @@
|
||||
pub mod array_dimensions;
|
||||
pub use array_dimensions::*;
|
||||
|
||||
pub mod assignee;
|
||||
pub use assignee::*;
|
||||
|
||||
pub mod declare;
|
||||
pub use declare::*;
|
||||
|
||||
pub mod identifier;
|
||||
pub use identifier::*;
|
||||
|
||||
@ -46,9 +40,3 @@ pub use span::*;
|
||||
|
||||
pub mod spread_or_expression;
|
||||
pub use spread_or_expression::*;
|
||||
|
||||
pub mod variables;
|
||||
pub use variables::*;
|
||||
|
||||
pub mod variable_name;
|
||||
pub use variable_name::*;
|
||||
|
@ -1,58 +0,0 @@
|
||||
// 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::{Type, VariableName};
|
||||
use leo_grammar::common::Variables as GrammarVariables;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
/// A variable that is assigned to a value in the constrained program
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Variables {
|
||||
pub names: Vec<VariableName>,
|
||||
pub type_: Option<Type>,
|
||||
}
|
||||
|
||||
impl<'ast> From<GrammarVariables<'ast>> for Variables {
|
||||
fn from(variables: GrammarVariables<'ast>) -> Self {
|
||||
let names = variables.names.into_iter().map(VariableName::from).collect::<Vec<_>>();
|
||||
|
||||
let type_ = variables.type_.map(Type::from);
|
||||
|
||||
Self { names, type_ }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Variables {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if self.names.len() == 1 {
|
||||
// mut a
|
||||
write!(f, "{}", self.names[0])?;
|
||||
} else {
|
||||
// (a, mut b)
|
||||
let names = self.names.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",");
|
||||
|
||||
write!(f, "({})", names)?;
|
||||
}
|
||||
|
||||
if self.type_.is_some() {
|
||||
write!(f, ": {}", self.type_.as_ref().unwrap())?;
|
||||
}
|
||||
|
||||
write!(f, "")
|
||||
}
|
||||
}
|
@ -29,9 +29,6 @@ pub use self::circuits::*;
|
||||
pub mod common;
|
||||
pub use self::common::*;
|
||||
|
||||
pub mod console;
|
||||
pub use self::console::*;
|
||||
|
||||
pub mod errors;
|
||||
pub use self::errors::*;
|
||||
|
||||
|
@ -14,15 +14,19 @@
|
||||
// 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::{Identifier, PositiveNumber, RangeOrExpression, Span};
|
||||
use leo_grammar::{access::AssigneeAccess as GrammarAssigneeAccess, common::Assignee as GrammarAssignee};
|
||||
use crate::{Expression, Identifier, PositiveNumber, Span};
|
||||
use leo_grammar::{
|
||||
access::{ArrayAccess, AssigneeAccess as GrammarAssigneeAccess},
|
||||
common::{Assignee as GrammarAssignee, Range, RangeOrExpression},
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum AssigneeAccess {
|
||||
Array(RangeOrExpression),
|
||||
ArrayRange(Option<Expression>, Option<Expression>),
|
||||
ArrayIndex(Expression),
|
||||
Tuple(PositiveNumber, Span),
|
||||
Member(Identifier),
|
||||
}
|
||||
@ -30,7 +34,14 @@ pub enum AssigneeAccess {
|
||||
impl<'ast> From<GrammarAssigneeAccess<'ast>> for AssigneeAccess {
|
||||
fn from(access: GrammarAssigneeAccess<'ast>) -> Self {
|
||||
match access {
|
||||
GrammarAssigneeAccess::Array(array) => AssigneeAccess::Array(RangeOrExpression::from(array.expression)),
|
||||
GrammarAssigneeAccess::Array(ArrayAccess {
|
||||
expression: RangeOrExpression::Range(Range { from, to, .. }),
|
||||
..
|
||||
}) => AssigneeAccess::ArrayRange(from.map(Expression::from), to.map(Expression::from)),
|
||||
GrammarAssigneeAccess::Array(ArrayAccess {
|
||||
expression: RangeOrExpression::Expression(index),
|
||||
..
|
||||
}) => AssigneeAccess::ArrayIndex(Expression::from(index)),
|
||||
GrammarAssigneeAccess::Tuple(tuple) => {
|
||||
AssigneeAccess::Tuple(PositiveNumber::from(tuple.number), Span::from(tuple.span))
|
||||
}
|
||||
@ -74,7 +85,11 @@ impl fmt::Display for Assignee {
|
||||
|
||||
for access in &self.accesses {
|
||||
match access {
|
||||
AssigneeAccess::Array(expression) => write!(f, "[{}]", expression)?,
|
||||
AssigneeAccess::ArrayRange(Some(left), Some(right)) => write!(f, "[{}..{}]", left, right)?,
|
||||
AssigneeAccess::ArrayRange(None, Some(right)) => write!(f, "[..{}]", right)?,
|
||||
AssigneeAccess::ArrayRange(Some(left), None) => write!(f, "[{}..]", left)?,
|
||||
AssigneeAccess::ArrayRange(None, None) => write!(f, "[..]")?,
|
||||
AssigneeAccess::ArrayIndex(index) => write!(f, "[{}]", index)?,
|
||||
AssigneeAccess::Tuple(index, _span) => write!(f, ".{}", index)?,
|
||||
AssigneeAccess::Member(member) => write!(f, ".{}", member)?,
|
||||
}
|
90
ast/src/statements/assign/mod.rs
Normal file
90
ast/src/statements/assign/mod.rs
Normal file
@ -0,0 +1,90 @@
|
||||
// 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::{Expression, Node, Span};
|
||||
|
||||
pub use leo_grammar::operations::AssignOperation as GrammarAssignOperation;
|
||||
use leo_grammar::statements::AssignStatement as GrammarAssignStatement;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
mod assignee;
|
||||
pub use assignee::*;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub enum AssignOperation {
|
||||
Assign,
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Pow,
|
||||
}
|
||||
|
||||
impl AsRef<str> for AssignOperation {
|
||||
fn as_ref(&self) -> &'static str {
|
||||
match self {
|
||||
AssignOperation::Assign => "=",
|
||||
AssignOperation::Add => "+=",
|
||||
AssignOperation::Sub => "-=",
|
||||
AssignOperation::Mul => "*=",
|
||||
AssignOperation::Div => "/=",
|
||||
AssignOperation::Pow => "**=",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub struct AssignStatement {
|
||||
pub operation: AssignOperation,
|
||||
pub assignee: Assignee,
|
||||
pub value: Expression,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl fmt::Display for AssignStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} {} {};", self.assignee, self.operation.as_ref(), self.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<GrammarAssignStatement<'ast>> for AssignStatement {
|
||||
fn from(statement: GrammarAssignStatement<'ast>) -> Self {
|
||||
AssignStatement {
|
||||
operation: match statement.assign {
|
||||
GrammarAssignOperation::Assign(_) => AssignOperation::Assign,
|
||||
GrammarAssignOperation::AddAssign(_) => AssignOperation::Add,
|
||||
GrammarAssignOperation::SubAssign(_) => AssignOperation::Sub,
|
||||
GrammarAssignOperation::MulAssign(_) => AssignOperation::Mul,
|
||||
GrammarAssignOperation::DivAssign(_) => AssignOperation::Div,
|
||||
GrammarAssignOperation::PowAssign(_) => AssignOperation::Pow,
|
||||
},
|
||||
assignee: Assignee::from(statement.assignee),
|
||||
value: Expression::from(statement.expression),
|
||||
span: Span::from(statement.span),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for AssignStatement {
|
||||
fn span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
}
|
@ -14,21 +14,23 @@
|
||||
// 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 crate::{Node, Span, Statement};
|
||||
use leo_grammar::statements::Block as GrammarBlock;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub struct Block {
|
||||
pub statements: Vec<Statement>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl<'ast> From<GrammarBlock<'ast>> for Block {
|
||||
fn from(block: GrammarBlock<'ast>) -> Self {
|
||||
Block {
|
||||
statements: block.statements.into_iter().map(Statement::from).collect(),
|
||||
span: Span::from(block.span),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -46,3 +48,13 @@ impl fmt::Display for Block {
|
||||
write!(f, "}}")
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for Block {
|
||||
fn span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
}
|
||||
|
@ -14,17 +14,18 @@
|
||||
// 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::{Block, ConditionalNestedOrEndStatement, Expression};
|
||||
use leo_grammar::statements::ConditionalStatement as GrammarConditionalStatement;
|
||||
use crate::{Block, Expression, Node, Span, Statement};
|
||||
use leo_grammar::statements::{ConditionalNestedOrEndStatement, ConditionalStatement as GrammarConditionalStatement};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub struct ConditionalStatement {
|
||||
pub condition: Expression,
|
||||
pub block: Block,
|
||||
pub next: Option<ConditionalNestedOrEndStatement>,
|
||||
pub next: Option<Box<Statement>>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl<'ast> From<GrammarConditionalStatement<'ast>> for ConditionalStatement {
|
||||
@ -34,8 +35,14 @@ impl<'ast> From<GrammarConditionalStatement<'ast>> for ConditionalStatement {
|
||||
block: Block::from(statement.block),
|
||||
next: statement
|
||||
.next
|
||||
.map(|n_or_e| Some(ConditionalNestedOrEndStatement::from(n_or_e)))
|
||||
.unwrap_or(None),
|
||||
.map(|nested_statement| match nested_statement {
|
||||
ConditionalNestedOrEndStatement::Nested(conditional_statement) => {
|
||||
Statement::Conditional(ConditionalStatement::from(*conditional_statement))
|
||||
}
|
||||
ConditionalNestedOrEndStatement::End(block) => Statement::Block(Block::from(block)),
|
||||
})
|
||||
.map(Box::new),
|
||||
span: Span::from(statement.span),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -49,3 +56,13 @@ impl fmt::Display for ConditionalStatement {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for ConditionalStatement {
|
||||
fn span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
// 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::{Block, ConditionalStatement};
|
||||
use leo_grammar::statements::ConditionalNestedOrEndStatement as GrammarConditionalNestedOrEndStatement;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum ConditionalNestedOrEndStatement {
|
||||
Nested(Box<ConditionalStatement>),
|
||||
End(Block),
|
||||
}
|
||||
|
||||
impl<'ast> From<GrammarConditionalNestedOrEndStatement<'ast>> for ConditionalNestedOrEndStatement {
|
||||
fn from(statement: GrammarConditionalNestedOrEndStatement<'ast>) -> Self {
|
||||
match statement {
|
||||
GrammarConditionalNestedOrEndStatement::Nested(nested) => {
|
||||
ConditionalNestedOrEndStatement::Nested(Box::new(ConditionalStatement::from(*nested)))
|
||||
}
|
||||
GrammarConditionalNestedOrEndStatement::End(block) => {
|
||||
ConditionalNestedOrEndStatement::End(Block::from(block))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 block) => write!(f, "else {}", block),
|
||||
}
|
||||
}
|
||||
}
|
@ -14,35 +14,45 @@
|
||||
// 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::{ConsoleFunction, Span};
|
||||
use crate::{ConsoleFunction, Node, Span};
|
||||
use leo_grammar::console::ConsoleFunctionCall as GrammarConsoleFunctionCall;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ConsoleFunctionCall {
|
||||
pub struct ConsoleStatement {
|
||||
pub function: ConsoleFunction,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl<'ast> From<GrammarConsoleFunctionCall<'ast>> for ConsoleFunctionCall {
|
||||
impl<'ast> From<GrammarConsoleFunctionCall<'ast>> for ConsoleStatement {
|
||||
fn from(console: GrammarConsoleFunctionCall<'ast>) -> Self {
|
||||
ConsoleFunctionCall {
|
||||
ConsoleStatement {
|
||||
function: ConsoleFunction::from(console.function),
|
||||
span: Span::from(console.span),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ConsoleFunctionCall {
|
||||
impl fmt::Display for ConsoleStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "console.{};", self.function)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ConsoleFunctionCall {
|
||||
impl fmt::Debug for ConsoleStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "console.{};", self.function)
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for ConsoleStatement {
|
||||
fn span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
}
|
@ -14,13 +14,13 @@
|
||||
// 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::Span;
|
||||
use crate::{Node, Span};
|
||||
use leo_grammar::console::FormattedContainer as GrammarFormattedContainer;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub struct FormattedContainer {
|
||||
pub span: Span,
|
||||
}
|
||||
@ -38,3 +38,13 @@ impl fmt::Display for FormattedContainer {
|
||||
write!(f, "{{}}")
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for FormattedContainer {
|
||||
fn span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
}
|
@ -14,17 +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::{FormattedContainer, FormattedParameter, Span};
|
||||
use crate::{Expression, FormattedContainer, Node, Span};
|
||||
use leo_grammar::console::FormattedString as GrammarFormattedString;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub struct FormattedString {
|
||||
pub string: String,
|
||||
pub containers: Vec<FormattedContainer>,
|
||||
pub parameters: Vec<FormattedParameter>,
|
||||
pub parameters: Vec<Expression>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ impl<'ast> From<GrammarFormattedString<'ast>> for FormattedString {
|
||||
let string = formatted.string;
|
||||
let span = Span::from(formatted.span);
|
||||
let containers = formatted.containers.into_iter().map(FormattedContainer::from).collect();
|
||||
let parameters = formatted.parameters.into_iter().map(FormattedParameter::from).collect();
|
||||
let parameters = formatted.parameters.into_iter().map(Expression::from).collect();
|
||||
|
||||
Self {
|
||||
string,
|
||||
@ -49,3 +49,13 @@ impl fmt::Display for FormattedString {
|
||||
write!(f, "{}", self.string)
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for FormattedString {
|
||||
fn span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
}
|
@ -17,14 +17,11 @@
|
||||
pub mod console_function;
|
||||
pub use console_function::*;
|
||||
|
||||
pub mod console_function_call;
|
||||
pub use console_function_call::*;
|
||||
pub mod console_statement;
|
||||
pub use console_statement::*;
|
||||
|
||||
pub mod formatted_container;
|
||||
pub use formatted_container::*;
|
||||
|
||||
pub mod formatted_parameter;
|
||||
pub use formatted_parameter::*;
|
||||
|
||||
pub mod formatted_string;
|
||||
pub use formatted_string::*;
|
92
ast/src/statements/definition/mod.rs
Normal file
92
ast/src/statements/definition/mod.rs
Normal file
@ -0,0 +1,92 @@
|
||||
// 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::{Expression, Node, Span, Type};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
mod variable_name;
|
||||
pub use variable_name::*;
|
||||
|
||||
mod declare;
|
||||
pub use declare::*;
|
||||
use leo_grammar::statements::DefinitionStatement as GrammarDefinitionStatement;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub struct DefinitionStatement {
|
||||
pub declaration_type: Declare,
|
||||
pub variable_names: Vec<VariableName>,
|
||||
pub type_: Option<Type>,
|
||||
pub value: Expression,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl fmt::Display for DefinitionStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} ", self.declaration_type)?;
|
||||
if self.variable_names.len() == 1 {
|
||||
// mut a
|
||||
write!(f, "{}", self.variable_names[0])?;
|
||||
} else {
|
||||
// (a, mut b)
|
||||
let names = self
|
||||
.variable_names
|
||||
.iter()
|
||||
.map(|x| x.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(",");
|
||||
|
||||
write!(f, "({})", names)?;
|
||||
}
|
||||
|
||||
if self.type_.is_some() {
|
||||
write!(f, ": {}", self.type_.as_ref().unwrap())?;
|
||||
}
|
||||
write!(f, " = {};", self.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<GrammarDefinitionStatement<'ast>> for DefinitionStatement {
|
||||
fn from(statement: GrammarDefinitionStatement<'ast>) -> Self {
|
||||
let variable_names = statement
|
||||
.variables
|
||||
.names
|
||||
.into_iter()
|
||||
.map(VariableName::from)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let type_ = statement.variables.type_.map(Type::from);
|
||||
|
||||
DefinitionStatement {
|
||||
declaration_type: Declare::from(statement.declare),
|
||||
variable_names,
|
||||
type_,
|
||||
value: Expression::from(statement.expression),
|
||||
span: Span::from(statement.span),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for DefinitionStatement {
|
||||
fn span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
}
|
@ -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::common::{Identifier, Span};
|
||||
use crate::{Identifier, Node, Span};
|
||||
use leo_grammar::common::VariableName as GrammarVariableName;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -46,3 +46,13 @@ impl fmt::Display for VariableName {
|
||||
write!(f, "{}", self.identifier)
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for VariableName {
|
||||
fn span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
}
|
53
ast/src/statements/expression.rs
Normal file
53
ast/src/statements/expression.rs
Normal file
@ -0,0 +1,53 @@
|
||||
// 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::{Expression, Node, Span};
|
||||
|
||||
use leo_grammar::statements::ExpressionStatement as GrammarExpressionStatement;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub struct ExpressionStatement {
|
||||
pub expression: Expression,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl fmt::Display for ExpressionStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{};", self.expression)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<GrammarExpressionStatement<'ast>> for ExpressionStatement {
|
||||
fn from(statement: GrammarExpressionStatement<'ast>) -> Self {
|
||||
// why do we have this span-setting logic?
|
||||
let span = Span::from(statement.span);
|
||||
let mut expression = Expression::from(statement.expression);
|
||||
expression.set_span(span.clone());
|
||||
ExpressionStatement { expression, span }
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for ExpressionStatement {
|
||||
fn span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
}
|
62
ast/src/statements/iteration.rs
Normal file
62
ast/src/statements/iteration.rs
Normal file
@ -0,0 +1,62 @@
|
||||
// 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::{Block, Expression, Identifier, Node, Span};
|
||||
|
||||
use leo_grammar::statements::ForStatement;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub struct IterationStatement {
|
||||
pub variable: Identifier,
|
||||
pub start: Expression,
|
||||
pub stop: Expression,
|
||||
pub block: Block,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl fmt::Display for IterationStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"for {} in {}..{} {}",
|
||||
self.variable, self.start, self.stop, self.block
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<ForStatement<'ast>> for IterationStatement {
|
||||
fn from(statement: ForStatement<'ast>) -> Self {
|
||||
IterationStatement {
|
||||
variable: Identifier::from(statement.index),
|
||||
start: Expression::from(statement.start),
|
||||
stop: Expression::from(statement.stop),
|
||||
block: Block::from(statement.block),
|
||||
span: Span::from(statement.span),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for IterationStatement {
|
||||
fn span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
}
|
@ -14,14 +14,29 @@
|
||||
// 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/>.
|
||||
|
||||
pub mod conditional_nested_or_end_statement;
|
||||
pub use conditional_nested_or_end_statement::*;
|
||||
|
||||
pub mod conditional_statement;
|
||||
pub use conditional_statement::*;
|
||||
|
||||
pub mod statement;
|
||||
pub use statement::*;
|
||||
|
||||
pub mod conditional;
|
||||
pub use conditional::*;
|
||||
|
||||
pub mod block;
|
||||
pub use block::*;
|
||||
|
||||
pub mod return_statement;
|
||||
pub use return_statement::*;
|
||||
|
||||
pub mod iteration;
|
||||
pub use iteration::*;
|
||||
|
||||
pub mod expression;
|
||||
pub use expression::*;
|
||||
|
||||
pub mod definition;
|
||||
pub use definition::*;
|
||||
|
||||
pub mod console;
|
||||
pub use console::*;
|
||||
|
||||
pub mod assign;
|
||||
pub use assign::*;
|
||||
|
@ -14,29 +14,39 @@
|
||||
// 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::{Expression, Span};
|
||||
use leo_grammar::console::FormattedParameter as GrammarFormattedParameter;
|
||||
use crate::{Expression, Node, Span};
|
||||
|
||||
use leo_grammar::statements::ReturnStatement as GrammarReturnStatement;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct FormattedParameter {
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub struct ReturnStatement {
|
||||
pub expression: Expression,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl<'ast> From<GrammarFormattedParameter<'ast>> for FormattedParameter {
|
||||
fn from(parameter: GrammarFormattedParameter<'ast>) -> Self {
|
||||
Self {
|
||||
expression: Expression::from(parameter.expression),
|
||||
span: Span::from(parameter.span),
|
||||
impl fmt::Display for ReturnStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "return {}", self.expression)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<GrammarReturnStatement<'ast>> for ReturnStatement {
|
||||
fn from(statement: GrammarReturnStatement<'ast>) -> Self {
|
||||
ReturnStatement {
|
||||
expression: Expression::from(statement.expression),
|
||||
span: Span::from(statement.span),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for FormattedParameter {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.expression)
|
||||
impl Node for ReturnStatement {
|
||||
fn span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
}
|
@ -14,163 +14,83 @@
|
||||
// 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,
|
||||
BinaryExpression,
|
||||
BinaryOperation,
|
||||
Block,
|
||||
ConditionalStatement,
|
||||
ConsoleFunctionCall,
|
||||
Declare,
|
||||
Expression,
|
||||
Identifier,
|
||||
Node,
|
||||
Span,
|
||||
Variables,
|
||||
};
|
||||
use crate::{ConditionalStatement, Node, Span};
|
||||
|
||||
use leo_grammar::{
|
||||
console::ConsoleFunctionCall as GrammarConsoleFunctionCall,
|
||||
operations::AssignOperation,
|
||||
statements::{
|
||||
AssignStatement,
|
||||
DefinitionStatement,
|
||||
ExpressionStatement,
|
||||
ForStatement,
|
||||
ReturnStatement,
|
||||
Statement as GrammarStatement,
|
||||
},
|
||||
};
|
||||
use leo_grammar::statements::Statement as GrammarStatement;
|
||||
|
||||
use super::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
/// Program statement that defines some action (or expression) to be carried out.
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
pub enum Statement {
|
||||
Return(Expression, Span),
|
||||
Definition(Declare, Variables, Expression, Span),
|
||||
Assign(Assignee, Expression, Span),
|
||||
Conditional(ConditionalStatement, Span),
|
||||
Iteration(Identifier, Box<(Expression, Expression)>, Block, Span),
|
||||
Console(ConsoleFunctionCall),
|
||||
Expression(Expression, Span),
|
||||
}
|
||||
|
||||
impl<'ast> From<ReturnStatement<'ast>> for Statement {
|
||||
fn from(statement: ReturnStatement<'ast>) -> Self {
|
||||
Statement::Return(Expression::from(statement.expression), Span::from(statement.span))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<DefinitionStatement<'ast>> for Statement {
|
||||
fn from(statement: DefinitionStatement<'ast>) -> Self {
|
||||
let span = Span::from(statement.span);
|
||||
|
||||
Statement::Definition(
|
||||
Declare::from(statement.declare),
|
||||
Variables::from(statement.variables),
|
||||
Expression::from(statement.expression),
|
||||
span,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<AssignStatement<'ast>> for Statement {
|
||||
fn from(statement: AssignStatement<'ast>) -> Self {
|
||||
match statement.assign {
|
||||
AssignOperation::Assign(ref _assign) => Statement::Assign(
|
||||
Assignee::from(statement.assignee),
|
||||
Expression::from(statement.expression),
|
||||
Span::from(statement.span),
|
||||
),
|
||||
operation_assign => {
|
||||
// convert assignee into postfix expression
|
||||
let converted = Expression::from(statement.assignee.clone());
|
||||
|
||||
let operator = match operation_assign {
|
||||
AssignOperation::AddAssign(ref _assign) => BinaryOperation::Add,
|
||||
AssignOperation::SubAssign(ref _assign) => BinaryOperation::Sub,
|
||||
AssignOperation::MulAssign(ref _assign) => BinaryOperation::Mul,
|
||||
AssignOperation::DivAssign(ref _assign) => BinaryOperation::Div,
|
||||
AssignOperation::PowAssign(ref _assign) => BinaryOperation::Pow,
|
||||
AssignOperation::Assign(ref _assign) => unimplemented!("cannot assign twice to assign statement"),
|
||||
};
|
||||
|
||||
Statement::Assign(
|
||||
Assignee::from(statement.assignee),
|
||||
Expression::Binary(BinaryExpression {
|
||||
left: Box::new(converted),
|
||||
right: Box::new(Expression::from(statement.expression)),
|
||||
op: operator,
|
||||
span: Span::from(statement.span.clone()),
|
||||
}),
|
||||
Span::from(statement.span),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<ForStatement<'ast>> for Statement {
|
||||
fn from(statement: ForStatement<'ast>) -> Self {
|
||||
Statement::Iteration(
|
||||
Identifier::from(statement.index),
|
||||
Box::new((Expression::from(statement.start), Expression::from(statement.stop))),
|
||||
Block::from(statement.block),
|
||||
Span::from(statement.span),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<GrammarConsoleFunctionCall<'ast>> for Statement {
|
||||
fn from(function_call: GrammarConsoleFunctionCall<'ast>) -> Self {
|
||||
Statement::Console(ConsoleFunctionCall::from(function_call))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ast> From<ExpressionStatement<'ast>> for Statement {
|
||||
fn from(statement: ExpressionStatement<'ast>) -> Self {
|
||||
let span = Span::from(statement.span);
|
||||
let mut expression = Expression::from(statement.expression);
|
||||
|
||||
expression.set_span(span.clone());
|
||||
|
||||
Statement::Expression(expression, span)
|
||||
}
|
||||
Return(ReturnStatement),
|
||||
Definition(DefinitionStatement),
|
||||
Assign(AssignStatement),
|
||||
Conditional(ConditionalStatement),
|
||||
Iteration(IterationStatement),
|
||||
Console(ConsoleStatement),
|
||||
Expression(ExpressionStatement),
|
||||
Block(Block),
|
||||
}
|
||||
|
||||
impl<'ast> From<GrammarStatement<'ast>> for Statement {
|
||||
fn from(statement: GrammarStatement<'ast>) -> Self {
|
||||
match statement {
|
||||
GrammarStatement::Return(statement) => Statement::from(statement),
|
||||
GrammarStatement::Definition(statement) => Statement::from(statement),
|
||||
GrammarStatement::Assign(statement) => Statement::from(statement),
|
||||
GrammarStatement::Conditional(statement) => {
|
||||
let span = Span::from(statement.span.clone());
|
||||
Statement::Conditional(ConditionalStatement::from(statement), span)
|
||||
}
|
||||
GrammarStatement::Iteration(statement) => Statement::from(statement),
|
||||
GrammarStatement::Console(console) => Statement::from(console),
|
||||
GrammarStatement::Expression(statement) => Statement::from(statement),
|
||||
GrammarStatement::Return(statement) => Statement::Return(ReturnStatement::from(statement)),
|
||||
GrammarStatement::Definition(statement) => Statement::Definition(DefinitionStatement::from(statement)),
|
||||
GrammarStatement::Assign(statement) => Statement::Assign(AssignStatement::from(statement)),
|
||||
GrammarStatement::Conditional(statement) => Statement::Conditional(ConditionalStatement::from(statement)),
|
||||
GrammarStatement::Iteration(statement) => Statement::Iteration(IterationStatement::from(statement)),
|
||||
GrammarStatement::Console(statement) => Statement::Console(ConsoleStatement::from(statement)),
|
||||
GrammarStatement::Expression(statement) => Statement::Expression(ExpressionStatement::from(statement)),
|
||||
GrammarStatement::Block(statement) => Statement::Block(Block::from(statement)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Statement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Statement::Return(ref expression, ref _span) => write!(f, "return {}", expression),
|
||||
Statement::Definition(ref declare, ref variable, ref expression, ref _span) => {
|
||||
write!(f, "{} {} = {};", declare, variable, expression)
|
||||
}
|
||||
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 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),
|
||||
match self {
|
||||
Statement::Return(x) => x.fmt(f),
|
||||
Statement::Definition(x) => x.fmt(f),
|
||||
Statement::Assign(x) => x.fmt(f),
|
||||
Statement::Conditional(x) => x.fmt(f),
|
||||
Statement::Iteration(x) => x.fmt(f),
|
||||
Statement::Console(x) => x.fmt(f),
|
||||
Statement::Expression(x) => x.fmt(f),
|
||||
Statement::Block(x) => x.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for Statement {
|
||||
fn span(&self) -> &Span {
|
||||
use Statement::*;
|
||||
match &self {
|
||||
Return(n) => n.span(),
|
||||
Definition(n) => n.span(),
|
||||
Assign(n) => n.span(),
|
||||
Conditional(n) => n.span(),
|
||||
Iteration(n) => n.span(),
|
||||
Console(n) => n.span(),
|
||||
Expression(n) => n.span(),
|
||||
Block(n) => n.span(),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_span(&mut self, span: Span) {
|
||||
use Statement::*;
|
||||
match self {
|
||||
Return(n) => n.set_span(span),
|
||||
Definition(n) => n.set_span(span),
|
||||
Assign(n) => n.set_span(span),
|
||||
Conditional(n) => n.set_span(span),
|
||||
Iteration(n) => n.set_span(span),
|
||||
Console(n) => n.set_span(span),
|
||||
Expression(n) => n.set_span(span),
|
||||
Block(n) => n.set_span(span),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,8 @@
|
||||
"block" : {
|
||||
"statements": [
|
||||
{
|
||||
"Return": [
|
||||
{
|
||||
"Return": {
|
||||
"expression": {
|
||||
"Binary": {
|
||||
"left": {
|
||||
"Value": {
|
||||
@ -49,15 +49,21 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"span" : {
|
||||
"text": " return 1 + 1",
|
||||
"line": 2,
|
||||
"start": 5,
|
||||
"end": 17
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
"span" : {
|
||||
"text": " return 1 + 1",
|
||||
"line": 2,
|
||||
"start": 5,
|
||||
"end": 17
|
||||
}
|
||||
},
|
||||
"span": {
|
||||
"text": " function main() {",
|
||||
|
@ -17,7 +17,7 @@
|
||||
//! Evaluates a macro in a compiled Leo program.
|
||||
|
||||
use crate::{errors::ConsoleError, program::ConstrainedProgram, statement::get_indicator_value, GroupType};
|
||||
use leo_ast::{ConsoleFunction, ConsoleFunctionCall};
|
||||
use leo_ast::{ConsoleFunction, ConsoleStatement};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
@ -31,7 +31,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
indicator: &Boolean,
|
||||
console: ConsoleFunctionCall,
|
||||
console: ConsoleStatement,
|
||||
) -> Result<(), ConsoleError> {
|
||||
match console.function {
|
||||
ConsoleFunction::Assert(expression) => {
|
||||
|
@ -52,8 +52,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
let mut result = string.to_string();
|
||||
|
||||
for parameter in formatted.parameters.into_iter() {
|
||||
let parameter_value =
|
||||
self.enforce_expression(cs, file_scope, function_scope, None, parameter.expression)?;
|
||||
let parameter_value = self.enforce_expression(cs, file_scope, function_scope, None, parameter)?;
|
||||
|
||||
result = result.replacen("{}", ¶meter_value.to_string(), 1);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ pub fn generate_constraints<F: Field + PrimeField, G: GroupType<F>, CS: Constrai
|
||||
|
||||
match main.clone() {
|
||||
ConstrainedValue::Function(_circuit_identifier, function) => {
|
||||
let result = resolved_program.enforce_main_function(cs, &program_name, function, input)?;
|
||||
let result = resolved_program.enforce_main_function(cs, &program_name, *function, input)?;
|
||||
Ok(result)
|
||||
}
|
||||
_ => Err(CompilerError::NoMainFunction),
|
||||
|
@ -56,7 +56,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
let resolved_function_name = new_scope(program_name, &function_name.name);
|
||||
self.store(
|
||||
resolved_function_name,
|
||||
ConstrainedValue::Function(None, function.clone()),
|
||||
ConstrainedValue::Function(None, Box::new(function.clone())),
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -72,12 +72,36 @@ impl StatementError {
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn array_assign_interior_index(span: Span) -> Self {
|
||||
let message = "Cannot assign single index to interior of array of values".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn array_assign_range(span: Span) -> Self {
|
||||
let message = "Cannot assign range of array values to single value".to_string();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn array_assign_index_bounds(index: usize, length: usize, span: Span) -> Self {
|
||||
let message = format!(
|
||||
"Array assign index `{}` out of range for array of length `{}`",
|
||||
index, length
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn array_assign_range_order(start: usize, stop: usize, length: usize, span: Span) -> Self {
|
||||
let message = format!(
|
||||
"Array assign range `{}`..`{}` out of range for array of length `{}`",
|
||||
start, stop, length
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn conditional_boolean(actual: String, span: Span) -> Self {
|
||||
let message = format!("If, else conditional must resolve to a boolean, found `{}`", actual);
|
||||
|
||||
@ -166,6 +190,15 @@ impl StatementError {
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn tuple_assign_index_bounds(index: usize, length: usize, span: Span) -> Self {
|
||||
let message = format!(
|
||||
"Tuple assign index `{}` out of range for tuple of length `{}`",
|
||||
index, length
|
||||
);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn tuple_type(type_: String, span: Span) -> Self {
|
||||
let message = format!("Expected tuple type, found type `{}`", type_);
|
||||
|
||||
|
@ -82,7 +82,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
CircuitMember::CircuitFunction(function) => {
|
||||
let identifier = function.identifier.clone();
|
||||
let constrained_function_value =
|
||||
ConstrainedValue::Function(Some(circuit_identifier.clone()), function);
|
||||
ConstrainedValue::Function(Some(circuit_identifier.clone()), Box::new(function));
|
||||
|
||||
resolved_members.push(ConstrainedCircuitMember(identifier, constrained_function_value));
|
||||
}
|
||||
|
@ -72,6 +72,9 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
}
|
||||
};
|
||||
|
||||
Ok(ConstrainedValue::Function(Some(circuit.circuit_name), function))
|
||||
Ok(ConstrainedValue::Function(
|
||||
Some(circuit.circuit_name),
|
||||
Box::new(function),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
let name = new_scope(scope, &identifier.name);
|
||||
let value = ConstrainedValue::Import(
|
||||
program_name.to_owned(),
|
||||
Box::new(ConstrainedValue::Function(None, function.clone())),
|
||||
Box::new(ConstrainedValue::Function(None, Box::new(function.clone()))),
|
||||
);
|
||||
|
||||
self.store(name, value);
|
||||
@ -72,7 +72,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
match matched_function {
|
||||
Some((_function_name, function)) => ConstrainedValue::Import(
|
||||
program_name.to_owned(),
|
||||
Box::new(ConstrainedValue::Function(None, function.clone())),
|
||||
Box::new(ConstrainedValue::Function(None, Box::new(function.clone()))),
|
||||
),
|
||||
None => return Err(ImportError::unknown_symbol(symbol.to_owned(), program_name.to_owned())),
|
||||
}
|
||||
|
@ -1,105 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Enforces an array assignment statement in a compiled Leo program.
|
||||
|
||||
use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||
use leo_ast::{RangeOrExpression, Span};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::{
|
||||
r1cs::ConstraintSystem,
|
||||
utilities::{boolean::Boolean, select::CondSelectGadget},
|
||||
},
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn assign_array<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
indicator: &Boolean,
|
||||
name: &str,
|
||||
range_or_expression: RangeOrExpression,
|
||||
mut new_value: ConstrainedValue<F, G>,
|
||||
span: &Span,
|
||||
) -> Result<(), StatementError> {
|
||||
// Resolve index so we know if we are assigning to a single value or a range of values
|
||||
match range_or_expression {
|
||||
RangeOrExpression::Expression(index) => {
|
||||
let index = self.enforce_index(cs, file_scope, function_scope, index, span)?;
|
||||
|
||||
// Modify the single value of the array in place
|
||||
match self.get_mutable_assignee(name, &span)? {
|
||||
ConstrainedValue::Array(old) => {
|
||||
new_value.resolve_type(Some(old[index].to_type(&span)?), &span)?;
|
||||
|
||||
let selected_value = ConstrainedValue::conditionally_select(
|
||||
cs.ns(|| format!("select {} {}:{}", new_value, span.line, span.start)),
|
||||
indicator,
|
||||
&new_value,
|
||||
&old[index],
|
||||
)
|
||||
.map_err(|_| {
|
||||
StatementError::select_fail(new_value.to_string(), old[index].to_string(), span.to_owned())
|
||||
})?;
|
||||
|
||||
old[index] = selected_value;
|
||||
}
|
||||
_ => return Err(StatementError::array_assign_index(span.to_owned())),
|
||||
}
|
||||
}
|
||||
RangeOrExpression::Range(from, to) => {
|
||||
let from_index = match from {
|
||||
Some(integer) => self.enforce_index(cs, file_scope, function_scope, integer, span)?,
|
||||
None => 0usize,
|
||||
};
|
||||
let to_index_option = match to {
|
||||
Some(integer) => Some(self.enforce_index(cs, file_scope, function_scope, integer, span)?),
|
||||
None => None,
|
||||
};
|
||||
|
||||
// Modify the range of values of the array
|
||||
let old_array = self.get_mutable_assignee(name, &span)?;
|
||||
let new_array = match (old_array.clone(), new_value) {
|
||||
(ConstrainedValue::Array(mut mutable), ConstrainedValue::Array(new)) => {
|
||||
let to_index = to_index_option.unwrap_or(mutable.len());
|
||||
|
||||
mutable.splice(from_index..to_index, new.iter().cloned());
|
||||
ConstrainedValue::Array(mutable)
|
||||
}
|
||||
_ => return Err(StatementError::array_assign_range(span.to_owned())),
|
||||
};
|
||||
let selected_array = ConstrainedValue::conditionally_select(
|
||||
cs.ns(|| format!("select {} {}:{}", new_array, span.line, span.start)),
|
||||
indicator,
|
||||
&new_array,
|
||||
old_array,
|
||||
)
|
||||
.map_err(|_| {
|
||||
StatementError::select_fail(new_array.to_string(), old_array.to_string(), span.to_owned())
|
||||
})?;
|
||||
|
||||
*old_array = selected_array;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -17,14 +17,14 @@
|
||||
//! Enforces an assign statement in a compiled Leo program.
|
||||
|
||||
use crate::{
|
||||
assignee::resolve_assignee,
|
||||
arithmetic::*,
|
||||
errors::StatementError,
|
||||
new_scope,
|
||||
program::ConstrainedProgram,
|
||||
value::ConstrainedValue,
|
||||
GroupType,
|
||||
};
|
||||
use leo_ast::{Assignee, AssigneeAccess, Expression, Span};
|
||||
use leo_ast::{AssignOperation, AssignStatement, AssigneeAccess, Span};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
@ -44,71 +44,109 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
declared_circuit_reference: &str,
|
||||
indicator: &Boolean,
|
||||
mut_self: bool,
|
||||
assignee: Assignee,
|
||||
expression: Expression,
|
||||
span: &Span,
|
||||
statement: AssignStatement,
|
||||
) -> Result<(), StatementError> {
|
||||
// Get the name of the variable we are assigning to
|
||||
let variable_name = resolve_assignee(function_scope.to_string(), assignee.clone());
|
||||
let mut new_value = self.enforce_expression(cs, file_scope, function_scope, None, statement.value)?;
|
||||
let mut resolved_assignee = self.resolve_assignee(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope,
|
||||
declared_circuit_reference,
|
||||
mut_self,
|
||||
statement.assignee.clone(),
|
||||
)?;
|
||||
|
||||
// Evaluate new value
|
||||
let mut new_value = self.enforce_expression(cs, file_scope, function_scope, None, expression)?;
|
||||
if resolved_assignee.len() == 1 {
|
||||
new_value.resolve_type(Some(resolved_assignee[0].to_type(&statement.span)?), &statement.span)?;
|
||||
|
||||
// Mutate the old value into the new value
|
||||
if assignee.accesses.is_empty() {
|
||||
let old_value = self.get_mutable_assignee(&variable_name, span)?;
|
||||
let span = statement.span.clone();
|
||||
|
||||
new_value.resolve_type(Some(old_value.to_type(&span)?), span)?;
|
||||
|
||||
let selected_value = ConstrainedValue::conditionally_select(
|
||||
cs.ns(|| format!("select {} {}:{}", new_value, span.line, span.start)),
|
||||
Self::enforce_assign_operation(
|
||||
cs,
|
||||
indicator,
|
||||
&new_value,
|
||||
old_value,
|
||||
)
|
||||
.map_err(|_| StatementError::select_fail(new_value.to_string(), old_value.to_string(), span.to_owned()))?;
|
||||
|
||||
*old_value = selected_value;
|
||||
|
||||
Ok(())
|
||||
format!("select {} {}:{}", new_value, &span.line, &span.start),
|
||||
&statement.operation,
|
||||
resolved_assignee[0],
|
||||
new_value,
|
||||
&span,
|
||||
)?;
|
||||
} else {
|
||||
match assignee.accesses[0].clone() {
|
||||
AssigneeAccess::Array(range_or_expression) => self.assign_array(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope,
|
||||
indicator,
|
||||
&variable_name,
|
||||
range_or_expression,
|
||||
new_value,
|
||||
span,
|
||||
),
|
||||
AssigneeAccess::Tuple(index, span) => {
|
||||
self.assign_tuple(cs, indicator, &variable_name, index, new_value, &span)
|
||||
}
|
||||
AssigneeAccess::Member(identifier) => {
|
||||
// Mutate a circuit variable using the self keyword.
|
||||
if assignee.identifier.is_self() && mut_self {
|
||||
let self_circuit_variable_name = new_scope(&assignee.identifier.name, &identifier.name);
|
||||
let self_variable_name = new_scope(file_scope, &self_circuit_variable_name);
|
||||
let value = self.mutate_circuit_variable(
|
||||
match new_value {
|
||||
ConstrainedValue::Array(new_values) => {
|
||||
let span = statement.span.clone();
|
||||
|
||||
for (i, (old_ref, new_value)) in
|
||||
resolved_assignee.into_iter().zip(new_values.into_iter()).enumerate()
|
||||
{
|
||||
Self::enforce_assign_operation(
|
||||
cs,
|
||||
indicator,
|
||||
declared_circuit_reference,
|
||||
identifier,
|
||||
format!("select-splice {} {} {}:{}", i, new_value, &span.line, &span.start),
|
||||
&statement.operation,
|
||||
old_ref,
|
||||
new_value,
|
||||
span,
|
||||
&span,
|
||||
)?;
|
||||
|
||||
self.store(self_variable_name, value);
|
||||
} else {
|
||||
let _value =
|
||||
self.mutate_circuit_variable(cs, indicator, &variable_name, identifier, new_value, span)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
_ => return Err(StatementError::array_assign_range(statement.span)),
|
||||
};
|
||||
}
|
||||
|
||||
// self re-store logic -- structure is already checked by enforce_assign_operation
|
||||
if statement.assignee.identifier.is_self() && mut_self {
|
||||
if let Some(AssigneeAccess::Member(member_name)) = statement.assignee.accesses.get(0) {
|
||||
let self_circuit_variable_name = new_scope(&statement.assignee.identifier.name, &member_name.name);
|
||||
let self_variable_name = new_scope(file_scope, &self_circuit_variable_name);
|
||||
// get circuit ref
|
||||
let target = match self.get(declared_circuit_reference) {
|
||||
Some(ConstrainedValue::Mutable(value)) => &**value,
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
// get freshly assigned member ref, and clone it
|
||||
let source = match target {
|
||||
ConstrainedValue::CircuitExpression(_circuit_name, members) => {
|
||||
let matched_variable = members.iter().find(|member| &member.0 == member_name);
|
||||
|
||||
match matched_variable {
|
||||
Some(member) => &member.1,
|
||||
None => unimplemented!(),
|
||||
}
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
.clone();
|
||||
self.store(self_variable_name, source);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn enforce_assign_operation<CS: ConstraintSystem<F>>(
|
||||
cs: &mut CS,
|
||||
condition: &Boolean,
|
||||
scope: String,
|
||||
operation: &AssignOperation,
|
||||
target: &mut ConstrainedValue<F, G>,
|
||||
mut new_value: ConstrainedValue<F, G>,
|
||||
span: &Span,
|
||||
) -> Result<(), StatementError> {
|
||||
new_value.resolve_type(Some(target.to_type(span)?), span)?;
|
||||
|
||||
let new_value = match operation {
|
||||
AssignOperation::Assign => new_value,
|
||||
AssignOperation::Add => enforce_add(cs, target.clone(), new_value, span)?,
|
||||
AssignOperation::Sub => enforce_sub(cs, target.clone(), new_value, span)?,
|
||||
AssignOperation::Mul => enforce_mul(cs, target.clone(), new_value, span)?,
|
||||
AssignOperation::Div => enforce_div(cs, target.clone(), new_value, span)?,
|
||||
AssignOperation::Pow => enforce_pow(cs, target.clone(), new_value, span)?,
|
||||
};
|
||||
let selected_value = ConstrainedValue::conditionally_select(cs.ns(|| scope), condition, &new_value, target)
|
||||
.map_err(|_| StatementError::select_fail(new_value.to_string(), target.to_string(), span.clone()))?;
|
||||
|
||||
*target = selected_value;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -16,16 +16,223 @@
|
||||
|
||||
//! Resolves assignees in a compiled Leo program.
|
||||
|
||||
use crate::{errors::StatementError, new_scope, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||
use leo_ast::{Assignee, Span};
|
||||
use crate::{
|
||||
errors::StatementError,
|
||||
new_scope,
|
||||
parse_index,
|
||||
program::ConstrainedProgram,
|
||||
value::ConstrainedValue,
|
||||
GroupType,
|
||||
};
|
||||
use leo_ast::{Assignee, AssigneeAccess, Identifier, PositiveNumber, Span};
|
||||
|
||||
use snarkos_models::curves::{Field, PrimeField};
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::r1cs::ConstraintSystem,
|
||||
};
|
||||
|
||||
pub fn resolve_assignee(scope: String, assignee: Assignee) -> String {
|
||||
new_scope(&scope, &assignee.identifier().to_string())
|
||||
enum ResolvedAssigneeAccess {
|
||||
ArrayRange(Option<usize>, Option<usize>),
|
||||
ArrayIndex(usize),
|
||||
Tuple(PositiveNumber, Span),
|
||||
Member(Identifier),
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn resolve_assignee<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
declared_circuit_reference: &str,
|
||||
mut_self: bool,
|
||||
assignee: Assignee,
|
||||
) -> Result<Vec<&mut ConstrainedValue<F, G>>, StatementError> {
|
||||
let value_ref = if assignee.identifier.is_self() {
|
||||
if !mut_self {
|
||||
return Err(StatementError::immutable_assign("self".to_string(), assignee.span));
|
||||
}
|
||||
declared_circuit_reference.to_string()
|
||||
} else {
|
||||
new_scope(&function_scope, &assignee.identifier().to_string())
|
||||
};
|
||||
|
||||
let span = assignee.span.clone();
|
||||
let identifier_string = assignee.identifier.to_string();
|
||||
|
||||
let resolved_accesses = assignee
|
||||
.accesses
|
||||
.into_iter()
|
||||
.map(|access| match access {
|
||||
AssigneeAccess::ArrayRange(start, stop) => {
|
||||
let start_index = start
|
||||
.map(|start| self.enforce_index(cs, file_scope, function_scope, start, &span))
|
||||
.transpose()?;
|
||||
let stop_index = stop
|
||||
.map(|stop| self.enforce_index(cs, file_scope, function_scope, stop, &span))
|
||||
.transpose()?;
|
||||
Ok(ResolvedAssigneeAccess::ArrayRange(start_index, stop_index))
|
||||
}
|
||||
AssigneeAccess::ArrayIndex(index) => {
|
||||
let index = self.enforce_index(cs, file_scope, function_scope, index, &span)?;
|
||||
|
||||
Ok(ResolvedAssigneeAccess::ArrayIndex(index))
|
||||
}
|
||||
AssigneeAccess::Tuple(index, span) => Ok(ResolvedAssigneeAccess::Tuple(index, span)),
|
||||
AssigneeAccess::Member(identifier) => Ok(ResolvedAssigneeAccess::Member(identifier)),
|
||||
})
|
||||
.collect::<Result<Vec<_>, crate::errors::ExpressionError>>()?;
|
||||
|
||||
let mut result = vec![match self.get_mut(&value_ref) {
|
||||
Some(value) => match value {
|
||||
ConstrainedValue::Mutable(mutable) => &mut **mutable,
|
||||
_ => return Err(StatementError::immutable_assign(identifier_string, span)),
|
||||
},
|
||||
None => return Err(StatementError::undefined_variable(identifier_string, span)),
|
||||
}];
|
||||
|
||||
for access in resolved_accesses {
|
||||
result = Self::resolve_assignee_access(access, &span, result)?;
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn check_range_index(start_index: usize, stop_index: usize, len: usize, span: &Span) -> Result<(), StatementError> {
|
||||
if stop_index < start_index {
|
||||
Err(StatementError::array_assign_range_order(
|
||||
start_index,
|
||||
stop_index,
|
||||
len,
|
||||
span.clone(),
|
||||
))
|
||||
} else if start_index > len {
|
||||
Err(StatementError::array_assign_index_bounds(
|
||||
start_index,
|
||||
len,
|
||||
span.clone(),
|
||||
))
|
||||
} else if stop_index > len {
|
||||
Err(StatementError::array_assign_index_bounds(stop_index, len, span.clone()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// discards unnecessary mutable wrappers
|
||||
fn unwrap_mutable(input: &mut ConstrainedValue<F, G>) -> &mut ConstrainedValue<F, G> {
|
||||
match input {
|
||||
ConstrainedValue::Mutable(x) => &mut **x,
|
||||
x => x,
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_assignee_access<'a>(
|
||||
access: ResolvedAssigneeAccess,
|
||||
span: &Span,
|
||||
mut value: Vec<&'a mut ConstrainedValue<F, G>>,
|
||||
) -> Result<Vec<&'a mut ConstrainedValue<F, G>>, StatementError> {
|
||||
match access {
|
||||
ResolvedAssigneeAccess::ArrayIndex(index) => {
|
||||
if value.len() != 1 {
|
||||
return Err(StatementError::array_assign_interior_index(span.clone()));
|
||||
}
|
||||
match Self::unwrap_mutable(value.remove(0)) {
|
||||
ConstrainedValue::Array(old) => {
|
||||
if index > old.len() {
|
||||
Err(StatementError::array_assign_index_bounds(
|
||||
index,
|
||||
old.len(),
|
||||
span.clone(),
|
||||
))
|
||||
} else {
|
||||
Ok(vec![old.get_mut(index).unwrap()])
|
||||
}
|
||||
}
|
||||
_ => Err(StatementError::array_assign_index(span.clone())),
|
||||
}
|
||||
}
|
||||
ResolvedAssigneeAccess::ArrayRange(start_index, stop_index) => {
|
||||
let start_index = start_index.unwrap_or(0);
|
||||
|
||||
if value.len() == 1 {
|
||||
// not a range of a range
|
||||
match Self::unwrap_mutable(value.remove(0)) {
|
||||
ConstrainedValue::Array(old) => {
|
||||
let stop_index = stop_index.unwrap_or(old.len());
|
||||
Self::check_range_index(start_index, stop_index, old.len(), &span)?;
|
||||
|
||||
Ok(old[start_index..stop_index].iter_mut().collect())
|
||||
}
|
||||
_ => Err(StatementError::array_assign_index(span.clone())),
|
||||
}
|
||||
} else {
|
||||
// range of a range
|
||||
let stop_index = stop_index.unwrap_or(value.len());
|
||||
Self::check_range_index(start_index, stop_index, value.len(), &span)?;
|
||||
|
||||
Ok(value.drain(start_index..stop_index).map(Self::unwrap_mutable).collect())
|
||||
}
|
||||
}
|
||||
ResolvedAssigneeAccess::Tuple(index, span) => {
|
||||
let index = parse_index(&index, &span)?;
|
||||
|
||||
if value.len() != 1 {
|
||||
return Err(StatementError::array_assign_interior_index(span));
|
||||
}
|
||||
match Self::unwrap_mutable(value.remove(0)) {
|
||||
ConstrainedValue::Tuple(old) => {
|
||||
if index > old.len() {
|
||||
Err(StatementError::tuple_assign_index_bounds(index, old.len(), span))
|
||||
} else {
|
||||
Ok(vec![&mut old[index]])
|
||||
}
|
||||
}
|
||||
_ => Err(StatementError::tuple_assign_index(span)),
|
||||
}
|
||||
}
|
||||
ResolvedAssigneeAccess::Member(name) => {
|
||||
if value.len() != 1 {
|
||||
return Err(StatementError::array_assign_interior_index(span.clone()));
|
||||
}
|
||||
match Self::unwrap_mutable(value.remove(0)) {
|
||||
ConstrainedValue::CircuitExpression(_variable, members) => {
|
||||
// Modify the circuit variable in place
|
||||
let matched_variable = members.iter_mut().find(|member| member.0 == name);
|
||||
|
||||
match matched_variable {
|
||||
Some(member) => match &mut member.1 {
|
||||
ConstrainedValue::Function(_circuit_identifier, function) => {
|
||||
// Throw an error if we try to mutate a circuit function
|
||||
Err(StatementError::immutable_circuit_function(
|
||||
function.identifier.to_string(),
|
||||
span.to_owned(),
|
||||
))
|
||||
}
|
||||
ConstrainedValue::Static(_circuit_function) => {
|
||||
// Throw an error if we try to mutate a static circuit function
|
||||
Err(StatementError::immutable_circuit_function(
|
||||
"static".into(),
|
||||
span.to_owned(),
|
||||
))
|
||||
}
|
||||
value => Ok(vec![value]),
|
||||
},
|
||||
None => {
|
||||
// Throw an error if the circuit variable does not exist in the circuit
|
||||
Err(StatementError::undefined_circuit_variable(
|
||||
name.to_string(),
|
||||
span.to_owned(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
// Throw an error if the circuit definition does not exist in the file
|
||||
_ => Err(StatementError::undefined_circuit(name.to_string(), span.to_owned())),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_mutable_assignee(
|
||||
&mut self,
|
||||
name: &str,
|
||||
|
@ -1,105 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Enforces a circuit variable assignment statement in a compiled Leo program.
|
||||
|
||||
use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||
use leo_ast::{Identifier, Span};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::{
|
||||
r1cs::ConstraintSystem,
|
||||
utilities::{boolean::Boolean, select::CondSelectGadget},
|
||||
},
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn mutate_circuit_variable<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
indicator: &Boolean,
|
||||
circuit_name: &str,
|
||||
variable_name: Identifier,
|
||||
mut new_value: ConstrainedValue<F, G>,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<F, G>, StatementError> {
|
||||
// Get the mutable circuit by name
|
||||
match self.get_mutable_assignee(circuit_name, span)? {
|
||||
ConstrainedValue::CircuitExpression(_variable, members) => {
|
||||
// Modify the circuit variable in place
|
||||
let matched_variable = members.iter_mut().find(|member| member.0 == variable_name);
|
||||
|
||||
match matched_variable {
|
||||
Some(member) => match &member.1 {
|
||||
ConstrainedValue::Function(_circuit_identifier, function) => {
|
||||
// Throw an error if we try to mutate a circuit function
|
||||
Err(StatementError::immutable_circuit_function(
|
||||
function.identifier.to_string(),
|
||||
span.to_owned(),
|
||||
))
|
||||
}
|
||||
ConstrainedValue::Static(_circuit_function) => {
|
||||
// Throw an error if we try to mutate a static circuit function
|
||||
Err(StatementError::immutable_circuit_function(
|
||||
"static".into(),
|
||||
span.to_owned(),
|
||||
))
|
||||
}
|
||||
value => {
|
||||
// Check that the new value type == old value type
|
||||
new_value.resolve_type(Some(value.to_type(span)?), span)?;
|
||||
|
||||
// Conditionally select the value if this branch is executed.
|
||||
let mut selected_value = ConstrainedValue::conditionally_select(
|
||||
cs.ns(|| format!("select {} {}:{}", new_value, span.line, span.start)),
|
||||
indicator,
|
||||
&new_value,
|
||||
&member.1,
|
||||
)
|
||||
.map_err(|_| {
|
||||
StatementError::select_fail(
|
||||
new_value.to_string(),
|
||||
member.1.to_string(),
|
||||
span.to_owned(),
|
||||
)
|
||||
})?;
|
||||
|
||||
// Make sure the new value is still mutable
|
||||
selected_value = ConstrainedValue::Mutable(Box::new(selected_value));
|
||||
|
||||
member.1 = selected_value.to_owned();
|
||||
|
||||
Ok(selected_value)
|
||||
}
|
||||
},
|
||||
None => {
|
||||
// Throw an error if the circuit variable does not exist in the circuit
|
||||
Err(StatementError::undefined_circuit_variable(
|
||||
variable_name.to_string(),
|
||||
span.to_owned(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
// Throw an error if the circuit definition does not exist in the file
|
||||
_ => Err(StatementError::undefined_circuit(
|
||||
variable_name.to_string(),
|
||||
span.to_owned(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
@ -16,17 +16,8 @@
|
||||
|
||||
//! Methods to enforce constraints on assign statements in a compiled Leo program.
|
||||
|
||||
pub mod array;
|
||||
pub use self::array::*;
|
||||
|
||||
pub mod assign;
|
||||
pub use self::assign::*;
|
||||
|
||||
pub mod assignee;
|
||||
pub use self::assignee::*;
|
||||
|
||||
pub mod circuit_variable;
|
||||
pub use self::circuit_variable::*;
|
||||
|
||||
pub mod tuple;
|
||||
pub use self::tuple::*;
|
||||
|
@ -1,65 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Enforces a tuple assignment statement in a compiled Leo program.
|
||||
|
||||
use crate::{errors::StatementError, parse_index, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||
use leo_ast::{PositiveNumber, Span};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::{
|
||||
r1cs::ConstraintSystem,
|
||||
utilities::{boolean::Boolean, select::CondSelectGadget},
|
||||
},
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
pub fn assign_tuple<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
indicator: &Boolean,
|
||||
name: &str,
|
||||
index: PositiveNumber,
|
||||
mut new_value: ConstrainedValue<F, G>,
|
||||
span: &Span,
|
||||
) -> Result<(), StatementError> {
|
||||
// Parse the index.
|
||||
let index_usize = parse_index(&index, &span)?;
|
||||
|
||||
// Modify the single value of the tuple in place
|
||||
match self.get_mutable_assignee(name, &span)? {
|
||||
ConstrainedValue::Tuple(old) => {
|
||||
new_value.resolve_type(Some(old[index_usize].to_type(&span)?), &span)?;
|
||||
|
||||
let selected_value = ConstrainedValue::conditionally_select(
|
||||
cs.ns(|| format!("select {} {}:{}", new_value, span.line, span.start)),
|
||||
indicator,
|
||||
&new_value,
|
||||
&old[index_usize],
|
||||
)
|
||||
.map_err(|_| {
|
||||
StatementError::select_fail(new_value.to_string(), old[index_usize].to_string(), span.to_owned())
|
||||
})?;
|
||||
|
||||
old[index_usize] = selected_value;
|
||||
}
|
||||
_ => return Err(StatementError::tuple_assign_index(span.to_owned())),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -42,7 +42,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
let mut results = Vec::with_capacity(block.statements.len());
|
||||
// Evaluate statements. Only allow a single return argument to be returned.
|
||||
for statement in block.statements.into_iter() {
|
||||
let mut value = self.enforce_statement(
|
||||
let value = self.enforce_statement(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope,
|
||||
@ -53,7 +53,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
mut_self,
|
||||
)?;
|
||||
|
||||
results.append(&mut value);
|
||||
results.extend(value);
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
|
@ -24,7 +24,7 @@ use crate::{
|
||||
IndicatorAndConstrainedValue,
|
||||
StatementResult,
|
||||
};
|
||||
use leo_ast::{ConditionalNestedOrEndStatement, ConditionalStatement, Span, Type};
|
||||
use leo_ast::{ConditionalStatement, Type};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
@ -50,11 +50,10 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
indicator: &Boolean,
|
||||
statement: ConditionalStatement,
|
||||
return_type: Option<Type>,
|
||||
declared_circuit_reference: &str,
|
||||
mut_self: bool,
|
||||
span: &Span,
|
||||
statement: ConditionalStatement,
|
||||
) -> StatementResult<Vec<IndicatorAndConstrainedValue<F, G>>> {
|
||||
let statement_string = statement.to_string();
|
||||
|
||||
@ -70,7 +69,12 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
statement.condition.clone(),
|
||||
)? {
|
||||
ConstrainedValue::Boolean(resolved) => resolved,
|
||||
value => return Err(StatementError::conditional_boolean(value.to_string(), span.to_owned())),
|
||||
value => {
|
||||
return Err(StatementError::conditional_boolean(
|
||||
value.to_string(),
|
||||
statement.span.clone(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
// If outer_indicator && inner_indicator, then select branch 1
|
||||
@ -81,11 +85,16 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
outer_indicator_string, inner_indicator_string
|
||||
);
|
||||
let branch_1_indicator = Boolean::and(
|
||||
&mut cs.ns(|| format!("branch 1 {} {}:{}", statement_string, span.line, span.start)),
|
||||
&mut cs.ns(|| {
|
||||
format!(
|
||||
"branch 1 {} {}:{}",
|
||||
statement_string, &statement.span.line, &statement.span.start
|
||||
)
|
||||
}),
|
||||
outer_indicator,
|
||||
&inner_indicator,
|
||||
)
|
||||
.map_err(|_| StatementError::indicator_calculation(branch_1_name, span.to_owned()))?;
|
||||
.map_err(|_| StatementError::indicator_calculation(branch_1_name, statement.span.clone()))?;
|
||||
|
||||
let mut results = vec![];
|
||||
|
||||
@ -110,38 +119,26 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
"branch indicator 2 {} && {}",
|
||||
outer_indicator_string, inner_indicator_string
|
||||
);
|
||||
let span = statement.span.clone();
|
||||
let branch_2_indicator = Boolean::and(
|
||||
&mut cs.ns(|| format!("branch 2 {} {}:{}", statement_string, span.line, span.start)),
|
||||
&mut cs.ns(|| format!("branch 2 {} {}:{}", statement_string, &span.line, &span.start)),
|
||||
&outer_indicator,
|
||||
&inner_indicator,
|
||||
)
|
||||
.map_err(|_| StatementError::indicator_calculation(branch_2_name, span.to_owned()))?;
|
||||
.map_err(|_| StatementError::indicator_calculation(branch_2_name, span.clone()))?;
|
||||
|
||||
// Evaluate branch 2
|
||||
let mut branch_2_result = match statement.next {
|
||||
Some(next) => match next {
|
||||
ConditionalNestedOrEndStatement::Nested(nested) => self.enforce_conditional_statement(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope,
|
||||
&branch_2_indicator,
|
||||
*nested,
|
||||
return_type,
|
||||
declared_circuit_reference,
|
||||
mut_self,
|
||||
span,
|
||||
)?,
|
||||
ConditionalNestedOrEndStatement::End(block) => self.evaluate_block(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope,
|
||||
&branch_2_indicator,
|
||||
block,
|
||||
return_type,
|
||||
declared_circuit_reference,
|
||||
mut_self,
|
||||
)?,
|
||||
},
|
||||
Some(next) => self.enforce_statement(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope,
|
||||
&branch_2_indicator,
|
||||
*next,
|
||||
return_type,
|
||||
declared_circuit_reference,
|
||||
mut_self,
|
||||
)?,
|
||||
None => vec![],
|
||||
};
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
//! Enforces a definition statement in a compiled Leo program.
|
||||
|
||||
use crate::{errors::StatementError, program::ConstrainedProgram, ConstrainedValue, GroupType};
|
||||
use leo_ast::{Declare, Expression, Span, VariableName, Variables};
|
||||
use leo_ast::{Declare, DefinitionStatement, Span, VariableName};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
@ -53,19 +53,19 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
cs: &mut CS,
|
||||
function_scope: &str,
|
||||
is_constant: bool,
|
||||
variables: Variables,
|
||||
variable_names: Vec<VariableName>,
|
||||
values: Vec<ConstrainedValue<F, G>>,
|
||||
span: &Span,
|
||||
) -> Result<(), StatementError> {
|
||||
if values.len() != variables.names.len() {
|
||||
if values.len() != variable_names.len() {
|
||||
return Err(StatementError::invalid_number_of_definitions(
|
||||
values.len(),
|
||||
variables.names.len(),
|
||||
variable_names.len(),
|
||||
span.to_owned(),
|
||||
));
|
||||
}
|
||||
|
||||
for (variable, value) in variables.names.into_iter().zip(values.into_iter()) {
|
||||
for (variable, value) in variable_names.into_iter().zip(values.into_iter()) {
|
||||
self.enforce_single_definition(cs, function_scope, is_constant, variable, value, span)?;
|
||||
}
|
||||
|
||||
@ -78,33 +78,37 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
cs: &mut CS,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
declare: Declare,
|
||||
variables: Variables,
|
||||
expression: Expression,
|
||||
span: &Span,
|
||||
statement: DefinitionStatement,
|
||||
) -> Result<(), StatementError> {
|
||||
let num_variables = variables.names.len();
|
||||
let is_constant = match declare {
|
||||
let num_variables = statement.variable_names.len();
|
||||
let is_constant = match statement.declaration_type {
|
||||
Declare::Let => false,
|
||||
Declare::Const => true,
|
||||
};
|
||||
let expression =
|
||||
self.enforce_expression(cs, file_scope, function_scope, variables.type_.clone(), expression)?;
|
||||
self.enforce_expression(cs, file_scope, function_scope, statement.type_.clone(), statement.value)?;
|
||||
|
||||
if num_variables == 1 {
|
||||
// Define a single variable with a single value
|
||||
let variable = variables.names[0].clone();
|
||||
let variable = statement.variable_names[0].clone();
|
||||
|
||||
self.enforce_single_definition(cs, function_scope, is_constant, variable, expression, span)
|
||||
self.enforce_single_definition(cs, function_scope, is_constant, variable, expression, &statement.span)
|
||||
} else {
|
||||
// Define multiple variables for an expression that returns multiple results (multiple definition)
|
||||
let values = match expression {
|
||||
// ConstrainedValue::Return(values) => values,
|
||||
ConstrainedValue::Tuple(values) => values,
|
||||
value => return Err(StatementError::multiple_definition(value.to_string(), span.to_owned())),
|
||||
value => return Err(StatementError::multiple_definition(value.to_string(), statement.span)),
|
||||
};
|
||||
|
||||
self.enforce_multiple_definition(cs, function_scope, is_constant, variables, values, span)
|
||||
self.enforce_multiple_definition(
|
||||
cs,
|
||||
function_scope,
|
||||
is_constant,
|
||||
statement.variable_names,
|
||||
values,
|
||||
&statement.span,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ use crate::{
|
||||
Integer,
|
||||
StatementResult,
|
||||
};
|
||||
use leo_ast::{Block, Expression, Identifier, Span, Type};
|
||||
use leo_ast::{IterationStatement, Type};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
@ -43,25 +43,22 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
indicator: &Boolean,
|
||||
index: Identifier,
|
||||
start: Expression,
|
||||
stop: Expression,
|
||||
block: Block,
|
||||
return_type: Option<Type>,
|
||||
declared_circuit_reference: &str,
|
||||
mut_self: bool,
|
||||
span: &Span,
|
||||
statement: IterationStatement,
|
||||
) -> StatementResult<Vec<IndicatorAndConstrainedValue<F, G>>> {
|
||||
let mut results = vec![];
|
||||
|
||||
let from = self.enforce_index(cs, file_scope, function_scope, start, span)?;
|
||||
let to = self.enforce_index(cs, file_scope, function_scope, stop, span)?;
|
||||
let from = self.enforce_index(cs, file_scope, function_scope, statement.start, &statement.span)?;
|
||||
let to = self.enforce_index(cs, file_scope, function_scope, statement.stop, &statement.span)?;
|
||||
|
||||
let span = statement.span.clone();
|
||||
for i in from..to {
|
||||
// Store index in current function scope.
|
||||
// For loop scope is not implemented.
|
||||
|
||||
let index_name = new_scope(function_scope, &index.name);
|
||||
let index_name = new_scope(function_scope, &statement.variable.name);
|
||||
|
||||
self.store(
|
||||
index_name,
|
||||
@ -69,18 +66,18 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
);
|
||||
|
||||
// Evaluate statements and possibly return early
|
||||
let mut result = self.evaluate_block(
|
||||
&mut cs.ns(|| format!("for loop iteration {} {}:{}", i, span.line, span.start)),
|
||||
let result = self.evaluate_block(
|
||||
&mut cs.ns(|| format!("for loop iteration {} {}:{}", i, &span.line, &span.start)),
|
||||
file_scope,
|
||||
function_scope,
|
||||
indicator,
|
||||
block.clone(),
|
||||
statement.block.clone(),
|
||||
return_type.clone(),
|
||||
declared_circuit_reference,
|
||||
mut_self,
|
||||
)?;
|
||||
|
||||
results.append(&mut result);
|
||||
results.extend(result);
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
|
@ -17,7 +17,7 @@
|
||||
//! Enforces a return statement in a compiled Leo program.
|
||||
|
||||
use crate::{errors::StatementError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||
use leo_ast::{Expression, Span, Type};
|
||||
use leo_ast::{ReturnStatement, Span, Type};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
@ -43,15 +43,21 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
cs: &mut CS,
|
||||
file_scope: &str,
|
||||
function_scope: &str,
|
||||
expression: Expression,
|
||||
return_type: Option<Type>,
|
||||
span: &Span,
|
||||
statement: ReturnStatement,
|
||||
) -> Result<ConstrainedValue<F, G>, StatementError> {
|
||||
let result = self.enforce_operand(cs, file_scope, function_scope, return_type.clone(), expression, span)?;
|
||||
let result = self.enforce_operand(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope,
|
||||
return_type.clone(),
|
||||
statement.expression,
|
||||
&statement.span,
|
||||
)?;
|
||||
|
||||
// Make sure we return the correct type.
|
||||
if let Some(expected) = return_type {
|
||||
check_return_type(&expected, &result.to_type(span)?, span)?;
|
||||
check_return_type(&expected, &result.to_type(&statement.span)?, &statement.span)?;
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
|
@ -50,26 +50,18 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
let mut results = vec![];
|
||||
|
||||
match statement {
|
||||
Statement::Return(expression, span) => {
|
||||
Statement::Return(statement) => {
|
||||
let return_value = (
|
||||
indicator.to_owned(),
|
||||
self.enforce_return_statement(cs, file_scope, function_scope, expression, return_type, &span)?,
|
||||
*indicator,
|
||||
self.enforce_return_statement(cs, file_scope, function_scope, return_type, statement)?,
|
||||
);
|
||||
|
||||
results.push(return_value);
|
||||
}
|
||||
Statement::Definition(declare, variables, expressions, span) => {
|
||||
self.enforce_definition_statement(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope,
|
||||
declare,
|
||||
variables,
|
||||
expressions,
|
||||
&span,
|
||||
)?;
|
||||
Statement::Definition(statement) => {
|
||||
self.enforce_definition_statement(cs, file_scope, function_scope, statement)?;
|
||||
}
|
||||
Statement::Assign(variable, expression, span) => {
|
||||
Statement::Assign(statement) => {
|
||||
self.enforce_assign_statement(
|
||||
cs,
|
||||
file_scope,
|
||||
@ -77,60 +69,67 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
declared_circuit_reference,
|
||||
indicator,
|
||||
mut_self,
|
||||
variable,
|
||||
expression,
|
||||
&span,
|
||||
statement,
|
||||
)?;
|
||||
}
|
||||
Statement::Conditional(statement, span) => {
|
||||
let mut result = self.enforce_conditional_statement(
|
||||
Statement::Conditional(statement) => {
|
||||
let result = self.enforce_conditional_statement(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope,
|
||||
indicator,
|
||||
return_type,
|
||||
declared_circuit_reference,
|
||||
mut_self,
|
||||
statement,
|
||||
)?;
|
||||
|
||||
results.extend(result);
|
||||
}
|
||||
Statement::Iteration(statement) => {
|
||||
let result = self.enforce_iteration_statement(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope,
|
||||
indicator,
|
||||
return_type,
|
||||
declared_circuit_reference,
|
||||
mut_self,
|
||||
statement,
|
||||
)?;
|
||||
|
||||
results.extend(result);
|
||||
}
|
||||
Statement::Console(statement) => {
|
||||
self.evaluate_console_function_call(cs, file_scope, function_scope, indicator, statement)?;
|
||||
}
|
||||
Statement::Expression(statement) => {
|
||||
let expression_string = statement.expression.to_string();
|
||||
let value = self.enforce_expression(cs, file_scope, function_scope, None, statement.expression)?;
|
||||
// handle empty return value cases
|
||||
match &value {
|
||||
ConstrainedValue::Tuple(values) => {
|
||||
if !values.is_empty() {
|
||||
results.push((*indicator, value));
|
||||
}
|
||||
}
|
||||
_ => return Err(StatementError::unassigned(expression_string, statement.span)),
|
||||
}
|
||||
}
|
||||
Statement::Block(statement) => {
|
||||
let span = statement.span.clone();
|
||||
let result = self.evaluate_block(
|
||||
&mut cs.ns(|| format!("block {}:{}", &span.line, &span.start)),
|
||||
file_scope,
|
||||
function_scope,
|
||||
indicator,
|
||||
statement,
|
||||
return_type,
|
||||
declared_circuit_reference,
|
||||
mut_self,
|
||||
&span,
|
||||
)?;
|
||||
|
||||
results.append(&mut result);
|
||||
}
|
||||
Statement::Iteration(index, start_stop, block, span) => {
|
||||
let mut result = self.enforce_iteration_statement(
|
||||
cs,
|
||||
file_scope,
|
||||
function_scope,
|
||||
indicator,
|
||||
index,
|
||||
start_stop.0,
|
||||
start_stop.1,
|
||||
block,
|
||||
return_type,
|
||||
declared_circuit_reference,
|
||||
mut_self,
|
||||
&span,
|
||||
)?;
|
||||
|
||||
results.append(&mut result);
|
||||
}
|
||||
Statement::Console(console) => {
|
||||
self.evaluate_console_function_call(cs, file_scope, function_scope, indicator, console)?;
|
||||
}
|
||||
Statement::Expression(expression, span) => {
|
||||
let expression_string = expression.to_string();
|
||||
let value = self.enforce_expression(cs, file_scope, function_scope, None, expression)?;
|
||||
|
||||
// Handle empty return value cases.
|
||||
match &value {
|
||||
ConstrainedValue::Tuple(values) => {
|
||||
if !values.is_empty() {
|
||||
results.push((*indicator, value));
|
||||
}
|
||||
}
|
||||
_ => return Err(StatementError::unassigned(expression_string, span)),
|
||||
}
|
||||
results.extend(result);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -62,7 +62,7 @@ pub enum ConstrainedValue<F: Field + PrimeField, G: GroupType<F>> {
|
||||
CircuitExpression(Identifier, Vec<ConstrainedCircuitMember<F, G>>),
|
||||
|
||||
// Functions
|
||||
Function(Option<Identifier>, Function), // (optional circuit identifier, function definition)
|
||||
Function(Option<Identifier>, Box<Function>), // (optional circuit identifier, function definition)
|
||||
|
||||
// Modifiers
|
||||
Mutable(Box<ConstrainedValue<F, G>>),
|
||||
@ -214,7 +214,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedValue<F, G> {
|
||||
}
|
||||
}
|
||||
|
||||
Ok((outer_scope, function))
|
||||
Ok((outer_scope, *function))
|
||||
}
|
||||
ConstrainedValue::Import(import_scope, function) => function.extract_function(&import_scope, span),
|
||||
value => Err(ExpressionError::undefined_function(value.to_string(), span.to_owned())),
|
||||
|
9
compiler/tests/mutability/array_splice_mut.leo
Normal file
9
compiler/tests/mutability/array_splice_mut.leo
Normal file
@ -0,0 +1,9 @@
|
||||
// Adding the `mut` keyword makes an array variable mutable.
|
||||
function main() {
|
||||
let mut a = [1u32, 2u32, 3u32];
|
||||
a[0u32..2u32] = [4u32, 5u32];
|
||||
|
||||
console.assert(a[0] == 4u32);
|
||||
console.assert(a[1] == 5u32);
|
||||
console.assert(a[2] == 3u32);
|
||||
}
|
8
compiler/tests/mutability/array_tuple_mut.leo
Normal file
8
compiler/tests/mutability/array_tuple_mut.leo
Normal file
@ -0,0 +1,8 @@
|
||||
// Adding the `mut` keyword makes an array variable mutable.
|
||||
function main() {
|
||||
let mut a = [(1u32, 2u32)];
|
||||
a[0u32].1 = 3u32;
|
||||
|
||||
console.assert(a[0u32].0 == 1u32);
|
||||
console.assert(a[0u32].1 == 3u32);
|
||||
}
|
@ -73,6 +73,22 @@ fn test_array_mut() {
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_tuple_mut() {
|
||||
let bytes = include_str!("array_tuple_mut.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_array_splice_mut() {
|
||||
let bytes = include_str!("array_splice_mut.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_circuit() {
|
||||
let program_string = include_str!("circuit.leo");
|
||||
|
9
compiler/tests/statements/block.leo
Normal file
9
compiler/tests/statements/block.leo
Normal file
@ -0,0 +1,9 @@
|
||||
function main() {
|
||||
let mut x = 4u32;
|
||||
|
||||
{
|
||||
x = 5u32;
|
||||
}
|
||||
|
||||
console.assert(x == 5u32);
|
||||
}
|
@ -64,3 +64,11 @@ fn test_num_returns_fail() {
|
||||
|
||||
expect_type_inference_error(error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_block() {
|
||||
let bytes = include_str!("block.leo");
|
||||
let program = parse_program(bytes).unwrap();
|
||||
|
||||
assert_satisfied(program);
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ use leo_ast::{
|
||||
Identifier,
|
||||
IntegerType,
|
||||
PositiveNumber,
|
||||
ReturnStatement,
|
||||
Span,
|
||||
Statement,
|
||||
Type,
|
||||
@ -110,8 +111,8 @@ impl CoreCircuit for Blake2sCircuit {
|
||||
}]),
|
||||
)),
|
||||
block: Block {
|
||||
statements: vec![Statement::Return(
|
||||
Expression::Call(CallExpression {
|
||||
statements: vec![Statement::Return(ReturnStatement {
|
||||
expression: Expression::Call(CallExpression {
|
||||
function: Box::new(Expression::Identifier(Identifier::new_with_span(&Self::name(), &span))),
|
||||
arguments: vec![
|
||||
Expression::Identifier(Identifier::new_with_span("seed", &span)),
|
||||
@ -119,8 +120,9 @@ impl CoreCircuit for Blake2sCircuit {
|
||||
],
|
||||
span: span.clone(),
|
||||
}),
|
||||
span.clone(),
|
||||
)],
|
||||
span: span.clone(),
|
||||
})],
|
||||
span: span.clone(),
|
||||
},
|
||||
span,
|
||||
})],
|
||||
|
@ -1,37 +0,0 @@
|
||||
// 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, expressions::Expression, SpanDef};
|
||||
|
||||
use pest::Span;
|
||||
use pest_ast::FromPest;
|
||||
use serde::Serialize;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq, Serialize)]
|
||||
#[pest_ast(rule(Rule::formatted_parameter))]
|
||||
pub struct FormattedParameter<'ast> {
|
||||
pub expression: Expression<'ast>,
|
||||
#[pest_ast(outer())]
|
||||
#[serde(with = "SpanDef")]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for FormattedParameter<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.expression)
|
||||
}
|
||||
}
|
@ -16,7 +16,8 @@
|
||||
|
||||
use crate::{
|
||||
ast::{span_into_string, Rule},
|
||||
console::{FormattedContainer, FormattedParameter},
|
||||
console::FormattedContainer,
|
||||
expressions::Expression,
|
||||
SpanDef,
|
||||
};
|
||||
|
||||
@ -31,7 +32,7 @@ pub struct FormattedString<'ast> {
|
||||
#[pest_ast(outer(with(span_into_string)))]
|
||||
pub string: String,
|
||||
pub containers: Vec<FormattedContainer<'ast>>,
|
||||
pub parameters: Vec<FormattedParameter<'ast>>,
|
||||
pub parameters: Vec<Expression<'ast>>,
|
||||
#[pest_ast(outer())]
|
||||
#[serde(with = "SpanDef")]
|
||||
pub span: Span<'ast>,
|
||||
|
@ -38,8 +38,5 @@ pub use console_log::*;
|
||||
pub mod formatted_container;
|
||||
pub use formatted_container::*;
|
||||
|
||||
pub mod formatted_parameter;
|
||||
pub use formatted_parameter::*;
|
||||
|
||||
pub mod formatted_string;
|
||||
pub use formatted_string::*;
|
||||
|
@ -390,6 +390,7 @@ statement = {
|
||||
| statement_definition
|
||||
| statement_assign
|
||||
| statement_expression
|
||||
| block
|
||||
) ~ NEWLINE*
|
||||
}
|
||||
|
||||
@ -504,15 +505,12 @@ formatted_string = {
|
||||
"\""
|
||||
~ (!"\"" ~ (formatted_container | ANY))*
|
||||
~ "\""
|
||||
~ ("," ~ formatted_parameter)*
|
||||
~ ("," ~ expression)*
|
||||
}
|
||||
|
||||
// Declared in console/formatted_container.rs
|
||||
formatted_container = { "{" ~ "}"}
|
||||
|
||||
// Declared in console/formatted_parameter.rs
|
||||
formatted_parameter = { expression }
|
||||
|
||||
/// Annotations
|
||||
|
||||
// Declared in annotations/annotation.rs
|
||||
|
@ -30,6 +30,7 @@ pub enum Statement<'ast> {
|
||||
Iteration(ForStatement<'ast>),
|
||||
Console(ConsoleFunctionCall<'ast>),
|
||||
Expression(ExpressionStatement<'ast>),
|
||||
Block(Block<'ast>),
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for Statement<'ast> {
|
||||
@ -42,6 +43,7 @@ impl<'ast> fmt::Display for Statement<'ast> {
|
||||
Statement::Iteration(ref statement) => write!(f, "{}", statement),
|
||||
Statement::Console(ref statement) => write!(f, "{}", statement),
|
||||
Statement::Expression(ref statement) => write!(f, "{}", statement.expression),
|
||||
Statement::Block(ref block) => write!(f, "{}", block),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,24 +17,19 @@
|
||||
use crate::{FrameError, Scope, TypeAssertion};
|
||||
use leo_ast::{
|
||||
expression::*,
|
||||
statements::*,
|
||||
ArrayDimensions,
|
||||
Assignee,
|
||||
AssigneeAccess,
|
||||
Block,
|
||||
CircuitVariableDefinition,
|
||||
ConditionalNestedOrEndStatement,
|
||||
ConditionalStatement,
|
||||
Declare,
|
||||
Expression,
|
||||
Function,
|
||||
Identifier,
|
||||
IntegerType,
|
||||
PositiveNumber,
|
||||
RangeOrExpression,
|
||||
Span,
|
||||
SpreadOrExpression,
|
||||
Statement,
|
||||
Variables,
|
||||
};
|
||||
use leo_symbol_table::{CircuitType, FunctionType, SymbolTable, Type, TypeVariable};
|
||||
|
||||
@ -244,24 +239,21 @@ impl Frame {
|
||||
///
|
||||
fn parse_statement(&mut self, statement: &Statement) -> Result<(), FrameError> {
|
||||
match statement {
|
||||
Statement::Return(expression, span) => self.parse_return(expression, span),
|
||||
Statement::Definition(declare, variables, expression, span) => {
|
||||
self.parse_definition(declare, variables, expression, span)
|
||||
}
|
||||
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, block, span) => {
|
||||
self.parse_iteration(identifier, from_to, block, span)
|
||||
}
|
||||
Statement::Expression(expression, span) => self.parse_statement_expression(expression, span),
|
||||
Statement::Return(statement) => self.parse_return(statement),
|
||||
Statement::Definition(statement) => self.parse_definition(statement),
|
||||
Statement::Assign(statement) => self.parse_assign(statement),
|
||||
Statement::Conditional(statement) => self.parse_statement_conditional(statement),
|
||||
Statement::Iteration(statement) => self.parse_iteration(statement),
|
||||
Statement::Expression(statement) => self.parse_statement_expression(statement),
|
||||
Statement::Console(_console_call) => Ok(()), // Console function calls do not generate type assertions.
|
||||
Statement::Block(statement) => self.parse_block(statement),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Collects `TypeAssertion` predicates from a return statement.
|
||||
///
|
||||
fn parse_return(&mut self, expression: &Expression, span: &Span) -> Result<(), FrameError> {
|
||||
fn parse_return(&mut self, statement: &ReturnStatement) -> Result<(), FrameError> {
|
||||
// Get the function output type.
|
||||
let output_type = &self.function_type.output.type_;
|
||||
|
||||
@ -269,10 +261,10 @@ impl Frame {
|
||||
let left = output_type.clone();
|
||||
|
||||
// Create the right hand side from the statement return expression.
|
||||
let right = self.parse_expression(expression)?;
|
||||
let right = self.parse_expression(&statement.expression)?;
|
||||
|
||||
// Create a new type assertion for the statement return.
|
||||
self.assert_equal(left, right, span);
|
||||
self.assert_equal(left, right, &statement.span);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -280,58 +272,52 @@ impl Frame {
|
||||
///
|
||||
/// Collects `Type Assertion` predicates from a definition statement.
|
||||
///
|
||||
fn parse_definition(
|
||||
&mut self,
|
||||
_declare: &Declare,
|
||||
variables: &Variables,
|
||||
expression: &Expression,
|
||||
span: &Span,
|
||||
) -> Result<(), FrameError> {
|
||||
fn parse_definition(&mut self, statement: &DefinitionStatement) -> Result<(), FrameError> {
|
||||
// Parse the definition expression.
|
||||
let actual_type = self.parse_expression(expression)?;
|
||||
let actual_type = self.parse_expression(&statement.value)?;
|
||||
|
||||
// Check if an explicit type is given.
|
||||
if let Some(type_) = variables.type_.clone() {
|
||||
if let Some(type_) = statement.type_.clone() {
|
||||
// Check the expected type.
|
||||
let expected_type = match self.self_type {
|
||||
Some(ref circuit_type) => Type::new_from_circuit(
|
||||
&self.user_defined_types,
|
||||
type_,
|
||||
circuit_type.identifier.clone(),
|
||||
span.clone(),
|
||||
statement.span.clone(),
|
||||
)
|
||||
.unwrap(),
|
||||
None => Type::new(&self.user_defined_types, type_, span.clone()).unwrap(),
|
||||
None => Type::new(&self.user_defined_types, type_, statement.span.clone()).unwrap(),
|
||||
};
|
||||
|
||||
// Assert that the expected type is equal to the actual type.
|
||||
self.assert_equal(expected_type, actual_type.clone(), span)
|
||||
self.assert_equal(expected_type, actual_type.clone(), &statement.span)
|
||||
}
|
||||
|
||||
// Check for multiple defined variables.
|
||||
if variables.names.len() == 1 {
|
||||
if statement.variable_names.len() == 1 {
|
||||
// Insert variable into symbol table
|
||||
let variable = variables.names[0].clone();
|
||||
self.insert_variable(variable.identifier.name, actual_type, span)?;
|
||||
let variable = statement.variable_names[0].clone();
|
||||
self.insert_variable(variable.identifier.name, actual_type, &statement.span)?;
|
||||
} else {
|
||||
// Expect a tuple type.
|
||||
let types = match actual_type {
|
||||
Type::Tuple(types) => types,
|
||||
_ => return Err(FrameError::not_enough_values(span)),
|
||||
_ => return Err(FrameError::not_enough_values(&statement.span)),
|
||||
};
|
||||
|
||||
// Check number of variables == number of types.
|
||||
if types.len() != variables.names.len() {
|
||||
if types.len() != statement.variable_names.len() {
|
||||
return Err(FrameError::invalid_number_of_values(
|
||||
types.len(),
|
||||
variables.names.len(),
|
||||
span,
|
||||
statement.variable_names.len(),
|
||||
&statement.span,
|
||||
));
|
||||
}
|
||||
|
||||
// Insert variables into symbol table
|
||||
for (variable, type_) in variables.names.iter().zip(types) {
|
||||
self.insert_variable(variable.identifier.name.clone(), type_, span)?;
|
||||
for (variable, type_) in statement.variable_names.iter().zip(types) {
|
||||
self.insert_variable(variable.identifier.name.clone(), type_, &statement.span)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -341,15 +327,15 @@ impl Frame {
|
||||
///
|
||||
/// Asserts that the assignee's type is equal to the `Expression` type.
|
||||
///
|
||||
fn parse_assign(&mut self, assignee: &Assignee, expression: &Expression, span: &Span) -> Result<(), FrameError> {
|
||||
fn parse_assign(&mut self, statement: &AssignStatement) -> Result<(), FrameError> {
|
||||
// Parse assignee type.
|
||||
let assignee_type = self.parse_assignee(assignee, span)?;
|
||||
let assignee_type = self.parse_assignee(&statement.assignee, &statement.span)?;
|
||||
|
||||
// Parse expression type.
|
||||
let expression_type = self.parse_expression(expression)?;
|
||||
let expression_type = self.parse_expression(&statement.value)?;
|
||||
|
||||
// Assert that the assignee_type == expression_type.
|
||||
self.assert_equal(assignee_type, expression_type, span);
|
||||
self.assert_equal(assignee_type, expression_type, &statement.span);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -374,10 +360,8 @@ impl Frame {
|
||||
// Iteratively evaluate assignee access types.
|
||||
for access in &assignee.accesses {
|
||||
let access_type = match access {
|
||||
AssigneeAccess::Array(RangeOrExpression::Expression(index)) => {
|
||||
self.parse_array_access(type_, index, span)
|
||||
}
|
||||
AssigneeAccess::Array(RangeOrExpression::Range(left, right)) => {
|
||||
AssigneeAccess::ArrayIndex(index) => self.parse_array_access(type_, index, span),
|
||||
AssigneeAccess::ArrayRange(left, right) => {
|
||||
self.parse_array_range_access(type_, left.as_ref(), right.as_ref(), span)
|
||||
}
|
||||
AssigneeAccess::Tuple(index, _) => self.parse_tuple_access(type_, &index, span),
|
||||
@ -393,7 +377,7 @@ impl Frame {
|
||||
///
|
||||
/// Collects `TypeAssertion` predicates from a block of statements.
|
||||
///
|
||||
fn parse_block(&mut self, block: &Block, _span: &Span) -> Result<(), FrameError> {
|
||||
fn parse_block(&mut self, block: &Block) -> Result<(), FrameError> {
|
||||
// Push new scope.
|
||||
let scope = Scope::new(self.scopes.last().cloned());
|
||||
self.push_scope(scope);
|
||||
@ -414,80 +398,56 @@ impl Frame {
|
||||
///
|
||||
/// Creates a new scope for each code block in the conditional.
|
||||
///
|
||||
fn parse_statement_conditional(
|
||||
&mut self,
|
||||
conditional: &ConditionalStatement,
|
||||
span: &Span,
|
||||
) -> Result<(), FrameError> {
|
||||
fn parse_statement_conditional(&mut self, conditional: &ConditionalStatement) -> Result<(), FrameError> {
|
||||
// Parse the condition expression.
|
||||
let condition = self.parse_expression(&conditional.condition)?;
|
||||
|
||||
// Assert that the condition is a boolean type.
|
||||
let boolean_type = Type::Boolean;
|
||||
self.assert_equal(boolean_type, condition, span);
|
||||
self.assert_equal(boolean_type, condition, &conditional.span);
|
||||
|
||||
// Parse conditional statements.
|
||||
self.parse_block(&conditional.block, span)?;
|
||||
self.parse_block(&conditional.block)?;
|
||||
|
||||
// Parse conditional or end.
|
||||
if let Some(cond_or_end) = &conditional.next {
|
||||
self.parse_conditional_nested_or_end(cond_or_end, span)?;
|
||||
self.parse_statement(cond_or_end)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Collects `TypeAssertion` predicates from a conditional statement.
|
||||
///
|
||||
fn parse_conditional_nested_or_end(
|
||||
&mut self,
|
||||
cond_or_end: &ConditionalNestedOrEndStatement,
|
||||
span: &Span,
|
||||
) -> Result<(), FrameError> {
|
||||
match cond_or_end {
|
||||
ConditionalNestedOrEndStatement::Nested(nested) => self.parse_statement_conditional(nested, span),
|
||||
ConditionalNestedOrEndStatement::End(statements) => self.parse_block(statements, span),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Collects `TypeAssertion` predicates from an iteration statement.
|
||||
///
|
||||
fn parse_iteration(
|
||||
&mut self,
|
||||
identifier: &Identifier,
|
||||
from_to: &(Expression, Expression),
|
||||
statements: &Block,
|
||||
span: &Span,
|
||||
) -> Result<(), FrameError> {
|
||||
fn parse_iteration(&mut self, statement: &IterationStatement) -> Result<(), FrameError> {
|
||||
// Insert variable into symbol table with u32 type.
|
||||
let u32_type = Type::IntegerType(IntegerType::U32);
|
||||
let _expect_none = self.insert_variable(identifier.name.to_owned(), u32_type.clone(), span);
|
||||
let _expect_none = self.insert_variable(statement.variable.name.to_owned(), u32_type.clone(), &statement.span);
|
||||
|
||||
// Parse `from` and `to` expressions.
|
||||
let from_type = self.parse_expression(&from_to.0)?;
|
||||
let to_type = self.parse_expression(&from_to.1)?;
|
||||
let from_type = self.parse_expression(&statement.start)?;
|
||||
let to_type = self.parse_expression(&statement.stop)?;
|
||||
|
||||
// Assert `from` and `to` types are a u32 or implicit.
|
||||
self.assert_equal(u32_type.clone(), from_type, span);
|
||||
self.assert_equal(u32_type, to_type, span);
|
||||
self.assert_equal(u32_type.clone(), from_type, &statement.span);
|
||||
self.assert_equal(u32_type, to_type, &statement.span);
|
||||
|
||||
// Parse block of statements.
|
||||
self.parse_block(statements, span)
|
||||
self.parse_block(&statement.block)
|
||||
}
|
||||
|
||||
///
|
||||
/// Asserts that the statement `UnresolvedExpression` returns an empty tuple.
|
||||
///
|
||||
fn parse_statement_expression(&mut self, expression: &Expression, span: &Span) -> Result<(), FrameError> {
|
||||
fn parse_statement_expression(&mut self, statement: &ExpressionStatement) -> Result<(), FrameError> {
|
||||
// Create empty tuple type.
|
||||
let expected_type = Type::Tuple(Vec::new());
|
||||
|
||||
// Parse the actual type of the expression.
|
||||
let actual_type = self.parse_expression(expression)?;
|
||||
let actual_type = self.parse_expression(&statement.expression)?;
|
||||
|
||||
self.assert_equal(expected_type, actual_type, span);
|
||||
self.assert_equal(expected_type, actual_type, &statement.span);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user