Dokumen ini berfungsi sebagai referensi Dokumen API terpadu untuk Common Expression Language (CEL). Dokumen ini mencantumkan semua makro, operator, dan fungsi standar, yang menunjukkan tanda tangan, perilaku, dan status dukungannya di seluruh stack CEL resmi.
Untuk mengetahui detail selengkapnya tentang perilaku dan spesifikasi bahasa, lihat Definisi Bahasa CEL.
Versi Stack
Dokumen referensi ini didasarkan pada versi stack CEL berikut:
- CEL Go:
v0.29.2(dan yang lebih baru) - CEL C++:
v0.15.0 - CEL Java:
v0.13.1 - CEL Python:
v0.1.3 - CEL C: Snapshot pengembangan (belum dirilis)
Duplikasi GitHub
Implementasi resmi CEL diduplikasi di GitHub di organisasi cel-expr:
1. Makro Inti
Ini adalah makro bawaan yang diperluas pada waktu kompilasi.
| Makro | Deskripsi | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
has(container.field) |
Menguji apakah kolom ada dalam pesan, atau kunci dalam peta. Tanda Tangan: has(container.field) -> boolContoh: has(request.auth.claims.email) |
✓ | ✓ | ✓ | ✓ | ✓ |
list.all(var, predicate) |
Menguji apakah semua elemen dalam daftar memenuhi predikat. Tanda Tangan: list.all(var, predicate) -> boolContoh: [1, 2, 3].all(x, x > 0) // true |
✓ | ✓ | ✓ | ✓ | ✓¹ |
list.exists(var, predicate) |
Menguji apakah setidaknya satu elemen dalam daftar memenuhi predikat. Tanda tangan: list.exists(var, predicate) -> boolContoh: [1, 2, 3].exists(x, x > 2) // true |
✓ | ✓ | ✓ | ✓ | ✓¹ |
list.exists_one(var, predicate) |
Menguji apakah tepat satu elemen dalam daftar memenuhi predikat. Tanda tangan: list.exists_one(var, predicate) -> boolContoh: [1, 2, 3].exists_one(x, x == 2) // true |
✓ | ✓ | ✓ | ✓ | ✓¹ |
list.filter(var, predicate) |
Memfilter elemen daftar sesuai dengan predikat. Tanda tangan: list.filter(var, predicate) -> listContoh: [1, 2, 3].filter(x, x > 1) // [2, 3] |
✓ | ✓ | ✓ | ✓ | ✓¹ |
list.map(var, transform) |
Mengubah setiap elemen daftar menggunakan ekspresi. Tanda tangan: list.map(var, transform) -> listContoh: [1, 2, 3].map(x, x * 2) // [2, 4, 6] |
✓ | ✓ | ✓ | ✓ | ✓¹ |
list.map(var, filter, transform) |
Mengubah elemen daftar yang memenuhi predikat filter. Tanda Tangan: list.map(var, filter, transform) -> listContoh: [1, 2, 3].map(x, x > 1, x * 2) // [4, 6] |
✓ | ✓ | ✓ | ✓ | ✓¹ |
¹ Didukung di runtime C karena makro diperluas menjadi pemahaman selama kompilasi oleh compiler host.
2. Operator Inti
| Operator | Deskripsi | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
Aritmetika (+, -, *, /, %) |
Operasi aritmatika standar. Negasi (-x) dan Identitas (+x). Penggabungan daftar (list + list) didukung di Go, C++, Java, dan Python.Tanda Tangan: T + T -> TT - T -> TT * T -> TT / T -> TT % T -> T-T -> T+T -> Tlist + list -> listContoh: 1 + 2 * 3 // 7[1] + [2] // [1, 2] |
✓ | ✓ | ✓ | ✓ | ✓² |
Perbandingan (==, !=, <, <=, >, >=) |
Perbandingan standar. Perbandingan numerik bersifat heterogen (misalnya, 1 == 1.0).Tanda Tangan: T == T -> boolT != T -> boolT < T -> boolT <= T -> boolT > T -> boolT >= T -> boolContoh: x < 42.01 == 1.0 // true |
✓ | ✓ | ✓ | ✓ | ✓ |
Logis (!, &&, ||, ? :) |
Logika NOT, AND, OR, dan Kondisional Ternary. DAN/ATAU gunakan evaluasi short-circuit. Tanda tangan: !bool -> boolbool && bool -> boolbool || bool -> boolbool ? T : T -> TContoh: x > 0 ? "positive" : "non-positive" |
✓ | ✓ | ✓ | ✓ | ✓ |
Pengindeksan ([]) |
Mengakses elemen daftar menurut indeks, atau kunci pencarian dalam peta. Tanda tangan: list[int] -> Tmap[K] -> VContoh: tags[0]users['john'] |
✓ | ✓ | ✓ | ✓ | ✓ |
Keanggotaan (in) |
Periksa apakah elemen ada dalam daftar, atau kunci ada dalam peta. Tanda Tangan: T in list -> boolK in map -> boolContoh: 'admin' in roles |
✓ | ✓ | ✓ | ✓ | ✓ |
² Penggabungan daftar (list + list) tidak didukung di runtime C,
meskipun operator aritmatika lainnya didukung.
3. Fungsi Inti
Fungsi Umum & String
| Fungsi | Deskripsi | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
size |
Menampilkan ukuran string (karakter), byte, daftar, atau peta. Tanda tangan: size(T) -> int (dengan T adalah string, bytes, list, atau map)<br /><br />**Examples:**<br />size("hello") // 5` |
✓ | ✓ | ✓ | ✓ | ✓ |
contains |
Menampilkan apakah string berisi substring. Tanda tangan: string.contains(string) -> boolContoh: "hello".contains("ell") // true |
✓ | ✓ | ✓ | ✓ | ✓ |
startsWith |
Menampilkan apakah string dimulai dengan awalan. Tanda Tangan: string.startsWith(string) -> boolContoh: "hello".startsWith("he") // true |
✓ | ✓ | ✓ | ✓ | ✓ |
endsWith |
Menampilkan apakah string diakhiri dengan akhiran. Tanda Tangan: string.endsWith(string) -> boolContoh: "hello".endsWith("lo") // true |
✓ | ✓ | ✓ | ✓ | ✓ |
matches |
Menampilkan apakah string cocok dengan ekspresi reguler RE2. Tanda Tangan: string.matches(string) -> boolContoh: "123".matches(r"^\d+$") // true |
✓ | ✓ | ✓ | ✓ | ✓ |
Fungsi Pemilih Tanggal dan Waktu
Fungsi ini mengekstrak komponen dari google.protobuf.Timestamp atau google.protobuf.Duration.
| Fungsi | Deskripsi | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
getFullYear |
Menampilkan tahun 4 digit. Tanda Tangan: timestamp.getFullYear([tz]) -> intContoh: timestamp("2026-07-23T00:00:00Z").getFullYear() // 2026 |
✓ | ✓ | ✓ | ✓ | ✗ |
getMonth |
Menampilkan bulan (0-11). Tanda tangan: timestamp.getMonth([tz]) -> intContoh: timestamp("2026-07-23T00:00:00Z").getMonth() // 6 |
✓ | ✓ | ✓ | ✓ | ✗ |
getDayOfMonth |
Menampilkan hari dalam sebulan (1-31). Tanda tangan: timestamp.getDayOfMonth([tz]) -> intContoh: timestamp("2026-07-23T00:00:00Z").getDayOfMonth() // 23 |
✓ | ✓ | ✓ | ✓ | ✗ |
getDayOfWeek |
Menampilkan hari dalam seminggu (0 = Minggu). Tanda tangan: timestamp.getDayOfWeek([tz]) -> intContoh: timestamp("2026-07-23T00:00:00Z").getDayOfWeek() // 4 |
✓ | ✓ | ✓ | ✓ | ✗ |
getDayOfYear |
Menampilkan hari dalam setahun (0-365). Tanda tangan: timestamp.getDayOfYear([tz]) -> intContoh: timestamp("2026-07-23T00:00:00Z").getDayOfYear() // 203 |
✓ | ✓ | ✓ | ✓ | ✗ |
getHours |
Menampilkan jam (0-23). Tanda tangan: timestamp.getHours([tz]) -> intduration.getHours() -> intContoh: duration("1h30m").getHours() // 1 |
✓ | ✓ | ✓ | ✓ | ✗ |
getMinutes |
Menampilkan menit (0-59). Tanda Tangan: timestamp.getMinutes([tz]) -> intduration.getMinutes() -> intContoh: duration("1h30m").getMinutes() // 30 |
✓ | ✓ | ✓ | ✓ | ✗ |
getSeconds |
Menampilkan detik (0-59). Tanda tangan: timestamp.getSeconds([tz]) -> intduration.getSeconds() -> intContoh: duration("1h30m45s").getSeconds() // 45 |
✓ | ✓ | ✓ | ✓ | ✗ |
getMilliseconds |
Menampilkan milidetik (0-999). Tanda tangan: timestamp.getMilliseconds([tz]) -> intduration.getMilliseconds() -> intContoh: duration("1.5s").getMilliseconds() // 500 |
✓ | ✓ | ✓ | ✓ | ✗ |
Konversi Jenis
| Jenis Target | Deskripsi | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
bool |
Dikonversi menjadi boolean. Tanda tangan: bool(bool) -> boolbool(string) -> boolContoh: bool("true") // true |
✓ | ✓ | ✓ | ✓ | ✓ |
bytes |
Dikonversi menjadi byte. Tanda Tangan: bytes(bytes) -> bytesbytes(string) -> bytesContoh: bytes("hello") // b"hello" |
✓ | ✓ | ✓ | ✓ | ✓ |
double |
Dikonversi menjadi float presisi ganda. Tanda Tangan: double(double) -> doubledouble(int) -> doubledouble(uint) -> doubledouble(string) -> doubleContoh: double(1) // 1.0 |
✓ | ✓ | ✓ | ✓ | ✓ |
duration |
Mengonversi ke durasi. Tanda tangan: duration(duration) -> durationduration(string) -> durationContoh: duration("1.5s") // 1.5s duration |
✓ | ✓ | ✓ | ✓ | ✓ |
int |
Mengonversi ke bilangan bulat 64-bit yang telah ditandai. Tanda tangan: int(int) -> intint(uint) -> intint(double) -> int (membulatkan ke nol)int(string) -> intint(timestamp) -> int (detik sejak epoch)Contoh: int(1.5) // 1 |
✓ | ✓ | ✓ | ✓ | ✓ |
string |
Mengonversi ke string. Tanda tangan: string(T) -> string (mendukung bool, int, uint, double, bytes, timestamp, duration)<br /><br />**Examples:**<br />string(1.5) // "1.5"` |
✓ | ✓ | ✓ | ✓ | ✓ |
timestamp |
Mengonversi ke stempel waktu. Tanda tangan: timestamp(timestamp) -> timestamptimestamp(string) -> timestamp (RFC3339)Contoh: timestamp("2026-07-23T00:00:00Z") |
✓ | ✓ | ✓ | ✓ | ✓ |
uint |
Mengonversi ke bilangan bulat 64-bit tanpa tanda. Tanda tangan: uint(uint) -> uintuint(int) -> uintuint(double) -> uintuint(string) -> uintContoh: uint(1) // 1u |
✓ | ✓ | ✓ | ✓ | ✓ |
dyn |
Mengubah nilai menjadi jenis dinamis untuk pemeriksaan jenis. Tanda tangan: dyn(T) -> dynContoh: dyn([1, "two"]) |
✓ | ✓ | ✓ | ✓ | ✗ |
type |
Menampilkan jenis nilai. Tanda Tangan: type(T) -> typeContoh: type(1) // int |
✓ | ✓ | ✓ | ✓ | ✗ |
4. Ekstensi (Library)
Library Pengikatan
| Fungsi | Deskripsi | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
cel.bind |
Mengikat variabel lokal untuk menghindari evaluasi duplikat. Tanda Tangan: cel.bind(varName, initExpr, resultExpr) -> TContoh: cel.bind(x, a + b, x * x) |
✓ (v0.15.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
Cara Mengaktifkan
- Go: Teruskan
ext.Bindings()kecel.NewEnv(). - C++: Tambahkan
BindingsCompilerLibrary()keCompilerBuilder. (Runtime ditangani secara otomatis). - Java: Tambahkan
CelExtensions.bindings()ke builderCelCompilerdanCelRuntime. - Python: Impor
cel_expr_python.ext.ext_bindingsdan gunakanExtBindings()dicel.NewEnv(extensions=[...]).
Pustaka Encoder
| Fungsi | Deskripsi | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
base64.encode |
Mengenkode byte ke string base64. Tanda tangan: base64.encode(bytes) -> stringContoh: base64.encode(b"hello") // "aGVsbG8=" |
✓ (v0.6.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
base64.decode |
Mendekode string base64 ke byte. Menampilkan error pada input yang tidak valid. Tanda tangan: base64.decode(string) -> bytesContoh: base64.decode("aGVsbG8=") // b"hello" |
✓ (v0.6.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
json.encode |
Menyerialkan nilai CEL ke string JSON. Tanda Tangan: json.encode(dyn) -> stringContoh: json.encode([1, 2]) // "[1,2]" |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
Cara Mengaktifkan
- Go: Teruskan
ext.Encoders()kecel.NewEnv(). - C++:
- Compiler: Tambahkan
EncodersCompilerLibrary()keCompilerBuilder. - Waktu proses: Hubungi
RegisterEncodersFunctions()diFunctionRegistry.
- Compiler: Tambahkan
- Java: Tambahkan
CelExtensions.encoders()ke builderCelCompilerdanCelRuntime. - Python: Impor
cel_expr_python.ext.ext_encodersdan gunakanExtEncoders()dicel.NewEnv(extensions=[...]).
Library Matematika
| Fungsi | Deskripsi | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
math.greatest |
Menampilkan argumen numerik terbesar (atau daftar numerik). Tanda tangan: math.greatest(arg, ...) -> TContoh: math.greatest(1, 3, 2) // 3 |
✓ (v0.13.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
math.least |
Menampilkan argumen numerik terkecil (atau daftar numerik). Sintaksis: math.least(arg, ...) -> TContoh: math.least([1, 3, 2]) // 1 |
✓ (v0.13.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
math.abs |
Nilai absolut. Tanda tangan: math.abs(T) -> T (mendukung 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 |
Akar kuadrat. Tanda tangan: math.sqrt(T) -> double (mendukung 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 |
Bitwise AND. Tanda tangan: math.bitAnd(T, T) -> T (mendukung 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 |
Bitwise OR. Tanda tangan: math.bitOr(T, T) -> T (mendukung 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 |
Bitwise XOR. Tanda tangan: math.bitXor(T, T) -> T (mendukung 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 |
Bitwise NOT. Tanda tangan: math.bitNot(T) -> T (mendukung int, uint)<br /><br />**Examples:**<br />math.bitNot(1) // -2` |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.bitShiftLeft |
Bitwise shift left. Tanda tangan: math.bitShiftLeft(T, int) -> T (mendukung 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 |
Bitwise shift right. Tanda tangan: math.bitShiftRight(T, int) -> T (mendukung 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 |
Pembulatan ke atas. Tanda tangan: math.ceil(double) -> doubleContoh: math.ceil(1.2) // 2.0 |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.floor |
Pembulatan ke bawah. Tanda tangan: math.floor(double) -> doubleContoh: math.floor(1.8) // 1.0 |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.round |
Pembulatan bilangan bulat terdekat. Tanda tangan: math.round(double) -> doubleContoh: math.round(1.5) // 2.0 |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.trunc |
Pembulatan pemotongan (menuju nol). Tanda tangan: math.trunc(double) -> doubleContoh: math.trunc(-1.8) // -1.0 |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.isInf |
Memeriksa apakah ganda adalah tak terhingga positif atau negatif. Tanda Tangan: math.isInf(double) -> boolContoh: math.isInf(1.0/0.0) // true |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.isNaN |
Memeriksa apakah ganda adalah NaN. Tanda Tangan: math.isNaN(double) -> boolContoh: math.isNaN(0.0/0.0) // true |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.isFinite |
Memeriksa apakah ganda terbatas. Tanda Tangan: math.isFinite(double) -> boolContoh: math.isFinite(1.2) // true |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
math.sign |
Menampilkan tanda nilai (-1, 0, atau 1). Tanda Tangan: math.sign(T) -> T (mendukung int, uint, double)<br /><br />**Examples:**<br />math.sign(-42) // -1` |
✓ (v0.21.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
Cara Mengaktifkan
- Go: Teruskan
ext.Math()kecel.NewEnv(). - C++:
- Compiler: Tambahkan
MathCompilerLibrary()keCompilerBuilder. - Waktu proses: Hubungi
RegisterMathExtensionFunctions()diFunctionRegistry.
- Compiler: Tambahkan
- Java: Tambahkan
CelExtensions.math()ke builderCelCompilerdanCelRuntime. - Python: Impor
cel_expr_python.ext.ext_mathdan gunakanExtMath()dicel.NewEnv(extensions=[...]).
Library Protos
| Fungsi | Deskripsi | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
proto.getExt |
Mendapatkan kolom ekstensi proto2, atau default jika tidak ditetapkan. Tanda tangan: proto.getExt(msg, extName) -> TContoh: proto.getExt(msg, google.api.expr.test.int32_ext) |
✓ (v0.13.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
proto.hasExt |
Memeriksa apakah kolom ekstensi proto2 disetel. Tanda tangan: proto.hasExt(msg, extName) -> boolContoh: proto.hasExt(msg, google.api.expr.test.int32_ext) |
✓ (v0.13.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
Cara Mengaktifkan
- Go: Teruskan
ext.Protos()kecel.NewEnv(). - C++: Tambahkan
ProtoExtCompilerLibrary()keCompilerBuilder. (Runtime ditangani secara otomatis). - Java: Tambahkan
CelExtensions.protos()ke builderCelCompilerdanCelRuntime. - Python: Impor
cel_expr_python.ext.ext_protodan gunakanExtProto()dicel.NewEnv(extensions=[...]).
Library Daftar
| Fungsi | Deskripsi | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
distinct |
Menampilkan elemen yang berbeda. Tanda tangan: list.distinct() -> listContoh: [1, 2, 2].distinct() // [1, 2] |
✓ (v0.22.0) | ✓ (v0.11.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
flatten |
Meratakan daftar bertingkat. Tanda tangan: list.flatten([depth]) -> listContoh: [[1], [2, 3]].flatten() // [1, 2, 3] |
✓ (v0.22.0) | ✓ (v0.11.0) | ✓ (v0.7.1) | ✓ (v0.1.1) | ✗ |
lists.range |
Menampilkan daftar bilangan bulat [0, ..., n-1].Tanda Tangan: lists.range(int) -> list(int)Contoh: lists.range(3) // [0, 1, 2] |
✓ (v0.22.0) | ✓ (v0.11.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
reverse |
Membalikkan daftar. Tanda tangan: list.reverse() -> listContoh: [1, 2].reverse() // [2, 1] |
✓ (v0.22.0) | ✓ (v0.11.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
slice |
Menampilkan sub-daftar (start inklusif, end eksklusif). Tanda tangan: list.slice(start, end) -> listContoh: [1, 2, 3].slice(1, 3) // [2, 3] |
✓ (v0.17.0) | ✓ (v0.11.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
sort |
Mengurutkan daftar elemen yang dapat dibandingkan. Tanda Tangan: list.sort() -> listContoh: [3, 1, 2].sort() // [1, 2, 3] |
✓ (v0.22.0) | ✓ (v0.11.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
sortBy |
Mengurutkan daftar berdasarkan kunci yang dievaluasi dari ekspresi. Tanda tangan: list.sortBy(var, expr) -> listContoh: [{"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 |
Menampilkan elemen pertama sebagai opsional. Memerlukan perpanjangan waktu Opsional. Tanda tangan: list.first() -> optionalContoh: [1, 2].first() // optional(1) |
✓ (v0.23.0) | ✓ (v0.15.0) | ✓ (v0.11.0) | ✓ (v0.1.2) | ✗ |
last |
Menampilkan elemen terakhir sebagai opsional. Memerlukan perpanjangan waktu Opsional. Tanda tangan: list.last() -> optionalContoh: [1, 2].last() // optional(2) |
✓ (v0.23.0) | ✓ (v0.15.0) | ✓ (v0.11.0) | ✓ (v0.1.2) | ✗ |
Cara Mengaktifkan
- Go: Teruskan
ext.Lists()kecel.NewEnv(). - C++:
- Compiler: Tambahkan
ListsCompilerLibrary()keCompilerBuilder. - Runtime: Panggil
RegisterListsFunctions()diFunctionRegistrydanRegisterListsMacros()diMacroRegistry.
- Compiler: Tambahkan
- Java: Tambahkan
CelExtensions.lists()ke builderCelCompilerdanCelRuntime. - Python: Aktifkan melalui
cel.EnvConfigdengan menambahkanlistske daftarextensions.
Library Set
| Fungsi | Deskripsi | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
sets.contains |
Memeriksa apakah list1 berisi semua elemen list2. Tanda tangan: sets.contains(list1, list2) -> boolContoh: sets.contains([1, 2], [1]) // true |
✓ (v0.15.0) | ✓ (v0.10.0) | ✓ (v0.6.0) | ✓ (v0.1.1) | ✗ |
sets.equivalent |
Memeriksa apakah daftar setara (berisi elemen unik yang sama). Tanda tangan: sets.equivalent(list1, list2) -> boolContoh: sets.equivalent([1, 2], [2, 1, 1]) // true |
✓ (v0.15.0) | ✓ (v0.10.0) | ✓ (v0.6.0) | ✓ (v0.1.1) | ✗ |
sets.intersects |
Memeriksa apakah daftar memiliki minimal satu elemen yang sama. Tanda Tangan: sets.intersects(list1, list2) -> boolContoh: sets.intersects([1, 2], [2, 3]) // true |
✓ (v0.15.0) | ✓ (v0.10.0) | ✓ (v0.6.0) | ✓ (v0.1.1) | ✗ |
Cara Mengaktifkan
- Go: Teruskan
ext.Sets()kecel.NewEnv(). - C++:
- Compiler: Tambahkan
SetsCompilerLibrary()keCompilerBuilder. - Waktu proses: Hubungi
RegisterSetsFunctions()diFunctionRegistry.
- Compiler: Tambahkan
- Java: Tambahkan
CelExtensions.sets()ke builderCelCompilerdanCelRuntime. - Python: Aktifkan melalui
cel.EnvConfigdengan menambahkansetske daftarextensions.
Library String
| Fungsi | Deskripsi | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
charAt |
Menampilkan karakter pada indeks. Tanda tangan: string.charAt(int) -> stringContoh: "hello".charAt(1) // "e" |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
indexOf |
Menampilkan indeks kemunculan pertama substring, atau -1. Tanda Tangan: string.indexOf(substr, [start]) -> intContoh: "hello".indexOf("l") // 2 |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
lastIndexOf |
Menampilkan indeks kemunculan terakhir substring, atau -1. Tanda tangan: string.lastIndexOf(substr, [end]) -> intContoh: "hello".lastIndexOf("l") // 3 |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
join |
Menggabungkan string. Tanda tangan: list(string).join([separator]) -> stringContoh: ["a", "b"].join("-") // "a-b" |
✓ (v0.10.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
split |
Memisahkan string berdasarkan pemisah. Tanda tangan: string.split(separator, [limit]) -> list(string)Contoh: "a-b".split("-") // ["a", "b"] |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
substring |
Menampilkan substring (mulai inklusif, akhir eksklusif). Tanda tangan: string.substring(start, [end]) -> stringContoh: "hello".substring(1, 3) // "el" |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
trim |
Memangkas spasi kosong Unicode. Tanda tangan: string.trim() -> stringContoh: " hello ".trim() // "hello" |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
replace |
Mengganti kemunculan lama dengan yang baru. Tanda Tangan: string.replace(old, new, [limit]) -> stringContoh: "hello".replace("l", "w") // "hewwo" |
✓ (v0.4.0) | ✓ (v0.10.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
reverse |
Membalikkan poin kode Unicode. Tanda tangan: string.reverse() -> stringContoh: "abc".reverse() // "cba" |
✓ (v0.18.0) | ✓ (v0.14.0) | ✓ (v0.13.0) | ✓ (v0.1.1) | ✗ |
lowerAscii |
Mengonversi karakter ASCII menjadi huruf kecil. Tanda Tangan: string.lowerAscii() -> stringContoh: "Hello".lowerAscii() // "hello" |
✓ (v0.6.0) | ✓ (v0.11.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
upperAscii |
Mengonversi karakter ASCII menjadi huruf besar. Tanda tangan: string.upperAscii() -> stringContoh: "Hello".upperAscii() // "HELLO" |
✓ (v0.6.0) | ✓ (v0.11.0) | ✓ (v0.2.0) | ✓ (v0.1.1) | ✗ |
quote |
Meng-escape string untuk pencetakan yang aman. Tanda tangan: strings.quote(string) -> stringContoh: strings.quote("a\tb") // "\"a\\tb\"" |
✓ (v0.14.0) | ✓ (v0.14.0) | ✓ (v0.13.0) | ✓ (v0.1.1) | ✗ |
Cara Mengaktifkan
- Go: Teruskan
ext.Strings()kecel.NewEnv(). - C++:
- Compiler: Tambahkan
StringsCompilerLibrary()keCompilerBuilder. - Waktu proses: Hubungi
RegisterStringsFunctions()diFunctionRegistry.
- Compiler: Tambahkan
- Java: Tambahkan
CelExtensions.strings()ke builderCelCompilerdanCelRuntime. - Python: Impor
cel_expr_python.ext.ext_stringsdan gunakanExtStrings()dicel.NewEnv(extensions=[...]).
Pustaka Ekspresi Reguler
| Fungsi | Deskripsi | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
regex.replace |
Mengganti kecocokan dengan string pengganti (mendukung referensi balik). Tanda tangan: regex.replace(target, pat, repl, [limit]) -> stringContoh: 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 |
Menampilkan kecocokan pertama pola (harus memiliki satu grup tangkapan). Tanda tangan: regex.extract(target, pat) -> optional(string)Contoh: regex.extract("a123b", r"(\d+)") // optional("123") |
✓ (v0.25.1) | ✓ (v0.13.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
regex.extractAll |
Menampilkan semua kecocokan pola (harus memiliki satu grup tangkapan). Tanda Tangan: regex.extractAll(target, pat) -> list(string)Contoh: regex.extractAll("a1b2", r"(\d+)") // ["1", "2"] |
✓ (v0.25.1) | ✓ (v0.13.0) | ✓ (v0.10.1) | ✓ (v0.1.1) | ✗ |
Cara Mengaktifkan
- Go: Teruskan
ext.Regex()kecel.NewEnv(). - C++:
- Compiler: Tambahkan
RegexExtCompilerLibrary()keCompilerBuilder. - Waktu proses: Hubungi
RegisterRegexExtensionFunctions()diFunctionRegistry.
- Compiler: Tambahkan
- Java: Tambahkan
CelExtensions.regex()ke builderCelCompilerdanCelRuntime. - Python: Aktifkan melalui
cel.EnvConfigdengan menambahkanregexdanoptionalke daftarextensions.
Pemahaman Dua Variabel
| Makro | Deskripsi | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
all |
Memperpendek AND logika melalui kunci/indeks dan nilai. Tanda tangan: list.all(i, v, pred) -> boolmap.all(k, v, pred) -> boolContoh: [1, 2].all(i, v, v > 0) // true |
✓ (v0.22.0) | ✓ (v0.14.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
exists |
Memperpendek OR logika melalui kunci/indeks dan nilai. Tanda Tangan: list.exists(i, v, pred) -> boolmap.exists(k, v, pred) -> boolContoh: [1, 2].exists(i, v, v == 2) // true |
✓ (v0.22.0) | ✓ (v0.14.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
existsOne |
Memeriksa apakah tepat satu pasangan memenuhi predikat. Tanda tangan: list.existsOne(i, v, pred) -> boolmap.existsOne(k, v, pred) -> boolContoh: [1, 2].existsOne(i, v, v == 2) // true |
✓ (v0.22.0) | ✓ (v0.14.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
transformList |
Mengubah/memfilter daftar/peta menjadi daftar. Tanda tangan: list.transformList(i, v, [filter], transform) -> listmap.transformList(k, v, [filter], transform) -> listContoh: [1, 2].transformList(i, v, v * 2) // [2, 4] |
✓ (v0.22.0) | ✓ (v0.14.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
transformMap |
Mengubah nilai daftar/peta menjadi peta (kunci tetap). Tanda tangan: list.transformMap(i, v, [filter], transform) -> mapmap.transformMap(k, v, [filter], transform) -> mapContoh: [1, 2].transformMap(i, v, v * 2) // {0: 2, 1: 4} |
✓ (v0.22.0) | ✓ (v0.14.0) | ✓ (v0.11.0) | ✓ (v0.1.1) | ✗ |
transformMapEntry |
Berubah menjadi peta. Tanda tangan: list.transformMapEntry(i, v, [filter], transform_entry) -> mapmap.transformMapEntry(k, v, [filter], transform_entry) -> mapContoh: [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) | ✗ |
Cara Mengaktifkan
- Go: Teruskan
ext.TwoVarComprehensions()kecel.NewEnv(). - C++:
- Compiler: Tambahkan
ComprehensionsV2CompilerLibrary()keCompilerBuilder. - Runtime: Panggil
RegisterComprehensionsV2Functions()diFunctionRegistrydanRegisterComprehensionsV2Macros()diMacroRegistry.
- Compiler: Tambahkan
- Java: Tambahkan
CelExtensions.comprehensions()ke builderCelCompilerdanCelRuntime. - Python: Aktifkan melalui
cel.EnvConfigdengan menambahkantwo-var-comprehensionske daftarextensions.
Native Types Library
| Fitur | Deskripsi | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
| Struktur Native | Mendaftarkan dan membuat instance jenis native host (struct Go / POJO Java) di CEL. Contoh: Account{id: 123} (POJO Java yang dibuat instance di CEL) |
✓ (v0.13.0) | ✗ | ✓ (v0.13.0) | ✗ | ✗ |
Cara Mengaktifkan
- Go: Teruskan
ext.NativeTypes(...)(menyediakan jenis refleksi) kecel.NewEnv(). - C++: Tidak didukung.
- Java: Tambahkan
CelExtensions.nativeTypes()(menyediakan class Java) ke builderCelCompilerdanCelRuntime. - Python: Tidak didukung.
Library Jaringan
Library Jaringan menyediakan fungsi untuk mengurai, memvalidasi, dan memanipulasi alamat IP dan blok CIDR.
| Fungsi | Deskripsi | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
ip |
Mengurai string menjadi alamat IP, atau mengekstrak IP dari CIDR. Tanda Tangan: ip(string) -> IPCIDR.ip() -> IPContoh: ip("192.168.0.1")cidr("192.168.0.0/24").ip() |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isIP |
Memeriksa apakah string adalah alamat IP yang valid. Tanda Tangan: isIP(string) -> boolContoh: isIP("192.168.0.1") // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
ip.isCanonical |
Memeriksa apakah string alamat IP dalam format kanoniknya. Tanda Tangan: ip.isCanonical(string) -> boolContoh: ip.isCanonical("192.168.0.1") // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
cidr |
Mengurai string menjadi blok CIDR. Tanda tangan: cidr(string) -> CIDRContoh: cidr("192.168.0.0/24") |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isCIDR |
Memeriksa apakah string adalah blok CIDR yang valid. Tanda tangan: isCIDR(string) -> boolContoh: isCIDR("192.168.0.0/24") // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
containsIP |
Memeriksa apakah blok CIDR berisi alamat IP. Tanda tangan: CIDR.containsIP(IP) -> boolCIDR.containsIP(string) -> boolContoh: cidr("192.168.0.0/24").containsIP(ip("192.168.0.1")) // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
containsCIDR |
Memeriksa apakah blok CIDR berisi blok CIDR lain. Tanda Tangan: CIDR.containsCIDR(CIDR) -> boolCIDR.containsCIDR(string) -> boolContoh: cidr("192.168.0.0/16").containsCIDR(cidr("192.168.1.0/24")) // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
family |
Menampilkan keluarga IP (4 untuk IPv4, 6 untuk IPv6). Tanda Tangan: IP.family() -> intContoh: ip("192.168.0.1").family() // 4 |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isGlobalUnicast |
Memeriksa apakah IP adalah alamat unicast global. Tanda tangan: IP.isGlobalUnicast() -> boolContoh: ip("192.168.0.1").isGlobalUnicast() // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isLinkLocalMulticast |
Memeriksa apakah IP adalah alamat multicast link-local. Tanda tangan: IP.isLinkLocalMulticast() -> boolContoh: ip("224.0.0.1").isLinkLocalMulticast() // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isLinkLocalUnicast |
Memeriksa apakah IP adalah alamat unicast link-local. Tanda tangan: IP.isLinkLocalUnicast() -> boolContoh: ip("169.254.0.1").isLinkLocalUnicast() // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isLoopback |
Memeriksa apakah IP adalah alamat loopback. Tanda tangan: IP.isLoopback() -> boolContoh: ip("127.0.0.1").isLoopback() // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isMask |
Memeriksa apakah CIDR adalah subnet mask yang valid. Tanda tangan: CIDR.isMask() -> boolContoh: cidr("255.255.255.0/24").isMask() // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
isUnspecified |
Memeriksa apakah IP adalah alamat yang tidak ditentukan (misalnya, 0.0.0.0).Tanda tangan: IP.isUnspecified() -> boolContoh: ip("0.0.0.0").isUnspecified() // true |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
masked |
Menampilkan blok CIDR yang di-masking. Tanda Tangan: CIDR.masked() -> CIDRContoh: cidr("192.168.0.1/24").masked() // 192.168.0.0/24 |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
prefixLength |
Menampilkan panjang awalan blok CIDR. Tanda Tangan: CIDR.prefixLength() -> intContoh: cidr("192.168.0.0/24").prefixLength() // 24 |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
string |
Mengonversi IP atau CIDR menjadi string. Tanda tangan: string(IP) -> stringstring(CIDR) -> stringContoh: string(ip("192.168.0.1")) // "192.168.0.1" |
✓ (v0.29.0) | ✗ | ✗ | ✗ | ✗ |
Cara Mengaktifkan
- Go: Teruskan
ext.Network()kecel.NewEnv(). - C++: Tidak didukung.
- Java: Tidak didukung.
- Python: Tidak didukung.
5. Fitur Lanjutan
Ringkasan Fitur Lanjutan
| Fitur | Deskripsi | Go | C++ | Java | Python | C |
|---|---|---|---|---|---|---|
| Evaluasi Sebagian | Mengevaluasi dengan input yang tidak ada; menampilkan nilai tidak diketahui atau ekspresi yang disederhanakan. | ✓³ | ✓⁴ | ✓⁴ | ✗ | ✗ |
| Evaluasi Asinkron | Eksekusi serentak fungsi ekstensi yang tidak memblokir. | ✓⁵ | ✗ | ✓⁶ | ✗ | ✗ |
| Validator AST | Pemeriksaan analisis statis pada AST yang Diperiksa setelah pemeriksaan jenis. | ✓ | ✓ | ✓ | ✗ | ✗ |
| Pengoptimal AST | Penulisan ulang AST (pelipatan konstanta, penyisipan, CSE) untuk meningkatkan performa. | ✓ | ✓ | ✓ | ✗ | ✗ |
| Pengompilasi Kebijakan CEL | Mengompilasi struktur kebijakan berbasis YAML menjadi AST CEL standar. | ✓ | ✓ | ✓ | ✗ | ✗ |
³ Go mendukung pembuatan Residual AST (AST yang di-pruning). ⁴ C++ dan Java mendukung
pengembalian UnknownSet / CelUnknownSet saat runtime, tetapi tidak mengekspos API publik
untuk pembuatan AST residual. ⁵ Go menggunakan AsyncBinding / AsyncOp yang menampilkan saluran. ⁶ Java menggunakan CelAsyncRuntime yang menampilkan ListenableFuture.
Evaluasi Parsial (Tidak Diketahui)
Evaluasi parsial memungkinkan evaluasi ekspresi saat hanya subset variabel input (argumen) yang diketahui. Daripada gagal, evaluasi menghasilkan hasil yang menunjukkan apa yang kurang, atau ekspresi yang disederhanakan.
- Go: Dukungan penuh. Memungkinkan penentuan
PartialActivationdengan pola atribut yang tidak diketahui. Evaluasi menampilkan nilaitypes.Unknown. Go mendukung pembuatan AST Sisa (Env.ResidualAst) yang merupakan AST yang telah dipangkas dan disederhanakan yang hanya berisi bagian ekspresi yang tidak dapat dievaluasi. - C++: Mendukung nilai
Unknown. Pola atribut yang tidak diketahui dikonfigurasi melaluiActivation::set_unknown_attribute_patterns. Evaluasi menampilkanUnknownSet. API publik saat ini tidak mengekspos pembuatan AST sisa. - Java: Mendukung evaluasi parsial melalui
PartialVarsyang diteruskan keProgram.eval(). Evaluasi menampilkanCelUnknownSet. API publik saat ini tidak mengekspos pembuatan AST residual. - Python / C: Tidak ada dukungan native.
Evaluasi Asinkron
Evaluasi asinkron memungkinkan ekspresi CEL memanggil fungsi yang dieksekusi secara asinkron (misalnya, membuat RPC atau kueri database) dan memblokir evaluasi hingga hasilnya tersedia, tanpa memblokir thread eksekusi utama.
- Go: Mendukung penggantian fungsi asinkron melalui
AsyncBindingdanAsyncOp. Fungsi asinkron menampilkan channel Go (<-chan ref.Val), dan interpreter mengelola eksekusi dan sinkronisasi serentak. - Java: Mendukung evaluasi asinkron melalui
CelAsyncRuntimedanAsyncProgram. Library ini menggunakanListenableFutureuntuk merepresentasikan nilai yang tertunda dan secara otomatis mendorong evaluasi hingga selesai saat future diselesaikan. - C++ / Python / C: Tidak ada dukungan bawaan.
Validator AST
Validator melakukan analisis statis pada AST yang Diperiksa setelah pemeriksaan jenis untuk menerapkan batasan khusus domain sebelum program dieksekusi.
- Go: Mendukung antarmuka
ASTValidator. Validator kanonis mencakupcel.validator.duration,cel.validator.timestamp,cel.validator.matches(regex),cel.validator.homogeneous_literals, dancel.validator.comprehension_nesting_limit. - C++: Mendukung
cel::Validator. Validasi kanonis mencakupAstDepthValidator,ComprehensionNestingLimitValidator,DurationLiteralValidator,HomogeneousLiteralValidator,MatchesValidator, danTimestampLiteralValidator. - Java: Mendukung
CelValidatordanCelAstValidator. Validator kanonis mencakupAstDepthLimitValidator,ComprehensionNestingLimitValidator,DurationLiteralValidator,HomogeneousLiteralValidator,RegexLiteralValidator, danTimestampLiteralValidator. - Python / C: Tidak ada dukungan langsung.
Pengoptimal AST
Pengoptimal menulis ulang AST untuk meningkatkan performa eksekusi. Pengoptimal termasuk dalam salah satu dari dua kategori: pengoptimal statis dan runtime. C++, Java, dan Go mendukung pengoptimalan runtime. CEL Java dan Go juga mendukung pengoptimal statis. Pengoptimalan umum mencakup pelipatan konstanta (pra-evaluasi sub-ekspresi dengan input konstanta) dan penghapusan subekspresi umum (CSE).
- Go: Mendukung pelipatan AST selama kompilasi/perencanaan.
- C++: Mendukung pelipatan konstanta melalui ekstensi
cel::extensions::EnableConstantFoldingpada waktu perencanaan. - Java: Mendukung antarmuka
CelOptimizer. Pengoptimal kanonis mencakupConstantFoldingOptimizer(yang dapat melipat cabang short-circuit dengan mensimulasikan evaluasi parsial),InliningOptimizer, danSubexpressionOptimizer(CSE). - Python / C: Tidak ada dukungan langsung.
Compiler Kebijakan CEL
Kebijakan CEL adalah format berbasis YAML untuk menyusun beberapa ekspresi CEL bersama dengan variabel, blok kecocokan, output bersyarat, dan aturan bertingkat. Dirancang untuk mesin kebijakan yang kompleks (seperti Kontrol Penerimaan Kubernetes) yang membuat ekspresi CEL tunggal menjadi tidak dapat dibaca.
Pengompilasi Kebijakan mengompilasi kebijakan YAML ini menjadi satu AST CEL standar, yang berarti kebijakan tersebut sepenuhnya kompatibel dengan runtime CEL standar dan mewarisi semua jaminan performa dan keamanan.
- Go: Didukung melalui
third_party/cel/go/policy. - C++: Didukung melalui
third_party/cel/cpp/policy. - Java: Didukung melalui
third_party/java/cel/policy. - Python / C: Tidak didukung secara langsung.