staging commit for the sizeof operator

This commit is contained in:
damirka 2021-09-07 19:33:02 +03:00
parent d2f63432f8
commit 2942bf85fe
17 changed files with 276 additions and 0 deletions

View File

@ -65,6 +65,9 @@ pub use variable_ref::*;
mod cast;
pub use cast::*;
mod sizeof;
pub use sizeof::*;
use crate::{ConstValue, FromAst, Node, PartialType, Scope, Type};
use leo_errors::{Result, Span};
@ -76,6 +79,7 @@ pub enum Expression<'a> {
Unary(UnaryExpression<'a>),
Ternary(TernaryExpression<'a>),
Cast(CastExpression<'a>),
SizeOf(SizeOfExpression<'a>),
ArrayInline(ArrayInlineExpression<'a>),
ArrayInit(ArrayInitExpression<'a>),
@ -107,6 +111,7 @@ impl<'a> Node for Expression<'a> {
Unary(x) => x.span(),
Ternary(x) => x.span(),
Cast(x) => x.span(),
SizeOf(x) => x.span(),
ArrayInline(x) => x.span(),
ArrayInit(x) => x.span(),
ArrayAccess(x) => x.span(),
@ -141,6 +146,7 @@ impl<'a> ExpressionNode<'a> for Expression<'a> {
Unary(x) => x.set_parent(parent),
Ternary(x) => x.set_parent(parent),
Cast(x) => x.set_parent(parent),
SizeOf(x) => x.set_parent(parent),
ArrayInline(x) => x.set_parent(parent),
ArrayInit(x) => x.set_parent(parent),
ArrayAccess(x) => x.set_parent(parent),
@ -162,6 +168,7 @@ impl<'a> ExpressionNode<'a> for Expression<'a> {
Unary(x) => x.get_parent(),
Ternary(x) => x.get_parent(),
Cast(x) => x.get_parent(),
SizeOf(x) => x.get_parent(),
ArrayInline(x) => x.get_parent(),
ArrayInit(x) => x.get_parent(),
ArrayAccess(x) => x.get_parent(),
@ -183,6 +190,7 @@ impl<'a> ExpressionNode<'a> for Expression<'a> {
Unary(x) => x.enforce_parents(expr),
Ternary(x) => x.enforce_parents(expr),
Cast(x) => x.enforce_parents(expr),
SizeOf(x) => x.enforce_parents(expr),
ArrayInline(x) => x.enforce_parents(expr),
ArrayInit(x) => x.enforce_parents(expr),
ArrayAccess(x) => x.enforce_parents(expr),
@ -204,6 +212,7 @@ impl<'a> ExpressionNode<'a> for Expression<'a> {
Unary(x) => x.get_type(),
Ternary(x) => x.get_type(),
Cast(x) => x.get_type(),
SizeOf(x) => x.get_type(),
ArrayInline(x) => x.get_type(),
ArrayInit(x) => x.get_type(),
ArrayAccess(x) => x.get_type(),
@ -225,6 +234,7 @@ impl<'a> ExpressionNode<'a> for Expression<'a> {
Unary(x) => x.is_mut_ref(),
Ternary(x) => x.is_mut_ref(),
Cast(x) => x.is_mut_ref(),
SizeOf(x) => x.is_mut_ref(),
ArrayInline(x) => x.is_mut_ref(),
ArrayInit(x) => x.is_mut_ref(),
ArrayAccess(x) => x.is_mut_ref(),
@ -246,6 +256,7 @@ impl<'a> ExpressionNode<'a> for Expression<'a> {
Unary(x) => x.const_value(),
Ternary(x) => x.const_value(),
Cast(x) => x.const_value(),
SizeOf(x) => x.const_value(),
ArrayInline(x) => x.const_value(),
ArrayInit(x) => x.const_value(),
ArrayAccess(x) => x.const_value(),
@ -267,6 +278,7 @@ impl<'a> ExpressionNode<'a> for Expression<'a> {
Unary(x) => x.is_consty(),
Ternary(x) => x.is_consty(),
Cast(x) => x.is_consty(),
SizeOf(x) => x.is_consty(),
ArrayInline(x) => x.is_consty(),
ArrayInit(x) => x.is_consty(),
ArrayAccess(x) => x.is_consty(),
@ -305,6 +317,10 @@ impl<'a> FromAst<'a, leo_ast::Expression> for &'a Expression<'a> {
.context
.alloc_expression(CastExpression::from_ast(scope, cast, expected_type).map(Expression::Cast)?),
SizeOf(sizeof) => scope
.context
.alloc_expression(SizeOfExpression::from_ast(scope, sizeof, expected_type).map(Expression::SizeOf)?),
ArrayInline(array_inline) => scope.context.alloc_expression(
ArrayInlineExpression::from_ast(scope, array_inline, expected_type).map(Expression::ArrayInline)?,
),
@ -357,6 +373,7 @@ impl<'a> Into<leo_ast::Expression> for &Expression<'a> {
Unary(x) => leo_ast::Expression::Unary(x.into()),
Ternary(x) => leo_ast::Expression::Ternary(x.into()),
Cast(x) => leo_ast::Expression::Cast(x.into()),
SizeOf(x) => leo_ast::Expression::SizeOf(x.into()),
ArrayInline(x) => leo_ast::Expression::ArrayInline(x.into()),
ArrayInit(x) => leo_ast::Expression::ArrayInit(x.into()),
ArrayAccess(x) => leo_ast::Expression::ArrayAccess(x.into()),

View File

@ -0,0 +1,102 @@
// Copyright (C) 2019-2021 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::{ConstValue, Expression, ExpressionNode, FromAst, IntegerType, Node, PartialType, Scope, Type};
pub use leo_ast::UnaryOperation;
use leo_errors::{Result, Span};
use std::cell::Cell;
#[derive(Clone)]
pub struct SizeOfExpression<'a> {
pub parent: Cell<Option<&'a Expression<'a>>>,
pub span: Option<Span>,
pub inner: Cell<&'a Expression<'a>>,
}
impl<'a> Node for SizeOfExpression<'a> {
fn span(&self) -> Option<&Span> {
self.span.as_ref()
}
}
impl<'a> ExpressionNode<'a> for SizeOfExpression<'a> {
fn set_parent(&self, parent: &'a Expression<'a>) {
self.parent.replace(Some(parent));
}
fn get_parent(&self) -> Option<&'a Expression<'a>> {
self.parent.get()
}
fn enforce_parents(&self, expr: &'a Expression<'a>) {
self.inner.get().set_parent(expr);
}
fn get_type(&self) -> Option<Type<'a>> {
// TODO: make decision on get type method
// Should it be always u32? For indexes?
// How type casts are applied to this?
Some(Type::Integer(IntegerType::U32))
}
fn is_mut_ref(&self) -> bool {
false
}
fn const_value(&self) -> Option<ConstValue> {
let _value = self.inner.get().const_value()?;
// match value {
// ConstValue::Int(int) => match &self.target_type {
// Type::Integer(target) => Some(ConstValue::Int(int.cast_to(target))),
// _ => None,
// },
// _ => None,
// }
// TODO: IMPLEMENT CONST VALUE
None
}
fn is_consty(&self) -> bool {
true
}
}
impl<'a> FromAst<'a, leo_ast::SizeOfExpression> for SizeOfExpression<'a> {
fn from_ast(
scope: &'a Scope<'a>,
value: &leo_ast::SizeOfExpression,
_expected_type: Option<PartialType<'a>>,
) -> Result<SizeOfExpression<'a>> {
let inner = <&Expression<'a>>::from_ast(scope, &*value.inner, None)?;
Ok(SizeOfExpression {
parent: Cell::new(None),
span: Some(value.span.clone()),
inner: Cell::new(inner),
})
}
}
impl<'a> Into<leo_ast::SizeOfExpression> for &SizeOfExpression<'a> {
fn into(self) -> leo_ast::SizeOfExpression {
leo_ast::SizeOfExpression {
inner: Box::new(self.inner.get().into()),
span: self.span.clone().unwrap_or_default(),
}
}
}

View File

@ -48,6 +48,7 @@ impl<'a, T: Monoid, R: MonoidalReducerExpression<'a, T>> MonoidalDirector<'a, T,
Expression::CircuitInit(e) => self.reduce_circuit_init(e),
Expression::Ternary(e) => self.reduce_ternary_expression(e),
Expression::Cast(e) => self.reduce_cast_expression(e),
Expression::SizeOf(e) => self.reduce_sizeof_expression(e),
Expression::Constant(e) => self.reduce_constant(e),
Expression::TupleAccess(e) => self.reduce_tuple_access(e),
Expression::TupleInit(e) => self.reduce_tuple_init(e),
@ -138,6 +139,12 @@ impl<'a, T: Monoid, R: MonoidalReducerExpression<'a, T>> MonoidalDirector<'a, T,
self.reducer.reduce_cast_expression(input, inner)
}
pub fn reduce_sizeof_expression(&mut self, input: &SizeOfExpression<'a>) -> T {
let inner = self.reduce_expression(input.inner.get());
self.reducer.reduce_sizeof_expression(input, inner)
}
pub fn reduce_constant(&mut self, input: &Constant<'a>) -> T {
self.reducer.reduce_constant(input)
}

View File

@ -68,6 +68,10 @@ pub trait MonoidalReducerExpression<'a, T: Monoid> {
inner
}
fn reduce_sizeof_expression(&mut self, input: &SizeOfExpression<'a>, inner: T) -> T {
inner
}
fn reduce_constant(&mut self, input: &Constant<'a>) -> T {
T::default()
}

View File

@ -48,6 +48,7 @@ impl<'a, R: ReconstructingReducerExpression<'a>> ReconstructingDirector<'a, R> {
Expression::CircuitInit(e) => self.reduce_circuit_init(e),
Expression::Ternary(e) => self.reduce_ternary_expression(e),
Expression::Cast(e) => self.reduce_cast_expression(e),
Expression::SizeOf(e) => Expression::SizeOf(e), //self.reduce_sizeof_expression(e), // TODO: implement REDUCER
Expression::Constant(e) => self.reduce_constant(e),
Expression::TupleAccess(e) => self.reduce_tuple_access(e),
Expression::TupleInit(e) => self.reduce_tuple_init(e),

View File

@ -76,6 +76,10 @@ pub trait ExpressionVisitor<'a> {
Default::default()
}
fn visit_sizeof_expression(&mut self, input: &SizeOfExpression<'a>) -> VisitResult {
Default::default()
}
fn visit_constant(&mut self, input: &Constant<'a>) -> VisitResult {
Default::default()
}

View File

@ -61,6 +61,7 @@ impl<'a, R: ExpressionVisitor<'a>> VisitorDirector<'a, R> {
Expression::CircuitInit(e) => self.visit_circuit_init(e),
Expression::Ternary(e) => self.visit_ternary_expression(e),
Expression::Cast(e) => self.visit_cast_expression(e),
Expression::SizeOf(e) => self.visit_sizeof_expression(e),
Expression::Constant(e) => self.visit_constant(e),
Expression::TupleAccess(e) => self.visit_tuple_access(e),
Expression::TupleInit(e) => self.visit_tuple_init(e),
@ -195,6 +196,16 @@ impl<'a, R: ExpressionVisitor<'a>> VisitorDirector<'a, R> {
}
}
pub fn visit_sizeof_expression(&mut self, input: &SizeOfExpression<'a>) -> ConcreteVisitResult {
match self.visitor.visit_sizeof_expression(input) {
VisitResult::VisitChildren => {
self.visit_expression(&input.inner)?;
Ok(())
}
x => x.into(),
}
}
pub fn visit_constant(&mut self, input: &Constant<'a>) -> ConcreteVisitResult {
self.visitor.visit_constant(input).into()
}

