Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions common/source.cc
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,51 @@ absl::optional<std::pair<int32_t, SourcePosition>> Source::FindLine(
return std::make_pair(line, line_offsets[static_cast<size_t>(line) - 2]);
}

SourceSubrange::SourceSubrange(const Source& source, SourceRange range)
: source_(source), range_(range) {
SourcePosition size = source_.content().size();
ABSL_DCHECK(range_.begin >= 0);
ABSL_DCHECK(range_.begin <= size);
ABSL_DCHECK(range_.end >= range_.begin);
ABSL_DCHECK(range_.end <= size);
if (range_.begin < 0) {
range_.begin = 0;
}
if (range_.begin > size) {
range_.begin = size;
}
if (range_.end < range_.begin) {
range_.end = range_.begin;
}
if (range_.end > size) {
range_.end = size;
}
for (const auto& line_offset : source_.line_offsets()) {
if (line_offset > range_.begin && line_offset <= range_.end) {
line_offsets_.push_back(line_offset - range_.begin);
}
}
line_offsets_.push_back(range_.end - range_.begin + 1);
}

SourceContentView SourceSubrange::content() const {
auto parent_content = source_.content();
if (parent_content.empty() || range_.begin >= range_.end) {
return EmptyContentView();
}
return absl::visit(
[this](auto view) {
return SourceContentView(
view.subspan(static_cast<size_t>(range_.begin),
static_cast<size_t>(range_.end - range_.begin)));
},
parent_content.view_);
}

absl::Span<const SourcePosition> SourceSubrange::line_offsets() const {
return absl::MakeConstSpan(line_offsets_);
}

