From 88b46c7fb182a12ef54e223b109b32b7956473e5 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Sun, 18 Aug 2024 20:08:03 -0300 Subject: [PATCH 1/4] Add Expr::as_array and Expr::as_slice --- .../src/hir/comptime/interpreter/builtin.rs | 40 ++++++++++++++++++- noir_stdlib/src/meta/expr.nr | 6 +++ .../comptime_exp/src/main.nr | 10 +++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index cec4b1fd434..84df2463cc8 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -17,8 +17,8 @@ use rustc_hash::FxHashMap as HashMap; use crate::{ ast::{ - ExpressionKind, FunctionKind, FunctionReturnType, IntegerBitSize, Literal, UnaryOp, - UnresolvedType, UnresolvedTypeData, Visibility, + ArrayLiteral, ExpressionKind, FunctionKind, FunctionReturnType, IntegerBitSize, Literal, + UnaryOp, UnresolvedType, UnresolvedTypeData, Visibility, }, hir::comptime::{errors::IResult, value::add_token_spans, InterpreterError, Value}, hir_def::function::FunctionBody, @@ -47,6 +47,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "array_as_str_unchecked" => array_as_str_unchecked(interner, arguments, location), "array_len" => array_len(interner, arguments, location), "as_slice" => as_slice(interner, arguments, location), + "expr_as_array" => expr_as_array(arguments, return_type, location), "expr_as_binary_op" => expr_as_binary_op(arguments, return_type, location), "expr_as_bool" => expr_as_bool(arguments, return_type, location), "expr_as_function_call" => expr_as_function_call(arguments, return_type, location), @@ -55,6 +56,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "expr_as_integer" => expr_as_integer(arguments, return_type, location), "expr_as_member_access" => expr_as_member_access(arguments, return_type, location), "expr_as_unary_op" => expr_as_unary_op(arguments, return_type, location), + "expr_as_slice" => expr_as_slice(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), @@ -758,6 +760,23 @@ fn zeroed(return_type: Type) -> IResult { } } +// fn as_array(self) -> Option<[Expr]> +fn expr_as_array( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + expr_as(arguments, return_type, location, |expr| { + if let ExpressionKind::Literal(Literal::Array(ArrayLiteral::Standard(exprs))) = expr { + let exprs = exprs.into_iter().map(|expr| Value::Expr(expr.kind)).collect(); + let typ = Type::Slice(Box::new(Type::Quoted(QuotedType::Expr))); + Some(Value::Slice(exprs, typ)) + } else { + None + } + }) +} + // fn as_bool(self) -> Option fn expr_as_bool( arguments: Vec<(Value, Location)>, @@ -942,6 +961,23 @@ fn expr_as_binary_op( }) } +// fn as_slice(self) -> Option<[Expr]> +fn expr_as_slice( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + expr_as(arguments, return_type, location, |expr| { + if let ExpressionKind::Literal(Literal::Slice(ArrayLiteral::Standard(exprs))) = expr { + let exprs = exprs.into_iter().map(|expr| Value::Expr(expr.kind)).collect(); + let typ = Type::Slice(Box::new(Type::Quoted(QuotedType::Expr))); + Some(Value::Slice(exprs, typ)) + } 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 55c49531017..4a344ca7cfc 100644 --- a/noir_stdlib/src/meta/expr.nr +++ b/noir_stdlib/src/meta/expr.nr @@ -3,6 +3,9 @@ use crate::meta::op::UnaryOp; use crate::meta::op::BinaryOp; impl Expr { + #[builtin(expr_as_array)] + fn as_array(self) -> Option<[Expr]> {} + #[builtin(expr_as_integer)] fn as_integer(self) -> Option<(Field, bool)> {} @@ -24,6 +27,9 @@ impl Expr { #[builtin(expr_as_member_access)] fn as_member_access(self) -> Option<(Expr, Quoted)> {} + #[builtin(expr_as_slice)] + fn as_slice(self) -> Option<[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 7b25dcb5097..a29415fe717 100644 --- a/test_programs/compile_success_empty/comptime_exp/src/main.nr +++ b/test_programs/compile_success_empty/comptime_exp/src/main.nr @@ -71,6 +71,16 @@ fn main() { let expr = quote { foo.bar }.as_expr().unwrap(); let (_, name) = expr.as_member_access().unwrap(); assert_eq(name, quote { bar }); + + // Check Expr::as_array + let expr = quote { [1, 2, 3] }.as_expr().unwrap(); + let elems = expr.as_array().unwrap(); + assert_eq(elems.len(), 3); + + // Check Expr::as_slice + let expr = quote { &[1, 2, 3] }.as_expr().unwrap(); + let elems = expr.as_slice().unwrap(); + assert_eq(elems.len(), 3); } } From da2f3b681f902c6ce1eeb22b029f0c70adac65b5 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Sun, 18 Aug 2024 20:14:30 -0300 Subject: [PATCH 2/4] Sort builtins alphabetically --- .../src/hir/comptime/interpreter/builtin.rs | 136 +++++++++--------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 84df2463cc8..afd6295b1b7 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -55,9 +55,9 @@ impl<'local, 'context> Interpreter<'local, 'context> { "expr_as_index" => expr_as_index(arguments, return_type, location), "expr_as_integer" => expr_as_integer(arguments, return_type, location), "expr_as_member_access" => expr_as_member_access(arguments, return_type, location), - "expr_as_unary_op" => expr_as_unary_op(arguments, return_type, location), "expr_as_slice" => expr_as_slice(arguments, return_type, location), "expr_as_tuple" => expr_as_tuple(arguments, return_type, location), + "expr_as_unary_op" => expr_as_unary_op(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), @@ -777,6 +777,39 @@ fn expr_as_array( }) } +// fn as_binary_op(self) -> Option<(Expr, BinaryOp, Expr)> +fn expr_as_binary_op( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + expr_as(arguments, return_type.clone(), location, |expr| { + if let ExpressionKind::Infix(infix_expr) = expr { + let option_type = extract_option_generic_type(return_type); + let Type::Tuple(mut tuple_types) = option_type else { + panic!("Expected the return type option generic arg to be a tuple"); + }; + assert_eq!(tuple_types.len(), 3); + + tuple_types.pop().unwrap(); + let binary_op_type = tuple_types.pop().unwrap(); + + // For the op value we use the enum member index, which should match noir_stdlib/src/meta/op.nr + let binary_op_value = infix_expr.operator.contents as u128; + + let mut fields = HashMap::default(); + fields.insert(Rc::new("op".to_string()), Value::Field(binary_op_value.into())); + + let unary_op = Value::Struct(fields, binary_op_type); + let lhs = Value::Expr(infix_expr.lhs.kind); + let rhs = Value::Expr(infix_expr.rhs.kind); + Some(Value::Tuple(vec![lhs, unary_op, rhs])) + } else { + None + } + }) +} + // fn as_bool(self) -> Option fn expr_as_bool( arguments: Vec<(Value, Location)>, @@ -891,6 +924,40 @@ fn expr_as_member_access( }) } +// fn as_slice(self) -> Option<[Expr]> +fn expr_as_slice( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + expr_as(arguments, return_type, location, |expr| { + if let ExpressionKind::Literal(Literal::Slice(ArrayLiteral::Standard(exprs))) = expr { + let exprs = exprs.into_iter().map(|expr| Value::Expr(expr.kind)).collect(); + let typ = Type::Slice(Box::new(Type::Quoted(QuotedType::Expr))); + Some(Value::Slice(exprs, typ)) + } else { + None + } + }) +} + +// 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 + } + }) +} + // fn as_unary_op(self) -> Option<(UnaryOp, Expr)> fn expr_as_unary_op( arguments: Vec<(Value, Location)>, @@ -928,73 +995,6 @@ fn expr_as_unary_op( }) } -// fn as_binary_op(self) -> Option<(Expr, BinaryOp, Expr)> -fn expr_as_binary_op( - arguments: Vec<(Value, Location)>, - return_type: Type, - location: Location, -) -> IResult { - expr_as(arguments, return_type.clone(), location, |expr| { - if let ExpressionKind::Infix(infix_expr) = expr { - let option_type = extract_option_generic_type(return_type); - let Type::Tuple(mut tuple_types) = option_type else { - panic!("Expected the return type option generic arg to be a tuple"); - }; - assert_eq!(tuple_types.len(), 3); - - tuple_types.pop().unwrap(); - let binary_op_type = tuple_types.pop().unwrap(); - - // For the op value we use the enum member index, which should match noir_stdlib/src/meta/op.nr - let binary_op_value = infix_expr.operator.contents as u128; - - let mut fields = HashMap::default(); - fields.insert(Rc::new("op".to_string()), Value::Field(binary_op_value.into())); - - let unary_op = Value::Struct(fields, binary_op_type); - let lhs = Value::Expr(infix_expr.lhs.kind); - let rhs = Value::Expr(infix_expr.rhs.kind); - Some(Value::Tuple(vec![lhs, unary_op, rhs])) - } else { - None - } - }) -} - -// fn as_slice(self) -> Option<[Expr]> -fn expr_as_slice( - arguments: Vec<(Value, Location)>, - return_type: Type, - location: Location, -) -> IResult { - expr_as(arguments, return_type, location, |expr| { - if let ExpressionKind::Literal(Literal::Slice(ArrayLiteral::Standard(exprs))) = expr { - let exprs = exprs.into_iter().map(|expr| Value::Expr(expr.kind)).collect(); - let typ = Type::Slice(Box::new(Type::Quoted(QuotedType::Expr))); - Some(Value::Slice(exprs, typ)) - } else { - None - } - }) -} - -// 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)>, From f4ba855c8a8b09e84c52b84cc0bc823e0954e20c Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Sun, 18 Aug 2024 20:14:40 -0300 Subject: [PATCH 3/4] Add Expr::as_repeated_array/slice_element --- .../src/hir/comptime/interpreter/builtin.rs | 44 +++++++++++++++++++ noir_stdlib/src/meta/expr.nr | 6 +++ .../comptime_exp/src/main.nr | 22 +++++++++- 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index afd6295b1b7..f65c5ae8cdf 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -55,6 +55,12 @@ impl<'local, 'context> Interpreter<'local, 'context> { "expr_as_index" => expr_as_index(arguments, return_type, location), "expr_as_integer" => expr_as_integer(arguments, return_type, location), "expr_as_member_access" => expr_as_member_access(arguments, return_type, location), + "expr_as_repeated_element_array" => { + expr_as_repeated_element_array(arguments, return_type, location) + } + "expr_as_repeated_element_slice" => { + expr_as_repeated_element_slice(arguments, return_type, location) + } "expr_as_slice" => expr_as_slice(arguments, return_type, location), "expr_as_tuple" => expr_as_tuple(arguments, return_type, location), "expr_as_unary_op" => expr_as_unary_op(arguments, return_type, location), @@ -924,6 +930,44 @@ fn expr_as_member_access( }) } +// fn as_repeated_element_array(self) -> Option<(Expr, Expr)> +fn expr_as_repeated_element_array( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + expr_as(arguments, return_type, location, |expr| { + if let ExpressionKind::Literal(Literal::Array(ArrayLiteral::Repeated { + repeated_element, + length, + })) = expr + { + Some(Value::Tuple(vec![Value::Expr(repeated_element.kind), Value::Expr(length.kind)])) + } else { + None + } + }) +} + +// fn as_repeated_element_slice(self) -> Option<(Expr, Expr)> +fn expr_as_repeated_element_slice( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + expr_as(arguments, return_type, location, |expr| { + if let ExpressionKind::Literal(Literal::Slice(ArrayLiteral::Repeated { + repeated_element, + length, + })) = expr + { + Some(Value::Tuple(vec![Value::Expr(repeated_element.kind), Value::Expr(length.kind)])) + } else { + None + } + }) +} + // fn as_slice(self) -> Option<[Expr]> fn expr_as_slice( arguments: Vec<(Value, Location)>, diff --git a/noir_stdlib/src/meta/expr.nr b/noir_stdlib/src/meta/expr.nr index 4a344ca7cfc..e04f815a90d 100644 --- a/noir_stdlib/src/meta/expr.nr +++ b/noir_stdlib/src/meta/expr.nr @@ -27,6 +27,12 @@ impl Expr { #[builtin(expr_as_member_access)] fn as_member_access(self) -> Option<(Expr, Quoted)> {} + #[builtin(expr_as_repeated_element_array)] + fn as_repeated_element_array(self) -> Option<(Expr, Expr)> {} + + #[builtin(expr_as_repeated_element_slice)] + fn as_repeated_element_slice(self) -> Option<(Expr, Expr)> {} + #[builtin(expr_as_slice)] fn as_slice(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 a29415fe717..626452950f9 100644 --- a/test_programs/compile_success_empty/comptime_exp/src/main.nr +++ b/test_programs/compile_success_empty/comptime_exp/src/main.nr @@ -73,14 +73,32 @@ fn main() { assert_eq(name, quote { bar }); // Check Expr::as_array - let expr = quote { [1, 2, 3] }.as_expr().unwrap(); + let expr = quote { [1, 2, 4] }.as_expr().unwrap(); let elems = expr.as_array().unwrap(); assert_eq(elems.len(), 3); + assert_eq(elems[0].as_integer().unwrap(), (1, false)); + assert_eq(elems[1].as_integer().unwrap(), (2, false)); + assert_eq(elems[2].as_integer().unwrap(), (4, false)); // Check Expr::as_slice - let expr = quote { &[1, 2, 3] }.as_expr().unwrap(); + let expr = quote { &[1, 3, 5] }.as_expr().unwrap(); let elems = expr.as_slice().unwrap(); assert_eq(elems.len(), 3); + assert_eq(elems[0].as_integer().unwrap(), (1, false)); + assert_eq(elems[1].as_integer().unwrap(), (3, false)); + assert_eq(elems[2].as_integer().unwrap(), (5, false)); + + // Check Expr::as_repeated_element_array + let expr = quote { [1; 3] }.as_expr().unwrap(); + let (expr, length) = expr.as_repeated_element_array().unwrap(); + assert_eq(expr.as_integer().unwrap(), (1, false)); + assert_eq(length.as_integer().unwrap(), (3, false)); + + // Check Expr::as_repeated_element_slice + let expr = quote { &[1; 3] }.as_expr().unwrap(); + let (expr, length) = expr.as_repeated_element_slice().unwrap(); + assert_eq(expr.as_integer().unwrap(), (1, false)); + assert_eq(length.as_integer().unwrap(), (3, false)); } } From 45754994ec44fdf64186214b93605c8f1e47f27a Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Mon, 19 Aug 2024 14:12:42 -0300 Subject: [PATCH 4/4] Move comptime expr tests to stdlib --- noir_stdlib/src/meta/expr.nr | 184 ++++++++++++++++++ .../comptime_exp/Nargo.toml | 7 - .../comptime_exp/src/main.nr | 115 ----------- 3 files changed, 184 insertions(+), 122 deletions(-) delete mode 100644 test_programs/compile_success_empty/comptime_exp/Nargo.toml delete mode 100644 test_programs/compile_success_empty/comptime_exp/src/main.nr diff --git a/noir_stdlib/src/meta/expr.nr b/noir_stdlib/src/meta/expr.nr index e04f815a90d..94889b7c3dd 100644 --- a/noir_stdlib/src/meta/expr.nr +++ b/noir_stdlib/src/meta/expr.nr @@ -42,3 +42,187 @@ impl Expr { #[builtin(expr_as_unary_op)] fn as_unary_op(self) -> Option<(UnaryOp, Expr)> {} } + +mod tests { + use crate::meta::op::UnaryOp; + use crate::meta::op::BinaryOp; + + #[test] + fn test_expr_as_array() { + comptime + { + let expr = quote { [1, 2, 4] }.as_expr().unwrap(); + let elems = expr.as_array().unwrap(); + assert_eq(elems.len(), 3); + assert_eq(elems[0].as_integer().unwrap(), (1, false)); + assert_eq(elems[1].as_integer().unwrap(), (2, false)); + assert_eq(elems[2].as_integer().unwrap(), (4, false)); + } + } + + #[test] + fn test_expr_as_integer() { + comptime + { + let expr = quote { 1 }.as_expr().unwrap(); + assert_eq((1, false), expr.as_integer().unwrap()); + + let expr = quote { -2 }.as_expr().unwrap(); + assert_eq((2, true), expr.as_integer().unwrap()); + } + } + + #[test] + fn test_expr_as_binary_op() { + comptime + { + assert(get_binary_op(quote { x + y }).is_add()); + assert(get_binary_op(quote { x - y }).is_subtract()); + assert(get_binary_op(quote { x * y }).is_multiply()); + assert(get_binary_op(quote { x / y }).is_divide()); + assert(get_binary_op(quote { x == y }).is_equal()); + assert(get_binary_op(quote { x != y }).is_not_equal()); + assert(get_binary_op(quote { x > y }).is_greater()); + assert(get_binary_op(quote { x >= y }).is_greater_or_equal()); + assert(get_binary_op(quote { x & y }).is_and()); + assert(get_binary_op(quote { x | y }).is_or()); + assert(get_binary_op(quote { x ^ y }).is_xor()); + assert(get_binary_op(quote { x >> y }).is_shift_right()); + assert(get_binary_op(quote { x << y }).is_shift_left()); + assert(get_binary_op(quote { x % y }).is_modulo()); + } + } + + #[test] + fn test_expr_as_bool() { + comptime + { + let expr = quote { false }.as_expr().unwrap(); + assert(expr.as_bool().unwrap() == false); + + let expr = quote { true }.as_expr().unwrap(); + assert_eq(expr.as_bool().unwrap(), true); + } + } + + #[test] + fn test_expr_as_function_call() { + comptime + { + let expr = quote { foo(42) }.as_expr().unwrap(); + let (_function, args) = expr.as_function_call().unwrap(); + assert_eq(args.len(), 1); + assert_eq(args[0].as_integer().unwrap(), (42, false)); + } + } + + #[test] + fn test_expr_as_if() { + comptime + { + 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()); + } + } + + #[test] + fn test_expr_as_index() { + comptime + { + let expr = quote { foo[bar] }.as_expr().unwrap(); + assert(expr.as_index().is_some()); + } + } + + #[test] + fn test_expr_as_member_access() { + comptime + { + let expr = quote { foo.bar }.as_expr().unwrap(); + let (_, name) = expr.as_member_access().unwrap(); + assert_eq(name, quote { bar }); + } + } + + #[test] + fn test_expr_as_repeated_element_array() { + comptime + { + let expr = quote { [1; 3] }.as_expr().unwrap(); + let (expr, length) = expr.as_repeated_element_array().unwrap(); + assert_eq(expr.as_integer().unwrap(), (1, false)); + assert_eq(length.as_integer().unwrap(), (3, false)); + } + } + + #[test] + fn test_expr_as_repeated_element_slice() { + comptime + { + let expr = quote { &[1; 3] }.as_expr().unwrap(); + let (expr, length) = expr.as_repeated_element_slice().unwrap(); + assert_eq(expr.as_integer().unwrap(), (1, false)); + assert_eq(length.as_integer().unwrap(), (3, false)); + } + } + + #[test] + fn test_expr_as_slice() { + comptime + { + let expr = quote { &[1, 3, 5] }.as_expr().unwrap(); + let elems = expr.as_slice().unwrap(); + assert_eq(elems.len(), 3); + assert_eq(elems[0].as_integer().unwrap(), (1, false)); + assert_eq(elems[1].as_integer().unwrap(), (3, false)); + assert_eq(elems[2].as_integer().unwrap(), (5, false)); + } + } + + #[test] + fn test_expr_as_tuple() { + comptime + { + let expr = quote { (1, 2) }.as_expr().unwrap(); + let tuple_exprs = expr.as_tuple().unwrap(); + assert_eq(tuple_exprs.len(), 2); + } + } + + #[test] + fn test_expr_as_unary_op() { + comptime + { + assert(get_unary_op(quote { -x }).is_minus()); + assert(get_unary_op(quote { !x }).is_not()); + assert(get_unary_op(quote { &mut x }).is_mutable_reference()); + assert(get_unary_op(quote { *x }).is_dereference()); + } + } + + #[test] + fn test_automatically_unwraps_parenthesized_expression() { + comptime + { + let expr = quote { ((if 1 { 2 })) }.as_expr().unwrap(); + assert(expr.as_if().is_some()); + } + } + + comptime fn get_unary_op(quoted: Quoted) -> UnaryOp { + let expr = quoted.as_expr().unwrap(); + let (op, _) = expr.as_unary_op().unwrap(); + op + } + + comptime fn get_binary_op(quoted: Quoted) -> BinaryOp { + let expr = quoted.as_expr().unwrap(); + let (_, op, _) = expr.as_binary_op().unwrap(); + op + } +} diff --git a/test_programs/compile_success_empty/comptime_exp/Nargo.toml b/test_programs/compile_success_empty/comptime_exp/Nargo.toml deleted file mode 100644 index df36e0e05b0..00000000000 --- a/test_programs/compile_success_empty/comptime_exp/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "comptime_exp" -type = "bin" -authors = [""] -compiler_version = ">=0.31.0" - -[dependencies] \ No newline at end of file diff --git a/test_programs/compile_success_empty/comptime_exp/src/main.nr b/test_programs/compile_success_empty/comptime_exp/src/main.nr deleted file mode 100644 index 626452950f9..00000000000 --- a/test_programs/compile_success_empty/comptime_exp/src/main.nr +++ /dev/null @@ -1,115 +0,0 @@ -use std::meta::op::UnaryOp; -use std::meta::op::BinaryOp; - -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_index - let expr = quote { foo[bar] }.as_expr().unwrap(); - let _ = expr.as_index().unwrap(); - - // 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); - - // 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()); - - // Check parenthesized expression is automatically unwrapped - let expr = quote { ((if 1 { 2 })) }.as_expr().unwrap(); - assert(expr.as_if().is_some()); - - // Check Expr::as_bool - let expr = quote { false }.as_expr().unwrap(); - assert(expr.as_bool().unwrap() == false); - - let expr = quote { true }.as_expr().unwrap(); - assert_eq(expr.as_bool().unwrap(), true); - - // Check Expr::as_unary_op - assert(get_unary_op(quote { -x }).is_minus()); - assert(get_unary_op(quote { !x }).is_not()); - assert(get_unary_op(quote { &mut x }).is_mutable_reference()); - assert(get_unary_op(quote { *x }).is_dereference()); - - // Check Expr::as_binary_op - assert(get_binary_op(quote { x + y }).is_add()); - assert(get_binary_op(quote { x - y }).is_subtract()); - assert(get_binary_op(quote { x * y }).is_multiply()); - assert(get_binary_op(quote { x / y }).is_divide()); - assert(get_binary_op(quote { x == y }).is_equal()); - assert(get_binary_op(quote { x != y }).is_not_equal()); - assert(get_binary_op(quote { x > y }).is_greater()); - assert(get_binary_op(quote { x >= y }).is_greater_or_equal()); - assert(get_binary_op(quote { x & y }).is_and()); - assert(get_binary_op(quote { x | y }).is_or()); - assert(get_binary_op(quote { x ^ y }).is_xor()); - assert(get_binary_op(quote { x >> y }).is_shift_right()); - assert(get_binary_op(quote { x << y }).is_shift_left()); - assert(get_binary_op(quote { x % y }).is_modulo()); - - // Check Expr::as_integer - let expr = quote { 1 }.as_expr().unwrap(); - assert_eq((1, false), expr.as_integer().unwrap()); - - let expr = quote { -2 }.as_expr().unwrap(); - assert_eq((2, true), expr.as_integer().unwrap()); - - // Check Expr::as_member_access - let expr = quote { foo.bar }.as_expr().unwrap(); - let (_, name) = expr.as_member_access().unwrap(); - assert_eq(name, quote { bar }); - - // Check Expr::as_array - let expr = quote { [1, 2, 4] }.as_expr().unwrap(); - let elems = expr.as_array().unwrap(); - assert_eq(elems.len(), 3); - assert_eq(elems[0].as_integer().unwrap(), (1, false)); - assert_eq(elems[1].as_integer().unwrap(), (2, false)); - assert_eq(elems[2].as_integer().unwrap(), (4, false)); - - // Check Expr::as_slice - let expr = quote { &[1, 3, 5] }.as_expr().unwrap(); - let elems = expr.as_slice().unwrap(); - assert_eq(elems.len(), 3); - assert_eq(elems[0].as_integer().unwrap(), (1, false)); - assert_eq(elems[1].as_integer().unwrap(), (3, false)); - assert_eq(elems[2].as_integer().unwrap(), (5, false)); - - // Check Expr::as_repeated_element_array - let expr = quote { [1; 3] }.as_expr().unwrap(); - let (expr, length) = expr.as_repeated_element_array().unwrap(); - assert_eq(expr.as_integer().unwrap(), (1, false)); - assert_eq(length.as_integer().unwrap(), (3, false)); - - // Check Expr::as_repeated_element_slice - let expr = quote { &[1; 3] }.as_expr().unwrap(); - let (expr, length) = expr.as_repeated_element_slice().unwrap(); - assert_eq(expr.as_integer().unwrap(), (1, false)); - assert_eq(length.as_integer().unwrap(), (3, false)); - } -} - -comptime fn get_unary_op(quoted: Quoted) -> UnaryOp { - let expr = quoted.as_expr().unwrap(); - let (op, _) = expr.as_unary_op().unwrap(); - op -} - -comptime fn get_binary_op(quoted: Quoted) -> BinaryOp { - let expr = quoted.as_expr().unwrap(); - let (_, op, _) = expr.as_binary_op().unwrap(); - op -}