View File

@ -54,6 +54,8 @@ mod call;
pub use call::*;
mod cast;
pub use cast::*;
mod sizeof;
pub use sizeof::*;
/// Expression that evaluates to a value
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@ -64,6 +66,7 @@ pub enum Expression {
Unary(UnaryExpression),
Ternary(TernaryExpression),
Cast(CastExpression),
SizeOf(SizeOfExpression),
ArrayInline(ArrayInlineExpression),
ArrayInit(ArrayInitExpression),
@ -100,6 +103,7 @@ impl Node for Expression {
CircuitStaticFunctionAccess(n) => n.span(),
Call(n) => n.span(),
Cast(n) => n.span(),
SizeOf(n) => n.span(),
}
}
@ -122,6 +126,7 @@ impl Node for Expression {
CircuitStaticFunctionAccess(n) => n.set_span(span),
Call(n) => n.set_span(span),
Cast(n) => n.set_span(span),
SizeOf(n) => n.set_span(span),
}
}
}
@ -146,6 +151,7 @@ impl fmt::Display for Expression {
CircuitStaticFunctionAccess(n) => n.fmt(f),
Call(n) => n.fmt(f),
Cast(n) => n.fmt(f),
SizeOf(n) => n.fmt(f),
}
}
}

View File

@ -0,0 +1,41 @@
// Copyright (C) 2019-2021 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;
use super::*;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SizeOfExpression {
pub inner: Box<Expression>,
pub span: Span,
}
impl fmt::Display for SizeOfExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "sizeof {}", self.inner)
}
}
impl Node for SizeOfExpression {
fn span(&self) -> &Span {
&self.span
}
fn set_span(&mut self, span: Span) {
self.span = span;
}
}

