Skip to content

Commit 5a9d660

Browse files
l46kokcopybara-github
authored andcommitted
Add PolicySource
PiperOrigin-RevId: 646279818
1 parent f2d2635 commit 5a9d660

File tree

20 files changed

+480
-62
lines changed

20 files changed

+480
-62
lines changed

common/BUILD.bazel

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,9 @@ java_library(
5959
name = "proto_json_adapter",
6060
exports = ["//common/src/main/java/dev/cel/common:proto_json_adapter"],
6161
)
62+
63+
java_library(
64+
name = "source",
65+
visibility = ["//visibility:public"],
66+
exports = ["//common/src/main/java/dev/cel/common:source"],
67+
)

common/src/main/java/dev/cel/common/BUILD.bazel

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ java_library(
3939
],
4040
deps = [
4141
":error_codes",
42+
":source",
4243
"//:auto_value",
4344
"//common/annotations",
4445
"//common/ast",
@@ -62,6 +63,7 @@ java_library(
6263
],
6364
deps = [
6465
":common",
66+
":source",
6567
"//:auto_value",
6668
"//common/annotations",
6769
"//common/internal:safe_string_formatter",
@@ -175,3 +177,16 @@ java_library(
175177
"@maven//:com_google_protobuf_protobuf_java_util",
176178
],
177179
)
180+
181+
java_library(
182+
name = "source",
183+
srcs = [
184+
"CelSourceHelper.java",
185+
"Source.java",
186+
],
187+
deps = [
188+
"//common/annotations",
189+
"//common/internal",
190+
"@maven//:com_google_guava_guava",
191+
],
192+
)

common/src/main/java/dev/cel/common/CelIssue.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public static CelIssue formatError(int line, int column, String message) {
7474
private static final char WIDE_HAT = '\uff3e';
7575

7676
/** Returns a string representing this error that is suitable for displaying to humans. */
77-
public String toDisplayString(CelSource source) {
77+
public String toDisplayString(Source source) {
7878
// Based onhttps://github.com/google/cel-go/blob/v0.5.1/common/error.go#L42.
7979
String result =
8080
SafeStringFormatter.format(

common/src/main/java/dev/cel/common/CelSource.java

Lines changed: 16 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616

1717
import static com.google.common.base.Preconditions.checkArgument;
1818
import static com.google.common.base.Preconditions.checkNotNull;
19+
import static com.google.common.base.Preconditions.checkState;
1920

2021
import com.google.auto.value.AutoValue;
21-
import com.google.common.base.Splitter;
2222
import com.google.common.collect.ImmutableList;
2323
import com.google.common.collect.ImmutableMap;
2424
import com.google.common.collect.ImmutableSet;
@@ -36,8 +36,7 @@
3636

3737
/** Represents the source content of an expression and related metadata. */
3838
@Immutable
39-
public final class CelSource {
40-
private static final Splitter LINE_SPLITTER = Splitter.on('\n');
39+
public final class CelSource implements Source {
4140

4241
private final CelCodePointArray codePoints;
4342
private final String description;
@@ -55,10 +54,12 @@ private CelSource(Builder builder) {
5554
this.extensions = checkNotNull(builder.extensions.build());
5655
}
5756

57+
@Override
5858
public CelCodePointArray getContent() {
5959
return codePoints;
6060
}
6161

62+
@Override
6263
public String getDescription() {
6364
return description;
6465
}
@@ -109,24 +110,9 @@ public Optional<CelSourceLocation> getOffsetLocation(int offset) {
109110
return getOffsetLocationImpl(lineOffsets, offset);
110111
}
111112

112-
/**
113-
* Get the text from the source expression that corresponds to {@code line}.
114-
*
115-
* @param line the line number starting from 1.
116-
*/
113+
@Override
117114
public Optional<String> getSnippet(int line) {
118-
checkArgument(line > 0);
119-
int start = findLineOffset(lineOffsets, line);
120-
if (start == -1) {
121-
return Optional.empty();
122-
}
123-
int end = findLineOffset(lineOffsets, line + 1);
124-
if (end == -1) {
125-
end = codePoints.size();
126-
} else {
127-
end--;
128-
}
129-
return Optional.of(end != start ? codePoints.slice(start, end).toString() : "");
115+
return CelSourceHelper.getSnippet(codePoints, line);
130116
}
131117

132118
/**
@@ -140,7 +126,7 @@ private static Optional<Integer> getLocationOffsetImpl(
140126
List<Integer> lineOffsets, int line, int column) {
141127
checkArgument(line > 0);
142128
checkArgument(column >= 0);
143-
int offset = findLineOffset(lineOffsets, line);
129+
int offset = CelSourceHelper.findLineOffset(lineOffsets, line);
144130
if (offset == -1) {
145131
return Optional.empty();
146132
}
@@ -157,16 +143,6 @@ public static Optional<CelSourceLocation> getOffsetLocationImpl(
157143
return Optional.of(CelSourceLocation.of(lineAndOffset.line, offset - lineAndOffset.offset));
158144
}
159145

160-
private static int findLineOffset(List<Integer> lineOffsets, int line) {
161-
if (line == 1) {
162-
return 0;
163-
}
164-
if (line > 1 && line <= lineOffsets.size()) {
165-
return lineOffsets.get(line - 2);
166-
}
167-
return -1;
168-
}
169-
170146
private static LineAndOffset findLine(List<Integer> lineOffsets, int offset) {
171147
int line = 1;
172148
for (int index = 0; index < lineOffsets.size(); index++) {
@@ -194,13 +170,8 @@ public static Builder newBuilder() {
194170
}
195171

196172
public static Builder newBuilder(String text) {
197-
List<Integer> lineOffsets = new ArrayList<>();
198-
int lineOffset = 0;
199-
for (String line : LINE_SPLITTER.split(text)) {
200-
lineOffset += (int) (line.codePoints().count() + 1);
201-
lineOffsets.add(lineOffset);
202-
}
203-
return new Builder(CelCodePointArray.fromString(text), lineOffsets);
173+
CelCodePointArray codePointArray = CelCodePointArray.fromString(text);
174+
return new Builder(codePointArray, codePointArray.lineOffsets());
204175
}
205176

206177
/** Builder for {@link CelSource}. */
@@ -212,6 +183,7 @@ public static final class Builder {
212183
private final Map<Long, CelExpr> macroCalls;
213184
private final ImmutableSet.Builder<Extension> extensions;
214185

186+
private final boolean lineOffsetsAlreadyComputed;
215187
private String description;
216188

217189
private Builder() {
@@ -225,6 +197,7 @@ private Builder(CelCodePointArray codePoints, List<Integer> lineOffsets) {
225197
this.macroCalls = new HashMap<>();
226198
this.extensions = ImmutableSet.builder();
227199
this.description = "";
200+
this.lineOffsetsAlreadyComputed = !lineOffsets.isEmpty();
228201
}
229202

230203
@CanIgnoreReturnValue
@@ -236,6 +209,9 @@ public Builder setDescription(String description) {
236209
@CanIgnoreReturnValue
237210
public Builder addLineOffsets(int lineOffset) {
238211
checkArgument(lineOffset >= 0);
212+
checkState(
213+
!lineOffsetsAlreadyComputed,
214+
"Line offsets were already been computed through the provided code points.");
239215
lineOffsets.add(lineOffset);
240216
return this;
241217
}
@@ -362,8 +338,8 @@ private LineAndOffset(int line, int offset) {
362338
this.offset = offset;
363339
}
364340

365-
int line;
366-
int offset;
341+
private final int line;
342+
private final int offset;
367343
}
368344

369345
/**
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package dev.cel.common;
16+
17+
import static com.google.common.base.Preconditions.checkArgument;
18+
19+
import com.google.common.collect.ImmutableList;
20+
import dev.cel.common.annotations.Internal;
21+
import dev.cel.common.internal.CelCodePointArray;
22+
import java.util.List;
23+
import java.util.Optional;
24+
25+
/**
26+
* Helper methods for common source handling in CEL.
27+
*
28+
* <p>CEL Library Internals. Do Not Use.
29+
*/
30+
@Internal
31+
public final class CelSourceHelper {
32+
33+
/** Extract the snippet text that corresponds to {@code line}. */
34+
public static Optional<String> getSnippet(CelCodePointArray content, int line) {
35+
checkArgument(line > 0);
36+
ImmutableList<Integer> lineOffsets = content.lineOffsets();
37+
int start = findLineOffset(lineOffsets, line);
38+
if (start == -1) {
39+
return Optional.empty();
40+
}
41+
int end = findLineOffset(lineOffsets, line + 1);
42+
if (end == -1) {
43+
end = content.size();
44+
} else {
45+
end--;
46+
}
47+
return Optional.of(end != start ? content.slice(start, end).toString() : "");
48+
}
49+
50+
static int findLineOffset(List<Integer> lineOffsets, int line) {
51+
if (line == 1) {
52+
return 0;
53+
}
54+
if (line > 1 && line <= lineOffsets.size()) {
55+
return lineOffsets.get(line - 2);
56+
}
57+
return -1;
58+
}
59+
60+
private CelSourceHelper() {}
61+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2024 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package dev.cel.common;
16+
17+
import dev.cel.common.annotations.Internal;
18+
import dev.cel.common.internal.CelCodePointArray;
19+
import java.util.Optional;
20+
21+
/**
22+
* Common interface definition for source properties.
23+
*
24+
* <p>CEL Library Internals. Do Not Use. Consumers should instead use the canonical implementations
25+
* such as CelSource.
26+
*/
27+
@Internal
28+
public interface Source {
29+
30+
/** Gets the original textual content of this source, represented in an array of code points. */
31+
CelCodePointArray getContent();
32+
33+
/**
34+
* Gets the description of this source that may optionally be set (example: location of the file
35+
* containing the source).
36+
*/
37+
String getDescription();
38+
39+
/**
40+
* Get the text from the source text that corresponds to {@code line}. Snippets are split based on
41+
* the newline ('\n').
42+
*
43+
* @param line the line number starting from 1.
44+
*/
45+
Optional<String> getSnippet(int line);
46+
}

common/src/main/java/dev/cel/common/internal/BasicCodePointArray.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static com.google.common.base.Preconditions.checkPositionIndexes;
2020

2121
import com.google.common.annotations.VisibleForTesting;
22+
import com.google.common.collect.ImmutableList;
2223
import com.google.errorprone.annotations.Immutable;
2324
import dev.cel.common.annotations.Internal;
2425

@@ -38,21 +39,23 @@ public final class BasicCodePointArray extends CelCodePointArray {
3839

3940
private final int offset;
4041
private final int size;
42+
private final ImmutableList<Integer> lineOffsets;
4143

42-
BasicCodePointArray(char[] codePoints, int size) {
43-
this(codePoints, 0, size);
44+
BasicCodePointArray(char[] codePoints, int size, ImmutableList<Integer> lineOffsets) {
45+
this(codePoints, 0, lineOffsets, size);
4446
}
4547

46-
BasicCodePointArray(char[] codePoints, int offset, int size) {
48+
BasicCodePointArray(char[] codePoints, int offset, ImmutableList<Integer> lineOffsets, int size) {
4749
this.codePoints = checkNotNull(codePoints);
4850
this.offset = offset;
4951
this.size = size;
52+
this.lineOffsets = lineOffsets;
5053
}
5154

5255
@Override
5356
public BasicCodePointArray slice(int i, int j) {
5457
checkPositionIndexes(i, j, size());
55-
return new BasicCodePointArray(codePoints, offset + i, j - i);
58+
return new BasicCodePointArray(codePoints, offset + i, lineOffsets, j - i);
5659
}
5760

5861
@Override
@@ -66,6 +69,11 @@ public int size() {
6669
return size;
6770
}
6871

72+
@Override
73+
public ImmutableList<Integer> lineOffsets() {
74+
return lineOffsets;
75+
}
76+
6977
@Override
7078
public String toString() {
7179
return new String(codePoints, offset, size);

0 commit comments

Comments
 (0)