Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: format for stmt #3333

Merged
merged 5 commits into from Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 125 additions & 8 deletions compiler/noirc_frontend/src/ast/statement.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
use std::fmt::Display;
use std::sync::atomic::{AtomicU32, Ordering};

use crate::lexer::token::SpannedToken;
use crate::parser::{ParserError, ParserErrorReason};
use crate::token::Token;
use crate::{Expression, ExpressionKind, IndexExpression, MemberAccessExpression, UnresolvedType};
use crate::{
BlockExpression, Expression, ExpressionKind, IndexExpression, MemberAccessExpression,
MethodCallExpression, UnresolvedType,
};
use acvm::FieldElement;
use iter_extended::vecmap;
use noirc_errors::{Span, Spanned};

Expand Down Expand Up @@ -478,12 +483,123 @@ impl LValue {
}
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ForRange {
Range(/*start:*/ Expression, /*end:*/ Expression),
Array(Expression),
}

impl ForRange {
/// Create a 'for' expression taking care of desugaring a 'for e in array' loop
/// into the following if needed:
///
/// {
/// let fresh1 = array;
/// for fresh2 in 0 .. std::array::len(fresh1) {
/// let elem = fresh1[fresh2];
/// ...
/// }
/// }
pub(crate) fn into_for(
self,
identifier: Ident,
block: Expression,
for_loop_span: Span,
) -> StatementKind {
/// Counter used to generate unique names when desugaring
/// code in the parser requires the creation of fresh variables.
/// The parser is stateless so this is a static global instead.
static UNIQUE_NAME_COUNTER: AtomicU32 = AtomicU32::new(0);

match self {
ForRange::Range(..) => {
unreachable!()
}
ForRange::Array(array) => {
let array_span = array.span;
let start_range = ExpressionKind::integer(FieldElement::zero());
let start_range = Expression::new(start_range, array_span);

let next_unique_id = UNIQUE_NAME_COUNTER.fetch_add(1, Ordering::Relaxed);
let array_name = format!("$i{next_unique_id}");
let array_span = array.span;
let array_ident = Ident::new(array_name, array_span);

// let fresh1 = array;
let let_array = Statement {
kind: StatementKind::Let(LetStatement {
pattern: Pattern::Identifier(array_ident.clone()),
r#type: UnresolvedType::unspecified(),
expression: array,
}),
span: array_span,
};

// array.len()
let segments = vec![array_ident];
let array_ident =
ExpressionKind::Variable(Path { segments, kind: PathKind::Plain });

let end_range = ExpressionKind::MethodCall(Box::new(MethodCallExpression {
object: Expression::new(array_ident.clone(), array_span),
method_name: Ident::new("len".to_string(), array_span),
arguments: vec![],
}));
let end_range = Expression::new(end_range, array_span);

let next_unique_id = UNIQUE_NAME_COUNTER.fetch_add(1, Ordering::Relaxed);
let index_name = format!("$i{next_unique_id}");
let fresh_identifier = Ident::new(index_name.clone(), array_span);

// array[i]
let segments = vec![Ident::new(index_name, array_span)];
let index_ident =
ExpressionKind::Variable(Path { segments, kind: PathKind::Plain });

let loop_element = ExpressionKind::Index(Box::new(IndexExpression {
collection: Expression::new(array_ident, array_span),
index: Expression::new(index_ident, array_span),
}));

// let elem = array[i];
let let_elem = Statement {
kind: StatementKind::Let(LetStatement {
pattern: Pattern::Identifier(identifier),
r#type: UnresolvedType::unspecified(),
expression: Expression::new(loop_element, array_span),
}),
span: array_span,
};

let block_span = block.span;
let new_block = BlockExpression(vec![
let_elem,
Statement { kind: StatementKind::Expression(block), span: block_span },
]);
let new_block = Expression::new(ExpressionKind::Block(new_block), block_span);
let for_loop = Statement {
kind: StatementKind::For(ForLoopStatement {
identifier: fresh_identifier,
range: ForRange::Range(start_range, end_range),
block: new_block,
span: for_loop_span,
}),
span: for_loop_span,
};

let block = ExpressionKind::Block(BlockExpression(vec![let_array, for_loop]));
StatementKind::Expression(Expression::new(block, for_loop_span))
}
}
}
}

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ForLoopStatement {
pub identifier: Ident,
pub start_range: Expression,
pub end_range: Expression,
pub range: ForRange,
pub block: Expression,
pub span: Span,
}