View File

@ -57,6 +57,7 @@ impl<R: ReconstructingReducer> ReconstructingDirector<R> {
Expression::Unary(unary) => Expression::Unary(self.reduce_unary(unary)?),
Expression::Ternary(ternary) => Expression::Ternary(self.reduce_ternary(ternary)?),
Expression::Cast(cast) => Expression::Cast(self.reduce_cast(cast)?),
Expression::SizeOf(sizeof) => Expression::SizeOf(sizeof.clone()), // Expression::SizeOf(self.reduce_sizeof(sizeof)?), // TODO: add reducer
Expression::ArrayInline(array_inline) => Expression::ArrayInline(self.reduce_array_inline(array_inline)?),
Expression::ArrayInit(array_init) => Expression::ArrayInit(self.reduce_array_init(array_init)?),

View File

@ -98,6 +98,9 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
// Cast
Expression::Cast(_) => unimplemented!("casts not implemented"),
// SizeOf
Expression::SizeOf(sizeof) => self.enforce_sizeof(cs, sizeof, span),
// Variables
Expression::VariableRef(variable_ref) => self.evaluate_ref(variable_ref),

View File

@ -43,6 +43,9 @@ pub use self::variable_ref::*;
pub mod logical;
pub use self::logical::*;
pub mod operator;
pub use self::operator::*;
pub mod relational;
pub use self::relational::*;

View File

@ -0,0 +1,18 @@
// Copyright (C) 2019-2021 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/>.
pub mod sizeof;
pub use self::sizeof::*;

View File

@ -0,0 +1,47 @@
// Copyright (C) 2019-2021 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 sizeof operator in a compiled Leo program.
use crate::{
program::ConstrainedProgram,
value::{ConstrainedValue, Integer},
GroupType,
};
use leo_asg::{ConstInt, SizeOfExpression};
use leo_errors::{Result, Span};
use snarkvm_fields::PrimeField;
use snarkvm_r1cs::ConstraintSystem;
impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
/// Enforce array expressions
pub fn enforce_sizeof<CS: ConstraintSystem<F>>(
&mut self,
cs: &mut CS,
sizeof: &'a SizeOfExpression<'a>,
_span: &Span,
) -> Result<ConstrainedValue<'a, F, G>> {
let value = self.enforce_expression(cs, sizeof.inner.get())?;
Ok(match value {
ConstrainedValue::Array(array) => {
ConstrainedValue::Integer(Integer::new(&ConstInt::U32(array.len() as u32)))
}
_ => unimplemented!("sizeof can only be used for arrays"),
})
}
}

