leo/ast/src/expression.rs

582 lines
23 KiB
Rust

// 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::{
ArrayDimensions,
CircuitVariableDefinition,
GroupValue,
Identifier,
IntegerType,
PositiveNumber,
RangeOrExpression,
Span,
SpreadOrExpression,
};
use leo_grammar::{
access::{Access, AssigneeAccess},
common::{Assignee, Identifier as GrammarIdentifier},
expressions::{
ArrayInitializerExpression,
ArrayInlineExpression,
BinaryExpression,
CircuitInlineExpression,
Expression as GrammarExpression,
PostfixExpression,
TernaryExpression,
UnaryExpression,
},
operations::{BinaryOperation, UnaryOperation},
values::{
AddressValue,
BooleanValue,
FieldValue,
GroupValue as GrammarGroupValue,
IntegerValue,
NumberValue as GrammarNumber,
Value,
},
};
use leo_grammar::{access::TupleAccess, expressions::TupleExpression};
use serde::{Deserialize, Serialize};
use std::fmt;
/// Expression that evaluates to a value
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Expression {
// Identifier
Identifier(Identifier),
// Values
Address(String, Span),
Boolean(String, Span),
Field(String, Span),
Group(Box<GroupValue>),
Implicit(String, Span),
Integer(IntegerType, String, Span),
// Number operations
Add(Box<(Expression, Expression)>, Span),
Sub(Box<(Expression, Expression)>, Span),
Mul(Box<(Expression, Expression)>, Span),
Div(Box<(Expression, Expression)>, Span),
Pow(Box<(Expression, Expression)>, Span),
// Boolean operations
Not(Box<Expression>, Span),
Negate(Box<Expression>, Span),
Or(Box<(Expression, Expression)>, Span),
And(Box<(Expression, Expression)>, Span),
Eq(Box<(Expression, Expression)>, Span),
Ge(Box<(Expression, Expression)>, Span),
Gt(Box<(Expression, Expression)>, Span),
Le(Box<(Expression, Expression)>, Span),
Lt(Box<(Expression, Expression)>, Span),
// Conditionals
// (conditional, first_value, second_value, span)
IfElse(Box<(Expression, Expression, Expression)>, Span),
// Arrays
// (array_elements, span)
ArrayInline(Vec<SpreadOrExpression>, Span),
// ((array element, dimensions), span)
ArrayInitializer(Box<(Expression, ArrayDimensions)>, Span),
// ((array_name, range), span)
ArrayAccess(Box<(Expression, RangeOrExpression)>, Span),
// Tuples
// (tuple_elements, span)
Tuple(Vec<Expression>, Span),
// ((tuple_name, index), span)
TupleAccess(Box<(Expression, PositiveNumber)>, Span),
// Circuits
// (defined_circuit_name, circuit_members, span)
Circuit(Identifier, Vec<CircuitVariableDefinition>, Span),
// (declared_circuit name, circuit_member_name, span)
CircuitMemberAccess(Box<Expression>, Identifier, Span),
// (defined_circuit name, circuit_static_function_name, span)
CircuitStaticFunctionAccess(Box<Expression>, Identifier, Span),
// Functions
// (declared_function_name, function_arguments, span)
FunctionCall(Box<Expression>, Vec<Expression>, Span),
// (core_function_name, function_arguments, span)
CoreFunctionCall(String, Vec<Expression>, Span),
}
impl Expression {
pub fn set_span(&mut self, new_span: Span) {
match self {
Expression::Field(_, old_span) => *old_span = new_span,
Expression::Group(value) => value.set_span(new_span),
Expression::Add(_, old_span) => *old_span = new_span,
Expression::Sub(_, old_span) => *old_span = new_span,
Expression::Mul(_, old_span) => *old_span = new_span,
Expression::Div(_, old_span) => *old_span = new_span,
Expression::Pow(_, old_span) => *old_span = new_span,
Expression::Not(_, old_span) => *old_span = new_span,
Expression::Or(_, old_span) => *old_span = new_span,
Expression::And(_, old_span) => *old_span = new_span,
Expression::Eq(_, old_span) => *old_span = new_span,
Expression::Ge(_, old_span) => *old_span = new_span,
Expression::Gt(_, old_span) => *old_span = new_span,
Expression::Le(_, old_span) => *old_span = new_span,
Expression::Lt(_, old_span) => *old_span = new_span,
Expression::IfElse(_, old_span) => *old_span = new_span,
Expression::ArrayInline(_, old_span) => *old_span = new_span,
Expression::ArrayInitializer(_, old_span) => *old_span = new_span,
Expression::ArrayAccess(_, old_span) => *old_span = new_span,
Expression::Tuple(_, old_span) => *old_span = new_span,
Expression::TupleAccess(_, old_span) => *old_span = new_span,
Expression::Circuit(_, _, old_span) => *old_span = new_span,
Expression::CircuitMemberAccess(_, _, old_span) => *old_span = new_span,
Expression::CircuitStaticFunctionAccess(_, _, old_span) => *old_span = new_span,
Expression::FunctionCall(_, _, old_span) => *old_span = new_span,
Expression::CoreFunctionCall(_, _, old_span) => *old_span = new_span,
_ => {}
}
}
}
impl<'ast> fmt::Display for Expression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
// Variables
Expression::Identifier(ref variable) => write!(f, "{}", variable),
// Values
Expression::Address(ref address, ref _span) => write!(f, "{}", address),
Expression::Boolean(ref bool, ref _span) => write!(f, "{}", bool),
Expression::Field(ref field, ref _span) => write!(f, "{}", field),
Expression::Group(ref group) => write!(f, "{}", group),
Expression::Implicit(ref value, ref _span) => write!(f, "{}", value),
Expression::Integer(ref type_, ref integer, ref _span) => write!(f, "{}{}", integer, type_),
// Number operations
Expression::Negate(ref expression, ref _span) => write!(f, "-{}", expression),
Expression::Add(ref left_right, ref _span) => write!(f, "{} + {}", left_right.0, left_right.1),
Expression::Sub(ref left_right, ref _span) => write!(f, "{} - {}", left_right.0, left_right.1),
Expression::Mul(ref left_right, ref _span) => write!(f, "{} * {}", left_right.0, left_right.1),
Expression::Div(ref left_right, ref _span) => write!(f, "{} / {}", left_right.0, left_right.1),
Expression::Pow(ref left_right, ref _span) => write!(f, "{} ** {}", left_right.0, left_right.1),
// Boolean operations
Expression::Not(ref expression, ref _span) => write!(f, "!{}", expression),
Expression::Or(ref lhs_rhs, ref _span) => write!(f, "{} || {}", lhs_rhs.0, lhs_rhs.1),
Expression::And(ref lhs_rhs, ref _span) => write!(f, "{} && {}", lhs_rhs.0, lhs_rhs.1),
Expression::Eq(ref lhs_rhs, ref _span) => write!(f, "{} == {}", lhs_rhs.0, lhs_rhs.1),
Expression::Ge(ref lhs_rhs, ref _span) => write!(f, "{} >= {}", lhs_rhs.0, lhs_rhs.1),
Expression::Gt(ref lhs_rhs, ref _span) => write!(f, "{} > {}", lhs_rhs.0, lhs_rhs.1),
Expression::Le(ref lhs_rhs, ref _span) => write!(f, "{} <= {}", lhs_rhs.0, lhs_rhs.1),
Expression::Lt(ref lhs_rhs, ref _span) => write!(f, "{} < {}", lhs_rhs.0, lhs_rhs.1),
// Conditionals
Expression::IfElse(ref triplet, ref _span) => {
write!(f, "if {} then {} else {} fi", triplet.0, triplet.1, triplet.2)
}
// Arrays
Expression::ArrayInline(ref array, ref _span) => {
write!(f, "[")?;
for (i, e) in array.iter().enumerate() {
write!(f, "{}", e)?;
if i < array.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "]")
}
Expression::ArrayInitializer(ref array, ref _span) => write!(f, "[{}; {}]", array.0, array.1),
Expression::ArrayAccess(ref array_w_index, ref _span) => {
write!(f, "{}[{}]", array_w_index.0, array_w_index.1)
}
// Tuples
Expression::Tuple(ref tuple, ref _span) => {
let values = tuple.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(", ");
write!(f, "({})", values)
}
Expression::TupleAccess(ref tuple_w_index, ref _span) => {
write!(f, "{}.{}", tuple_w_index.0, tuple_w_index.1)
}
// Circuits
Expression::Circuit(ref var, ref members, ref _span) => {
write!(f, "{} {{", var)?;
for (i, member) in members.iter().enumerate() {
write!(f, "{}: {}", member.identifier, member.expression)?;
if i < members.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, "}}")
}
Expression::CircuitMemberAccess(ref circuit_name, ref member, ref _span) => {
write!(f, "{}.{}", circuit_name, member)
}
Expression::CircuitStaticFunctionAccess(ref circuit_name, ref member, ref _span) => {
write!(f, "{}::{}", circuit_name, member)
}
// Function calls
Expression::FunctionCall(ref function, ref arguments, ref _span) => {
write!(f, "{}(", function,)?;
for (i, param) in arguments.iter().enumerate() {
write!(f, "{}", param)?;
if i < arguments.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, ")")
}
Expression::CoreFunctionCall(ref function, ref arguments, ref _span) => {
write!(f, "{}(", function,)?;
for (i, param) in arguments.iter().enumerate() {
write!(f, "{}", param)?;
if i < arguments.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, ")")
}
}
}
}
impl<'ast> From<CircuitInlineExpression<'ast>> for Expression {
fn from(expression: CircuitInlineExpression<'ast>) -> Self {
let circuit_name = Identifier::from(expression.name);
let members = expression
.members
.into_iter()
.map(CircuitVariableDefinition::from)
.collect::<Vec<CircuitVariableDefinition>>();
Expression::Circuit(circuit_name, members, Span::from(expression.span))
}
}
impl<'ast> From<PostfixExpression<'ast>> for Expression {
fn from(expression: PostfixExpression<'ast>) -> Self {
let variable = Expression::Identifier(Identifier::from(expression.name));
// ast::PostFixExpression contains an array of "accesses": `a(34)[42]` is represented as `[a, [Call(34), Select(42)]]`, but Access call expressions
// are recursive, so it is `Select(Call(a, 34), 42)`. We apply this transformation here
// we start with the id, and we fold the array of accesses by wrapping the current value
expression
.accesses
.into_iter()
.fold(variable, |acc, access| match access {
// Handle array accesses
Access::Array(array) => Expression::ArrayAccess(
Box::new((acc, RangeOrExpression::from(array.expression))),
Span::from(array.span),
),
// Handle tuple access
Access::Tuple(tuple) => Expression::TupleAccess(
Box::new((acc, PositiveNumber::from(tuple.number))),
Span::from(tuple.span),
),
// Handle function calls
Access::Call(function) => {
let span = Span::from(function.span);
Expression::FunctionCall(
Box::new(acc),
function.expressions.into_iter().map(Expression::from).collect(),
span,
)
}
// Handle circuit member accesses
Access::Object(circuit_object) => Expression::CircuitMemberAccess(
Box::new(acc),
Identifier::from(circuit_object.identifier),
Span::from(circuit_object.span),
),
Access::StaticObject(circuit_object) => Expression::CircuitStaticFunctionAccess(
Box::new(acc),
Identifier::from(circuit_object.identifier),
Span::from(circuit_object.span),
),
})
}
}
impl<'ast> From<GrammarExpression<'ast>> for Expression {
fn from(expression: GrammarExpression<'ast>) -> Self {
match expression {
GrammarExpression::Value(value) => Expression::from(value),
GrammarExpression::Identifier(variable) => Expression::from(variable),
GrammarExpression::Unary(expression) => Expression::from(*expression),
GrammarExpression::Binary(expression) => Expression::from(*expression),
GrammarExpression::Ternary(expression) => Expression::from(*expression),
GrammarExpression::ArrayInline(expression) => Expression::from(expression),
GrammarExpression::ArrayInitializer(expression) => Expression::from(*expression),
GrammarExpression::Tuple(expression) => Expression::from(expression),
GrammarExpression::CircuitInline(expression) => Expression::from(expression),
GrammarExpression::Postfix(expression) => Expression::from(expression),
}
}
}
// Assignee -> Expression for operator assign statements
impl<'ast> From<Assignee<'ast>> for Expression {
fn from(assignee: Assignee<'ast>) -> Self {
let variable = Expression::Identifier(Identifier::from(assignee.name));
// we start with the id, and we fold the array of accesses by wrapping the current value
assignee
.accesses
.into_iter()
.fold(variable, |acc, access| match access {
AssigneeAccess::Member(circuit_member) => Expression::CircuitMemberAccess(
Box::new(acc),
Identifier::from(circuit_member.identifier),
Span::from(circuit_member.span),
),
AssigneeAccess::Array(array) => Expression::ArrayAccess(
Box::new((acc, RangeOrExpression::from(array.expression))),
Span::from(array.span),
),
AssigneeAccess::Tuple(tuple) => Expression::TupleAccess(
Box::new((acc, PositiveNumber::from(tuple.number))),
Span::from(tuple.span.clone()),
),
})
}
}
impl<'ast> From<BinaryExpression<'ast>> for Expression {
fn from(expression: BinaryExpression<'ast>) -> Self {
match expression.operation {
// Boolean operations
BinaryOperation::Or => Expression::Or(
Box::new((Expression::from(expression.left), Expression::from(expression.right))),
Span::from(expression.span),
),
BinaryOperation::And => Expression::And(
Box::new((Expression::from(expression.left), Expression::from(expression.right))),
Span::from(expression.span),
),
BinaryOperation::Eq => Expression::Eq(
Box::new((Expression::from(expression.left), Expression::from(expression.right))),
Span::from(expression.span),
),
BinaryOperation::Ne => {
let span = Span::from(expression.span);
let negated = Expression::Eq(
Box::new((Expression::from(expression.left), Expression::from(expression.right))),
span.clone(),
);
Expression::Not(Box::new(negated), span)
}
BinaryOperation::Ge => Expression::Ge(
Box::new((Expression::from(expression.left), Expression::from(expression.right))),
Span::from(expression.span),
),
BinaryOperation::Gt => Expression::Gt(
Box::new((Expression::from(expression.left), Expression::from(expression.right))),
Span::from(expression.span),
),
BinaryOperation::Le => Expression::Le(
Box::new((Expression::from(expression.left), Expression::from(expression.right))),
Span::from(expression.span),
),
BinaryOperation::Lt => Expression::Lt(
Box::new((Expression::from(expression.left), Expression::from(expression.right))),
Span::from(expression.span),
),
// Number operations
BinaryOperation::Add => Expression::Add(
Box::new((Expression::from(expression.left), Expression::from(expression.right))),
Span::from(expression.span),
),
BinaryOperation::Sub => Expression::Sub(
Box::new((Expression::from(expression.left), Expression::from(expression.right))),
Span::from(expression.span),
),
BinaryOperation::Mul => Expression::Mul(
Box::new((Expression::from(expression.left), Expression::from(expression.right))),
Span::from(expression.span),
),
BinaryOperation::Div => Expression::Div(
Box::new((Expression::from(expression.left), Expression::from(expression.right))),
Span::from(expression.span),
),
BinaryOperation::Pow => Expression::Pow(
Box::new((Expression::from(expression.left), Expression::from(expression.right))),
Span::from(expression.span),
),
}
}
}
impl<'ast> From<TernaryExpression<'ast>> for Expression {
fn from(expression: TernaryExpression<'ast>) -> Self {
Expression::IfElse(
Box::new((
Expression::from(expression.first),
Expression::from(expression.second),
Expression::from(expression.third),
)),
Span::from(expression.span),
)
}
}
impl<'ast> From<ArrayInlineExpression<'ast>> for Expression {
fn from(array: ArrayInlineExpression<'ast>) -> Self {
Expression::ArrayInline(
array.expressions.into_iter().map(SpreadOrExpression::from).collect(),
Span::from(array.span),
)
}
}
impl<'ast> From<ArrayInitializerExpression<'ast>> for Expression {
fn from(array: ArrayInitializerExpression<'ast>) -> Self {
Expression::ArrayInitializer(
Box::new((
Expression::from(array.expression),
ArrayDimensions::from(array.dimensions),
)),
Span::from(array.span),
)
}
}
impl<'ast> From<TupleExpression<'ast>> for Expression {
fn from(tuple: TupleExpression<'ast>) -> Self {
Expression::Tuple(
tuple.expressions.into_iter().map(Expression::from).collect(),
Span::from(tuple.span),
)
}
}
impl<'ast> From<Value<'ast>> for Expression {
fn from(value: Value<'ast>) -> Self {
match value {
Value::Address(address) => Expression::from(address),
Value::Boolean(boolean) => Expression::from(boolean),
Value::Field(field) => Expression::from(field),
Value::Group(group) => Expression::from(group),
Value::Implicit(number) => Expression::from(number),
Value::Integer(integer) => Expression::from(integer),
}
}
}
impl<'ast> From<UnaryExpression<'ast>> for Expression {
fn from(expression: UnaryExpression<'ast>) -> Self {
match expression.operation {
UnaryOperation::Not(_) => Expression::Not(
Box::new(Expression::from(expression.expression)),
Span::from(expression.span),
),
UnaryOperation::Negate(_) => Expression::Negate(
Box::new(Expression::from(expression.expression)),
Span::from(expression.span),
),
}
}
}
impl<'ast> From<AddressValue<'ast>> for Expression {
fn from(address: AddressValue<'ast>) -> Self {
Expression::Address(address.address.value, Span::from(address.span))
}
}
impl<'ast> From<BooleanValue<'ast>> for Expression {
fn from(boolean: BooleanValue<'ast>) -> Self {
Expression::Boolean(boolean.value, Span::from(boolean.span))
}
}
impl<'ast> From<FieldValue<'ast>> for Expression {
fn from(field: FieldValue<'ast>) -> Self {
Expression::Field(field.number.to_string(), Span::from(field.span))
}
}
impl<'ast> From<GrammarGroupValue<'ast>> for Expression {
fn from(ast_group: GrammarGroupValue<'ast>) -> Self {
Expression::Group(Box::new(GroupValue::from(ast_group)))
}
}
impl<'ast> From<GrammarNumber<'ast>> for Expression {
fn from(number: GrammarNumber<'ast>) -> Self {
let (value, span) = match number {
GrammarNumber::Positive(number) => (number.value, number.span),
GrammarNumber::Negative(number) => (number.value, number.span),
};
Expression::Implicit(value, Span::from(span))
}
}
impl<'ast> From<IntegerValue<'ast>> for Expression {
fn from(integer: IntegerValue<'ast>) -> Self {
let span = Span::from(integer.span().clone());
let (type_, value) = match integer {
IntegerValue::Signed(integer) => {
let type_ = IntegerType::from(integer.type_);
let number = match integer.number {
GrammarNumber::Negative(number) => number.value,
GrammarNumber::Positive(number) => number.value,
};
(type_, number)
}
IntegerValue::Unsigned(integer) => {
let type_ = IntegerType::from(integer.type_);
let number = integer.number.value;
(type_, number)
}
};
Expression::Integer(type_, value, span)
}
}
impl<'ast> From<TupleAccess<'ast>> for Expression {
fn from(tuple: TupleAccess<'ast>) -> Self {
Expression::Implicit(tuple.number.to_string(), Span::from(tuple.span))
}
}
impl<'ast> From<GrammarIdentifier<'ast>> for Expression {
fn from(identifier: GrammarIdentifier<'ast>) -> Self {
Expression::Identifier(Identifier::from(identifier))
}
}