Skip to content

Commit 9841e3e

Browse files
authored
Merge pull request #103 from google/cpp-sync
Export of internal changes
2 parents 9b0c01c + 9cacfc6 commit 9841e3e

File tree

14 files changed

+625
-230
lines changed

14 files changed

+625
-230
lines changed

base/status_macros.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,4 @@ inline To down_cast(From* f) { // so we only accept pointers
6767
#define EXPECT_OK(expression) EXPECT_TRUE(expression.ok())
6868
#endif
6969

70-
#if !defined(CHECK_OK)
71-
#define CHECK_OK(expression) assert(expression.ok())
72-
#endif
73-
7470
#endif // THIRD_PARTY_CEL_CPP_BASE_STATUS_MACROS_H_

common/escaping.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ absl::optional<std::string> unescape(const std::string& s, bool is_bytes) {
294294
}
295295
value = value.substr(1, n - 2);
296296
// If there is nothing to escape, then return.
297-
if (is_raw_literal || (value.find("\\") == std::string::npos)) {
297+
if (is_raw_literal || (value.find('\\') == std::string::npos)) {
298298
return value;
299299
}
300300

conformance/BUILD

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ cc_binary(
5353
testonly = 1,
5454
srcs = ["server.cc"],
5555
deps = [
56-
"//base:status_macros",
5756
"//eval/public:builtin_func_registrar",
5857
"//eval/public:cel_expr_builder_factory",
5958
"//eval/public:transform_utility",
@@ -88,22 +87,14 @@ cc_binary(
8887
# TODO(issues/94): Missing timestamp conversion functions (type / string)
8988
"--skip_test=timestamps/timestamp_conversions/toType_timestamp,toString_timestamp",
9089
"--skip_test=timestamps/duration_conversions/toType_duration,toString_duration",
91-
# TODO(issues/78): Missing bytes() conversion functions
92-
"--skip_test=conversions/bytes",
93-
# TODO(issues/79): Missing double() conversion functions
94-
"--skip_test=conversions/double",
95-
# TODO(issues/80): Missing dyn() conversion functions
96-
"--skip_test=conversions/dyn/dyn_heterogeneous_list",
97-
# TODO(issues/81): Conversion functions for int() which can be
98-
# uncommented when the spec changes to truncation rather than
99-
# rounding.
90+
# TODO(issues/81): Conversion functions for int(), uint() which can be
91+
# uncommented when the spec changes to truncation rather than rounding.
10092
"--skip_test=conversions/int/double_nearest,double_nearest_neg,double_half_away_neg,double_half_away_pos",
93+
"--skip_test=conversions/uint/double_nearest,double_nearest_int,double_half_away",
10194
# TODO(issues/82): Unexpected behavior when converting invalid bytes to string.
10295
"--skip_test=conversions/string/bytes_invalid",
10396
# TODO(issues/83): Missing type() conversion functions
10497
"--skip_test=conversions/type",
105-
# TODO(issues/84): Missing uint() conversion functions
106-
"--skip_test=conversions/uint",
10798
# TODO(issues/96): Well-known type conversion support.
10899
"--skip_test=proto2/literal_wellknown",
109100
"--skip_test=proto3/literal_wellknown",
@@ -116,13 +107,11 @@ cc_binary(
116107
"--skip_test=namespace/namespace/self_eval_container_lookup_unchecked",
117108
"--skip_test=basic/self_eval_nonzeroish/self_eval_bytes_invalid_utf8",
118109
# Requires heteregenous equality spec clarification
119-
"--skip_test=comparisons/eq_literal/eq_bytes",
120-
"--skip_test=comparisons/ne_literal/not_ne_bytes",
121110
"--skip_test=comparisons/in_list_literal/elem_in_mixed_type_list_error",
122111
"--skip_test=comparisons/in_map_literal/key_in_mixed_key_type_map_error",
123112
"--skip_test=fields/in/singleton",
124113
# Requires qualified bindings error message relaxation
125-
"--skip_test=fields/qualified_identifier_resolution/int64_field_select_unsupported,list_field_select_unsupported,map_key_null,qualified_identifier_resolution_unchecked",
114+
"--skip_test=fields/qualified_identifier_resolution/qualified_identifier_resolution_unchecked",
126115
"--skip_test=string/size/one_unicode,unicode",
127116
"--skip_test=string/bytes_concat/left_unit",
128117
# TODO(issues/85): The exists one macro should not short-circuit false.

conformance/server.cc

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
#include "parser/parser.h"
2424
#include "proto/test/v1/proto2/test_all_types.pb.h"
2525
#include "proto/test/v1/proto3/test_all_types.pb.h"
26-
#include "base/status_macros.h"
2726

2827

2928
using absl::Status;
@@ -41,17 +40,20 @@ namespace runtime {
4140

4241
class ConformanceServiceImpl {
4342
public:
44-
ConformanceServiceImpl(std::unique_ptr<CelExpressionBuilder> builder)
43+
explicit ConformanceServiceImpl(std::unique_ptr<CelExpressionBuilder> builder)
4544
: builder_(std::move(builder)),
4645
proto2Tests_(&google::api::expr::test::v1::proto2::TestAllTypes::
4746
default_instance()),
4847
proto3Tests_(&google::api::expr::test::v1::proto3::TestAllTypes::
4948
default_instance()) {}
5049

51-
Status Parse(const v1alpha1::ParseRequest* request,
52-
v1alpha1::ParseResponse* response) {
50+
void Parse(const v1alpha1::ParseRequest* request,
51+
v1alpha1::ParseResponse* response) {
5352
if (request->cel_source().empty()) {
54-
return Status(StatusCode::kInvalidArgument, "No source code.");
53+
auto issue = response->add_issues();
54+
issue->set_message("No source code");
55+
issue->set_code(google::rpc::Code::INVALID_ARGUMENT);
56+
return;
5557
}
5658
auto parse_status = parser::Parse(request->cel_source(), "");
5759
if (!parse_status.ok()) {
@@ -63,16 +65,17 @@ class ConformanceServiceImpl {
6365
(out).MergeFrom(parse_status.value());
6466
response->mutable_parsed_expr()->CopyFrom(out);
6567
}
66-
return absl::OkStatus();
6768
}
6869

69-
Status Check(const v1alpha1::CheckRequest* request,
70-
v1alpha1::CheckResponse* response) {
71-
return Status(StatusCode::kUnimplemented, "Check is not supported");
70+
void Check(const v1alpha1::CheckRequest* request,
71+
v1alpha1::CheckResponse* response) {
72+
auto issue = response->add_issues();
73+
issue->set_message("Check is not supported");
74+
issue->set_code(google::rpc::Code::UNIMPLEMENTED);
7275
}
7376

74-
Status Eval(const v1alpha1::EvalRequest* request,
75-
v1alpha1::EvalResponse* response) {
77+
void Eval(const v1alpha1::EvalRequest* request,
78+
v1alpha1::EvalResponse* response) {
7679
const v1alpha1::Expr* expr = nullptr;
7780
if (request->has_parsed_expr()) {
7881
expr = &request->parsed_expr().expr();
@@ -87,8 +90,10 @@ class ConformanceServiceImpl {
8790
auto cel_expression_status = builder_->CreateExpression(&out, &source_info);
8891

8992
if (!cel_expression_status.ok()) {
90-
return Status(StatusCode::kInternal,
91-
std::string(cel_expression_status.status().message()));
93+
auto issue = response->add_issues();
94+
issue->set_message(cel_expression_status.status().ToString());
95+
issue->set_code(google::rpc::Code::INTERNAL);
96+
return;
9297
}
9398

9499
auto cel_expression = std::move(cel_expression_status.value());
@@ -100,7 +105,10 @@ class ConformanceServiceImpl {
100105
(*import_value).MergeFrom(pair.second.value());
101106
auto import_status = ValueToCelValue(*import_value, &arena);
102107
if (!import_status.ok()) {
103-
return Status(StatusCode::kInternal, import_status.status().ToString());
108+
auto issue = response->add_issues();
109+
issue->set_message(import_status.status().ToString());
110+
issue->set_code(google::rpc::Code::INTERNAL);
111+
return;
104112
}
105113
activation.InsertValue(pair.first, import_status.value());
106114
}
@@ -111,7 +119,7 @@ class ConformanceServiceImpl {
111119
->mutable_error()
112120
->add_errors()
113121
->mutable_message() = eval_status.status().ToString();
114-
return absl::OkStatus();
122+
return;
115123
}
116124

117125
CelValue result = eval_status.value();
@@ -124,12 +132,14 @@ class ConformanceServiceImpl {
124132
google::api::expr::v1alpha1::Value export_value;
125133
auto export_status = CelValueToValue(result, &export_value);
126134
if (!export_status.ok()) {
127-
return Status(StatusCode::kInternal, export_status.ToString());
135+
auto issue = response->add_issues();
136+
issue->set_message(export_status.ToString());
137+
issue->set_code(google::rpc::Code::INTERNAL);
138+
return;
128139
}
129140
auto* result_value = response->mutable_result()->mutable_value();
130141
(*result_value).MergeFrom(export_value);
131142
}
132-
return absl::OkStatus();
133143
}
134144

135145
private:
@@ -178,15 +188,23 @@ int RunServer(bool optimize) {
178188
if (cmd == "parse") {
179189
v1alpha1::ParseRequest request;
180190
v1alpha1::ParseResponse response;
181-
CHECK_OK(JsonStringToMessage(input, &request));
182-
CHECK_OK(service.Parse(&request, &response));
183-
CHECK_OK(MessageToJsonString(response, &output));
191+
if (!JsonStringToMessage(input, &request).ok()) {
192+
std::cerr << "Failed to parse JSON" << std::endl;
193+
}
194+
service.Parse(&request, &response);
195+
if (!MessageToJsonString(response, &output).ok()) {
196+
std::cerr << "Failed to convert to JSON" << std::endl;
197+
}
184198
} else if (cmd == "eval") {
185199
v1alpha1::EvalRequest request;
186200
v1alpha1::EvalResponse response;
187-
CHECK_OK(JsonStringToMessage(input, &request));
188-
CHECK_OK(service.Eval(&request, &response));
189-
CHECK_OK(MessageToJsonString(response, &output));
201+
if (!JsonStringToMessage(input, &request).ok()) {
202+
std::cerr << "Failed to parse JSON" << std::endl;
203+
}
204+
service.Eval(&request, &response);
205+
if (!MessageToJsonString(response, &output).ok()) {
206+
std::cerr << "Failed to convert to JSON" << std::endl;
207+
}
190208
} else if (cmd.empty()) {
191209
return 0;
192210
} else {

eval/compiler/flat_expr_builder.cc

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "eval/compiler/flat_expr_builder.h"
22

3+
#include <memory>
4+
35
#include "google/api/expr/v1alpha1/checked.pb.h"
46
#include "stack"
57
#include "absl/container/node_hash_map.h"
@@ -658,8 +660,8 @@ void ComprehensionVisitor::PreVisit(const Expr*) {
658660

659661
void ComprehensionVisitor::PostVisitArg(int arg_num, const Expr* expr) {
660662
const Comprehension* comprehension = &expr->comprehension_expr();
661-
const auto accu_var = comprehension->accu_var();
662-
const auto iter_var = comprehension->iter_var();
663+
const auto& accu_var = comprehension->accu_var();
664+
const auto& iter_var = comprehension->iter_var();
663665
// TODO(issues/20): Consider refactoring the comprehension prologue step.
664666
switch (arg_num) {
665667
case ITER_RANGE: {
@@ -732,7 +734,7 @@ FlatExprBuilder::CreateExpressionImpl(
732734

733735
const Expr* effective_expr = expr;
734736
// transformed expression preserving expression IDs
735-
Expr rewrite_buffer;
737+
std::unique_ptr<Expr> rewrite_buffer = nullptr;
736738
// TODO(issues/98): A type checker may perform these rewrites, but there
737739
// currently isn't a signal to expose that in an expression. If that becomes
738740
// available, we can skip the reference resolve step here if it's already
@@ -745,19 +747,19 @@ FlatExprBuilder::CreateExpressionImpl(
745747
return rewritten.status();
746748
}
747749
if (rewritten.value().has_value()) {
748-
rewrite_buffer = std::move(rewritten)->value();
749-
effective_expr = &rewrite_buffer;
750+
rewrite_buffer =
751+
std::make_unique<Expr>(std::move(rewritten).value().value());
752+
effective_expr = rewrite_buffer.get();
750753
}
751754
// TODO(issues/99): we could setup a check step here that confirms all of
752755
// references are defined before actually evaluating.
753756
}
754757

758+
Expr const_fold_buffer;
755759
if (constant_folding_) {
756-
Expr buffer;
757760
FoldConstants(*effective_expr, *this->GetRegistry(), constant_arena_,
758-
idents, &buffer);
759-
rewrite_buffer = std::move(buffer);
760-
effective_expr = &rewrite_buffer;
761+
idents, &const_fold_buffer);
762+
effective_expr = &const_fold_buffer;
761763
}
762764

763765
std::set<std::string> iter_variable_names;
@@ -776,7 +778,8 @@ FlatExprBuilder::CreateExpressionImpl(
776778
absl::make_unique<CelExpressionFlatImpl>(
777779
expr, std::move(execution_path), comprehension_max_iterations_,
778780
std::move(iter_variable_names), enable_unknowns_,
779-
enable_unknown_function_results_, enable_missing_attribute_errors_);
781+
enable_unknown_function_results_, enable_missing_attribute_errors_,
782+
std::move(rewrite_buffer));
780783

781784
if (warnings != nullptr) {
782785
*warnings = std::move(warnings_builder).warnings();

eval/compiler/flat_expr_builder_test.cc

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,60 @@ TEST(FlatExprBuilderTest, CheckedExprActivationMissesReferences) {
614614
EXPECT_FALSE(result.BoolOrDie());
615615
}
616616

617+
TEST(FlatExprBuilderTest, CheckedExprWithReferenceMapAndConstantFolding) {
618+
CheckedExpr expr;
619+
// {`var1`: 'hello'}
620+
google::protobuf::TextFormat::ParseFromString(R"(
621+
reference_map {
622+
key: 3
623+
value {
624+
name: "var1"
625+
value {
626+
int64_value: 1
627+
}
628+
}
629+
}
630+
expr {
631+
id: 1
632+
struct_expr {
633+
entries {
634+
id: 2
635+
map_key {
636+
id: 3
637+
ident_expr {
638+
name: "var1"
639+
}
640+
}
641+
value {
642+
id: 4
643+
const_expr {
644+
string_value: "hello"
645+
}
646+
}
647+
}
648+
}
649+
})",
650+
&expr);
651+
652+
FlatExprBuilder builder;
653+
google::protobuf::Arena arena;
654+
builder.set_constant_folding(true, &arena);
655+
ASSERT_OK(RegisterBuiltinFunctions(builder.GetRegistry()));
656+
auto build_status = builder.CreateExpression(&expr);
657+
ASSERT_OK(build_status);
658+
659+
auto cel_expr = std::move(build_status.value());
660+
661+
Activation activation;
662+
auto result_or = cel_expr->Evaluate(activation, &arena);
663+
ASSERT_OK(result_or);
664+
CelValue result = result_or.value();
665+
ASSERT_TRUE(result.IsMap());
666+
auto m = result.MapOrDie();
667+
auto v = (*m)[CelValue::CreateInt64(1L)];
668+
EXPECT_THAT(v.value().StringOrDie().value(), Eq("hello"));
669+
}
670+
617671
TEST(FlatExprBuilderTest, ComprehensionWorksForError) {
618672
Expr expr;
619673
// {}[0].all(x, x) should evaluate OK but return an error value

eval/eval/evaluator_core.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ namespace runtime {
3434
// Forward declaration of ExecutionFrame, to resolve circular dependency.
3535
class ExecutionFrame;
3636

37+
using Expr = google::api::expr::v1alpha1::Expr;
38+
3739
// Class Expression represents single execution step.
3840
class ExpressionStep {
3941
public:
@@ -67,7 +69,7 @@ using ExecutionPath = std::vector<std::unique_ptr<const ExpressionStep>>;
6769
// stack as Span<>.
6870
class ValueStack {
6971
public:
70-
ValueStack(size_t max_size) : current_size_(0) {
72+
explicit ValueStack(size_t max_size) : current_size_(0) {
7173
stack_.resize(max_size);
7274
attribute_stack_.resize(max_size);
7375
}
@@ -336,8 +338,10 @@ class CelExpressionFlatImpl : public CelExpression {
336338
std::set<std::string> iter_variable_names,
337339
bool enable_unknowns = false,
338340
bool enable_unknown_function_results = false,
339-
bool enable_missing_attribute_errors = false)
340-
: path_(std::move(path)),
341+
bool enable_missing_attribute_errors = false,
342+
std::unique_ptr<Expr> rewritten_expr = nullptr)
343+
: rewritten_expr_(std::move(rewritten_expr)),
344+
path_(std::move(path)),
341345
max_iterations_(max_iterations),
342346
iter_variable_names_(std::move(iter_variable_names)),
343347
enable_unknowns_(enable_unknowns),
@@ -372,6 +376,8 @@ class CelExpressionFlatImpl : public CelExpression {
372376
CelEvaluationListener callback) const override;
373377

374378
private:
379+
// Maintain lifecycle of a modified expression.
380+
std::unique_ptr<Expr> rewritten_expr_;
375381
const ExecutionPath path_;
376382
const int max_iterations_;
377383
const std::set<std::string> iter_variable_names_;

0 commit comments

Comments
 (0)