View File

@ -727,6 +727,10 @@ impl ParserContext {
};
Expression::Identifier(ident)
}
Token::SizeOf => Expression::SizeOf(SizeOfExpression {
span,
inner: Box::new(self.parse_primary_expression()?),
}),
token => {
return Err(ParserError::unexpected_str(token, "expression", &span).into());
}

View File

@ -519,6 +519,7 @@ impl Token {
"string" => Token::String,
"true" => Token::True,
"type" => Token::Type,
"sizeof" => Token::SizeOf,
"u8" => Token::U8,
"u16" => Token::U16,
"u32" => Token::U32,

View File

@ -139,6 +139,10 @@ pub enum Token {
Static,
String,
Type,
// Operators
SizeOf,
// Not yet in ABNF
// BitAnd,
// BitAndEq,
@ -195,6 +199,7 @@ pub const KEYWORD_TOKENS: &[Token] = &[
Token::String,
Token::True,
Token::Type,
Token::SizeOf,
Token::U8,
Token::U16,
Token::U32,
@ -307,6 +312,7 @@ impl fmt::Display for Token {
Static => write!(f, "static"),
String => write!(f, "string"),
Type => write!(f, "type"),
SizeOf => write!(f, "sizeof"),
Eof => write!(f, ""),
// BitAnd => write!(f, "&"),
// BitAndEq => write!(f, "&="),