1616
1717import static com .google .common .base .Preconditions .checkArgument ;
1818import static com .google .common .base .Preconditions .checkNotNull ;
19+ import static com .google .common .base .Preconditions .checkState ;
1920
2021import com .google .auto .value .AutoValue ;
21- import com .google .common .base .Splitter ;
2222import com .google .common .collect .ImmutableList ;
2323import com .google .common .collect .ImmutableMap ;
2424import com .google .common .collect .ImmutableSet ;
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 /**
0 commit comments