Este documento sirve como referencia unificada de la documentación de la API para Common Expression Language (CEL). Enumera todas las macros, los operadores y las funciones estándar, y muestra sus firmas, comportamientos y estado de compatibilidad en todas las pilas de CEL oficiales.
Para obtener más detalles sobre el comportamiento y las especificaciones del lenguaje, consulta la Definición del lenguaje de CEL.
Versiones de la pila
Este documento de referencia se basa en las siguientes versiones de las pilas de CEL:
- CEL Go:
v0.29.2(y versiones posteriores) - CEL C++:
v0.15.0 - CEL en Java:
v0.13.1 - CEL de Python:
v0.1.3 - CEL C: Versión de desarrollo (sin lanzar)
Duplicaciones de GitHub
Las implementaciones oficiales de CEL se duplican en GitHub en la organización cel-expr:
1. Macros principales
Estas son macros integradas que se expanden en el tiempo de compilación.
| Macro | Descripción | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
has(container.field) |
Prueba si un campo está presente en un mensaje o una clave en un mapa. Firmas: has(container.field) -> boolEjemplos: has(request.auth.claims.email) |
✓ | ✓ | ✓ | ✓ | ✓ |
list.all(var, predicate) |
Prueba si todos los elementos de una lista satisfacen un predicado. Firmas: list.all(var, predicate) -> boolEjemplos: [1, 2, 3].all(x, x > 0) // true |
✓ | ✓ | ✓ | ✓ | ✓¹ |
list.exists(var, predicate) |
Prueba si al menos un elemento de una lista satisface un predicado. Firmas: list.exists(var, predicate) -> boolEjemplos: [1, 2, 3].exists(x, x > 2) // true |
✓ | ✓ | ✓ | ✓ | ✓¹ |
list.exists_one(var, predicate) |
Prueba si exactamente un elemento de una lista satisface un predicado. Firmas: list.exists_one(var, predicate) -> boolEjemplos: [1, 2, 3].exists_one(x, x == 2) // true |
✓ | ✓ | ✓ | ✓ | ✓¹ |
list.filter(var, predicate) |
Filtra los elementos de una lista según un predicado. Firmas: list.filter(var, predicate) -> listEjemplos: [1, 2, 3].filter(x, x > 1) // [2, 3] |
✓ | ✓ | ✓ | ✓ | ✓¹ |
list.map(var, transform) |
Transforma cada elemento de una lista con una expresión. Firmas: list.map(var, transform) -> listEjemplos: [1, 2, 3].map(x, x * 2) // [2, 4, 6] |
✓ | ✓ | ✓ | ✓ | ✓¹ |
list.map(var, filter, transform) |
Transforma los elementos de una lista que satisfacen un predicado de filtro. Firmas: list.map(var, filter, transform) -> listEjemplos: [1, 2, 3].map(x, x > 1, x * 2) // [4, 6] |
✓ | ✓ | ✓ | ✓ | ✓¹ |
¹ Se admite en el tiempo de ejecución de C porque el compilador host expande las macros en comprensiones durante la compilación.
2. Operadores principales
| Operador | Descripción | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
Aritmética (+, -, *, /, %) |
Operaciones aritméticas estándar. Negación (-x) e identidad (+x). La concatenación de listas (list + list) se admite en Go, C++, Java y Python.Firmas: T + T -> TT - T -> TT * T -> TT / T -> TT % T -> T-T -> T+T -> Tlist + list -> listEjemplos: 1 + 2 * 3 // 7[1] + [2] // [1, 2] |
✓ | ✓ | ✓ | ✓ | ✓² |
Comparación (==, !=, <, <=, >, >=) |
Comparación estándar. Las comparaciones numéricas son heterogéneas (p.ej., 1 == 1.0).Firmas: T == T -> boolT != T -> boolT < T -> boolT <= T -> boolT > T -> boolT >= T -> boolEjemplos: x < 42.01 == 1.0 // true |
✓ | ✓ | ✓ | ✓ | ✓ |
Lógicos (!, &&, ||, ? :) |
NOT, AND, OR lógicos y condicional ternario. AND/OR usa la evaluación de cortocircuito. Firmas: !bool -> boolbool && bool -> boolbool || bool -> boolbool ? T : T -> TEjemplos: x > 0 ? "positive" : "non-positive" |
✓ | ✓ | ✓ | ✓ | ✓ |
Indexación ([]) |
Accede al elemento de una lista por índice o a la clave de búsqueda en un mapa. Firmas: list[int] -> Tmap[K] -> VEjemplos: tags[0]users['john'] |
✓ | ✓ | ✓ | ✓ | ✓ |
Membresía (in) |
Verifica si un elemento está en una lista o si una clave está en un mapa. Firmas: T in list -> boolK in map -> boolEjemplos: 'admin' in roles |
✓ | ✓ | ✓ | ✓ | ✓ |
² La concatenación de listas (list + list) no se admite en el tiempo de ejecución de C, aunque sí se admiten otros operadores aritméticos.
3. Funciones principales
Funciones generales y de cadena
| Función | Descripción | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
size |
Devuelve el tamaño de una cadena (caracteres), bytes, lista o mapa. Firmas: size(T) -> int (donde T es string, bytes, list o map)<br /><br />**Examples:**<br />size("hello") // 5` |
✓ | ✓ | ✓ | ✓ | ✓ |
contains |
Devuelve un valor que indica si la cadena contiene una subcadena. Firmas: string.contains(string) -> boolEjemplos: "hello".contains("ell") // true |
✓ | ✓ | ✓ | ✓ | ✓ |
startsWith |
Devuelve si la cadena comienza con el prefijo. Firmas: string.startsWith(string) -> boolEjemplos: "hello".startsWith("he") // true |
✓ | ✓ | ✓ | ✓ | ✓ |
endsWith |
Devuelve si la cadena termina con el sufijo. Firmas: string.endsWith(string) -> boolEjemplos: "hello".endsWith("lo") // true |
✓ | ✓ | ✓ | ✓ | ✓ |
matches |
Devuelve si la cadena coincide con la expresión regular de RE2. Firmas: string.matches(string) -> boolEjemplos: "123".matches(r"^\d+$") // true |
✓ | ✓ | ✓ | ✓ | ✓ |
Funciones del selector de fecha y hora
Estas funciones extraen componentes de google.protobuf.Timestamp o google.protobuf.Duration.
| Función | Descripción | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
getFullYear |
Devuelve el año con 4 dígitos. Firmas: timestamp.getFullYear([tz]) -> intEjemplos: timestamp("2026-07-23T00:00:00Z").getFullYear() // 2026 |
✓ | ✓ | ✓ | ✓ | ✗ |
getMonth |
Devuelve el mes (de 0 a 11). Firmas: timestamp.getMonth([tz]) -> intEjemplos: timestamp("2026-07-23T00:00:00Z").getMonth() // 6 |
✓ | ✓ | ✓ | ✓ | ✗ |
getDayOfMonth |
Devuelve el día del mes (1-31). Firmas: timestamp.getDayOfMonth([tz]) -> intEjemplos: timestamp("2026-07-23T00:00:00Z").getDayOfMonth() // 23 |
✓ | ✓ | ✓ | ✓ | ✗ |
getDayOfWeek |
Devuelve el día de la semana (0 = domingo). Firmas: timestamp.getDayOfWeek([tz]) -> intEjemplos: timestamp("2026-07-23T00:00:00Z").getDayOfWeek() // 4 |
✓ | ✓ | ✓ | ✓ | ✗ |
getDayOfYear |
Devuelve el día del año (0-365). Firmas: timestamp.getDayOfYear([tz]) -> intEjemplos: timestamp("2026-07-23T00:00:00Z").getDayOfYear() // 203 |
✓ | ✓ | ✓ | ✓ | ✗ |
getHours |
Devuelve las horas (de 0 a 23). Firmas: timestamp.getHours([tz]) -> intduration.getHours() -> intEjemplos: duration("1h30m").getHours() // 1 |
✓ | ✓ | ✓ | ✓ | ✗ |
getMinutes |
Devuelve los minutos (0-59). Firmas: timestamp.getMinutes([tz]) -> intduration.getMinutes() -> intEjemplos: duration("1h30m").getMinutes() // 30 |
✓ | ✓ | ✓ | ✓ | ✗ |
getSeconds |
Devuelve los segundos (0-59). Firmas: timestamp.getSeconds([tz]) -> intduration.getSeconds() -> intEjemplos: duration("1h30m45s").getSeconds() // 45 |
✓ | ✓ | ✓ | ✓ | ✗ |
getMilliseconds |
Devuelve los milisegundos (de 0 a 999). Firmas: timestamp.getMilliseconds([tz]) -> intduration.getMilliseconds() -> intEjemplos: duration("1.5s").getMilliseconds() // 500 |
✓ | ✓ | ✓ | ✓ | ✗ |
Conversiones de tipos
| Tipo de objetivo | Descripción | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
bool |
Convierte a booleano. Firmas: bool(bool) -> boolbool(string) -> boolEjemplos: bool("true") // true |
✓ | ✓ | ✓ | ✓ | ✓ |
bytes |
Se convierte en bytes. Firmas: bytes(bytes) -> bytesbytes(string) -> bytesEjemplos: bytes("hello") // b"hello" |
✓ | ✓ | ✓ | ✓ | ✓ |
double |
Convierte a un número de punto flotante de doble precisión. Firmas: double(double) -> doubledouble(int) -> doubledouble(uint) -> doubledouble(string) -> doubleEjemplos: double(1) // 1.0 |
✓ | ✓ | ✓ | ✓ | ✓ |
duration |
Se convierte en duración. Firmas: duration(duration) -> durationduration(string) -> durationEjemplos: duration("1.5s") // 1.5s duration |
✓ | ✓ | ✓ | ✓ | ✓ |
int |
Convierte a un número entero de 64 bits con signo. Firmas: int(int) -> intint(uint) -> intint(double) -> int (redondea a cero)int(string) -> intint(timestamp) -> int (segundos desde la época)Ejemplos: int(1.5) // 1 |
✓ | ✓ | ✓ | ✓ | ✓ |
string |
Convierte a cadena. Firmas: string(T) -> string (admite bool, int, uint, double, bytes, timestamp, duration)<br /><br />**Examples:**<br />string(1.5) // "1.5"` |
✓ | ✓ | ✓ | ✓ | ✓ |
timestamp |
Convierte a marca de tiempo. Firmas: timestamp(timestamp) -> timestamptimestamp(string) -> timestamp (RFC3339)Ejemplos: timestamp("2026-07-23T00:00:00Z") |
✓ | ✓ | ✓ | ✓ | ✓ |
uint |
Convierte a un número entero de 64 bits sin firma. Firmas: uint(uint) -> uintuint(int) -> uintuint(double) -> uintuint(string) -> uintEjemplos: uint(1) // 1u |
✓ | ✓ | ✓ | ✓ | ✓ |
dyn |
Convierte el valor en un tipo dinámico para la verificación de tipos. Firmas: dyn(T) -> dynEjemplos: dyn([1, "two"]) |
✓ | ✓ | ✓ | ✓ | ✗ |
type |
Devuelve el tipo del valor. Firmas: type(T) -> typeEjemplos: type(1) // int |
✓ | ✓ | ✓ | ✓ | ✗ |
4. Extensiones (bibliotecas)
Biblioteca de vinculaciones
| Función | Descripción | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
cel.bind |
Vincula una variable local para evitar la evaluación duplicada. Firmas: cel.bind(varName, initExpr, resultExpr) -> TEjemplos: cel.bind(x, a + b, x * x) |
✓ (v0.15.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
Cómo habilitar
- Go: Pasa
ext.Bindings()acel.NewEnv(). - C++: Agrega
BindingsCompilerLibrary()aCompilerBuilder. (El tiempo de ejecución se controla automáticamente). - Java: Agrega
CelExtensions.bindings()a los compiladoresCelCompileryCelRuntime. - Python: Importa
cel_expr_python.ext.ext_bindingsy usaExtBindings()encel.NewEnv(extensions=[...]).
Biblioteca de codificadores
| Función | Descripción | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
base64.encode |
Codifica bytes en una cadena base64. Firmas: base64.encode(bytes) -> stringEjemplos: base64.encode(b"hello") // "aGVsbG8=" |
✓ (v0.6.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
base64.decode |
Decodifica una cadena en base64 en bytes. Genera un error si la entrada no es válida. Firmas: base64.decode(string) -> bytesEjemplos: base64.decode("aGVsbG8=") // b"hello" |
✓ (v0.6.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
json.encode |
Serializa un valor de CEL en una cadena JSON. Firmas: json.encode(dyn) -> stringEjemplos: json.encode([1, 2]) // "[1,2]" |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
Cómo habilitar
- Go: Pasa
ext.Encoders()acel.NewEnv(). - C++:
- Compilador: Agrega
EncodersCompilerLibrary()aCompilerBuilder. - Tiempo de ejecución: Llama a
RegisterEncodersFunctions()enFunctionRegistry.
- Compilador: Agrega
- Java: Agrega
CelExtensions.encoders()a los compiladoresCelCompileryCelRuntime. - Python: Importa
cel_expr_python.ext.ext_encodersy usaExtEncoders()encel.NewEnv(extensions=[...]).
Biblioteca de Math
| Función | Descripción | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
math.greatest |
Devuelve el mayor de los argumentos numéricos (o la lista de números). Firmas: math.greatest(arg, ...) -> TEjemplos: math.greatest(1, 3, 2) // 3 |
✓ (v0.13.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
math.least |
Devuelve el menor de los argumentos numéricos (o la lista de números). Firmas: math.least(arg, ...) -> TEjemplos: math.least([1, 3, 2]) // 1 |
✓ (v0.13.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
math.abs |
Valor absoluto. Firmas: math.abs(T) -> T (admite int, uint, double)<br /><br />**Examples:**<br />math.abs(-1) // 1` |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.sqrt |
Raíz cuadrada. Firmas: math.sqrt(T) -> double (admite int, uint, double)<br /><br />**Examples:**<br />math.sqrt(9) // 3.0` |
✓ (v0.25.1) | ✓ (v0.12.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
math.bitAnd |
AND bit a bit. Firmas: math.bitAnd(T, T) -> T (admite int, uint)<br /><br />**Examples:**<br />math.bitAnd(5, 3) // 1` |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.bitOr |
OR bit a bit. Firmas: math.bitOr(T, T) -> T (admite int, uint)<br /><br />**Examples:**<br />math.bitOr(5, 3) // 7` |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.bitXor |
XOR bit a bit. Firmas: math.bitXor(T, T) -> T (admite int, uint)<br /><br />**Examples:**<br />math.bitXor(5, 3) // 6` |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.bitNot |
NOT bit a bit. Firmas: math.bitNot(T) -> T (admite int, uint)<br /><br />**Examples:**<br />math.bitNot(1) // -2` |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.bitShiftLeft |
Desplaza bits hacia la izquierda. Firmas: math.bitShiftLeft(T, int) -> T (admite int, uint)<br /><br />**Examples:**<br />math.bitShiftLeft(1, 2) // 4` |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.bitShiftRight |
Desplaza bits hacia la derecha. Firmas: math.bitShiftRight(T, int) -> T (admite int, uint)<br /><br />**Examples:**<br />math.bitShiftRight(4, 2) // 1` |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.ceil |
Redondeo hacia arriba. Firmas: math.ceil(double) -> doubleEjemplos: math.ceil(1.2) // 2.0 |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.floor |
Redondeo hacia abajo. Firmas: math.floor(double) -> doubleEjemplos: math.floor(1.8) // 1.0 |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.round |
Redondeo al número entero más cercano. Firmas: math.round(double) -> doubleEjemplos: math.round(1.5) // 2.0 |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.trunc |
Redondeo por truncamiento (hacia cero). Firmas: math.trunc(double) -> doubleEjemplos: math.trunc(-1.8) // -1.0 |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.isInf |
Comprueba si el valor doble es infinito positivo o negativo. Firmas: math.isInf(double) -> boolEjemplos: math.isInf(1.0/0.0) // true |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.isNaN |
Verifica si el valor doble es NaN. Firmas: math.isNaN(double) -> boolEjemplos: math.isNaN(0.0/0.0) // true |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.isFinite |
Comprueba si el valor doble es finito. Firmas: math.isFinite(double) -> boolEjemplos: math.isFinite(1.2) // true |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.sign |
Devuelve el signo del valor (-1, 0 o 1). Firmas: math.sign(T) -> T (admite int, uint, double)<br /><br />**Examples:**<br />math.sign(-42) // -1` |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
Cómo habilitar
- Go: Pasa
ext.Math()acel.NewEnv(). - C++:
- Compilador: Agrega
MathCompilerLibrary()aCompilerBuilder. - Tiempo de ejecución: Llama a
RegisterMathExtensionFunctions()enFunctionRegistry.
- Compilador: Agrega
- Java: Agrega
CelExtensions.math()a los compiladoresCelCompileryCelRuntime. - Python: Importa
cel_expr_python.ext.ext_mathy usaExtMath()encel.NewEnv(extensions=[...]).
Biblioteca de protos
| Función | Descripción | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
proto.getExt |
Obtiene el campo de extensión de proto2 o el valor predeterminado si no se configura. Firmas: proto.getExt(msg, extName) -> TEjemplos: proto.getExt(msg, google.api.expr.test.int32_ext) |
✓ (v0.13.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
proto.hasExt |
Verifica si se configuró el campo de extensión proto2. Firmas: proto.hasExt(msg, extName) -> boolEjemplos: proto.hasExt(msg, google.api.expr.test.int32_ext) |
✓ (v0.13.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
Cómo habilitar
- Go: Pasa
ext.Protos()acel.NewEnv(). - C++: Agrega
ProtoExtCompilerLibrary()aCompilerBuilder. (El tiempo de ejecución se controla automáticamente). - Java: Agrega
CelExtensions.protos()a los compiladoresCelCompileryCelRuntime. - Python: Importa
cel_expr_python.ext.ext_protoy usaExtProto()encel.NewEnv(extensions=[...]).
Biblioteca de listas
| Función | Descripción | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
distinct |
Devuelve elementos distintos. Firmas: list.distinct() -> listEjemplos: [1, 2, 2].distinct() // [1, 2] |
✓ (v0.22.0) | ✓ (v0.11.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
flatten |
Aplanar listas anidadas. Firmas: list.flatten([depth]) -> listEjemplos: [[1], [2, 3]].flatten() // [1, 2, 3] |
✓ (v0.22.0) | ✓ (v0.11.0) | ✓ (v0.7.1) | ✓ (v0.1.1) | ✗ |
lists.range |
Devuelve una lista de números enteros [0, ..., n-1].Firmas: lists.range(int) -> list(int)Ejemplos: lists.range(3) // [0, 1, 2] |
✓ (v0.22.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
reverse |
Invierte el orden de la lista. Firmas: list.reverse() -> listEjemplos: [1, 2].reverse() // [2, 1] |
✓ (v0.22.0) | ✓ (v0.11.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
slice |
Devuelve una sublista (el inicio está incluido, el final no). Firmas: list.slice(start, end) -> listEjemplos: [1, 2, 3].slice(1, 3) // [2, 3] |
✓ (v0.17.0) | ✓ (v0.11.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
sort |
Ordena la lista de elementos comparables. Firmas: list.sort() -> listEjemplos: [3, 1, 2].sort() // [1, 2, 3] |
✓ (v0.22.0) | ✓ (v0.11.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
sortBy |
Ordena la lista según la clave evaluada a partir de la expresión. Firmas: list.sortBy(var, expr) -> listEjemplos: [{"val": 2}, {"val": 1}].sortBy(x, x.val) // [{"val": 1}, {"val": 2}] |
✓ (v0.22.0) | ✓ (v0.11.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
first |
Devuelve el primer elemento como opcional. Requiere la extensión Optional. Firmas: list.first() -> optionalEjemplos: [1, 2].first() // optional(1) |
✓ (v0.23.0) | ✓ (v0.15.0) | ✓ (v0.11.0) | ✓ (v0.1.2) | ✗ |
last |
Devuelve el último elemento como opcional. Requiere la extensión Optional. Firmas: list.last() -> optionalEjemplos: [1, 2].last() // optional(2) |
✓ (v0.23.0) | ✓ (v0.15.0) | ✓ (v0.11.0) | ✓ (v0.1.2) | ✗ |
Cómo habilitar
- Go: Pasa
ext.Lists()acel.NewEnv(). - C++:
- Compilador: Agrega
ListsCompilerLibrary()aCompilerBuilder. - Tiempo de ejecución: Llama a
RegisterListsFunctions()enFunctionRegistryy aRegisterListsMacros()enMacroRegistry.
- Compilador: Agrega
- Java: Agrega
CelExtensions.lists()a los compiladoresCelCompileryCelRuntime. - Python: Habilita la opción a través de
cel.EnvConfigagregandolistsa la listaextensions.
Biblioteca de conjuntos
| Función | Descripción | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
sets.contains |
Verifica si list1 contiene todos los elementos de list2. Firmas: sets.contains(list1, list2) -> boolEjemplos: sets.contains([1, 2], [1]) // true |
✓ (v0.15.0) | ✓ (v0.10.0) | ✓ (v0.6.0) | ✓ (v0.1.1) | ✗ |
sets.equivalent |
Comprueba si las listas son equivalentes en términos de conjuntos (contienen los mismos elementos únicos). Firmas: sets.equivalent(list1, list2) -> boolEjemplos: sets.equivalent([1, 2], [2, 1, 1]) // true |
✓ (v0.15.0) | ✓ (v0.10.0) | ✓ (v0.6.0) | ✓ (v0.1.1) | ✗ |
sets.intersects |
Verifica si las listas comparten al menos un elemento. Firmas: sets.intersects(list1, list2) -> boolEjemplos: sets.intersects([1, 2], [2, 3]) // true |
✓ (v0.15.0) | ✓ (v0.10.0) | ✓ (v0.6.0) | ✓ (v0.1.1) | ✗ |
Cómo habilitar
- Go: Pasa
ext.Sets()acel.NewEnv(). - C++:
- Compilador: Agrega
SetsCompilerLibrary()aCompilerBuilder. - Tiempo de ejecución: Llama a
RegisterSetsFunctions()enFunctionRegistry.
- Compilador: Agrega
- Java: Agrega
CelExtensions.sets()a los compiladoresCelCompileryCelRuntime. - Python: Habilita la opción a través de
cel.EnvConfigagregandosetsa la listaextensions.
Biblioteca de cadenas
| Función | Descripción | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
charAt |
Devuelve el carácter en el índice. Firmas: string.charAt(int) -> stringEjemplos: "hello".charAt(1) // "e" |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
indexOf |
Devuelve el índice de la primera ocurrencia de la subcadena o -1. Firmas: string.indexOf(substr, [start]) -> intEjemplos: "hello".indexOf("l") // 2 |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
lastIndexOf |
Devuelve el índice de la última ocurrencia de la subcadena o -1. Firmas: string.lastIndexOf(substr, [end]) -> intEjemplos: "hello".lastIndexOf("l") // 3 |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
join |
Concatena cadenas. Firmas: list(string).join([separator]) -> stringEjemplos: ["a", "b"].join("-") // "a-b" |
✓ (v0.10.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
split |
Divide la cadena por el separador. Firmas: string.split(separator, [limit]) -> list(string)Ejemplos: "a-b".split("-") // ["a", "b"] |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
substring |
Devuelve la substring (el inicio es inclusivo y el final es exclusivo). Firmas: string.substring(start, [end]) -> stringEjemplos: "hello".substring(1, 3) // "el" |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
trim |
Quita los espacios en blanco Unicode. Firmas: string.trim() -> stringEjemplos: " hello ".trim() // "hello" |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
replace |
Reemplaza las ocurrencias de old por new. Firmas: string.replace(old, new, [limit]) -> stringEjemplos: "hello".replace("l", "w") // "hewwo" |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
reverse |
Invierte los puntos de código Unicode. Firmas: string.reverse() -> stringEjemplos: "abc".reverse() // "cba" |
✓ (v0.18.0) | ✓ (v0.14.0) | ✓ (v0.13.0) | ✓ (v0.1.1) | ✗ |
lowerAscii |
Convierte caracteres ASCII a minúsculas. Firmas: string.lowerAscii() -> stringEjemplos: "Hello".lowerAscii() // "hello" |
✓ (v0.6.0) | ✓ (v0.11.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
upperAscii |
Convierte caracteres ASCII a mayúsculas. Firmas: string.upperAscii() -> stringEjemplos: "Hello".upperAscii() // "HELLO" |
✓ (v0.6.0) | ✓ (v0.11.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
quote |
Aplica caracteres de escape a la cadena para que se imprima de forma segura. Firmas: strings.quote(string) -> stringEjemplos: strings.quote("a\tb") // "\"a\\tb\"" |
✓ (v0.14.0) | ✓ (v0.14.0) | ✓ (v0.13.0) | ✓ (v0.1.1) | ✗ |
Cómo habilitar
- Go: Pasa
ext.Strings()acel.NewEnv(). - C++:
- Compilador: Agrega
StringsCompilerLibrary()aCompilerBuilder. - Tiempo de ejecución: Llama a
RegisterStringsFunctions()enFunctionRegistry.
- Compilador: Agrega
- Java: Agrega
CelExtensions.strings()a los compiladoresCelCompileryCelRuntime. - Python: Importa
cel_expr_python.ext.ext_stringsy usaExtStrings()encel.NewEnv(extensions=[...]).
Biblioteca de expresiones regulares
| Función | Descripción | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
regex.replace |
Reemplaza las coincidencias con la cadena de reemplazo (admite referencias inversas). Firmas: regex.replace(target, pat, repl, [limit]) -> stringEjemplos: regex.replace("123-456", r"(\d+)-(\d+)", r"\2-\1") // "456-123" |
✓ (v0.25.1) | ✓ (v0.13.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
regex.extract |
Devuelve la primera coincidencia del patrón (debe tener un grupo de captura). Firmas: regex.extract(target, pat) -> optional(string)Ejemplos: regex.extract("a123b", r"(\d+)") // optional("123") |
✓ (v0.25.1) | ✓ (v0.13.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
regex.extractAll |
Devuelve todas las coincidencias del patrón (debe tener un grupo de captura). Firmas: regex.extractAll(target, pat) -> list(string)Ejemplos: regex.extractAll("a1b2", r"(\d+)") // ["1", "2"] |
✓ (v0.25.1) | ✓ (v0.13.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
Cómo habilitar
- Go: Pasa
ext.Regex()acel.NewEnv(). - C++:
- Compilador: Agrega
RegexExtCompilerLibrary()aCompilerBuilder. - Tiempo de ejecución: Llama a
RegisterRegexExtensionFunctions()enFunctionRegistry.
- Compilador: Agrega
- Java: Agrega
CelExtensions.regex()a los compiladoresCelCompileryCelRuntime. - Python: Para habilitar la función, agrega
regexyoptionala la listaextensionsa través decel.EnvConfig.
Comprensiones de dos variables
| Macro | Descripción | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
all |
Cortocircuito de AND lógico sobre clave/índice y valor. Firmas: list.all(i, v, pred) -> boolmap.all(k, v, pred) -> boolEjemplos: [1, 2].all(i, v, v > 0) // true |
✓ (v0.22.0) | ✓ (v0.14.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
exists |
Cortocircuito de OR lógica sobre clave/índice y valor. Firmas: list.exists(i, v, pred) -> boolmap.exists(k, v, pred) -> boolEjemplos: [1, 2].exists(i, v, v == 2) // true |
✓ (v0.22.0) | ✓ (v0.14.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
existsOne |
Verifica si exactamente un par satisface el predicado. Firmas: list.existsOne(i, v, pred) -> boolmap.existsOne(k, v, pred) -> boolEjemplos: [1, 2].existsOne(i, v, v == 2) // true |
✓ (v0.22.0) | ✓ (v0.14.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
transformList |
Transforma o filtra una lista o un mapa en una lista. Firmas: list.transformList(i, v, [filter], transform) -> listmap.transformList(k, v, [filter], transform) -> listEjemplos: [1, 2].transformList(i, v, v * 2) // [2, 4] |
✓ (v0.22.0) | ✓ (v0.14.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
transformMap |
Transforma los valores de la lista o el mapa en un mapa (las claves permanecen fijas). Firmas: list.transformMap(i, v, [filter], transform) -> mapmap.transformMap(k, v, [filter], transform) -> mapEjemplos: [1, 2].transformMap(i, v, v * 2) // {0: 2, 1: 4} |
✓ (v0.22.0) | ✓ (v0.14.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
transformMapEntry |
Se transforma en un mapa. Firmas: list.transformMapEntry(i, v, [filter], transform_entry) -> mapmap.transformMapEntry(k, v, [filter], transform_entry) -> mapEjemplos: [1, 2].transformMapEntry(i, v, {string(v): v * 2}) // {"1": 2, "2": 4} |
✓ (v0.22.0) | ✓ (v0.14.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
Cómo habilitar
- Go: Pasa
ext.TwoVarComprehensions()acel.NewEnv(). - C++:
- Compilador: Agrega
ComprehensionsV2CompilerLibrary()aCompilerBuilder. - Tiempo de ejecución: Llama a
RegisterComprehensionsV2Functions()enFunctionRegistryy aRegisterComprehensionsV2Macros()enMacroRegistry.
- Compilador: Agrega
- Java: Agrega
CelExtensions.comprehensions()a los compiladoresCelCompileryCelRuntime. - Python: Para habilitar la función, agrega
two-var-comprehensionsa la listaextensionsa través decel.EnvConfig.
Biblioteca de tipos nativos
| Función | Descripción | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
| Structs nativos | Registro y creación de instancias de tipos nativos del host (structs de Go / POJOs de Java) en CEL. Ejemplos: Account{id: 123} (instancia de POJO de Java en CEL) |
✓ (v0.13.0) | ✗ | ✓ (v0.13.0) | ✗ | ✗ |
Cómo habilitar
- Ir: Pasa
ext.NativeTypes(...)(proporcionando tipos de reflejo) acel.NewEnv(). - C++: No admitido.
- Java: Agrega
CelExtensions.nativeTypes()(que proporciona clases de Java) a los compiladoresCelCompileryCelRuntime. - Python: No es compatible.
Biblioteca de red
La biblioteca de Network proporciona funciones para analizar, validar y manipular direcciones IP y bloques CIDR.
| Función | Descripción | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
ip |
Analiza una cadena para convertirla en una dirección IP o extrae la IP de un CIDR. Firmas: ip(string) -> IPCIDR.ip() -> IPEjemplos: ip("192.168.0.1")cidr("192.168.0.0/24").ip() |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isIP |
Comprueba si una cadena es una dirección IP válida. Firmas: isIP(string) -> boolEjemplos: isIP("192.168.0.1") // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
ip.isCanonical |
Comprueba si una cadena de dirección IP está en su formato canónico. Firmas: ip.isCanonical(string) -> boolEjemplos: ip.isCanonical("192.168.0.1") // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
cidr |
Analiza una cadena en un bloque CIDR. Firmas: cidr(string) -> CIDREjemplos: cidr("192.168.0.0/24") |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isCIDR |
Comprueba si una cadena es un bloque CIDR válido. Firmas: isCIDR(string) -> boolEjemplos: isCIDR("192.168.0.0/24") // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
containsIP |
Comprueba si un bloque CIDR contiene una dirección IP. Firmas: CIDR.containsIP(IP) -> boolCIDR.containsIP(string) -> boolEjemplos: cidr("192.168.0.0/24").containsIP(ip("192.168.0.1")) // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
containsCIDR |
Verifica si un bloque CIDR contiene otro bloque CIDR. Firmas: CIDR.containsCIDR(CIDR) -> boolCIDR.containsCIDR(string) -> boolEjemplos: cidr("192.168.0.0/16").containsCIDR(cidr("192.168.1.0/24")) // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
family |
Devuelve la familia de IP (4 para IPv4 y 6 para IPv6). Firmas: IP.family() -> intEjemplos: ip("192.168.0.1").family() // 4 |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isGlobalUnicast |
Comprueba si la IP es una dirección de unidifusión global. Firmas: IP.isGlobalUnicast() -> boolEjemplos: ip("192.168.0.1").isGlobalUnicast() // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isLinkLocalMulticast |
Comprueba si la IP es una dirección de multidifusión local de vínculo. Firmas: IP.isLinkLocalMulticast() -> boolEjemplos: ip("224.0.0.1").isLinkLocalMulticast() // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isLinkLocalUnicast |
Comprueba si la IP es una dirección unicast local de vínculo. Firmas: IP.isLinkLocalUnicast() -> boolEjemplos: ip("169.254.0.1").isLinkLocalUnicast() // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isLoopback |
Comprueba si la IP es una dirección de bucle invertido. Firmas: IP.isLoopback() -> boolEjemplos: ip("127.0.0.1").isLoopback() // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isMask |
Comprueba si el CIDR es una máscara de subred válida. Firmas: CIDR.isMask() -> boolEjemplos: cidr("255.255.255.0/24").isMask() // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isUnspecified |
Verifica si la IP es una dirección no especificada (p.ej., 0.0.0.0).Firmas: IP.isUnspecified() -> boolEjemplos: ip("0.0.0.0").isUnspecified() // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
masked |
Devuelve el bloque CIDR enmascarado. Firmas: CIDR.masked() -> CIDREjemplos: cidr("192.168.0.1/24").masked() // 192.168.0.0/24 |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
prefixLength |
Devuelve la longitud del prefijo del bloque CIDR. Firmas: CIDR.prefixLength() -> intEjemplos: cidr("192.168.0.0/24").prefixLength() // 24 |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
string |
Convierte la IP o el CIDR en una cadena. Firmas: string(IP) -> stringstring(CIDR) -> stringEjemplos: string(ip("192.168.0.1")) // "192.168.0.1" |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
Cómo habilitar
- Go: Pasa
ext.Network()acel.NewEnv(). - C++: No admitido.
- Java: No admitido.
- Python: No es compatible.
5. Funciones avanzadas
Resumen de las funciones avanzadas
| Función | Descripción | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
| Evaluación parcial | Evalúa con entradas faltantes; devuelve desconocidos o una expresión simplificada. | ✓³ | ✓⁴ | ✓⁴ | ✗ | ✗ |
| Evaluación asíncrona | Ejecución simultánea sin bloqueo de funciones de extensión. | ✓⁵ | ✗ | ✓⁶ | ✗ | ✗ |
| Validadores de AST | Verificaciones de análisis estático en el AST verificado después de la verificación de tipos. | ✓ | ✓ | ✓ | ✗ | ✗ |
| Optimizadores de AST | Reescrituras del AST (plegado de constantes, inserción en línea, CSE) para mejorar el rendimiento. | ✓ | ✓ | ✓ | ✗ | ✗ |
| Compilador de políticas de CEL | Compila estructuras de políticas basadas en YAML en AST de CEL estándar. | ✓ | ✓ | ✓ | ✗ | ✗ |
³ Go admite la generación de un AST residual (AST podado). ⁴ C++ y Java admiten la devolución de UnknownSet / CelUnknownSet en el tiempo de ejecución, pero no exponen APIs públicas para la generación de AST residual. ⁵ Go usa canales de devolución AsyncBinding / AsyncOp. ⁶ Java usa CelAsyncRuntime y devuelve ListenableFuture.
Evaluación parcial (desconocidos)
La evaluación parcial permite evaluar una expresión cuando solo se conoce un subconjunto de las variables de entrada (argumentos). En lugar de fallar, la evaluación produce un resultado que indica lo que falta o una expresión simplificada.
- Ir: Compatibilidad total. Permite definir un
PartialActivationcon patrones de atributos desconocidos. La evaluación devuelve un valortypes.Unknown. Go admite la generación de un AST residual (Env.ResidualAst), que es un AST simplificado y reducido que contiene solo las partes de la expresión que no se pudieron evaluar. - C++: Admite valores de
Unknown. Los patrones de atributos desconocidos se configuran a través deActivation::set_unknown_attribute_patterns. La evaluación devuelve unUnknownSet. Actualmente, la API pública no expone la generación de AST residual. - Java: Admite la evaluación parcial a través de
PartialVarsque se pasa aProgram.eval(). La evaluación devuelve unCelUnknownSet. Actualmente, la API pública no expone la generación de AST residual. - Python / C: No hay compatibilidad nativa.
Evaluación asíncrona
La evaluación asíncrona permite que las expresiones de CEL llamen a funciones que se ejecutan de forma asíncrona (p.ej., realizar RPC o consultas de bases de datos) y bloqueen la evaluación hasta que los resultados estén disponibles, sin bloquear el subproceso de ejecución principal.
- Go: Admite sobrecargas de funciones asíncronas a través de
AsyncBindingyAsyncOp. Las funciones asíncronas devuelven un canal de Go (<-chan ref.Val), y el intérprete administra la ejecución y la sincronización simultáneas. - Java: Admite la evaluación asíncrona a través de
CelAsyncRuntimeyAsyncProgram. UtilizaListenableFuturepara representar valores pendientes y, automáticamente, lleva la evaluación a su finalización a medida que se resuelven los futuros. - C++ / Python / C: No hay compatibilidad integrada.
Validadores de AST
Los validadores realizan un análisis estático en el AST verificado después de la verificación de tipos para aplicar restricciones específicas del dominio antes de que se ejecute el programa.
- Go: Admite la interfaz
ASTValidator. Los validadores canónicos incluyencel.validator.duration,cel.validator.timestamp,cel.validator.matches(regex),cel.validator.homogeneous_literalsycel.validator.comprehension_nesting_limit. - C++: Admite
cel::Validator. Las validaciones canónicas incluyenAstDepthValidator,ComprehensionNestingLimitValidator,DurationLiteralValidator,HomogeneousLiteralValidator,MatchesValidatoryTimestampLiteralValidator. - Java: Admite
CelValidatoryCelAstValidator. Los validadores canónicos incluyenAstDepthLimitValidator,ComprehensionNestingLimitValidator,DurationLiteralValidator,HomogeneousLiteralValidator,RegexLiteralValidatoryTimestampLiteralValidator. - Python / C: No hay compatibilidad directa.
Optimizadores de AST
Los optimizadores reescriben el AST para mejorar el rendimiento de la ejecución. Los optimizadores se dividen en dos categorías: estáticos y de tiempo de ejecución. C++, Java y Go admiten la optimización del tiempo de ejecución. CEL Java y Go también admiten optimizadores estáticos. Las optimizaciones típicas incluyen el plegado de constantes (pre-evaluación de subexpresiones con entradas constantes) y la eliminación de subexpresiones comunes (CSE).
- Go: Admite el plegado del AST durante la compilación o la planificación.
- C++: Admite el plegado de constantes a través de la extensión
cel::extensions::EnableConstantFoldingen el momento de la planificación. - Java: Admite la interfaz
CelOptimizer. Los optimizadores canónicos incluyenConstantFoldingOptimizer(que puede plegar ramas de cortocircuito simulando la evaluación parcial),InliningOptimizerySubexpressionOptimizer(CSE). - Python / C: No hay compatibilidad directa.
Compilador de políticas de CEL
La política de CEL es un formato basado en YAML para componer varias expresiones de CEL junto con variables, bloques de coincidencias, resultados condicionales y reglas anidadas. Está diseñado para motores de políticas complejos (como el Control de admisión de Kubernetes) en los que las expresiones CEL individuales serían ilegibles.
El compilador de políticas compila estas políticas de YAML en un solo AST de CEL estándar, lo que significa que son totalmente compatibles con los tiempos de ejecución de CEL estándar y heredan todas las garantías de rendimiento y seguridad.
- Ir: Se admite a través de
third_party/cel/go/policy. - C++: Se admite a través de
third_party/cel/cpp/policy. - Java: Se admite a través de
third_party/java/cel/policy. - Python / C: No se admite directamente.