Skip to content

Commit a7356e2

Browse files
authored
fix: allow method call after block, if and match (#7655)
1 parent 60d1368 commit a7356e2

File tree

3 files changed

+82
-16
lines changed

3 files changed

+82
-16
lines changed

compiler/noirc_frontend/src/parser/parser/expression.rs

+19
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,25 @@ impl Parser<'_> {
147147
self.parse_index(atom, start_location)
148148
}
149149

150+
pub(super) fn parse_member_accesses_or_method_calls_after_expression(
151+
&mut self,
152+
mut atom: Expression,
153+
start_location: Location,
154+
) -> Expression {
155+
let mut parsed;
156+
157+
loop {
158+
(atom, parsed) = self.parse_member_access_or_method_call(atom, start_location);
159+
if parsed {
160+
continue;
161+
} else {
162+
break;
163+
}
164+
}
165+
166+
atom
167+
}
168+
150169
/// CallExpression = Atom CallArguments
151170
fn parse_call(&mut self, atom: Expression, start_location: Location) -> (Expression, bool) {
152171
if let Some(call_arguments) = self.parse_call_arguments() {

compiler/noirc_frontend/src/parser/parser/function.rs

+40-2
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,8 @@ fn empty_body() -> BlockExpression {
324324
mod tests {
325325
use crate::{
326326
ast::{
327-
IntegerBitSize, ItemVisibility, NoirFunction, Signedness, UnresolvedTypeData,
328-
Visibility,
327+
ExpressionKind, IntegerBitSize, ItemVisibility, NoirFunction, Signedness,
328+
StatementKind, UnresolvedTypeData, Visibility,
329329
},
330330
parse_program_with_dummy_file,
331331
parser::{
@@ -570,4 +570,42 @@ mod tests {
570570
UnresolvedTypeData::Integer(Signedness::Signed, IntegerBitSize::SixtyFour)
571571
);
572572
}
573+
574+
#[test]
575+
fn parses_block_followed_by_call() {
576+
let src = "fn foo() { { 1 }.bar() }";
577+
let noir_function = parse_function_no_error(src);
578+
let statements = &noir_function.def.body.statements;
579+
assert_eq!(statements.len(), 1);
580+
581+
let StatementKind::Expression(expr) = &statements[0].kind else {
582+
panic!("Expected expression statement");
583+
};
584+
585+
let ExpressionKind::MethodCall(call) = &expr.kind else {
586+
panic!("Expected method call expression");
587+
};
588+
589+
assert!(matches!(call.object.kind, ExpressionKind::Block(_)));
590+
assert_eq!(call.method_name.to_string(), "bar");
591+
}
592+
593+
#[test]
594+
fn parses_if_followed_by_call() {
595+
let src = "fn foo() { if 1 { 2 } else { 3 }.bar() }";
596+
let noir_function = parse_function_no_error(src);
597+
let statements = &noir_function.def.body.statements;
598+
assert_eq!(statements.len(), 1);
599+
600+
let StatementKind::Expression(expr) = &statements[0].kind else {
601+
panic!("Expected expression statement");
602+
};
603+
604+
let ExpressionKind::MethodCall(call) = &expr.kind else {
605+
panic!("Expected method call expression");
606+
};
607+
608+
assert!(matches!(call.object.kind, ExpressionKind::If(_)));
609+
assert_eq!(call.method_name.to_string(), "bar");
610+
}
573611
}

compiler/noirc_frontend/src/parser/parser/statement.rs

+23-14
Original file line numberDiff line numberDiff line change
@@ -146,21 +146,12 @@ impl Parser<'_> {
146146
return Some(StatementKind::While(while_));
147147
}
148148

149-
if let Some(kind) = self.parse_if_expr() {
150-
let location = self.location_since(start_location);
151-
return Some(StatementKind::Expression(Expression { kind, location }));
152-
}
153-
154-
if let Some(kind) = self.parse_match_expr() {
149+
if let Some(kind) = self.parse_block_like() {
155150
let location = self.location_since(start_location);
156-
return Some(StatementKind::Expression(Expression { kind, location }));
157-
}
158-
159-
if let Some(block) = self.parse_block() {
160-
return Some(StatementKind::Expression(Expression {
161-
kind: ExpressionKind::Block(block),
162-
location: self.location_since(start_location),
163-
}));
151+
let expression = Expression { kind, location };
152+
let expression = self
153+
.parse_member_accesses_or_method_calls_after_expression(expression, start_location);
154+
return Some(StatementKind::Expression(expression));
164155
}
165156

166157
if let Some(token) = self.eat_kind(TokenKind::InternedLValue) {
@@ -214,6 +205,24 @@ impl Parser<'_> {
214205
Some(StatementKind::Expression(expression))
215206
}
216207

208+
/// Parses an expression that looks like a block (ends with '}'):
209+
/// `{ ... }`, `if { ... }` and `match { ... }`.
210+
fn parse_block_like(&mut self) -> Option<ExpressionKind> {
211+
if let Some(kind) = self.parse_if_expr() {
212+
return Some(kind);
213+
}
214+
215+
if let Some(kind) = self.parse_match_expr() {
216+
return Some(kind);
217+
}
218+
219+
if let Some(block) = self.parse_block() {
220+
return Some(ExpressionKind::Block(block));
221+
}
222+
223+
None
224+
}
225+
217226
fn next_is_op_assign(&mut self) -> Option<BinaryOp> {
218227
let start_location = self.current_token_location;
219228
let operator = if self.next_is(Token::Assign) {

0 commit comments

Comments
 (0)