All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.cel.common.CelSource Maven / Gradle / Ivy

The newest version!
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dev.cel.common;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.CheckReturnValue;
import com.google.errorprone.annotations.Immutable;
import dev.cel.common.ast.CelExpr;
import dev.cel.common.internal.CelCodePointArray;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/** Represents the source content of an expression and related metadata. */
@Immutable
@AutoValue
public abstract class CelSource implements Source {

  abstract CelCodePointArray codePoints();

  abstract String description();

  abstract ImmutableList lineOffsets();

  abstract ImmutableMap positions();

  abstract ImmutableMap macroCalls();

  abstract ImmutableSet extensions();

  @Override
  public CelCodePointArray getContent() {
    return codePoints();
  }

  @Override
  public String getDescription() {
    return description();
  }

  @Override
  public ImmutableMap getPositionsMap() {
    return positions();
  }

  /**
   * Get the code point offsets (NOT code unit offsets) for new line characters '\n' within the
   * source expression text.
   *
   * 

NOTE: The indices point to the index just after the '\n' not the index of '\n' itself. */ public ImmutableList getLineOffsets() { return lineOffsets(); } public ImmutableMap getMacroCalls() { return macroCalls(); } public ImmutableSet getExtensions() { return extensions(); } /** See {@link #getLocationOffset(int, int)}. */ public Optional getLocationOffset(CelSourceLocation location) { checkNotNull(location); return getLocationOffset(location.getLine(), location.getColumn()); } /** * Get the code point offset within the source expression text that corresponds with the {@code * line} and {@code column}. * * @param line the line number starting from 1 * @param column the column number starting from 0 */ public Optional getLocationOffset(int line, int column) { return getLocationOffsetImpl(lineOffsets(), line, column); } /** * Get the line and column in the source expression text for the given code point {@code offset}. */ public Optional getOffsetLocation(int offset) { return CelSourceHelper.getOffsetLocation(codePoints(), offset); } @Override public Optional getSnippet(int line) { return CelSourceHelper.getSnippet(codePoints(), line); } /** * Get the code point offset within the source expression text that corresponds with the {@code * line} and {@code column}. * * @param line the line number starting from 1 * @param column the column number starting from 0 */ private static Optional getLocationOffsetImpl( List lineOffsets, int line, int column) { if (line <= 0 || column < 0) { return Optional.empty(); } int offset = CelSourceHelper.findLineOffset(lineOffsets, line); if (offset == -1) { return Optional.empty(); } return Optional.of(offset + column); } public Builder toBuilder() { return new Builder(codePoints(), lineOffsets()) .setDescription(description()) .addPositionsMap(positions()) .addAllExtensions(extensions()) .addAllMacroCalls(macroCalls()); } public static Builder newBuilder() { return new Builder(); } public static Builder newBuilder(String text) { return newBuilder(CelCodePointArray.fromString(text)); } public static Builder newBuilder(CelCodePointArray codePointArray) { return new Builder(codePointArray, codePointArray.lineOffsets()); } /** Builder for {@link CelSource}. */ public static final class Builder { private final CelCodePointArray codePoints; private final List lineOffsets; private final Map positions; private final Map macroCalls; private final ImmutableSet.Builder extensions; private final boolean lineOffsetsAlreadyComputed; private String description; private Builder() { this(CelCodePointArray.fromString(""), new ArrayList<>()); } private Builder(CelCodePointArray codePoints, List lineOffsets) { this.codePoints = checkNotNull(codePoints); this.lineOffsets = checkNotNull(lineOffsets); this.positions = new HashMap<>(); this.macroCalls = new HashMap<>(); this.extensions = ImmutableSet.builder(); this.description = ""; this.lineOffsetsAlreadyComputed = !lineOffsets.isEmpty(); } @CanIgnoreReturnValue public Builder setDescription(String description) { this.description = checkNotNull(description); return this; } @CanIgnoreReturnValue public Builder addLineOffsets(int lineOffset) { checkArgument(lineOffset >= 0); checkState( !lineOffsetsAlreadyComputed, "Line offsets were already been computed through the provided code points."); lineOffsets.add(lineOffset); return this; } @CanIgnoreReturnValue public Builder addAllLineOffsets(Iterable lineOffsets) { for (int lineOffset : lineOffsets) { addLineOffsets(lineOffset); } return this; } @CanIgnoreReturnValue public Builder addPositionsMap(Map positionsMap) { checkNotNull(positionsMap); this.positions.putAll(positionsMap); return this; } @CanIgnoreReturnValue public Builder addPositions(long exprId, int position) { this.positions.put(exprId, position); return this; } @CanIgnoreReturnValue public Builder removePositions(long exprId) { this.positions.remove(exprId); return this; } @CanIgnoreReturnValue public Builder addMacroCalls(long exprId, CelExpr expr) { this.macroCalls.put(exprId, expr); return this; } @CanIgnoreReturnValue public Builder addAllMacroCalls(Map macroCalls) { this.macroCalls.putAll(macroCalls); return this; } public ImmutableSet getExtensions() { return extensions.build(); } /** * Adds one or more {@link Extension}s to the source information. Extensions implement set * semantics and deduped if same ones are provided. */ @CanIgnoreReturnValue public Builder addAllExtensions(Iterable extensions) { checkNotNull(extensions); this.extensions.addAll(extensions); return this; } /** * Adds one or more {@link Extension}s to the source information. Extensions implement set * semantics and deduped if same ones are provided. */ @CanIgnoreReturnValue public Builder addAllExtensions(Extension... extensions) { return addAllExtensions(Arrays.asList(extensions)); } /** See {@link #getLocationOffset(int, int)}. */ public Optional getLocationOffset(CelSourceLocation location) { checkNotNull(location); return getLocationOffset(location.getLine(), location.getColumn()); } /** * Get the code point offset within the source expression text that corresponds with the {@code * line} and {@code column}. * * @param line the line number starting from 1 * @param column the column number starting from 0 */ public Optional getLocationOffset(int line, int column) { return getLocationOffsetImpl(lineOffsets, line, column); } /** * Get the line and column in the source expression text for the given code point {@code * offset}. */ public Optional getOffsetLocation(int offset) { return CelSourceHelper.getOffsetLocation(codePoints, offset); } @CheckReturnValue public Map getPositionsMap() { return this.positions; } @CheckReturnValue public Map getMacroCalls() { return macroCalls; } @CheckReturnValue public boolean containsMacroCalls(long exprId) { return this.macroCalls.containsKey(exprId); } @CheckReturnValue public CelSource build() { return new AutoValue_CelSource( codePoints, description, ImmutableList.copyOf(lineOffsets), ImmutableMap.copyOf(positions), ImmutableMap.copyOf(macroCalls), extensions.build()); } } /** * Tag for an extension that were used while parsing or type checking the source expression. For * example, optimizations that require special runtime support may be specified. These are used to * check feature support between components in separate implementations. This can be used to * either skip redundant work or report an error if the extension is unsupported. */ @AutoValue @Immutable public abstract static class Extension { /** Identifier for the extension. Example: constant_folding */ abstract String id(); /** * Version info. May be skipped if it isn't meaningful for the extension. (for example * constant_folding might always be v0.0). */ abstract Version version(); /** * If set, the listed components must understand the extension for the expression to evaluate * correctly. */ abstract ImmutableList affectedComponents(); /** Version of the extension */ @AutoValue @Immutable public abstract static class Version { /** * Major version changes indicate different required support level from the required * components. */ abstract long major(); /** * Minor version changes must not change the observed behavior from existing implementations, * but may be provided informational. */ abstract long minor(); /** Create a new instance of Version with the provided major and minor values. */ public static Version of(long major, long minor) { return new AutoValue_CelSource_Extension_Version(major, minor); } } /** CEL component specifier. */ public enum Component { /** Unspecified, default. */ COMPONENT_UNSPECIFIED, /** Parser. Converts a CEL string to an AST. */ COMPONENT_PARSER, /** Type checker. Checks that references in an AST are defined and types agree. */ COMPONENT_TYPE_CHECKER, /** Runtime. Evaluates a parsed and optionally checked CEL AST against a context. */ COMPONENT_RUNTIME } @CheckReturnValue public static Extension create(String id, Version version, Iterable components) { checkNotNull(version); checkNotNull(components); return new AutoValue_CelSource_Extension(id, version, ImmutableList.copyOf(components)); } @CheckReturnValue public static Extension create(String id, Version version, Component... components) { return create(id, version, Arrays.asList(components)); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy