// Copyright 2024 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 // // http://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. syntax = "proto3"; package google.api.expr.v1alpha1; import "google/protobuf/duration.proto"; import "google/protobuf/struct.proto"; import "google/protobuf/timestamp.proto"; option cc_enable_arenas = true; option go_package = "google.golang.org/genproto/googleapis/api/expr/v1alpha1;expr"; option java_multiple_files = true; option java_outer_classname = "SyntaxProto"; option java_package = "com.google.api.expr.v1alpha1"; // A representation of the abstract syntax of the Common Expression Language. // An expression together with source information as returned by the parser. message ParsedExpr { // The parsed expression. Expr expr = 2; // The source info derived from input that generated the parsed `expr`. SourceInfo source_info = 3; } // An abstract representation of a common expression. // // Expressions are abstractly represented as a collection of identifiers, // select statements, function calls, literals, and comprehensions. All // operators with the exception of the '.' operator are modelled as function // calls. This makes it easy to represent new operators into the existing AST. // // All references within expressions must resolve to a // [Decl][google.api.expr.v1alpha1.Decl] provided at type-check for an // expression to be valid. A reference may either be a bare identifier `name` or // a qualified identifier `google.api.name`. References may either refer to a // value or a function declaration. // // For example, the expression `google.api.name.startsWith('expr')` references // the declaration `google.api.name` within a // [Expr.Select][google.api.expr.v1alpha1.Expr.Select] expression, and the // function declaration `startsWith`. message Expr { // An identifier expression. e.g. `request`. message Ident { // Required. Holds a single, unqualified identifier, possibly preceded by a // '.'. // // Qualified names are represented by the // [Expr.Select][google.api.expr.v1alpha1.Expr.Select] expression. string name = 1; } // A field selection expression. e.g. `request.auth`. message Select { // Required. The target of the selection expression. // // For example, in the select expression `request.auth`, the `request` // portion of the expression is the `operand`. Expr operand = 1; // Required. The name of the field to select. // // For example, in the select expression `request.auth`, the `auth` portion // of the expression would be the `field`. string field = 2; // Whether the select is to be interpreted as a field presence test. // // This results from the macro `has(request.auth)`. bool test_only = 3; } // A call expression, including calls to predefined functions and operators. // // For example, `value == 10`, `size(map_value)`. message Call { // The target of an method call-style expression. For example, `x` in // `x.f()`. Expr target = 1; // Required. The name of the function or method being called. string function = 2; // The arguments. repeated Expr args = 3; } // A list creation expression. // // Lists may either be homogenous, e.g. `[1, 2, 3]`, or heterogeneous, e.g. // `dyn([1, 'hello', 2.0])` message CreateList { // The elements part of the list. repeated Expr elements = 1; // The indices within the elements list which are marked as optional // elements. // // When an optional-typed value is present, the value it contains // is included in the list. If the optional-typed value is absent, the list // element is omitted from the CreateList result. repeated int32 optional_indices = 2; } // A map or message creation expression. // // Maps are constructed as `{'key_name': 'value'}`. Message construction is // similar, but prefixed with a type name and composed of field ids: // `types.MyType{field_id: 'value'}`. message CreateStruct { // Represents an entry. message Entry { // Required. An id assigned to this node by the parser which is unique // in a given expression tree. This is used to associate type // information and other attributes to the node. int64 id = 1; // The `Entry` key kinds. oneof key_kind { // The field key for a message creator statement. string field_key = 2; // The key expression for a map creation statement. Expr map_key = 3; } // Required. The value assigned to the key. // // If the optional_entry field is true, the expression must resolve to an // optional-typed value. If the optional value is present, the key will be // set; however, if the optional value is absent, the key will be unset. Expr value = 4; // Whether the key-value pair is optional. bool optional_entry = 5; } // The type name of the message to be created, empty when creating map // literals. string message_name = 1; // The entries in the creation expression. repeated Entry entries = 2; } // A comprehension expression applied to a list or map. // // Comprehensions are not part of the core syntax, but enabled with macros. // A macro matches a specific call signature within a parsed AST and replaces // the call with an alternate AST block. Macro expansion happens at parse // time. // // The following macros are supported within CEL: // // Aggregate type macros may be applied to all elements in a list or all keys // in a map: // // * `all`, `exists`, `exists_one` - test a predicate expression against // the inputs and return `true` if the predicate is satisfied for all, // any, or only one value `list.all(x, x < 10)`. // * `filter` - test a predicate expression against the inputs and return // the subset of elements which satisfy the predicate: // `payments.filter(p, p > 1000)`. // * `map` - apply an expression to all elements in the input and return the // output aggregate type: `[1, 2, 3].map(i, i * i)`. // // The `has(m.x)` macro tests whether the property `x` is present in struct // `m`. The semantics of this macro depend on the type of `m`. For proto2 // messages `has(m.x)` is defined as 'defined, but not set`. For proto3, the // macro tests whether the property is set to its default. For map and struct // types, the macro tests whether the property `x` is defined on `m`. // // Comprehensions for the standard environment macros evaluation can be best // visualized as the following pseudocode: // // ``` // let `accu_var` = `accu_init` // for (let `iter_var` in `iter_range`) { // if (!`loop_condition`) { // break // } // `accu_var` = `loop_step` // } // return `result` // ``` // // Comprehensions for the optional V2 macros which support map-to-map // translation differ slightly from the standard environment macros in that // they expose both the key or index in addition to the value for each list // or map entry: // // ``` // let `accu_var` = `accu_init` // for (let `iter_var`, `iter_var2` in `iter_range`) { // if (!`loop_condition`) { // break // } // `accu_var` = `loop_step` // } // return `result` // ``` message Comprehension { // The name of the first iteration variable. // When the iter_range is a list, this variable is the list element. // When the iter_range is a map, this variable is the map entry key. string iter_var = 1; // The name of the second iteration variable, empty if not set. // When the iter_range is a list, this variable is the integer index. // When the iter_range is a map, this variable is the map entry value. // This field is only set for comprehension v2 macros. string iter_var2 = 8; // The range over which the comprehension iterates. Expr iter_range = 2; // The name of the variable used for accumulation of the result. string accu_var = 3; // The initial value of the accumulator. Expr accu_init = 4; // An expression which can contain iter_var, iter_var2, and accu_var. // // Returns false when the result has been computed and may be used as // a hint to short-circuit the remainder of the comprehension. Expr loop_condition = 5; // An expression which can contain iter_var, iter_var2, and accu_var. // // Computes the next value of accu_var. Expr loop_step = 6; // An expression which can contain accu_var. // // Computes the result. Expr result = 7; } // Required. An id assigned to this node by the parser which is unique in a // given expression tree. This is used to associate type information and other // attributes to a node in the parse tree. int64 id = 2; // Required. Variants of expressions. oneof expr_kind { // A literal expression. Constant const_expr = 3; // An identifier expression. Ident ident_expr = 4; // A field selection expression, e.g. `request.auth`. Select select_expr = 5; // A call expression, including calls to predefined functions and operators. Call call_expr = 6; // A list creation expression. CreateList list_expr = 7; // A map or message creation expression. CreateStruct struct_expr = 8; // A comprehension expression. Comprehension comprehension_expr = 9; } } // Represents a primitive literal. // // Named 'Constant' here for backwards compatibility. // // This is similar as the primitives supported in the well-known type // `google.protobuf.Value`, but richer so it can represent CEL's full range of // primitives. // // Lists and structs are not included as constants as these aggregate types may // contain [Expr][google.api.expr.v1alpha1.Expr] elements which require // evaluation and are thus not constant. // // Examples of literals include: `"hello"`, `b'bytes'`, `1u`, `4.2`, `-2`, // `true`, `null`. message Constant { // Required. The valid constant kinds. oneof constant_kind { // null value. google.protobuf.NullValue null_value = 1; // boolean value. bool bool_value = 2; // int64 value. int64 int64_value = 3; // uint64 value. uint64 uint64_value = 4; // double value. double double_value = 5; // string value. string string_value = 6; // bytes value. bytes bytes_value = 7; // protobuf.Duration value. // // Deprecated: duration is no longer considered a builtin cel type. google.protobuf.Duration duration_value = 8 [deprecated = true]; // protobuf.Timestamp value. // // Deprecated: timestamp is no longer considered a builtin cel type. google.protobuf.Timestamp timestamp_value = 9 [deprecated = true]; } } // Source information collected at parse time. message SourceInfo { // An extension that was requested for the source expression. message Extension { // Version message Version { // Major version changes indicate different required support level from // the required components. int64 major = 1; // Minor version changes must not change the observed behavior from // existing implementations, but may be provided informationally. int64 minor = 2; } // CEL component specifier. enum Component { // Unspecified, default. COMPONENT_UNSPECIFIED = 0; // Parser. Converts a CEL string to an AST. COMPONENT_PARSER = 1; // Type checker. Checks that references in an AST are defined and types // agree. COMPONENT_TYPE_CHECKER = 2; // Runtime. Evaluates a parsed and optionally checked CEL AST against a // context. COMPONENT_RUNTIME = 3; } // Identifier for the extension. Example: constant_folding string id = 1; // If set, the listed components must understand the extension for the // expression to evaluate correctly. // // This field has set semantics, repeated values should be deduplicated. repeated Component affected_components = 2; // Version info. May be skipped if it isn't meaningful for the extension. // (for example constant_folding might always be v0.0). Version version = 3; } // The syntax version of the source, e.g. `cel1`. string syntax_version = 1; // The location name. All position information attached to an expression is // relative to this location. // // The location could be a file, UI element, or similar. For example, // `acme/app/AnvilPolicy.cel`. string location = 2; // Monotonically increasing list of code point offsets where newlines // `\n` appear. // // The line number of a given position is the index `i` where for a given // `id` the `line_offsets[i] < id_positions[id] < line_offsets[i+1]`. The // column may be derivd from `id_positions[id] - line_offsets[i]`. repeated int32 line_offsets = 3; // A map from the parse node id (e.g. `Expr.id`) to the code point offset // within the source. map positions = 4; // A map from the parse node id where a macro replacement was made to the // call `Expr` that resulted in a macro expansion. // // For example, `has(value.field)` is a function call that is replaced by a // `test_only` field selection in the AST. Likewise, the call // `list.exists(e, e > 10)` translates to a comprehension expression. The key // in the map corresponds to the expression id of the expanded macro, and the // value is the call `Expr` that was replaced. map macro_calls = 5; // A list of tags for extensions 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. repeated Extension extensions = 6; } // A specific position in source. message SourcePosition { // The soucre location name (e.g. file name). string location = 1; // The UTF-8 code unit offset. int32 offset = 2; // The 1-based index of the starting line in the source text // where the issue occurs, or 0 if unknown. int32 line = 3; // The 0-based index of the starting position within the line of source text // where the issue occurs. Only meaningful if line is nonzero. int32 column = 4; }