Skip to content

Commit

Permalink
Add Expr::as_binary_op
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite committed Aug 15, 2024
1 parent ae33811 commit 633377e
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 18 deletions.
44 changes: 39 additions & 5 deletions compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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_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),
"expr_as_if" => expr_as_if(arguments, return_type, location),
Expand Down Expand Up @@ -856,11 +857,11 @@ fn expr_as_unary_op(
let unary_op_type = tuple_types.pop().unwrap();

// These values should match the values used in noir_stdlib/src/meta/op.nr
let unary_op_value = match prefix_expr.operator {
UnaryOp::Minus => 0_u128,
UnaryOp::Not => 1_u128,
UnaryOp::MutableReference => 2_u128,
UnaryOp::Dereference { .. } => 3_u128,
let unary_op_value: u128 = match prefix_expr.operator {
UnaryOp::Minus => 0,
UnaryOp::Not => 1,
UnaryOp::MutableReference => 2,
UnaryOp::Dereference { .. } => 3,
};

let mut fields = HashMap::default();
Expand All @@ -875,6 +876,39 @@ 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<Value> {
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_tuple(self) -> Option<[Expr]>
fn expr_as_tuple(
arguments: Vec<(Value, Location)>,
Expand Down
4 changes: 4 additions & 0 deletions noir_stdlib/src/meta/expr.nr
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use crate::option::Option;
use crate::meta::op::UnaryOp;
use crate::meta::op::BinaryOp;

impl Expr {
#[builtin(expr_as_binary_op)]
fn as_binary_op(self) -> Option<(Expr, BinaryOp, Expr)> {}

#[builtin(expr_as_bool)]
fn as_bool(self) -> Option<bool> {}

Expand Down
71 changes: 71 additions & 0 deletions noir_stdlib/src/meta/op.nr
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,74 @@ impl UnaryOp {
self.op == 3
}
}

struct BinaryOp {
op: Field
}

impl BinaryOp {
fn is_add(self) -> bool {
self.op == 0
}

fn is_subtract(self) -> bool {
self.op == 1
}

fn is_multiply(self) -> bool {
self.op == 2
}

fn is_divide(self) -> bool {
self.op == 3
}

fn is_equal(self) -> bool {
self.op == 4
}

fn is_not_equal(self) -> bool {
self.op == 5
}

fn is_less(self) -> bool {
self.op == 6
}

fn is_less_equal(self) -> bool {
self.op == 7
}

fn is_greater(self) -> bool {
self.op == 8
}

fn is_greater_or_equal(self) -> bool {
self.op == 9
}

fn is_and(self) -> bool {
self.op == 10
}

fn is_or(self) -> bool {
self.op == 11
}

fn is_xor(self) -> bool {
self.op == 12
}

fn is_shift_right(self) -> bool {
self.op == 13
}

fn is_shift_left(self) -> bool {
self.op == 14
}

fn is_modulo(self) -> bool {
self.op == 15
}
}

46 changes: 33 additions & 13 deletions test_programs/compile_success_empty/comptime_exp/src/main.nr
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use std::meta::op::UnaryOp;
use std::meta::op::BinaryOp;

fn main() {
comptime
{
Expand Down Expand Up @@ -36,20 +39,37 @@ fn main() {
assert_eq(expr.as_bool().unwrap(), true);

// Check Expr::as_unary_op
let expr = quote { -x }.as_expr().unwrap();
let (op, _) = expr.as_unary_op().unwrap();
assert(op.is_minus());
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());

let expr = quote { !x }.as_expr().unwrap();
let (op, _) = expr.as_unary_op().unwrap();
assert(op.is_not());
// 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());
}
}

let expr = quote { &mut x }.as_expr().unwrap();
let (op, _) = expr.as_unary_op().unwrap();
assert(op.is_mutable_reference());
comptime fn get_unary_op(quoted: Quoted) -> UnaryOp {
let expr = quoted.as_expr().unwrap();
let (op, _) = expr.as_unary_op().unwrap();
op
}

let expr = quote { *x }.as_expr().unwrap();
let (op, _) = expr.as_unary_op().unwrap();
assert(op.is_dereference());
}
comptime fn get_binary_op(quoted: Quoted) -> BinaryOp {
let expr = quoted.as_expr().unwrap();
let (_, op, _) = expr.as_binary_op().unwrap();
op
}

0 comments on commit 633377e

Please sign in to comment.