absl::StatusOr<absl_nonnull SourcePtr> NewSource(absl::string_view content,
std::string description) {
return common_internal::NewSourceImpl(std::move(description), content,
Expand Down
32 changes: 32 additions & 0 deletions common/source.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include "absl/base/attributes.h"
#include "absl/base/nullability.h"
#include "absl/container/inlined_vector.h"
#include "absl/status/statusor.h"
#include "absl/strings/cord.h"
#include "absl/strings/string_view.h"
Expand All @@ -36,6 +37,7 @@ class SourceImpl;
} // namespace common_internal

class Source;
class SourceSubrange;

// SourcePosition represents an offset in source text.
using SourcePosition = int32_t;
Expand Down Expand Up @@ -94,6 +96,7 @@ class SourceContentView final {

private:
friend class Source;
friend class SourceSubrange;

constexpr SourceContentView() = default;

Expand Down Expand Up @@ -178,6 +181,7 @@ class Source {

private:
friend class common_internal::SourceImpl;
friend class SourceSubrange;

Source() = default;

Expand All @@ -187,6 +191,34 @@ class Source {
SourcePosition position) const;
};

// `SourceSubrange` is a view of a subrange fo an underlying `Source` object.
// Intended to be used when the CEL expression is embedded in a larger text
// representation (such as a.celpolicy).
//
// The parent `Source` must outlive this object.
class SourceSubrange final : public Source {
public:
SourceSubrange(const Source& source ABSL_ATTRIBUTE_LIFETIME_BOUND,
SourceRange range);

absl::string_view description() const ABSL_ATTRIBUTE_LIFETIME_BOUND override {
return source_.description();
}

// Returns a view of the underlying expression text.
ContentView content() const ABSL_ATTRIBUTE_LIFETIME_BOUND override;

// Returns a `absl::Span` of `SourcePosition` which represent the positions
// where new lines occur.
absl::Span<const SourcePosition> line_offsets() const
ABSL_ATTRIBUTE_LIFETIME_BOUND override;

private:
const Source& source_;
SourceRange range_;
absl::InlinedVector<SourcePosition, 1> line_offsets_;
};

using SourcePtr = std::unique_ptr<Source>;

absl::StatusOr<absl_nonnull SourcePtr> NewSource(
Expand Down
39 changes: 39 additions & 0 deletions common/source_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -223,5 +223,44 @@ TEST(Source, DisplayErrorLocationFullWidth) {
"\n | ..^");
}

TEST(SourceSubrange, Description) {
ASSERT_OK_AND_ASSIGN(auto source, NewSource("hello world", "subrange-test"));
SourceSubrange subrange(*source, SourceRange{0, 5});
EXPECT_THAT(subrange.description(), Eq("subrange-test"));
}

TEST(SourceSubrange, Content) {
ASSERT_OK_AND_ASSIGN(auto source, NewSource("hello world", "subrange-test"));
SourceSubrange subrange(*source, SourceRange{6, 11});
EXPECT_THAT(subrange.content().ToString(), Eq("world"));
}

TEST(SourceSubrange, ContentEmpty) {
ASSERT_OK_AND_ASSIGN(auto source, NewSource("hello world", "subrange-test"));
SourceSubrange subrange(*source, SourceRange{5, 5});
EXPECT_THAT(subrange.content().ToString(), Eq(""));
}

TEST(SourceSubrange, LineOffsetsNoNewlines) {
ASSERT_OK_AND_ASSIGN(auto source,
NewSource("hello\nworld\n", "subrange-test"));
SourceSubrange subrange(*source, SourceRange{0, 5});
EXPECT_THAT(subrange.line_offsets(), ElementsAre(6));
}

TEST(SourceSubrange, LineOffsetsWithNewlines) {
ASSERT_OK_AND_ASSIGN(auto source,
NewSource("hello\nworld\ncel", "subrange-test"));
SourceSubrange subrange(*source, SourceRange{0, 11});
EXPECT_THAT(subrange.line_offsets(), ElementsAre(6, 12));
}

TEST(SourceSubrange, LineOffsetsMiddleSubrange) {
ASSERT_OK_AND_ASSIGN(auto source,
NewSource("hello\nworld\ncel\ncpp", "subrange-test"));
SourceSubrange subrange(*source, SourceRange{6, 15});
EXPECT_THAT(subrange.line_offsets(), ElementsAre(6, 10));
}

} // namespace
} // namespace cel
1 change: 1 addition & 0 deletions compiler/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ cc_library(
"//checker:type_checker",
"//checker:type_checker_builder",
"//checker:validation_result",
"//common:source",
"//parser:options",
"//parser:parser_interface",
"//validator",
Expand Down
33 changes: 31 additions & 2 deletions compiler/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "checker/type_checker.h"
#include "checker/type_checker_builder.h"
#include "checker/validation_result.h"
#include "common/source.h"
#include "parser/options.h"
#include "parser/parser_interface.h"
#include "validator/validator.h"
Expand Down Expand Up @@ -129,9 +130,18 @@ class Compiler {
public:
virtual ~Compiler() = default;

virtual absl::StatusOr<ValidationResult> Compile(
absl::StatusOr<ValidationResult> Compile(
const Source& source, google::protobuf::Arena* absl_nullable arena) const {
return CompileImpl(source, arena);
}

absl::StatusOr<ValidationResult> Compile(const Source& source) const {
return CompileImpl(source, nullptr);
}

absl::StatusOr<ValidationResult> Compile(
absl::string_view source, absl::string_view description,
google::protobuf::Arena* absl_nullable arena) const = 0;
google::protobuf::Arena* absl_nullable arena) const;

absl::StatusOr<ValidationResult> Compile(absl::string_view source) const {
return Compile(source, "<input>", nullptr);
Expand Down Expand Up @@ -159,8 +169,27 @@ class Compiler {
// The returned builder does not share state with the compiler and may be
// modified independently.
virtual std::unique_ptr<CompilerBuilder> ToBuilder() const = 0;

protected:
virtual absl::StatusOr<ValidationResult> CompileImpl(
const Source& source, google::protobuf::Arena* absl_nullable arena) const = 0;
};

inline absl::StatusOr<ValidationResult> Compiler::Compile(
absl::string_view source, absl::string_view description,
google::protobuf::Arena* absl_nullable arena) const {
absl::StatusOr<SourcePtr> source_obj =
NewSource(source, std::string(description));
if (!source_obj.ok()) {
return source_obj.status();
}
absl::StatusOr<ValidationResult> result = CompileImpl(**source_obj, arena);
if (result.ok()) {
result->SetSource(std::move(*source_obj));
}
return result;
}

} // namespace cel

#endif // THIRD_PARTY_CEL_CPP_COMPILER_COMPILER_INTERFACE_H_
27 changes: 11 additions & 16 deletions compiler/compiler_factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,18 @@ class CompilerImpl : public Compiler {
validator_(std::move(validator)),
options_(options) {}

absl::StatusOr<ValidationResult> Compile(
absl::string_view expression, absl::string_view description,
google::protobuf::Arena* arena) const override {
CEL_ASSIGN_OR_RETURN(auto source,
cel::NewSource(expression, std::string(description)));
std::unique_ptr<CompilerBuilder> ToBuilder() const override;

const TypeChecker& GetTypeChecker() const override { return *type_checker_; }
const Parser& GetParser() const override { return *parser_; }
const Validator& GetValidator() const override { return validator_; }

protected:
absl::StatusOr<ValidationResult> CompileImpl(
const Source& source, google::protobuf::Arena* arena) const override {
std::vector<cel::ParseIssue> parse_issues;
absl::StatusOr<std::unique_ptr<cel::Ast>> ast =
parser_->Parse(*source, &parse_issues);
parser_->Parse(source, &parse_issues);
if (!ast.ok()) {
if (!options_.adapt_parser_errors ||
ast.status().code() != absl::StatusCode::kInvalidArgument ||
Expand All @@ -74,26 +78,17 @@ class CompilerImpl : public Compiler {
check_issues.push_back(TypeCheckIssue::CreateError(
issue.location(), std::string(issue.message())));
}
ValidationResult result(std::move(check_issues));
result.SetSource(std::move(source));
return result;
return ValidationResult(std::move(check_issues));
}
CEL_ASSIGN_OR_RETURN(ValidationResult result,
type_checker_->Check(*std::move(ast), arena));

result.SetSource(std::move(source));
if (!validator_.validations().empty()) {
validator_.UpdateValidationResult(result);
}
return result;
}

std::unique_ptr<CompilerBuilder> ToBuilder() const override;

const TypeChecker& GetTypeChecker() const override { return *type_checker_; }
const Parser& GetParser() const override { return *parser_; }
const Validator& GetValidator() const override { return validator_; }

private:
std::unique_ptr<TypeChecker> type_checker_;
std::unique_ptr<Parser> parser_;
Expand Down
14 changes: 14 additions & 0 deletions compiler/compiler_factory_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -427,5 +427,19 @@ TEST(CompilerFactoryTest, ReturnsIssuesFromParser) {
EXPECT_THAT(result.GetIssues(), testing::Not(testing::IsEmpty()));
}

TEST(CompilerFactoryTest, CompileSourceOverload) {
ASSERT_OK_AND_ASSIGN(
auto builder,
NewCompilerBuilder(cel::internal::GetSharedTestingDescriptorPool()));

ASSERT_THAT(builder->AddLibrary(StandardCompilerLibrary()), IsOk());
ASSERT_OK_AND_ASSIGN(auto compiler, builder->Build());

ASSERT_OK_AND_ASSIGN(auto source, cel::NewSource("1 + 2"));
ASSERT_OK_AND_ASSIGN(ValidationResult result, compiler->Compile(*source));

EXPECT_TRUE(result.IsValid());
}

} // namespace
} // namespace cel
Loading