From 22e36341fd750d7ebc6f919e5073a32d8cb72aad Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 15 Aug 2024 07:55:02 -0300 Subject: [PATCH 1/5] Add `Expr::as_tuple` --- .../src/hir/comptime/interpreter/builtin.rs | 18 ++++++++++++++++++ noir_stdlib/src/meta/expr.nr | 3 +++ .../comptime_exp/src/main.nr | 6 ++++++ 3 files changed, 27 insertions(+) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 5698cc8d3bd..94f4f7bba46 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -48,6 +48,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "array_len" => array_len(interner, arguments, location), "as_slice" => as_slice(interner, arguments, location), "expr_as_function_call" => expr_as_function_call(arguments, return_type, location), + "expr_as_tuple" => expr_as_tuple(arguments, return_type, location), "is_unconstrained" => Ok(Value::Bool(true)), "function_def_name" => function_def_name(interner, arguments, location), "function_def_parameters" => function_def_parameters(interner, arguments, location), @@ -770,6 +771,23 @@ fn expr_as_function_call( }) } +// fn as_tuple(self) -> Option<[Expr]> +fn expr_as_tuple( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + expr_as(arguments, return_type, location, |expr| { + if let ExpressionKind::Tuple(expressions) = expr { + let expressions = expressions.into_iter().map(|expr| Value::Expr(expr.kind)).collect(); + let typ = Type::Slice(Box::new(Type::Quoted(QuotedType::Expr))); + Some(Value::Slice(expressions, typ)) + } else { + None + } + }) +} + // Helper function for implementing the `expr_as_...` functions. fn expr_as( arguments: Vec<(Value, Location)>, diff --git a/noir_stdlib/src/meta/expr.nr b/noir_stdlib/src/meta/expr.nr index 54681632543..f59fff84281 100644 --- a/noir_stdlib/src/meta/expr.nr +++ b/noir_stdlib/src/meta/expr.nr @@ -3,4 +3,7 @@ use crate::option::Option; impl Expr { #[builtin(expr_as_function_call)] fn as_function_call(self) -> Option<(Expr, [Expr])> {} + + #[builtin(expr_as_tuple)] + fn as_tuple(self) -> Option<[Expr]> {} } diff --git a/test_programs/compile_success_empty/comptime_exp/src/main.nr b/test_programs/compile_success_empty/comptime_exp/src/main.nr index 8b6f7b480c7..5b6df5b5629 100644 --- a/test_programs/compile_success_empty/comptime_exp/src/main.nr +++ b/test_programs/compile_success_empty/comptime_exp/src/main.nr @@ -1,8 +1,14 @@ fn main() { comptime { + // Check Expr::as_function_call let expr = quote { foo(bar) }.as_expr().unwrap(); let (_function, args) = expr.as_function_call().unwrap(); assert_eq(args.len(), 1); + + // Check Expr::as_tuple + let expr = quote { (1, 2) }.as_expr().unwrap(); + let tuple_exprs = expr.as_tuple().unwrap(); + assert_eq(tuple_exprs.len(), 2); } } From f620b189cf68fb1dfae6c4265746eddd63469b3b Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 15 Aug 2024 08:26:43 -0300 Subject: [PATCH 2/5] Add `Expr::as_parenthesized` --- .../src/hir/comptime/interpreter/builtin.rs | 16 ++++++++++++++++ noir_stdlib/src/meta/expr.nr | 3 +++ .../comptime_exp/src/main.nr | 4 ++++ 3 files changed, 23 insertions(+) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 94f4f7bba46..4661ecba9f5 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -48,6 +48,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "array_len" => array_len(interner, arguments, location), "as_slice" => as_slice(interner, arguments, location), "expr_as_function_call" => expr_as_function_call(arguments, return_type, location), + "expr_as_parenthesized" => expr_as_parenthesized(arguments, return_type, location), "expr_as_tuple" => expr_as_tuple(arguments, return_type, location), "is_unconstrained" => Ok(Value::Bool(true)), "function_def_name" => function_def_name(interner, arguments, location), @@ -771,6 +772,21 @@ fn expr_as_function_call( }) } +// fn as_parentehsized(self) -> Option +fn expr_as_parenthesized( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + expr_as(arguments, return_type, location, |expr| { + if let ExpressionKind::Parenthesized(expr) = expr { + Some(Value::Expr(expr.kind)) + } else { + None + } + }) +} + // fn as_tuple(self) -> Option<[Expr]> fn expr_as_tuple( arguments: Vec<(Value, Location)>, diff --git a/noir_stdlib/src/meta/expr.nr b/noir_stdlib/src/meta/expr.nr index f59fff84281..a5acaa6305d 100644 --- a/noir_stdlib/src/meta/expr.nr +++ b/noir_stdlib/src/meta/expr.nr @@ -4,6 +4,9 @@ impl Expr { #[builtin(expr_as_function_call)] fn as_function_call(self) -> Option<(Expr, [Expr])> {} + #[builtin(expr_as_parenthesized)] + fn as_parenthesized(self) -> Option {} + #[builtin(expr_as_tuple)] fn as_tuple(self) -> Option<[Expr]> {} } diff --git a/test_programs/compile_success_empty/comptime_exp/src/main.nr b/test_programs/compile_success_empty/comptime_exp/src/main.nr index 5b6df5b5629..ea5ca98fb90 100644 --- a/test_programs/compile_success_empty/comptime_exp/src/main.nr +++ b/test_programs/compile_success_empty/comptime_exp/src/main.nr @@ -6,6 +6,10 @@ fn main() { let (_function, args) = expr.as_function_call().unwrap(); assert_eq(args.len(), 1); + // Check Expr::as_parenthesized + let expr = quote { (1) }.as_expr().unwrap(); + let _ = expr.as_parenthesized().unwrap(); + // Check Expr::as_tuple let expr = quote { (1, 2) }.as_expr().unwrap(); let tuple_exprs = expr.as_tuple().unwrap(); From 851fd7099e4594c807f5f59e9caefa48eb641d90 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 15 Aug 2024 08:31:47 -0300 Subject: [PATCH 3/5] Add `Expr::as_index` --- .../src/hir/comptime/interpreter/builtin.rs | 19 +++++++++++++++++++ noir_stdlib/src/meta/expr.nr | 3 +++ .../comptime_exp/src/main.nr | 4 ++++ 3 files changed, 26 insertions(+) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 4661ecba9f5..ba854b6e485 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -48,6 +48,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "array_len" => array_len(interner, arguments, location), "as_slice" => as_slice(interner, arguments, location), "expr_as_function_call" => expr_as_function_call(arguments, return_type, location), + "expr_as_index" => expr_as_index(arguments, return_type, location), "expr_as_parenthesized" => expr_as_parenthesized(arguments, return_type, location), "expr_as_tuple" => expr_as_tuple(arguments, return_type, location), "is_unconstrained" => Ok(Value::Bool(true)), @@ -772,6 +773,24 @@ fn expr_as_function_call( }) } +// fn as_index(self) -> Option +fn expr_as_index( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + expr_as(arguments, return_type, location, |expr| { + if let ExpressionKind::Index(index_expr) = expr { + Some(Value::Tuple(vec![ + Value::Expr(index_expr.collection.kind), + Value::Expr(index_expr.index.kind), + ])) + } else { + None + } + }) +} + // fn as_parentehsized(self) -> Option fn expr_as_parenthesized( arguments: Vec<(Value, Location)>, diff --git a/noir_stdlib/src/meta/expr.nr b/noir_stdlib/src/meta/expr.nr index a5acaa6305d..7031301c587 100644 --- a/noir_stdlib/src/meta/expr.nr +++ b/noir_stdlib/src/meta/expr.nr @@ -4,6 +4,9 @@ impl Expr { #[builtin(expr_as_function_call)] fn as_function_call(self) -> Option<(Expr, [Expr])> {} + #[builtin(expr_as_index)] + fn as_index(self) -> Option<(Expr, Expr)> {} + #[builtin(expr_as_parenthesized)] fn as_parenthesized(self) -> Option {} diff --git a/test_programs/compile_success_empty/comptime_exp/src/main.nr b/test_programs/compile_success_empty/comptime_exp/src/main.nr index ea5ca98fb90..30df2ca072a 100644 --- a/test_programs/compile_success_empty/comptime_exp/src/main.nr +++ b/test_programs/compile_success_empty/comptime_exp/src/main.nr @@ -6,6 +6,10 @@ fn main() { let (_function, args) = expr.as_function_call().unwrap(); assert_eq(args.len(), 1); + // Check Expr::as_index + let expr = quote { foo[bar] }.as_expr().unwrap(); + let _ = expr.as_index().unwrap(); + // Check Expr::as_parenthesized let expr = quote { (1) }.as_expr().unwrap(); let _ = expr.as_parenthesized().unwrap(); From 6fa75ee2b4395c1ff6cd2dbf913a8bbbf1baae81 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 15 Aug 2024 09:47:07 -0300 Subject: [PATCH 4/5] Add `Expr::as_if` --- .../src/hir/comptime/interpreter/builtin.rs | 31 +++++++++++++++++++ noir_stdlib/src/meta/expr.nr | 3 ++ .../comptime_exp/src/main.nr | 9 ++++++ 3 files changed, 43 insertions(+) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index ba854b6e485..121fcb65d0e 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -48,6 +48,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "array_len" => array_len(interner, arguments, location), "as_slice" => as_slice(interner, arguments, location), "expr_as_function_call" => expr_as_function_call(arguments, return_type, location), + "expr_as_if" => expr_as_if(arguments, return_type, location), "expr_as_index" => expr_as_index(arguments, return_type, location), "expr_as_parenthesized" => expr_as_parenthesized(arguments, return_type, location), "expr_as_tuple" => expr_as_tuple(arguments, return_type, location), @@ -773,6 +774,36 @@ fn expr_as_function_call( }) } +// fn as_if(self) -> Option<(Expr, Expr, Option)> +fn expr_as_if( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + expr_as(arguments, return_type.clone(), location, |expr| { + if let ExpressionKind::If(if_expr) = expr { + // Get the type of `Option` + let option_type = extract_option_generic_type(return_type.clone()); + let Type::Tuple(option_types) = option_type else { + panic!("Expected the return type option generic arg to be a tuple"); + }; + assert_eq!(option_types.len(), 3); + let alternative_option_type = option_types[2].clone(); + + let alternative = + option(alternative_option_type, if_expr.alternative.map(|e| Value::Expr(e.kind))); + + Some(Value::Tuple(vec![ + Value::Expr(if_expr.condition.kind), + Value::Expr(if_expr.consequence.kind), + alternative.ok()?, + ])) + } else { + None + } + }) +} + // fn as_index(self) -> Option fn expr_as_index( arguments: Vec<(Value, Location)>, diff --git a/noir_stdlib/src/meta/expr.nr b/noir_stdlib/src/meta/expr.nr index 7031301c587..3be4266b352 100644 --- a/noir_stdlib/src/meta/expr.nr +++ b/noir_stdlib/src/meta/expr.nr @@ -4,6 +4,9 @@ impl Expr { #[builtin(expr_as_function_call)] fn as_function_call(self) -> Option<(Expr, [Expr])> {} + #[builtin(expr_as_if)] + fn as_if(self) -> Option<(Expr, Expr, Option)> {} + #[builtin(expr_as_index)] fn as_index(self) -> Option<(Expr, Expr)> {} diff --git a/test_programs/compile_success_empty/comptime_exp/src/main.nr b/test_programs/compile_success_empty/comptime_exp/src/main.nr index 30df2ca072a..e014d73312b 100644 --- a/test_programs/compile_success_empty/comptime_exp/src/main.nr +++ b/test_programs/compile_success_empty/comptime_exp/src/main.nr @@ -18,5 +18,14 @@ fn main() { let expr = quote { (1, 2) }.as_expr().unwrap(); let tuple_exprs = expr.as_tuple().unwrap(); assert_eq(tuple_exprs.len(), 2); + + // Check Expr::as_if + let expr = quote { if 1 { 2 } }.as_expr().unwrap(); + let (_condition, _consequence, alternative) = expr.as_if().unwrap(); + assert(alternative.is_none()); + + let expr = quote { if 1 { 2 } else { 3 } }.as_expr().unwrap(); + let (_condition, _consequence, alternative) = expr.as_if().unwrap(); + assert(alternative.is_some()); } } From 7023473debf08c715aa242bd616d682611dce62a Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 15 Aug 2024 12:16:31 -0300 Subject: [PATCH 5/5] Remove `Expr::as_parenthesized` --- .../src/hir/comptime/interpreter/builtin.rs | 24 +++++-------------- noir_stdlib/src/meta/expr.nr | 3 --- .../comptime_exp/src/main.nr | 8 +++---- 3 files changed, 10 insertions(+), 25 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 121fcb65d0e..c3528434a72 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -50,7 +50,6 @@ impl<'local, 'context> Interpreter<'local, 'context> { "expr_as_function_call" => expr_as_function_call(arguments, return_type, location), "expr_as_if" => expr_as_if(arguments, return_type, location), "expr_as_index" => expr_as_index(arguments, return_type, location), - "expr_as_parenthesized" => expr_as_parenthesized(arguments, return_type, location), "expr_as_tuple" => expr_as_tuple(arguments, return_type, location), "is_unconstrained" => Ok(Value::Bool(true)), "function_def_name" => function_def_name(interner, arguments, location), @@ -822,21 +821,6 @@ fn expr_as_index( }) } -// fn as_parentehsized(self) -> Option -fn expr_as_parenthesized( - arguments: Vec<(Value, Location)>, - return_type: Type, - location: Location, -) -> IResult { - expr_as(arguments, return_type, location, |expr| { - if let ExpressionKind::Parenthesized(expr) = expr { - Some(Value::Expr(expr.kind)) - } else { - None - } - }) -} - // fn as_tuple(self) -> Option<[Expr]> fn expr_as_tuple( arguments: Vec<(Value, Location)>, @@ -865,8 +849,12 @@ where F: FnOnce(ExpressionKind) -> Option, { let self_argument = check_one_argument(arguments, location)?; - let expr = get_expr(self_argument)?; - let option_value = f(expr); + let mut expression_kind = get_expr(self_argument)?; + while let ExpressionKind::Parenthesized(expression) = expression_kind { + expression_kind = expression.kind; + } + + let option_value = f(expression_kind); option(return_type, option_value) } diff --git a/noir_stdlib/src/meta/expr.nr b/noir_stdlib/src/meta/expr.nr index 3be4266b352..2a463ef4d86 100644 --- a/noir_stdlib/src/meta/expr.nr +++ b/noir_stdlib/src/meta/expr.nr @@ -10,9 +10,6 @@ impl Expr { #[builtin(expr_as_index)] fn as_index(self) -> Option<(Expr, Expr)> {} - #[builtin(expr_as_parenthesized)] - fn as_parenthesized(self) -> Option {} - #[builtin(expr_as_tuple)] fn as_tuple(self) -> Option<[Expr]> {} } diff --git a/test_programs/compile_success_empty/comptime_exp/src/main.nr b/test_programs/compile_success_empty/comptime_exp/src/main.nr index e014d73312b..81531310ff5 100644 --- a/test_programs/compile_success_empty/comptime_exp/src/main.nr +++ b/test_programs/compile_success_empty/comptime_exp/src/main.nr @@ -10,10 +10,6 @@ fn main() { let expr = quote { foo[bar] }.as_expr().unwrap(); let _ = expr.as_index().unwrap(); - // Check Expr::as_parenthesized - let expr = quote { (1) }.as_expr().unwrap(); - let _ = expr.as_parenthesized().unwrap(); - // Check Expr::as_tuple let expr = quote { (1, 2) }.as_expr().unwrap(); let tuple_exprs = expr.as_tuple().unwrap(); @@ -27,5 +23,9 @@ fn main() { let expr = quote { if 1 { 2 } else { 3 } }.as_expr().unwrap(); let (_condition, _consequence, alternative) = expr.as_if().unwrap(); assert(alternative.is_some()); + + // Check parenthesized expression is automatically unwrapped + let expr = quote { ((if 1 { 2 })) }.as_expr().unwrap(); + assert(expr.as_if().is_some()); } }