impl Display for StatementKind {
Expand Down Expand Up @@ -575,10 +691,11 @@ impl Display for Pattern {

impl Display for ForLoopStatement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"for {} in {} .. {} {}",
self.identifier, self.start_range, self.end_range, self.block
)
let range = match &self.range {
ForRange::Range(start, end) => format!("{start}..{end}"),
ForRange::Array(expr) => expr.to_string(),
};

write!(f, "for {} in {range} {}", self.identifier, self.block)
}
}
55 changes: 35 additions & 20 deletions compiler/noirc_frontend/src/hir/resolution/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@
StatementKind,
};
use crate::{
ArrayLiteral, ContractFunctionType, Distinctness, FunctionVisibility, Generics, LValue,
NoirStruct, NoirTypeAlias, Path, PathKind, Pattern, Shared, StructType, Type, TypeAliasType,
TypeBinding, TypeVariable, UnaryOp, UnresolvedGenerics, UnresolvedTraitConstraint,
UnresolvedType, UnresolvedTypeData, UnresolvedTypeExpression, Visibility, ERROR_IDENT,
ArrayLiteral, ContractFunctionType, Distinctness, ForRange, FunctionVisibility, Generics,
LValue, NoirStruct, NoirTypeAlias, Path, PathKind, Pattern, Shared, StructType, Type,
TypeAliasType, TypeBinding, TypeVariable, UnaryOp, UnresolvedGenerics,
UnresolvedTraitConstraint, UnresolvedType, UnresolvedTypeData, UnresolvedTypeExpression,
Visibility, ERROR_IDENT,
};
use fm::FileId;
use iter_extended::vecmap;
Expand Down Expand Up @@ -89,7 +90,7 @@

/// True if the current module is a contract.
/// This is usually determined by self.path_resolver.module_id(), but it can
/// be overriden for impls. Impls are an odd case since the methods within resolve

Check warning on line 93 in compiler/noirc_frontend/src/hir/resolution/resolver.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (overriden)
/// as if they're in the parent module, but should be placed in a child module.
/// Since they should be within a child module, in_contract is manually set to false
/// for these so we can still resolve them in the parent module without them being in a contract.
Expand Down Expand Up @@ -1007,23 +1008,37 @@
HirStatement::Assign(stmt)
}
StatementKind::For(for_loop) => {
let start_range = self.resolve_expression(for_loop.start_range);
let end_range = self.resolve_expression(for_loop.end_range);
let (identifier, block) = (for_loop.identifier, for_loop.block);

// TODO: For loop variables are currently mutable by default since we haven't
// yet implemented syntax for them to be optionally mutable.
let (identifier, block) = self.in_new_scope(|this| {
let decl = this.add_variable_decl(
identifier,
false,
true,
DefinitionKind::Local(None),
);
(decl, this.resolve_expression(block))
});
match for_loop.range {
ForRange::Range(start_range, end_range) => {
let start_range = self.resolve_expression(start_range);
let end_range = self.resolve_expression(end_range);
let (identifier, block) = (for_loop.identifier, for_loop.block);

// TODO: For loop variables are currently mutable by default since we haven't
// yet implemented syntax for them to be optionally mutable.
let (identifier, block) = self.in_new_scope(|this| {
let decl = this.add_variable_decl(
identifier,
false,
true,
DefinitionKind::Local(None),
);
(decl, this.resolve_expression(block))
});

HirStatement::For(HirForStatement { start_range, end_range, block, identifier })
HirStatement::For(HirForStatement {
start_range,
end_range,
block,
identifier,
})
}
range @ ForRange::Array(_) => {
let for_stmt =
range.into_for(for_loop.identifier, for_loop.block, for_loop.span);
self.resolve_stmt(for_stmt)
}
}
}
StatementKind::Error => HirStatement::Error,
}
Expand Down
113 changes: 2 additions & 111 deletions compiler/noirc_frontend/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,20 @@ mod labels;
#[allow(clippy::module_inception)]
mod parser;

use std::sync::atomic::{AtomicU32, Ordering};

