mirror of
https://github.com/AleoHQ/leo.git
synced 2024-11-13 08:47:17 +03:00
Merge pull request #1333 from AleoHQ/array-len-function
[Feature] Adds .len() postfix to arrays
This commit is contained in:
commit
a5f74195cf
89
asg/src/expression/lengthof.rs
Normal file
89
asg/src/expression/lengthof.rs
Normal file
@ -0,0 +1,89 @@
|
||||
// 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 LengthOfExpression<'a> {
|
||||
pub parent: Cell<Option<&'a Expression<'a>>>,
|
||||
pub span: Option<Span>,
|
||||
pub inner: Cell<&'a Expression<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> Node for LengthOfExpression<'a> {
|
||||
fn span(&self) -> Option<&Span> {
|
||||
self.span.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExpressionNode<'a> for LengthOfExpression<'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>> {
|
||||
Some(Type::Integer(IntegerType::U32)) // For now we stick to U32 value type
|
||||
}
|
||||
|
||||
fn is_mut_ref(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn const_value(&self) -> Option<ConstValue> {
|
||||
None
|
||||
}
|
||||
|
||||
fn is_consty(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FromAst<'a, leo_ast::LengthOfExpression> for LengthOfExpression<'a> {
|
||||
fn from_ast(
|
||||
scope: &'a Scope<'a>,
|
||||
value: &leo_ast::LengthOfExpression,
|
||||
_expected_type: Option<PartialType<'a>>,
|
||||
) -> Result<LengthOfExpression<'a>> {
|
||||
let inner = <&Expression<'a>>::from_ast(scope, &*value.inner, None)?;
|
||||
|
||||
Ok(LengthOfExpression {
|
||||
parent: Cell::new(None),
|
||||
span: Some(value.span.clone()),
|
||||
inner: Cell::new(inner),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Into<leo_ast::LengthOfExpression> for &LengthOfExpression<'a> {
|
||||
fn into(self) -> leo_ast::LengthOfExpression {
|
||||
leo_ast::LengthOfExpression {
|
||||
inner: Box::new(self.inner.get().into()),
|
||||
span: self.span.clone().unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
}
|
@ -65,6 +65,9 @@ pub use variable_ref::*;
|
||||
mod cast;
|
||||
pub use cast::*;
|
||||
|
||||
mod lengthof;
|
||||
pub use lengthof::*;
|
||||
|
||||
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>),
|
||||
LengthOf(LengthOfExpression<'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(),
|
||||
LengthOf(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),
|
||||
LengthOf(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(),
|
||||
LengthOf(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),
|
||||
LengthOf(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(),
|
||||
LengthOf(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(),
|
||||
LengthOf(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(),
|
||||
LengthOf(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(),
|
||||
LengthOf(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)?),
|
||||
|
||||
LengthOf(lengthof) => scope.context.alloc_expression(
|
||||
LengthOfExpression::from_ast(scope, lengthof, expected_type).map(Expression::LengthOf)?,
|
||||
),
|
||||
|
||||
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()),
|
||||
LengthOf(x) => leo_ast::Expression::LengthOf(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()),
|
||||
|
@ -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::LengthOf(e) => self.reduce_lengthof_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_lengthof_expression(&mut self, input: &LengthOfExpression<'a>) -> T {
|
||||
let inner = self.reduce_expression(input.inner.get());
|
||||
|
||||
self.reducer.reduce_lengthof_expression(input, inner)
|
||||
}
|
||||
|
||||
pub fn reduce_constant(&mut self, input: &Constant<'a>) -> T {
|
||||
self.reducer.reduce_constant(input)
|
||||
}
|
||||
|
@ -68,6 +68,10 @@ pub trait MonoidalReducerExpression<'a, T: Monoid> {
|
||||
inner
|
||||
}
|
||||
|
||||
fn reduce_lengthof_expression(&mut self, input: &LengthOfExpression<'a>, inner: T) -> T {
|
||||
inner
|
||||
}
|
||||
|
||||
fn reduce_constant(&mut self, input: &Constant<'a>) -> T {
|
||||
T::default()
|
||||
}
|
||||
|
@ -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::LengthOf(e) => Expression::LengthOf(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),
|
||||
|
@ -76,6 +76,10 @@ pub trait ExpressionVisitor<'a> {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_lengthof_expression(&mut self, input: &LengthOfExpression<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn visit_constant(&mut self, input: &Constant<'a>) -> VisitResult {
|
||||
Default::default()
|
||||
}
|
||||
|
@ -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::LengthOf(e) => self.visit_lengthof_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_lengthof_expression(&mut self, input: &LengthOfExpression<'a>) -> ConcreteVisitResult {
|
||||
match self.visitor.visit_lengthof_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()
|
||||
}
|
||||
|
41
ast/src/expression/lengthof.rs
Normal file
41
ast/src/expression/lengthof.rs
Normal 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 LengthOfExpression {
|
||||
pub inner: Box<Expression>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl fmt::Display for LengthOfExpression {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}.len()", self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for LengthOfExpression {
|
||||
fn span(&self) -> &Span {
|
||||
&self.span
|
||||
}
|
||||
|
||||
fn set_span(&mut self, span: Span) {
|
||||
self.span = span;
|
||||
}
|
||||
}
|
@ -54,6 +54,8 @@ mod call;
|
||||
pub use call::*;
|
||||
mod cast;
|
||||
pub use cast::*;
|
||||
mod lengthof;
|
||||
pub use lengthof::*;
|
||||
|
||||
/// 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),
|
||||
LengthOf(LengthOfExpression),
|
||||
|
||||
ArrayInline(ArrayInlineExpression),
|
||||
ArrayInit(ArrayInitExpression),
|
||||
@ -100,6 +103,7 @@ impl Node for Expression {
|
||||
CircuitStaticFunctionAccess(n) => n.span(),
|
||||
Call(n) => n.span(),
|
||||
Cast(n) => n.span(),
|
||||
LengthOf(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),
|
||||
LengthOf(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),
|
||||
LengthOf(n) => n.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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::LengthOf(lengthof) => Expression::LengthOf(lengthof.clone()), // Expression::LengthOf(self.reduce_lengthof(lengthof)?), // 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)?),
|
||||
|
@ -98,6 +98,9 @@ impl<'a, F: PrimeField, G: GroupType<F>> ConstrainedProgram<'a, F, G> {
|
||||
// Cast
|
||||
Expression::Cast(_) => unimplemented!("casts not implemented"),
|
||||
|
||||
// LengthOf
|
||||
Expression::LengthOf(lengthof) => self.enforce_lengthof(cs, lengthof, span),
|
||||
|
||||
// Variables
|
||||
Expression::VariableRef(variable_ref) => self.evaluate_ref(variable_ref),
|
||||
|
||||
|
@ -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::*;
|
||||
|
||||
|
47
compiler/src/expression/operator/lengthof.rs
Normal file
47
compiler/src/expression/operator/lengthof.rs
Normal 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 lengthof operator in a compiled Leo program.
|
||||
|
||||
use crate::{
|
||||
program::ConstrainedProgram,
|
||||
value::{ConstrainedValue, Integer},
|
||||
GroupType,
|
||||
};
|
||||
use leo_asg::{ConstInt, LengthOfExpression};
|
||||
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_lengthof<CS: ConstraintSystem<F>>(
|
||||
&mut self,
|
||||
cs: &mut CS,
|
||||
lengthof: &'a LengthOfExpression<'a>,
|
||||
span: &Span,
|
||||
) -> Result<ConstrainedValue<'a, F, G>> {
|
||||
let value = self.enforce_expression(cs, lengthof.inner.get())?;
|
||||
|
||||
Ok(match value {
|
||||
ConstrainedValue::Array(array) => {
|
||||
ConstrainedValue::Integer(Integer::new(&ConstInt::U32(array.len() as u32)))
|
||||
}
|
||||
_ => return Err(leo_errors::CompilerError::lengthof_can_only_be_used_on_arrays(span).into()),
|
||||
})
|
||||
}
|
||||
}
|
18
compiler/src/expression/operator/mod.rs
Normal file
18
compiler/src/expression/operator/mod.rs
Normal 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 lengthof;
|
||||
pub use self::lengthof::*;
|
@ -111,7 +111,7 @@ In order to do something with the array, e.g. add all its elements and return th
|
||||
|
||||
Thus, this RFC also proposed to extend Leo with such an operator.
|
||||
A possibility is `<expression>.length`, where `<expression>` is an expression of array type.
|
||||
A variation is `<expression>.length()`, if we want it look more like a built-in method on arrays.
|
||||
A variation is `<expression>.len()`, if we want it look more like a built-in method on arrays.
|
||||
Yet another option is `length(<expression>)`, which is more like a built-in function.
|
||||
A shorter name could be `len`, leading to the three possibilities
|
||||
`<expression>.len`, `<expression>.len()`, and `len(<expression>)`.
|
||||
@ -148,4 +148,4 @@ None.
|
||||
|
||||
# Alternatives
|
||||
|
||||
None.
|
||||
None.
|
||||
|
@ -834,4 +834,11 @@ create_errors!(
|
||||
msg: format!("no implementation found for `{}`", operation),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
lengthof_can_only_be_used_on_arrays {
|
||||
args: (),
|
||||
msg: "len() can only be called on an array value".to_string(),
|
||||
help: None,
|
||||
}
|
||||
);
|
||||
|
@ -222,3 +222,8 @@ fn main() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_true() {
|
||||
assert!(true);
|
||||
}
|
||||
|
@ -402,8 +402,20 @@ impl ParserContext {
|
||||
///
|
||||
pub fn parse_postfix_expression(&mut self) -> Result<Expression> {
|
||||
let mut expr = self.parse_primary_expression()?;
|
||||
while let Some(token) = self.eat_any(&[Token::LeftSquare, Token::Dot, Token::LeftParen, Token::DoubleColon]) {
|
||||
while let Some(token) = self.eat_any(&[
|
||||
Token::LeftSquare,
|
||||
Token::Dot,
|
||||
Token::LeftParen,
|
||||
Token::DoubleColon,
|
||||
Token::LengthOf,
|
||||
]) {
|
||||
match token.token {
|
||||
Token::LengthOf => {
|
||||
expr = Expression::LengthOf(LengthOfExpression {
|
||||
span: expr.span().clone(),
|
||||
inner: Box::new(expr),
|
||||
})
|
||||
}
|
||||
Token::LeftSquare => {
|
||||
if self.eat(Token::DotDot).is_some() {
|
||||
let right = if self.peek_token().as_ref() != &Token::RightSquare {
|
||||
@ -727,6 +739,10 @@ impl ParserContext {
|
||||
};
|
||||
Expression::Identifier(ident)
|
||||
}
|
||||
// Token::LengthOf => Expression::LengthOf(LengthOfExpression {
|
||||
// span,
|
||||
// inner: Box::new(self.parse_primary_expression()?),
|
||||
// }),
|
||||
token => {
|
||||
return Err(ParserError::unexpected_str(token, "expression", &span).into());
|
||||
}
|
||||
|
@ -388,6 +388,9 @@ impl Token {
|
||||
return (len, Some(Token::DotDotDot));
|
||||
} else if let Some(len) = eat(input, "..") {
|
||||
return (len, Some(Token::DotDot));
|
||||
} else if let Some(len) = eat(input, ".len()") {
|
||||
// FIXME: remove this code once we allow method calls
|
||||
return (len, Some(Token::LengthOf));
|
||||
}
|
||||
return (1, Some(Token::Dot));
|
||||
}
|
||||
|
@ -138,6 +138,11 @@ pub enum Token {
|
||||
Return,
|
||||
Static,
|
||||
Type,
|
||||
|
||||
// Not yet in ABNF
|
||||
// arr.len() token - hacky zone
|
||||
LengthOf,
|
||||
|
||||
// Not yet in ABNF
|
||||
// BitAnd,
|
||||
// BitAndEq,
|
||||
@ -193,6 +198,7 @@ pub const KEYWORD_TOKENS: &[Token] = &[
|
||||
Token::Static,
|
||||
Token::True,
|
||||
Token::Type,
|
||||
Token::LengthOf,
|
||||
Token::U8,
|
||||
Token::U16,
|
||||
Token::U32,
|
||||
@ -304,6 +310,7 @@ impl fmt::Display for Token {
|
||||
Return => write!(f, "return"),
|
||||
Static => write!(f, "static"),
|
||||
Type => write!(f, "type"),
|
||||
LengthOf => write!(f, ".len()"), // FIXME
|
||||
Eof => write!(f, ""),
|
||||
// BitAnd => write!(f, "&"),
|
||||
// BitAndEq => write!(f, "&="),
|
||||
|
@ -1,6 +1,7 @@
|
||||
[main]
|
||||
y: bool = true;
|
||||
n: bool = false;
|
||||
a: [char; 11] = "hello world";
|
||||
|
||||
[registers]
|
||||
r0: bool = false;
|
||||
|
9
tests/compiler/array_without_size/length.leo
Normal file
9
tests/compiler/array_without_size/length.leo
Normal file
@ -0,0 +1,9 @@
|
||||
/*
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
input_file: input/dummy.in
|
||||
*/
|
||||
|
||||
function main(a: [char; 11], y: bool) -> bool {
|
||||
return y == (a.len() == 11);
|
||||
}
|
17
tests/compiler/array_without_size/length_function.leo
Normal file
17
tests/compiler/array_without_size/length_function.leo
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
input_file: input/dummy.in
|
||||
*/
|
||||
|
||||
function main(y: bool) -> bool {
|
||||
let x = 0u8;
|
||||
for i in 0..strlen("I swear to god I had something for this") {
|
||||
x += 1;
|
||||
}
|
||||
return (x == 39) == y;
|
||||
}
|
||||
|
||||
function strlen(str: [char; _]) -> u32 {
|
||||
return str.len();
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
---
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
outputs:
|
||||
- circuit:
|
||||
num_public_variables: 0
|
||||
num_private_variables: 12
|
||||
num_constraints: 1
|
||||
at: 336f487fe39f24aef980deaaf7d6dddcc0dbfa8f121c3470b05546c1ac13f87e
|
||||
bt: ae35381db5558456a49acb22132b4930efd53b90eb2668df06c5d9c1a6b0ab9f
|
||||
ct: cf1cbb66a638b4860a516671fb74850e6ccf787fe6c4c8d29e9c04efe880bd05
|
||||
output:
|
||||
- input_file: input/dummy.in
|
||||
output:
|
||||
registers:
|
||||
r0:
|
||||
type: bool
|
||||
value: "true"
|
||||
initial_ast: d8e3de13a7f12866871e4117b7c4cf9872350154b19e82087fe8100adeba1354
|
||||
imports_resolved_ast: d8e3de13a7f12866871e4117b7c4cf9872350154b19e82087fe8100adeba1354
|
||||
canonicalized_ast: d8e3de13a7f12866871e4117b7c4cf9872350154b19e82087fe8100adeba1354
|
||||
type_inferenced_ast: 06be9e7e193c4fcdca75ba8218de79dcc8317b1eb63d9c2f33ca790c614a472b
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
namespace: Compile
|
||||
expectation: Fail
|
||||
outputs:
|
||||
- "Error [EASG0373025]: unexpected type, expected: '()', received: 'bool'\n --> compiler-test:4:13\n |\n 4 | return (10u8.len() == 10u32) == y;\n | ^^^^^^^^^^^^^^^^^^^^^^^^^"
|
@ -0,0 +1,22 @@
|
||||
---
|
||||
namespace: Compile
|
||||
expectation: Pass
|
||||
outputs:
|
||||
- circuit:
|
||||
num_public_variables: 0
|
||||
num_private_variables: 1
|
||||
num_constraints: 1
|
||||
at: 042610d0fd1fe6d6ac112138f8755752f44c7d2a00f1b5960574d6da5cda393f
|
||||
bt: e97756698880ab7555a959a5fb5c6b4e15bd64612aa677adbfe2d0bd91f0a83c
|
||||
ct: cf1cbb66a638b4860a516671fb74850e6ccf787fe6c4c8d29e9c04efe880bd05
|
||||
output:
|
||||
- input_file: input/dummy.in
|
||||
output:
|
||||
registers:
|
||||
r0:
|
||||
type: bool
|
||||
value: "true"
|
||||
initial_ast: 9886d4d97c894fade697bd99ac9cbe2a56973037837f34884e3dbad4dd4d5d65
|
||||
imports_resolved_ast: 9886d4d97c894fade697bd99ac9cbe2a56973037837f34884e3dbad4dd4d5d65
|
||||
canonicalized_ast: 36dbb999756e8e8bb68c69388889f0cfc217fbdbb0467f43453e19feb5c55d22
|
||||
type_inferenced_ast: 4fff72622455ea5bfc073c8e90e2266545b01e3004b73e4ee909b37b0bd75f46
|
Loading…
Reference in New Issue
Block a user