Skip to content

Commit cf31ddf

Browse files
TristonianJonescopybara-github
authored andcommitted
Introduce Bind expression factory helper
PiperOrigin-RevId: 913778503
1 parent cb9dc8a commit cf31ddf

2 files changed

Lines changed: 74 additions & 0 deletions

File tree

common/expr_factory.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,29 @@ class ExprFactory {
352352
return expr;
353353
}
354354

355+
template <typename NextIdFunc, typename BindVar, typename BindExpr,
356+
typename RestExpr,
357+
typename = std::enable_if_t<
358+
std::is_invocable_r<ExprId, NextIdFunc>::value>,
359+
typename = std::enable_if_t<IsStringLike<BindVar>::value>,
360+
typename = std::enable_if_t<IsExprLike<BindExpr>::value>,
361+
typename = std::enable_if_t<IsExprLike<RestExpr>::value>>
362+
Expr NewBind(NextIdFunc next_id, BindVar bind_var, BindExpr bind_expr,
363+
RestExpr rest_expr) {
364+
Expr expr;
365+
expr.set_id(next_id());
366+
auto& comprehension_expr = expr.mutable_comprehension_expr();
367+
comprehension_expr.set_iter_var("#unused");
368+
comprehension_expr.set_iter_range(
369+
NewList(next_id(), std::vector<cel::ListExprElement>{}));
370+
comprehension_expr.set_accu_var(bind_var);
371+
comprehension_expr.set_accu_init(std::move(bind_expr));
372+
comprehension_expr.set_loop_condition(NewBoolConst(next_id(), false));
373+
comprehension_expr.set_loop_step(NewIdent(next_id(), bind_var));
374+
comprehension_expr.set_result(std::move(rest_expr));
375+
return expr;
376+
}
377+
355378
private:
356379
friend class MacroExprFactory;
357380
friend class ParserMacroExprFactory;

parser/macro_expr_factory_test.cc

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "parser/macro_expr_factory.h"
1616

1717
#include <cstdint>
18+
#include <utility>
1819
#include <vector>
1920

2021
#include "absl/strings/string_view.h"
@@ -39,6 +40,7 @@ class TestMacroExprFactory final : public MacroExprFactory {
3940
return NewUnspecified(NextId());
4041
}
4142

43+
using MacroExprFactory::NewBind;
4244
using MacroExprFactory::NewBoolConst;
4345
using MacroExprFactory::NewCall;
4446
using MacroExprFactory::NewComprehension;
@@ -69,6 +71,8 @@ class TestMacroExprFactory final : public MacroExprFactory {
6971

7072
namespace {
7173

74+
using ::testing::IsEmpty;
75+
7276
TEST(MacroExprFactory, CopyUnspecified) {
7377
TestMacroExprFactory factory;
7478
EXPECT_EQ(factory.Copy(factory.NewUnspecified()), factory.NewUnspecified(2));
@@ -147,5 +151,52 @@ TEST(MacroExprFactory, CopyComprehension) {
147151
factory.NewIdent(11, "foo"), factory.NewIdent(12, "bar")));
148152
}
149153

154+
TEST(MacroExprFactory, NewBind) {
155+
TestMacroExprFactory factory;
156+
Expr bind_expr = factory.NewIdent(10, "x");
157+
Expr rest_expr = factory.NewIdent(20, "y");
158+
159+
auto next_id = [id = 100]() mutable { return id++; };
160+
161+
Expr expr =
162+
factory.NewBind(next_id, "a", std::move(bind_expr), std::move(rest_expr));
163+
164+
EXPECT_EQ(expr.id(), 100);
165+
ASSERT_TRUE(expr.has_comprehension_expr());
166+
167+
const auto& comp = expr.comprehension_expr();
168+
EXPECT_EQ(comp.iter_var(), "#unused");
169+
170+
ASSERT_TRUE(comp.has_iter_range());
171+
EXPECT_EQ(comp.iter_range().id(), 101);
172+
EXPECT_EQ(comp.iter_range().kind_case(), ExprKindCase::kListExpr);
173+
EXPECT_THAT(comp.iter_range().list_expr().elements(), IsEmpty());
174+
175+
EXPECT_EQ(comp.accu_var(), "a");
176+
177+
ASSERT_TRUE(comp.has_accu_init());
178+
Expr expected_bind_expr;
179+
expected_bind_expr.set_id(10);
180+
expected_bind_expr.mutable_ident_expr().set_name("x");
181+
EXPECT_EQ(comp.accu_init(), expected_bind_expr);
182+
183+
ASSERT_TRUE(comp.has_loop_condition());
184+
EXPECT_EQ(comp.loop_condition().id(), 102);
185+
EXPECT_EQ(comp.loop_condition().kind_case(), ExprKindCase::kConstant);
186+
EXPECT_TRUE(comp.loop_condition().const_expr().has_bool_value());
187+
EXPECT_FALSE(comp.loop_condition().const_expr().bool_value());
188+
189+
ASSERT_TRUE(comp.has_loop_step());
190+
EXPECT_EQ(comp.loop_step().id(), 103);
191+
EXPECT_EQ(comp.loop_step().kind_case(), ExprKindCase::kIdentExpr);
192+
EXPECT_EQ(comp.loop_step().ident_expr().name(), "a");
193+
194+
ASSERT_TRUE(comp.has_result());
195+
Expr expected_rest_expr;
196+
expected_rest_expr.set_id(20);
197+
expected_rest_expr.mutable_ident_expr().set_name("y");
198+
EXPECT_EQ(comp.result(), expected_rest_expr);
199+
}
200+
150201
} // namespace
151202
} // namespace cel

0 commit comments

Comments
 (0)