use crate::token::{Keyword, Token};
use crate::{ast::ImportStatement, Expression, NoirStruct};
use crate::{
BlockExpression, ExpressionKind, ForLoopStatement, Ident, IndexExpression, LetStatement,
MethodCallExpression, NoirFunction, NoirTrait, NoirTraitImpl, NoirTypeAlias, Path, PathKind,
Pattern, Recoverable, Statement, StatementKind, TypeImpl, UnresolvedType, UseTree,
Ident, LetStatement, NoirFunction, NoirTrait, NoirTraitImpl, NoirTypeAlias, Recoverable,
StatementKind, TypeImpl, UseTree,
};

use acvm::FieldElement;
use chumsky::prelude::*;
use chumsky::primitive::Container;
pub use errors::ParserError;
pub use errors::ParserErrorReason;
use noirc_errors::Span;
pub use parser::parse_program;

/// Counter used to generate unique names when desugaring
/// code in the parser requires the creation of fresh variables.
/// The parser is stateless so this is a static global instead.
static UNIQUE_NAME_COUNTER: AtomicU32 = AtomicU32::new(0);

#[derive(Debug, Clone)]
pub(crate) enum TopLevelStatement {
Function(NoirFunction),
Expand Down Expand Up @@ -478,106 +469,6 @@ impl Precedence {
}
}

enum ForRange {
Range(/*start:*/ Expression, /*end:*/ Expression),
Array(Expression),
}

impl ForRange {
/// Create a 'for' expression taking care of desugaring a 'for e in array' loop
/// into the following if needed:
///
/// {
/// let fresh1 = array;
/// for fresh2 in 0 .. std::array::len(fresh1) {
/// let elem = fresh1[fresh2];
/// ...
/// }
/// }
fn into_for(self, identifier: Ident, block: Expression, for_loop_span: Span) -> StatementKind {
match self {
ForRange::Range(start_range, end_range) => {
StatementKind::For(ForLoopStatement { identifier, start_range, end_range, block })
}
ForRange::Array(array) => {
let array_span = array.span;
let start_range = ExpressionKind::integer(FieldElement::zero());
let start_range = Expression::new(start_range, array_span);

let next_unique_id = UNIQUE_NAME_COUNTER.fetch_add(1, Ordering::Relaxed);
let array_name = format!("$i{next_unique_id}");
let array_span = array.span;
let array_ident = Ident::new(array_name, array_span);

// let fresh1 = array;
let let_array = Statement {
kind: StatementKind::Let(LetStatement {
pattern: Pattern::Identifier(array_ident.clone()),
r#type: UnresolvedType::unspecified(),
expression: array,
}),
span: array_span,
};

// array.len()
let segments = vec![array_ident];
let array_ident =
ExpressionKind::Variable(Path { segments, kind: PathKind::Plain });

let end_range = ExpressionKind::MethodCall(Box::new(MethodCallExpression {
object: Expression::new(array_ident.clone(), array_span),
method_name: Ident::new("len".to_string(), array_span),
arguments: vec![],
}));
let end_range = Expression::new(end_range, array_span);

let next_unique_id = UNIQUE_NAME_COUNTER.fetch_add(1, Ordering::Relaxed);
let index_name = format!("$i{next_unique_id}");
let fresh_identifier = Ident::new(index_name.clone(), array_span);

// array[i]
let segments = vec![Ident::new(index_name, array_span)];
let index_ident =
ExpressionKind::Variable(Path { segments, kind: PathKind::Plain });

let loop_element = ExpressionKind::Index(Box::new(IndexExpression {
collection: Expression::new(array_ident, array_span),
index: Expression::new(index_ident, array_span),
}));

// let elem = array[i];
let let_elem = Statement {
kind: StatementKind::Let(LetStatement {
pattern: Pattern::Identifier(identifier),
r#type: UnresolvedType::unspecified(),
expression: Expression::new(loop_element, array_span),
}),
span: array_span,
};

let block_span = block.span;
let new_block = BlockExpression(vec![
let_elem,
Statement { kind: StatementKind::Expression(block), span: block_span },
]);
let new_block = Expression::new(ExpressionKind::Block(new_block), block_span);
let for_loop = Statement {
kind: StatementKind::For(ForLoopStatement {
identifier: fresh_identifier,
start_range,
end_range,
block: new_block,
}),
span: for_loop_span,
};

let block = ExpressionKind::Block(BlockExpression(vec![let_array, for_loop]));
StatementKind::Expression(Expression::new(block, for_loop_span))
}
}
}
}

impl std::fmt::Display for TopLevelStatement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expand Down
Loading
Loading